Initial commit: Telegram Management System
Some checks failed
Deploy / deploy (push) Has been cancelled

Full-stack web application for Telegram management
- Frontend: Vue 3 + Vben Admin
- Backend: NestJS
- Features: User management, group broadcast, statistics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
你的用户名
2025-11-04 15:37:50 +08:00
commit 237c7802e5
3674 changed files with 525172 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn,
Index,
} from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';
import { SmsPlatform } from './sms-platform.entity';
import { TgAccount } from './tg-account.entity';
export enum SmsStatus {
PENDING = 'pending',
WAITING = 'waiting',
RECEIVED = 'received',
COMPLETE = 'complete',
CANCEL = 'cancel',
TIMEOUT = 'timeout',
}
@Entity('sms_records')
@Index('idx_order_id', ['orderId'])
@Index('idx_platform_code', ['platformCode'])
@Index('idx_phone', ['phone'])
@Index('idx_status', ['status'])
@Index('idx_request_time', ['requestTime'])
@Index('idx_tg_account_id', ['tgAccountId'])
export class SmsRecord {
@ApiProperty({ description: '记录ID' })
@PrimaryGeneratedColumn()
id: number;
@ApiProperty({ description: '订单ID' })
@Column({
type: 'varchar',
length: 100,
unique: true,
comment: '订单ID'
})
orderId: string;
@ApiProperty({ description: '平台代码' })
@Column({
type: 'varchar',
length: 50,
comment: '平台代码'
})
platformCode: string;
@ApiProperty({ description: '手机号码' })
@Column({
type: 'varchar',
length: 20,
comment: '手机号码'
})
phone: string;
@ApiProperty({ description: '国家代码' })
@Column({
type: 'varchar',
length: 10,
nullable: true,
comment: '国家代码'
})
country?: string;
@ApiProperty({ description: '服务类型' })
@Column({
type: 'varchar',
length: 50,
default: 'tg',
comment: '服务类型'
})
service: string;
@ApiProperty({ description: '验证码' })
@Column({
type: 'varchar',
length: 10,
nullable: true,
comment: '验证码'
})
smsCode?: string;
@ApiProperty({ description: '价格' })
@Column({
type: 'decimal',
precision: 10,
scale: 4,
default: 0,
comment: '价格'
})
price: number;
@ApiProperty({ description: '货币单位' })
@Column({
type: 'varchar',
length: 10,
default: 'USD',
comment: '货币单位'
})
currency: string;
@ApiProperty({ description: '状态' })
@Column({
type: 'enum',
enum: SmsStatus,
default: SmsStatus.PENDING,
comment: '状态',
})
status: SmsStatus;
@ApiProperty({ description: '请求时间' })
@Column({
type: 'datetime',
default: () => 'CURRENT_TIMESTAMP',
comment: '请求时间'
})
requestTime: Date;
@ApiProperty({ description: '接收时间' })
@Column({
type: 'datetime',
nullable: true,
comment: '接收时间'
})
receiveTime?: Date;
@ApiProperty({ description: '完成时间' })
@Column({
type: 'datetime',
nullable: true,
comment: '完成时间'
})
completeTime?: Date;
@ApiProperty({ description: '重试次数' })
@Column({
type: 'int',
default: 0,
comment: '重试次数'
})
retryCount: number;
@ApiProperty({ description: '错误信息' })
@Column({
type: 'text',
nullable: true,
comment: '错误信息'
})
errorMessage?: string;
@ApiProperty({ description: '关联TG账号ID' })
@Column({
type: 'int',
nullable: true,
comment: '关联TG账号ID'
})
tgAccountId?: number;
@ApiProperty({ description: '操作员' })
@Column({
type: 'varchar',
length: 50,
nullable: true,
comment: '操作员'
})
operator?: string;
@ApiProperty({ description: '备注' })
@Column({
type: 'text',
nullable: true,
comment: '备注'
})
remark?: string;
@ApiProperty({ description: '创建时间' })
@CreateDateColumn({ comment: '创建时间' })
createdAt: Date;
@ApiProperty({ description: '更新时间' })
@UpdateDateColumn({ comment: '更新时间' })
updatedAt: Date;
// 关联关系
@ManyToOne(() => SmsPlatform, platform => platform.smsRecords)
@JoinColumn({ name: 'platformCode', referencedColumnName: 'platformCode' })
platform: SmsPlatform;
@ManyToOne(() => TgAccount)
@JoinColumn({ name: 'tgAccountId' })
tgAccount?: TgAccount;
// 计算属性
get isCompleted(): boolean {
return this.status === SmsStatus.COMPLETE;
}
get isFailed(): boolean {
return [SmsStatus.CANCEL, SmsStatus.TIMEOUT].includes(this.status);
}
get duration(): number {
if (!this.completeTime) return 0;
return this.completeTime.getTime() - this.requestTime.getTime();
}
get isExpired(): boolean {
if (this.status !== SmsStatus.WAITING) return false;
const now = new Date();
const expireTime = new Date(this.requestTime.getTime() + 10 * 60 * 1000); // 10分钟超时
return now > expireTime;
}
}