# 分享挑战关卡进度记录功能实现计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 实现用户在分享挑战中的单关通关进度上报功能,支持记录通关时间、是否通过、时间限制判断。 **Architecture:** 在现有 Share 模块基础上,新增 ShareLevelProgress 实体和 Repository,通过 ShareService.reportLevelProgress 方法处理业务逻辑,在 ShareController 新增 POST /v1/share/progress 接口。 **Tech Stack:** NestJS, TypeORM, MySQL --- ## 文件清单 | 操作 | 文件路径 | |------|----------| | 新增 | src/modules/share/entities/share-level-progress.entity.ts | | 新增 | src/modules/share/repositories/share-level-progress.repository.ts | | 新增 | src/modules/share/dto/report-level-progress.dto.ts | | 新增 | src/modules/share/dto/share-level-progress-response.dto.ts | | 修改 | src/modules/share/repositories/share-participant.repository.ts | | 修改 | src/modules/share/share.service.ts | | 修改 | src/modules/share/share.controller.ts | | 修改 | src/modules/share/share.module.ts | | 修改 | src/modules/wechat-game/entities/level.entity.ts | | 修改 | src/database/migrations/*.sql | --- ## Task 1: Level 实体增加 timeLimit 字段 **Files:** - Modify: `src/modules/wechat-game/entities/level.entity.ts` - [ ] **Step 1: 修改 Level 实体** ```typescript // src/modules/wechat-game/entities/level.entity.ts // 在 sortOrder 字段后添加 @Column({ type: 'int', name: 'time_limit', nullable: true, default: null }) timeLimit!: number | null; ``` - [ ] **Step 2: Commit** ```bash git add src/modules/wechat-game/entities/level.entity.ts git commit -m "feat(level): add timeLimit field for level time restriction" ``` --- ## Task 2: 创建 ShareLevelProgress 实体 **Files:** - Create: `src/modules/share/entities/share-level-progress.entity.ts` - [ ] **Step 1: 创建实体文件** ```typescript import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne, JoinColumn, Index, Unique, } from 'typeorm'; import { ShareParticipant } from './share-participant.entity'; import { Level } from '../../wechat-game/entities/level.entity'; @Entity('share_level_progress') @Unique('uq_participant_level', ['participantId', 'levelId']) export class ShareLevelProgress { @PrimaryGeneratedColumn('uuid') id!: string; @Index('idx_slp_participant_id') @Column({ type: 'char', length: 36, name: 'participant_id' }) participantId!: string; @ManyToOne(() => ShareParticipant) @JoinColumn({ name: 'participant_id' }) participant!: ShareParticipant; @Index('idx_slp_level_id') @Column({ type: 'char', length: 191, name: 'level_id' }) levelId!: string; @ManyToOne(() => Level) @JoinColumn({ name: 'level_id' }) level!: Level; @Column({ type: 'tinyint', width: 1, default: 0 }) passed!: boolean; @Column({ type: 'int', default: 0, name: 'time_spent' }) timeSpent!: number; @CreateDateColumn({ name: 'completed_at' }) completedAt!: Date; } ``` - [ ] **Step 2: Commit** ```bash git add src/modules/share/entities/share-level-progress.entity.ts git commit -m "feat(share): add ShareLevelProgress entity" ``` --- ## Task 3: 创建 ShareLevelProgressRepository **Files:** - Create: `src/modules/share/repositories/share-level-progress.repository.ts` - [ ] **Step 1: 创建 Repository** ```typescript import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ShareLevelProgress } from '../entities/share-level-progress.entity'; @Injectable() export class ShareLevelProgressRepository { constructor( @InjectRepository(ShareLevelProgress) private readonly repository: Repository, ) {} async findByParticipantId(participantId: string): Promise { return this.repository.find({ where: { participantId } }); } async findByParticipantAndLevel( participantId: string, levelId: string, ): Promise { return this.repository.findOne({ where: { participantId, levelId } }); } create(data: Partial): ShareLevelProgress { return this.repository.create(data); } async save(progress: ShareLevelProgress): Promise { return this.repository.save(progress); } } ``` - [ ] **Step 2: Commit** ```bash git add src/modules/share/repositories/share-level-progress.repository.ts git commit -m "feat(share): add ShareLevelProgressRepository" ``` --- ## Task 4: 创建 DTO 文件 **Files:** - Create: `src/modules/share/dto/report-level-progress.dto.ts` - Create: `src/modules/share/dto/share-level-progress-response.dto.ts` - [ ] **Step 1: 创建 ReportLevelProgressDto** ```typescript import { ApiProperty } from '@nestjs/swagger'; import { IsBoolean, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator'; export class ReportLevelProgressDto { @ApiProperty({ description: '分享码' }) @IsString() @IsNotEmpty() shareCode!: string; @ApiProperty({ description: '关卡 ID' }) @IsString() @IsNotEmpty() levelId!: string; @ApiProperty({ description: '是否通过' }) @IsBoolean() passed!: boolean; @ApiProperty({ description: '通关时间(秒)' }) @IsNumber() @Min(0) timeSpent!: number; } ``` - [ ] **Step 2: 创建 ReportLevelProgressResponseDto** ```typescript import { ApiProperty } from '@nestjs/swagger'; export class ReportLevelProgressResponseDto { @ApiProperty({ description: '是否通过' }) passed!: boolean; @ApiProperty({ description: '该关卡时间限制(秒),null 表示无限制' }) timeLimit!: number | null; @ApiProperty({ description: '是否在时间限制内通过' }) withinTimeLimit!: boolean; } ``` - [ ] **Step 3: Commit** ```bash git add src/modules/share/dto/report-level-progress.dto.ts src/modules/share/dto/share-level-progress-response.dto.ts git commit -m "feat(share): add DTOs for level progress reporting" ``` --- ## Task 5: ShareParticipantRepository 补充方法 **Files:** - Modify: `src/modules/share/repositories/share-participant.repository.ts` - [ ] **Step 1: 读取现有文件确认内容** ```typescript // src/modules/share/repositories/share-participant.repository.ts // 在现有方法后添加 findByShareConfigAndParticipant 方法 ``` - [ ] **Step 2: 添加新方法** ```typescript async findByShareConfigAndParticipant( shareConfigId: string, participantId: string, ): Promise { return this.repository.findOne({ where: { shareConfigId, participantId } }); } ``` - [ ] **Step 3: Commit** ```bash git add src/modules/share/repositories/share-participant.repository.ts git commit -m "feat(share): add findByShareConfigAndParticipant to ShareParticipantRepository" ``` --- ## Task 6: ShareService 新增 reportLevelProgress 方法 **Files:** - Modify: `src/modules/share/share.service.ts` - [ ] **Step 1: 读取现有文件确认 import 和 constructor** ```typescript // 需要新增的 imports import { ShareLevelProgressRepository } from './repositories/share-level-progress.repository'; import { ReportLevelProgressDto } from './dto/report-level-progress.dto'; import { ReportLevelProgressResponseDto } from './dto/share-level-progress-response.dto'; ``` - [ ] **Step 2: 在 ShareService 中添加方法** ```typescript async reportLevelProgress( userId: string, dto: ReportLevelProgressDto, ): Promise { // 1. 查找分享配置 const config = await this.shareConfigRepository.findByShareCode(dto.shareCode); if (!config) { throw new NotFoundException('分享不存在或已过期'); } // 2. 查找或创建 ShareParticipant let participant = await this.shareParticipantRepository.findByShareConfigAndParticipant( config.id, userId, ); if (!participant) { participant = await this.shareParticipantRepository.create({ shareConfigId: config.id, participantId: userId, }); participant = await this.shareParticipantRepository.save(participant); } // 3. 如果 passed=true,检查是否已有通关记录 if (dto.passed) { const existing = await this.shareLevelProgressRepository.findByParticipantAndLevel( participant.id, dto.levelId, ); if (existing?.passed) { return { passed: true, timeLimit: null, withinTimeLimit: false, }; } } // 4. 查找关卡获取时间限制 const level = await this.levelRepository.findById(dto.levelId); if (!level) { throw new NotFoundException('关卡不存在'); } // 5. 判断是否在时间限制内通过 const withinTimeLimit = dto.passed ? level.timeLimit === null || dto.timeSpent <= level.timeLimit : false; // 6. 创建或更新进度 let progress = await this.shareLevelProgressRepository.findByParticipantAndLevel( participant.id, dto.levelId, ); if (progress) { progress.passed = dto.passed; progress.timeSpent = dto.timeSpent; if (dto.passed) { progress.completedAt = new Date(); } } else { progress = this.shareLevelProgressRepository.create({ participantId: participant.id, levelId: dto.levelId, passed: dto.passed, timeSpent: dto.timeSpent, completedAt: dto.passed ? new Date() : null, }); } await this.shareLevelProgressRepository.save(progress); return { passed: dto.passed, timeLimit: level.timeLimit, withinTimeLimit, }; } ``` - [ ] **Step 3: Commit** ```bash git add src/modules/share/share.service.ts git commit -m "feat(share): add reportLevelProgress method" ``` --- ## Task 7: ShareController 新增接口 **Files:** - Modify: `src/modules/share/share.controller.ts` - [ ] **Step 1: 添加 import** ```typescript import { ReportLevelProgressDto } from './dto/report-level-progress.dto'; import { ReportLevelProgressResponseDto } from './dto/share-level-progress-response.dto'; ``` - [ ] **Step 2: 添加 Controller 方法** ```typescript @Post('progress') @UseGuards(JwtAuthGuard) @ApiBearerAuth() @ApiOperation({ summary: '上报单关进度', description: '用户在分享挑战中通关后上报进度,仅首次通关(passed=true)有效', }) @ApiResponse({ status: 200, description: '成功' }) @ApiResponse({ status: 404, description: '分享或关卡不存在' }) async reportLevelProgress( @CurrentUser() user: JwtPayload, @Body() dto: ReportLevelProgressDto, ): Promise> { const data = await this.shareService.reportLevelProgress(user.sub, dto); return ApiResponseDto.success(data); } ``` - [ ] **Step 3: Commit** ```bash git add src/modules/share/share.controller.ts git commit -m "feat(share): add POST /v1/share/progress endpoint" ``` --- ## Task 8: ShareModule 更新 **Files:** - Modify: `src/modules/share/share.module.ts` - [ ] **Step 1: 修改 import 和 providers** ```typescript import { ShareLevelProgress } from './entities/share-level-progress.entity'; import { ShareLevelProgressRepository } from './repositories/share-level-progress.repository'; // TypeOrmModule.forFeature 中添加 ShareLevelProgress TypeOrmModule.forFeature([ShareConfig, ShareParticipant, ShareLevelProgress]), // providers 中添加 ShareLevelProgressRepository providers: [ ShareService, ShareConfigRepository, ShareParticipantRepository, ShareLevelProgressRepository, ], ``` - [ ] **Step 2: Commit** ```bash git add src/modules/share/share.module.ts git commit -m "feat(share): register ShareLevelProgress in ShareModule" ``` --- ## Task 9: 数据库迁移 SQL **Files:** - Create: `src/database/migrations/002_add_share_level_progress.sql`(或按项目规范) - [ ] **Step 1: 创建迁移 SQL** ```sql -- Level 表增加 time_limit 字段 ALTER TABLE levels ADD COLUMN time_limit INT DEFAULT NULL COMMENT '通关时间限制(秒),NULL 表示无限制' AFTER sort_order; -- 新建 share_level_progress 表 CREATE TABLE IF NOT EXISTS share_level_progress ( id CHAR(36) PRIMARY KEY, participant_id CHAR(36) NOT NULL COMMENT '关联 share_participants.id', level_id CHAR(191) NOT NULL COMMENT '关卡ID', passed TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否通过', time_spent INT NOT NULL DEFAULT 0 COMMENT '通关时间(秒)', completed_at DATETIME DEFAULT NULL COMMENT '通关时间戳', UNIQUE KEY uq_participant_level (participant_id, level_id), INDEX idx_slp_participant_id (participant_id), INDEX idx_slp_level_id (level_id), FOREIGN KEY (participant_id) REFERENCES share_participants(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` - [ ] **Step 2: Commit** ```bash git add src/database/migrations/002_add_share_level_progress.sql git commit -m "chore: add migration for share level progress tables" ``` --- ## Task 10: 编译验证 - [ ] **Step 1: 运行 TypeScript 编译检查** ```bash cd /Users/richard/Documents/code/xieyingeng/MemeMind-Server && npx tsc --noEmit ``` 预期:无编译错误 - [ ] **Step 2: 如果有错误,修复后重新编译** - [ ] **Step 3: Commit(如果有代码修改)** --- ## 自检清单 完成实现后,对照设计文档检查: - [ ] Level 实体有 `timeLimit` 字段 - [ ] ShareLevelProgress 实体有 `participantId`, `levelId`, `passed`, `timeSpent`, `completedAt` 字段 - [ ] ShareLevelProgress 有唯一索引 `(participantId, levelId)` - [ ] ShareLevelProgressRepository 有 `findByParticipantId`, `findByParticipantAndLevel`, `create`, `save` 方法 - [ ] ShareParticipantRepository 有 `findByShareConfigAndParticipant` 方法 - [ ] ShareService.reportLevelProgress 实现了完整业务逻辑 - [ ] Controller 接口为 `POST /v1/share/progress` - [ ] DTO 包含 `shareCode`, `levelId`, `passed`, `timeSpent` - [ ] 响应 DTO 包含 `passed`, `timeLimit`, `withinTimeLimit` - [ ] ShareModule 注册了 ShareLevelProgress 实体和 Repository - [ ] 数据库迁移 SQL 包含 Level 表修改和 share_level_progress 表创建