feat(badges): 添加用户勋章系统,支持睡眠挑战勋章自动授予

实现完整的用户勋章功能模块:
- 新增 BadgeConfig 和 UserBadge 数据模型,支持勋章配置和用户勋章管理
- 新增 BadgeService 服务,提供勋章授予、查询、展示状态管理等核心功能
- 在挑战服务中集成勋章授予逻辑,完成首次睡眠打卡授予 goodSleep 勋章,完成睡眠挑战授予 sleepChallengeMonth 勋章
- 新增用户勋章相关接口:获取用户勋章列表、获取可用勋章列表、标记勋章已展示
- 支持勋章分类(睡眠、运动、饮食等)、排序、启用状态管理
- 支持勋章来源追踪(挑战、系统、手动授予)和元数据记录
This commit is contained in:
richarjiang
2025-11-14 17:08:02 +08:00
parent f04c2ccd5d
commit 7b4d7c4459
8 changed files with 792 additions and 3 deletions

View File

@@ -35,6 +35,7 @@ import { RestorePurchaseDto, RestorePurchaseResponseDto } from './dto/restore-pu
import { GetUserActivityHistoryResponseDto } from './dto/user-activity.dto';
import { UpdateWeightRecordDto, WeightRecordResponseDto, DeleteWeightRecordResponseDto } from './dto/weight-record.dto';
import { UpdateBodyMeasurementDto, UpdateBodyMeasurementResponseDto, GetBodyMeasurementHistoryResponseDto, GetBodyMeasurementAnalysisDto, GetBodyMeasurementAnalysisResponseDto } from './dto/body-measurement.dto';
import { GetUserBadgesResponseDto, GetAvailableBadgesResponseDto, MarkBadgeShownDto, MarkBadgeShownResponseDto } from './dto/badge.dto';
import { Public } from '../common/decorators/public.decorator';
import { CurrentUser } from '../common/decorators/current-user.decorator';
@@ -393,4 +394,53 @@ export class UsersController {
return this.usersService.getBodyMeasurementAnalysis(user.sub, period);
}
// ==================== 勋章相关接口 ====================
/**
* 获取用户勋章列表
*/
@UseGuards(JwtAuthGuard)
@Get('badges')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '获取用户勋章列表' })
@ApiResponse({ status: 200, description: '成功获取用户勋章列表', type: GetUserBadgesResponseDto })
async getUserBadges(
@CurrentUser() user: AccessTokenPayload,
): Promise<GetUserBadgesResponseDto> {
this.logger.log(`获取用户勋章列表 - 用户ID: ${user.sub}`);
return this.usersService.getUserBadges(user.sub);
}
/**
* 获取所有可用勋章(包含用户是否已获得)
*/
@UseGuards(JwtAuthGuard)
@Get('badges/available')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '获取所有可用勋章' })
@ApiResponse({ status: 200, description: '成功获取所有可用勋章', type: GetAvailableBadgesResponseDto })
async getAvailableBadges(
@CurrentUser() user: AccessTokenPayload,
): Promise<GetAvailableBadgesResponseDto> {
this.logger.log(`获取可用勋章列表 - 用户ID: ${user.sub}`);
return this.usersService.getAvailableBadges(user.sub);
}
/**
* 标记勋章已展示
*/
@UseGuards(JwtAuthGuard)
@Post('badges/mark-shown')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '标记勋章已展示(客户端展示勋章动画后调用)' })
@ApiBody({ type: MarkBadgeShownDto })
@ApiResponse({ status: 200, description: '成功标记勋章已展示', type: MarkBadgeShownResponseDto })
async markBadgeAsShown(
@Body() markBadgeShownDto: MarkBadgeShownDto,
@CurrentUser() user: AccessTokenPayload,
): Promise<MarkBadgeShownResponseDto> {
this.logger.log(`标记勋章已展示 - 用户ID: ${user.sub}, 勋章代码: ${markBadgeShownDto.badgeCode}`);
return this.usersService.markBadgeAsShown(user.sub, markBadgeShownDto.badgeCode);
}
}