feat(challenges): 新增挑战功能模块及完整接口实现
- 新增挑战列表、详情、加入/退出、进度上报等 REST 接口 - 定义 Challenge / ChallengeParticipant 数据模型与状态枚举 - 提供排行榜查询与用户排名计算 - 包含接口文档与数据库初始化脚本
This commit is contained in:
123
src/challenges/models/challenge.model.ts
Normal file
123
src/challenges/models/challenge.model.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { Table, Column, DataType, Model, HasMany } from 'sequelize-typescript';
|
||||
import { ChallengeParticipant } from './challenge-participant.model';
|
||||
|
||||
export enum ChallengeStatus {
|
||||
UPCOMING = 'upcoming',
|
||||
ONGOING = 'ongoing',
|
||||
EXPIRED = 'expired',
|
||||
}
|
||||
|
||||
@Table({
|
||||
tableName: 't_challenges',
|
||||
underscored: true,
|
||||
})
|
||||
export class Challenge extends Model {
|
||||
@Column({
|
||||
type: DataType.CHAR(36),
|
||||
defaultValue: DataType.UUIDV4,
|
||||
primaryKey: true,
|
||||
})
|
||||
declare id: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '挑战标题',
|
||||
})
|
||||
declare title: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(512),
|
||||
allowNull: true,
|
||||
comment: '挑战封面图',
|
||||
})
|
||||
declare image: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.DATE,
|
||||
allowNull: false,
|
||||
comment: '挑战开始时间',
|
||||
})
|
||||
declare startAt: Date;
|
||||
|
||||
@Column({
|
||||
type: DataType.DATE,
|
||||
allowNull: false,
|
||||
comment: '挑战结束时间',
|
||||
})
|
||||
declare endAt: Date;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(128),
|
||||
allowNull: true,
|
||||
comment: '周期标签,例如「21天挑战」',
|
||||
})
|
||||
declare periodLabel: string | null;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(128),
|
||||
allowNull: false,
|
||||
comment: '持续时间标签,例如「持续21天」',
|
||||
})
|
||||
declare durationLabel: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '挑战要求标签,例如「每日练习 1 次」',
|
||||
})
|
||||
declare requirementLabel: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.TEXT,
|
||||
allowNull: true,
|
||||
comment: '挑战概要说明',
|
||||
})
|
||||
declare summary: string | null;
|
||||
|
||||
@Column({
|
||||
type: DataType.INTEGER,
|
||||
allowNull: false,
|
||||
comment: '挑战目标值(例如需要完成的天数)',
|
||||
})
|
||||
declare targetValue: number;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(64),
|
||||
allowNull: false,
|
||||
defaultValue: '天',
|
||||
comment: '进度单位,用于展示排行榜指标',
|
||||
})
|
||||
declare progressUnit: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(255),
|
||||
allowNull: true,
|
||||
comment: '排行榜描述,例如「连续打卡榜」',
|
||||
})
|
||||
declare rankingDescription: string | null;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '高亮标题',
|
||||
})
|
||||
declare highlightTitle: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '高亮副标题',
|
||||
})
|
||||
declare highlightSubtitle: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(128),
|
||||
allowNull: false,
|
||||
comment: 'CTA 按钮文字',
|
||||
})
|
||||
declare ctaLabel: string;
|
||||
|
||||
@HasMany(() => ChallengeParticipant)
|
||||
declare participants?: ChallengeParticipant[];
|
||||
}
|
||||
Reference in New Issue
Block a user