feat(challenges): 新增今日打卡状态字段并更新进度构建逻辑

- 在 ChallengeProgressDto 中增加 checkedInToday 字段
- 修改 buildChallengeProgress 方法,支持传入 lastProgressAt 参数
- 所有调用处同步更新,确保返回包含今日打卡状态
- 使用 dayjs 判断最后进度时间是否为今日
This commit is contained in:
richarjiang
2025-09-29 17:12:54 +08:00
parent 64460a9d68
commit 12acbbd166
2 changed files with 15 additions and 7 deletions

View File

@@ -75,7 +75,7 @@ export class ChallengesService {
const completionTarget = challenge.minimumCheckInDays
const participation = participationMap.get(challenge.id);
const progress = participation
? this.buildChallengeProgress(participation.progressValue, completionTarget)
? this.buildChallengeProgress(participation.progressValue, completionTarget, participation.lastProgressAt)
: undefined;
return {
@@ -167,7 +167,7 @@ export class ChallengesService {
const completionTarget = challenge.minimumCheckInDays
const progress = participation
? this.buildChallengeProgress(participation.progressValue, completionTarget)
? this.buildChallengeProgress(participation.progressValue, completionTarget, participation.lastProgressAt)
: undefined;
const rankings: RankingItemDto[] = rankingsRaw.map((item, index) => {
@@ -245,7 +245,7 @@ export class ChallengesService {
existing.leftAt = null;
existing.lastProgressAt = null;
await existing.save();
return this.buildChallengeProgress(existing.progressValue, completionTarget);
return this.buildChallengeProgress(existing.progressValue, completionTarget, existing.lastProgressAt);
}
const participant = await this.participantModel.create({
@@ -257,7 +257,7 @@ export class ChallengesService {
joinedAt: new Date(),
});
return this.buildChallengeProgress(participant.progressValue, completionTarget);
return this.buildChallengeProgress(participant.progressValue, completionTarget, participant.lastProgressAt);
}
async leaveChallenge(userId: string, challengeId: string): Promise<boolean> {
@@ -392,21 +392,28 @@ export class ChallengesService {
});
return this.buildChallengeProgress(participant.progressValue, participant.targetValue);
return this.buildChallengeProgress(participant.progressValue, participant.targetValue, participant.lastProgressAt);
} catch (error) {
if (error instanceof UniqueConstraintError) {
return this.buildChallengeProgress(participant.progressValue, participant.targetValue);
return this.buildChallengeProgress(participant.progressValue, participant.targetValue, participant.lastProgressAt);
}
throw error;
}
}
private buildChallengeProgress(completed: number, target: number, unit = '天'): ChallengeProgressDto {
private buildChallengeProgress(
completed: number,
target: number,
lastProgressAt?: Date | string | null,
unit = '天',
): ChallengeProgressDto {
const remaining = Math.max(target - completed, 0);
const checkedInToday = lastProgressAt ? dayjs(lastProgressAt).isSame(dayjs(), 'day') : false;
return {
completed,
target,
remaining,
checkedInToday,
};
}

View File

@@ -2,6 +2,7 @@ export interface ChallengeProgressDto {
completed: number;
target: number;
remaining: number;
checkedInToday: boolean;
}
export interface RankingItemDto {