feat: 支持关卡配置分享
This commit is contained in:
111
src/modules/share/share.service.ts
Normal file
111
src/modules/share/share.service.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user