/** * 位置广播HTTP API控制器 * * 功能描述: * - 提供位置广播系统的REST API接口 * - 处理HTTP请求和响应格式化 * - 集成JWT认证和权限验证 * - 提供完整的API文档和错误处理 * * 职责分离: * - HTTP处理:专注于HTTP请求和响应的处理 * - 数据转换:请求参数和响应数据的格式转换 * - 权限验证:API访问权限的验证和控制 * - 文档生成:Swagger API文档的自动生成 * * 技术实现: * - NestJS控制器:使用装饰器定义API端点 * - Swagger集成:自动生成API文档 * - 数据验证:使用DTO进行请求数据验证 * - 异常处理:统一的HTTP异常处理机制 * * 最近修改: * - 2026-01-08: 功能新增 - 创建位置广播HTTP API控制器 * * @author moyin * @version 1.0.0 * @since 2026-01-08 * @lastModified 2026-01-08 */ import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, HttpStatus, HttpException, Logger, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery, ApiBearerAuth, ApiBody, } from '@nestjs/swagger'; import { JwtAuthGuard } from '../../../gateway/auth/jwt_auth.guard'; import { CurrentUser } from '../../../gateway/auth/current_user.decorator'; import { JwtPayload } from '../../../core/login_core/login_core.service'; // 导入业务服务 import { LocationBroadcastService, LocationSessionService, LocationPositionService, } from '../services'; // 导入DTO import { CreateSessionDto, SessionQueryDto, PositionQueryDto, UpdateSessionConfigDto, } from '../dto/api.dto'; /** * 位置广播API控制器 * * 提供以下API端点: * - 会话管理:创建、查询、配置会话 * - 位置管理:查询位置、获取统计信息 * - 用户管理:获取用户状态、清理数据 */ @ApiTags('位置广播') @Controller('location-broadcast') @ApiBearerAuth() @UseGuards(JwtAuthGuard) export class LocationBroadcastController { private readonly logger = new Logger(LocationBroadcastController.name); constructor( private readonly locationBroadcastService: LocationBroadcastService, private readonly locationSessionService: LocationSessionService, private readonly locationPositionService: LocationPositionService, ) {} /** * 创建新会话 */ @Post('sessions') @ApiOperation({ summary: '创建新游戏会话', description: '创建一个新的位置广播会话,支持自定义配置', }) @ApiResponse({ status: 201, description: '会话创建成功', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, sessionId: { type: 'string', example: 'session_12345' }, message: { type: 'string', example: '会话创建成功' }, }, }, }) @ApiResponse({ status: 400, description: '请求参数错误' }) @ApiResponse({ status: 409, description: '会话ID已存在' }) async createSession( @Body() createSessionDto: CreateSessionDto, @CurrentUser() user: JwtPayload, ) { try { const result = await this.locationSessionService.createSession({ ...createSessionDto, creatorId: user.sub, }); return { success: true, session: result, message: '会话创建成功', }; } catch (error: any) { this.logger.error('创建会话失败', error); throw new HttpException( error.message || '创建会话失败', error.status || HttpStatus.INTERNAL_SERVER_ERROR, ); } } /** * 查询会话列表 */ @Get('sessions') @ApiOperation({ summary: '查询会话列表', description: '根据条件查询游戏会话列表,支持分页和过滤', }) @ApiQuery({ name: 'status', required: false, description: '会话状态' }) @ApiQuery({ name: 'limit', required: false, description: '分页大小' }) @ApiQuery({ name: 'offset', required: false, description: '分页偏移' }) @ApiResponse({ status: 200, description: '查询成功', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, sessions: { type: 'array', items: { type: 'object' } }, total: { type: 'number', example: 10 }, message: { type: 'string', example: '查询成功' }, }, }, }) async querySessions( @Query() query: SessionQueryDto, @CurrentUser() user: JwtPayload, ) { try { const result = await this.locationSessionService.querySessions(query as any); return { success: true, ...result, message: '查询成功', }; } catch (error: any) { this.logger.error('查询会话失败', error); throw new HttpException( error.message || '查询会话失败', error.status || HttpStatus.INTERNAL_SERVER_ERROR, ); } } /** * 获取会话详情 */ @Get('sessions/:sessionId') @ApiOperation({ summary: '获取会话详情', description: '获取指定会话的详细信息,包括用户列表和位置信息', }) @ApiParam({ name: 'sessionId', description: '会话ID' }) @ApiResponse({ status: 200, description: '获取成功', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, session: { type: 'object' }, users: { type: 'array', items: { type: 'object' } }, message: { type: 'string', example: '获取成功' }, }, }, }) @ApiResponse({ status: 404, description: '会话不存在' }) async getSessionDetail( @Param('sessionId') sessionId: string, @CurrentUser() user: JwtPayload, ) { try { const result = await this.locationSessionService.getSessionDetail(sessionId); return { success: true, ...result, message: '获取成功', }; } catch (error: any) { this.logger.error('获取会话详情失败', error); throw new HttpException( error.message || '获取会话详情失败', error.status || HttpStatus.INTERNAL_SERVER_ERROR, ); } } /** * 查询位置信息 */ @Get('positions') @ApiOperation({ summary: '查询位置信息', description: '根据条件查询用户位置信息,支持范围查询和地图过滤', }) @ApiQuery({ name: 'mapId', required: false, description: '地图ID' }) @ApiQuery({ name: 'sessionId', required: false, description: '会话ID' }) @ApiQuery({ name: 'limit', required: false, description: '分页大小' }) @ApiResponse({ status: 200, description: '查询成功', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, positions: { type: 'array', items: { type: 'object' } }, total: { type: 'number', example: 5 }, message: { type: 'string', example: '查询成功' }, }, }, }) async queryPositions( @Query() query: PositionQueryDto, @CurrentUser() user: JwtPayload, ) { try { const result = await this.locationPositionService.queryPositions(query as any); return { success: true, ...result, message: '查询成功', }; } catch (error: any) { this.logger.error('查询位置失败', error); throw new HttpException( error.message || '查询位置失败', error.status || HttpStatus.INTERNAL_SERVER_ERROR, ); } } /** * 获取位置统计信息 */ @Get('positions/stats') @ApiOperation({ summary: '获取位置统计信息', description: '获取系统位置数据的统计信息,包括用户分布和活跃度', }) @ApiResponse({ status: 200, description: '获取成功', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, stats: { type: 'object' }, message: { type: 'string', example: '获取成功' }, }, }, }) async getPositionStats(@CurrentUser() user: JwtPayload) { try { const stats = await this.locationPositionService.getPositionStats({}); return { success: true, stats, message: '获取成功', }; } catch (error: any) { this.logger.error('获取位置统计失败', error); throw new HttpException( error.message || '获取位置统计失败', error.status || HttpStatus.INTERNAL_SERVER_ERROR, ); } } /** * 清理用户数据 */ @Delete('users/:userId/data') @ApiOperation({ summary: '清理用户数据', description: '清理指定用户的位置数据和会话信息', }) @ApiParam({ name: 'userId', description: '用户ID' }) @ApiResponse({ status: 200, description: '清理成功', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, message: { type: 'string', example: '清理成功' }, }, }, }) async cleanupUserData( @Param('userId') userId: string, @CurrentUser() user: JwtPayload, ) { try { // 只允许用户清理自己的数据,或管理员清理任意用户数据 if (user.sub !== userId && user.role !== 2) { throw new HttpException('权限不足', HttpStatus.FORBIDDEN); } await this.locationBroadcastService.cleanupUserData(userId); return { success: true, message: '清理成功', }; } catch (error: any) { this.logger.error('清理用户数据失败', error); throw new HttpException( error.message || '清理用户数据失败', error.status || HttpStatus.INTERNAL_SERVER_ERROR, ); } } }