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>
218 lines
4.7 KiB
TypeScript
218 lines
4.7 KiB
TypeScript
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;
|
|
}
|
|
} |