feat(challenges): 更新自定义挑战功能,支持时间戳转换及数据模型调整

This commit is contained in:
richarjiang
2025-11-26 10:43:42 +08:00
parent 93b4fcf553
commit 029b8f46b9
4 changed files with 918 additions and 35 deletions

View File

@@ -166,8 +166,8 @@ export class ChallengesService {
requirementLabel: challenge.requirementLabel,
status,
unit: challenge.progressUnit,
startAt: challenge.startAt,
endAt: challenge.endAt,
startAt: new Date(challenge.startAt).getTime(),
endAt: new Date(challenge.endAt).getTime(),
participantsCount: participantsCountMap.get(challenge.id) ?? 0,
rankingDescription: challenge.rankingDescription,
highlightTitle: challenge.highlightTitle,
@@ -617,7 +617,7 @@ export class ChallengesService {
}
private computeStatus(startAt: number, endAt: number): ChallengeStatus {
private computeStatus(startAt: Date | number, endAt: Date | number): ChallengeStatus {
const now = dayjs();
const start = dayjs(startAt);
const end = dayjs(endAt);
@@ -822,6 +822,15 @@ export class ChallengesService {
throw new BadRequestException('结束时间必须晚于开始时间');
}
// 将毫秒时间戳转换为 Date 对象,以匹配数据库 DATETIME 类型
const startAtDate = new Date(dto.startAt);
const endAtDate = new Date(dto.endAt);
// 验证日期是否有效
if (isNaN(startAtDate.getTime()) || isNaN(endAtDate.getTime())) {
throw new BadRequestException('无效的时间戳');
}
// 检查创建频率限制(每天最多创建 5 个)
const recentCount = await this.challengeModel.count({
where: {
@@ -839,13 +848,14 @@ export class ChallengesService {
// 生成分享码
const shareCode = await this.generateUniqueShareCode();
// 创建挑战
const challenge = await this.challengeModel.create({
title: dto.title,
type: dto.type,
image: dto.image || null,
startAt: dto.startAt,
endAt: dto.endAt,
startAt: startAtDate,
endAt: endAtDate,
periodLabel: dto.periodLabel || null,
durationLabel: dto.durationLabel,
requirementLabel: dto.requirementLabel,
@@ -854,9 +864,9 @@ export class ChallengesService {
progressUnit: dto.progressUnit || '天',
minimumCheckInDays: dto.minimumCheckInDays,
rankingDescription: dto.rankingDescription || '连续打卡榜',
highlightTitle: dto.highlightTitle || '坚持挑战',
highlightSubtitle: dto.highlightSubtitle || '养成好习惯',
ctaLabel: dto.ctaLabel || '立即加入',
highlightTitle: dto.title,
highlightSubtitle: dto.summary || '养成好习惯',
ctaLabel: '立即加入',
source: ChallengeSource.CUSTOM,
creatorId: userId,
shareCode,
@@ -865,7 +875,10 @@ export class ChallengesService {
challengeState: ChallengeState.ACTIVE,
});
this.winstonLogger.info('创建自定义挑战成功', {
// 创建者自动加入挑战
await this.joinChallenge(userId, challenge.id);
this.winstonLogger.info('创建自定义挑战成功,创建者已自动加入', {
context: 'createCustomChallenge',
userId,
challengeId: challenge.id,
@@ -1115,8 +1128,8 @@ export class ChallengesService {
creatorId: challenge.creatorId,
shareCode: challenge.shareCode,
image: challenge.image,
startAt: challenge.startAt,
endAt: challenge.endAt,
startAt: new Date(challenge.startAt).getTime(),
endAt: new Date(challenge.endAt).getTime(),
periodLabel: challenge.periodLabel,
durationLabel: challenge.durationLabel,
requirementLabel: challenge.requirementLabel,

View File

@@ -77,23 +77,6 @@ export class CreateCustomChallengeDto {
@MaxLength(255)
rankingDescription?: string;
@ApiProperty({ description: '高亮标题', example: '坚持21天', required: false })
@IsString()
@IsOptional()
@MaxLength(255)
highlightTitle?: string;
@ApiProperty({ description: '高亮副标题', example: '养成好习惯', required: false })
@IsString()
@IsOptional()
@MaxLength(255)
highlightSubtitle?: string;
@ApiProperty({ description: 'CTA 按钮文字', example: '立即加入', required: false })
@IsString()
@IsOptional()
@MaxLength(128)
ctaLabel?: string;
@ApiProperty({ description: '是否公开(可通过分享码加入)', default: true })
@IsBoolean()

View File

@@ -55,18 +55,18 @@ export class Challenge extends Model {
declare image: string;
@Column({
type: DataType.BIGINT,
type: DataType.DATE,
allowNull: false,
comment: '挑战开始时间(时间戳)',
comment: '挑战开始时间',
})
declare startAt: number;
declare startAt: Date;
@Column({
type: DataType.BIGINT,
type: DataType.DATE,
allowNull: false,
comment: '挑战结束时间(时间戳)',
comment: '挑战结束时间',
})
declare endAt: number;
declare endAt: Date;
@Column({
type: DataType.STRING(128),
@@ -142,7 +142,7 @@ export class Challenge extends Model {
@Column({
type: DataType.STRING(128),
allowNull: false,
allowNull: true,
comment: 'CTA 按钮文字',
})
declare ctaLabel: string;