feat: 支持关卡配置分享

This commit is contained in:
richarjiang
2026-04-06 17:32:20 +08:00
parent 9ab78555cb
commit 3a1b4d22bf
15 changed files with 418 additions and 3 deletions

View File

@@ -0,0 +1,111 @@
import {
Injectable,
NotFoundException,
BadRequestException,
} from '@nestjs/common';
import { nanoid } from 'nanoid';
import { ShareConfigRepository } from './repositories/share-config.repository';
import { ShareParticipantRepository } from './repositories/share-participant.repository';
import { LevelRepository } from '../wechat-game/repositories/level.repository';
import { CreateShareDto } from './dto/create-share.dto';
import {
CreateShareResponseDto,
JoinShareResponseDto,
ShareLevelDto,
} from './dto/share-response.dto';
@Injectable()
export class ShareService {
constructor(
private readonly shareConfigRepository: ShareConfigRepository,
private readonly shareParticipantRepository: ShareParticipantRepository,
private readonly levelRepository: LevelRepository,
) {}
async createShare(
userId: string,
dto: CreateShareDto,
): Promise<CreateShareResponseDto> {
const uniqueIds = [...new Set(dto.levelIds)];
if (uniqueIds.length !== 6) {
throw new BadRequestException('关卡ID不能重复需要恰好6个不同的关卡');
}
// 单次查询验证所有关卡存在
const levels = await this.levelRepository.findByIds(uniqueIds);
if (levels.length !== uniqueIds.length) {
const foundIds = new Set(levels.map((l) => l.id));
const missing = uniqueIds.filter((id) => !foundIds.has(id));
throw new NotFoundException(`以下关卡不存在: ${missing.join(', ')}`);
}
// 生成 8 位分享码(碰撞重试)
let shareCode: string;
let attempts = 0;
do {
shareCode = nanoid(8);
const existing =
await this.shareConfigRepository.findByShareCode(shareCode);
if (!existing) break;
attempts++;
} while (attempts < 3);
if (attempts >= 3) {
throw new BadRequestException('生成分享码失败,请重试');
}
const config = await this.shareConfigRepository.create({
shareCode,
title: dto.title,
sharerId: userId,
levelIds: dto.levelIds,
});
return {
shareCode: config.shareCode,
title: config.title,
levelCount: config.levelIds.length,
};
}
async joinShare(
userId: string,
code: string,
): Promise<JoinShareResponseDto> {
const config = await this.shareConfigRepository.findByShareCode(code);
if (!config) {
throw new NotFoundException('分享不存在或已过期');
}
if (userId !== config.sharerId) {
await this.shareParticipantRepository.addParticipant(config.id, userId);
}
// 单次查询获取所有关卡,再按 levelIds 顺序排列
const allLevels = await this.levelRepository.findByIds(config.levelIds);
const levelMap = new Map(allLevels.map((l) => [l.id, l]));
const levels: ShareLevelDto[] = config.levelIds.map((id, index) => {
const level = levelMap.get(id);
if (!level) {
throw new NotFoundException(`关卡 ${id} 不存在`);
}
return {
id: level.id,
level: index + 1,
imageUrl: level.imageUrl,
answer: level.answer,
hint1: level.hint1,
hint2: level.hint2,
hint3: level.hint3,
sortOrder: level.sortOrder,
};
});
return {
shareCode: config.shareCode,
title: config.title,
levels,
};
}
}