feat(challenges): 支持公开访问挑战列表与详情接口
- 在 GET /challenges、GET /challenges/:id、GET /challenges/:id/rankings 添加 @Public() 装饰器,允许未登录用户访问 - 将 userId 改为可选参数,未登录时仍可返回基础数据 - 列表接口过滤掉 UPCOMING 状态挑战,仅展示进行中/已结束 - 返回 DTO 新增 unit 字段,用于前端展示进度单位 - 鉴权守卫优化:公开接口若携带 token 仍尝试解析并注入 user,方便后续业务逻辑
This commit is contained in:
@@ -28,7 +28,7 @@ export class ChallengesService {
|
||||
private readonly progressReportModel: typeof ChallengeProgressReport,
|
||||
) { }
|
||||
|
||||
async getChallengesForUser(userId: string): Promise<ChallengeListItemDto[]> {
|
||||
async getChallengesForUser(userId?: string): Promise<ChallengeListItemDto[]> {
|
||||
const challenges = await this.challengeModel.findAll({
|
||||
order: [['startAt', 'ASC']],
|
||||
});
|
||||
@@ -50,6 +50,7 @@ export class ChallengesService {
|
||||
challenge,
|
||||
status: this.computeStatus(challenge.startAt, challenge.endAt),
|
||||
}))
|
||||
.filter(({ status }) => status !== ChallengeStatus.UPCOMING)
|
||||
.sort((a, b) => {
|
||||
const priorityDiff = statusPriority[a.status] - statusPriority[b.status];
|
||||
if (priorityDiff !== 0) {
|
||||
@@ -81,19 +82,22 @@ export class ChallengesService {
|
||||
}
|
||||
}
|
||||
|
||||
const userParticipations = await this.participantModel.findAll({
|
||||
where: {
|
||||
challengeId: challengeIds,
|
||||
userId,
|
||||
status: {
|
||||
[Op.ne]: ChallengeParticipantStatus.LEFT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const participationMap = new Map<string, ChallengeParticipant>();
|
||||
for (const participation of userParticipations) {
|
||||
participationMap.set(participation.challengeId, participation);
|
||||
|
||||
if (userId) {
|
||||
const userParticipations = await this.participantModel.findAll({
|
||||
where: {
|
||||
challengeId: challengeIds,
|
||||
userId,
|
||||
status: {
|
||||
[Op.ne]: ChallengeParticipantStatus.LEFT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const participation of userParticipations) {
|
||||
participationMap.set(participation.challengeId, participation);
|
||||
}
|
||||
}
|
||||
|
||||
return challengesWithStatus.map(({ challenge, status }) => {
|
||||
@@ -111,6 +115,7 @@ export class ChallengesService {
|
||||
durationLabel: challenge.durationLabel,
|
||||
requirementLabel: challenge.requirementLabel,
|
||||
status,
|
||||
unit: challenge.progressUnit,
|
||||
startAt: challenge.startAt,
|
||||
endAt: challenge.endAt,
|
||||
participantsCount: participantsCountMap.get(challenge.id) ?? 0,
|
||||
@@ -126,7 +131,7 @@ export class ChallengesService {
|
||||
});
|
||||
}
|
||||
|
||||
async getChallengeDetail(userId: string, challengeId: string): Promise<ChallengeDetailDto> {
|
||||
async getChallengeDetail(challengeId: string, userId?: string,): Promise<ChallengeDetailDto> {
|
||||
const challenge = await this.challengeModel.findByPk(challengeId);
|
||||
|
||||
if (!challenge) {
|
||||
@@ -147,15 +152,17 @@ export class ChallengesService {
|
||||
status: ChallengeParticipantStatus.ACTIVE,
|
||||
},
|
||||
}),
|
||||
this.participantModel.findOne({
|
||||
where: {
|
||||
challengeId,
|
||||
userId,
|
||||
status: {
|
||||
[Op.ne]: ChallengeParticipantStatus.LEFT,
|
||||
userId
|
||||
? this.participantModel.findOne({
|
||||
where: {
|
||||
challengeId,
|
||||
userId,
|
||||
status: {
|
||||
[Op.ne]: ChallengeParticipantStatus.LEFT,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
})
|
||||
: null,
|
||||
]);
|
||||
|
||||
this.winstonLogger.info('end get detail', {
|
||||
@@ -205,6 +212,7 @@ export class ChallengesService {
|
||||
progress,
|
||||
rankings,
|
||||
userRank,
|
||||
unit: challenge.progressUnit,
|
||||
type: challenge.type,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user