feat(share): 分享挑战关卡进度记录功能
- 新增 Level.timeLimit 字段支持关卡时间限制 - 新增 ShareLevelProgress 实体记录单关通关进度 - 新增 ShareLevelProgressRepository - 新增 DTO: ReportLevelProgressDto, ReportLevelProgressResponseDto - 新增 POST /v1/share/progress 接口用于上报进度 - 支持仅首次通关有效判断 - 支持时间限制内通关判断 - 不可变模式更新进度记录 - 数据库迁移脚本 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,13 +6,16 @@ import {
|
||||
import { nanoid } from 'nanoid';
|
||||
import { ShareConfigRepository } from './repositories/share-config.repository';
|
||||
import { ShareParticipantRepository } from './repositories/share-participant.repository';
|
||||
import { ShareLevelProgressRepository } from './repositories/share-level-progress.repository';
|
||||
import { LevelRepository } from '../wechat-game/repositories/level.repository';
|
||||
import { CreateShareDto } from './dto/create-share.dto';
|
||||
import { ReportLevelProgressDto } from './dto/report-level-progress.dto';
|
||||
import {
|
||||
CreateShareResponseDto,
|
||||
JoinShareResponseDto,
|
||||
ShareLevelDto,
|
||||
} from './dto/share-response.dto';
|
||||
import { ReportLevelProgressResponseDto } from './dto/share-level-progress-response.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ShareService {
|
||||
@@ -20,6 +23,7 @@ export class ShareService {
|
||||
private readonly shareConfigRepository: ShareConfigRepository,
|
||||
private readonly shareParticipantRepository: ShareParticipantRepository,
|
||||
private readonly levelRepository: LevelRepository,
|
||||
private readonly shareLevelProgressRepository: ShareLevelProgressRepository,
|
||||
) {}
|
||||
|
||||
async createShare(
|
||||
@@ -105,4 +109,97 @@ export class ShareService {
|
||||
levels,
|
||||
};
|
||||
}
|
||||
|
||||
async reportLevelProgress(
|
||||
userId: string,
|
||||
dto: ReportLevelProgressDto,
|
||||
): Promise<ReportLevelProgressResponseDto> {
|
||||
// 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) {
|
||||
const existingLevel = await this.levelRepository.findById(dto.levelId);
|
||||
if (!existingLevel) {
|
||||
throw new NotFoundException('关卡不存在');
|
||||
}
|
||||
const wasWithinTimeLimit =
|
||||
existingLevel.timeLimit === null ||
|
||||
existing.timeSpent <= existingLevel.timeLimit;
|
||||
return {
|
||||
passed: true,
|
||||
timeLimit: existingLevel.timeLimit,
|
||||
withinTimeLimit: wasWithinTimeLimit,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = this.shareLevelProgressRepository.create({
|
||||
...progress,
|
||||
passed: dto.passed,
|
||||
timeSpent: dto.timeSpent,
|
||||
completedAt: dto.passed ? new Date() : progress.completedAt,
|
||||
});
|
||||
} else {
|
||||
progress = this.shareLevelProgressRepository.create({
|
||||
participantId: participant.id,
|
||||
levelId: dto.levelId,
|
||||
passed: dto.passed,
|
||||
timeSpent: dto.timeSpent,
|
||||
completedAt: dto.passed ? new Date() : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
await this.shareLevelProgressRepository.save(progress);
|
||||
|
||||
return {
|
||||
passed: dto.passed,
|
||||
timeLimit: level.timeLimit,
|
||||
withinTimeLimit,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user