feat(badges): 更新勋章系统,支持UUID作为勋章ID类型

feat(challenges): 优化进度报告,添加睡眠挑战勋章授予逻辑
fix(push-notifications): 修复推送测试服务初始化返回值问题
This commit is contained in:
2025-11-15 23:25:02 +08:00
parent 9c7bcb6083
commit 1c033cd801
4 changed files with 46 additions and 33 deletions

View File

@@ -473,38 +473,51 @@ export class ChallengesService {
}
}
this.winstonLogger.info('progress report updated', {
context: 'reportProgress',
userId,
challengeId,
reportDate,
reportedValue,
})
// 🎖️ 检查是否为睡眠挑战且完成了第一次打卡,授予 goodSleep 勋章
if (challenge.type === ChallengeType.SLEEP) {
this.winstonLogger.info('检查是否为睡眠挑战且完成了第一次打卡,授予 goodSleep 勋章', {
context: 'reportProgress',
userId,
challengeId,
badgeCode: 'goodSleep',
})
try {
await this.badgeService.awardBadge(userId, 'goodSleep', {
source: BadgeSource.CHALLENGE,
sourceId: challengeId,
metadata: {
challengeName: challenge.title,
challengeType: challenge.type,
},
});
this.winstonLogger.info('授予睡眠挑战勋章成功', {
context: 'reportProgress',
userId,
challengeId,
badgeCode: 'goodSleep',
});
} catch (error) {
// 勋章授予失败不应影响主流程,仅记录日志
this.winstonLogger.error('授予睡眠挑战勋章失败', {
context: 'reportProgress',
userId,
challengeId,
error: error instanceof Error ? error.message : '未知错误',
});
}
}
if (report.reportedValue >= reportCompletedValue && !dayjs(participant.lastProgressAt).isSame(dayjs(), 'd')) {
participant.progressValue++
participant.lastProgressAt = now;
// 🎖️ 检查是否为睡眠挑战且完成了第一次打卡,授予 goodSleep 勋章
if (challenge.type === ChallengeType.SLEEP) {
try {
await this.badgeService.awardBadge(userId, 'goodSleep', {
source: BadgeSource.CHALLENGE,
sourceId: challengeId,
metadata: {
challengeName: challenge.title,
challengeType: challenge.type,
},
});
this.winstonLogger.info('授予睡眠挑战勋章成功', {
context: 'reportProgress',
userId,
challengeId,
badgeCode: 'goodSleep',
});
} catch (error) {
// 勋章授予失败不应影响主流程,仅记录日志
this.winstonLogger.error('授予睡眠挑战勋章失败', {
context: 'reportProgress',
userId,
challengeId,
error: error instanceof Error ? error.message : '未知错误',
});
}
}
}
if (participant.progressValue >= (participant.challenge?.minimumCheckInDays || 0) && participant.status !== ChallengeParticipantStatus.COMPLETED) {

View File

@@ -32,7 +32,7 @@ export class PushTestService implements OnModuleInit {
async onModuleInit() {
// 检查是否启用推送测试
const enablePushTest = this.configService.get<boolean>('ENABLE_PUSH_TEST', false);
return
if (!enablePushTest) {
this.logger.log('Push test is disabled. Skipping...');
return;

View File

@@ -31,11 +31,11 @@ export enum BadgeSource {
})
export class UserBadge extends Model {
@Column({
type: DataType.INTEGER,
type: DataType.CHAR(36),
defaultValue: DataType.UUIDV4,
primaryKey: true,
autoIncrement: true,
})
declare id: number;
declare id: string;
@ForeignKey(() => User)
@Column({

View File

@@ -78,7 +78,7 @@ export class BadgeService {
* @param userId 用户ID
*/
async getUserBadges(userId: string): Promise<Array<{
id: number;
id: string;
code: string;
name: string;
description: string;