From e261cb027d6fcf4e66bf3691b2d7000b584ab63f Mon Sep 17 00:00:00 2001 From: imeepos Date: Thu, 4 Sep 2025 20:02:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=9F=E4=B8=80API=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建 ResponseUtil 工具类,提供标准化的API响应格式 - 统一所有控制器的响应结构:code、message、data、timestamp、traceId - 修复 template.controller.ts 响应格式,使用 ResponseUtil.success() - 修复 app.controller.ts 回调接口,使用标准化错误处理 - 更新 unified-user.controller.ts 使用 ResponseUtil - 解决 Swagger ApiResponse 类型冲突问题 - 使用 crypto.randomUUID() 生成追踪ID,避免外部依赖 --- src/app.controller.ts | 18 +--- src/controllers/template.controller.ts | 80 +++++++------- .../controllers/unified-user.controller.ts | 9 +- src/utils/response.util.ts | 102 ++++++++++++++++++ 4 files changed, 148 insertions(+), 61 deletions(-) create mode 100644 src/utils/response.util.ts diff --git a/src/app.controller.ts b/src/app.controller.ts index 206eaf1..2539348 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -2,11 +2,7 @@ import { Body, Controller, Post } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { TemplateExecutionEntity, ExecutionStatus } from './entities/template-execution.entity'; -interface ApiResponse { - status: boolean | string; - data: T; - msg: string; -} +import { ResponseUtil, ApiResponse } from './utils/response.util'; @Controller() export class AppController { @@ -15,11 +11,11 @@ export class AppController { private readonly executionRepository: Repository, ) {} @Post('callback') - async callback(@Body() body: any): Promise> { + async callback(@Body() body: any): Promise> { console.log(`🚀 [回调] 开始执行回调`); console.log(`📋 回调参数: ${JSON.stringify(body, null, 2)}`); const task_id = body.task_id; - if (!task_id) return { status: false, msg: `缺少task_id`, data: null } + if (!task_id) return ResponseUtil.error('缺少task_id', 400) const res = body.data; let resultUrl = `` if (res.status) { @@ -37,7 +33,7 @@ export class AppController { if (!execution) { console.error(`未找到 taskId 为 ${task_id} 的执行记录`); - return { status: false, msg: `未找到对应的执行记录`, data: null }; + return ResponseUtil.error('未找到对应的执行记录', 404); } // 更新执行状态 @@ -65,10 +61,6 @@ export class AppController { await this.executionRepository.update(execution.id, updateData); - return { - status: true, - data: resultUrl, - msg: 'success', - }; + return ResponseUtil.success(resultUrl, '回调处理成功'); } } diff --git a/src/controllers/template.controller.ts b/src/controllers/template.controller.ts index 93bd28d..bc0bda0 100644 --- a/src/controllers/template.controller.ts +++ b/src/controllers/template.controller.ts @@ -16,7 +16,7 @@ import { import { ApiTags, ApiOperation, - ApiResponse, + ApiResponse as SwaggerApiResponse, ApiParam, ApiQuery, ApiBody, @@ -39,6 +39,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ApiCommonResponses } from '../decorators/api-common-responses.decorator'; import { PlatformAuthGuard } from 'src/platform/guards/platform-auth.guard'; +import { ResponseUtil, ApiResponse } from '../utils/response.util'; @ApiTags('AI模板系统') @Controller('templates') @@ -59,12 +60,12 @@ export class TemplateController { }) @ApiParam({ name: 'templateId', description: '模板ID', example: 1 }) @ApiBody({ type: TemplateExecuteDto }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '执行成功', type: TemplateExecuteResponseDto, }) - @ApiResponse({ + @SwaggerApiResponse({ status: 400, description: '参数错误', schema: { @@ -121,7 +122,7 @@ export class TemplateController { example: 'character_figurine_v1', }) @ApiBody({ type: TemplateExecuteDto }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '执行成功', type: TemplateExecuteResponseDto, @@ -130,7 +131,7 @@ export class TemplateController { @Param('code') code: string, @Body() body: { imageUrl: string }, @Request() req - ) { + ): Promise> { try { const { imageUrl } = body; @@ -167,10 +168,7 @@ export class TemplateController { const savedExecution = await this.executionRepository.save(execution); // 返回任务id (执行记录的ID) - return { - success: true, - data: savedExecution.id, - }; + return ResponseUtil.success(savedExecution.id, '模板执行已启动'); } catch (error) { console.error(error) throw new HttpException( @@ -187,7 +185,7 @@ export class TemplateController { }) @ApiParam({ name: 'templateId', description: '模板ID', example: 1 }) @ApiBody({ type: BatchExecuteDto }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '批量执行成功', schema: { @@ -247,34 +245,32 @@ export class TemplateController { summary: '获取所有模板列表', description: '获取所有可用的AI生成模板,支持按类型筛选', }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '获取成功', type: [TemplateListDto], }) - async getAllTemplates() { + async getAllTemplates(): Promise> { try { const templates = await this.templateFactory.getAllTemplates(); - return { - success: true, - data: templates.map((template) => ({ - id: template.id, - code: template.code, - name: template.name, - description: template.description, - creditCost: template.creditCost, - version: template.version, - templateType: template.templateType, - templateClass: template.templateClass, - tags: template.tags, - inputExample: template.inputExampleUrl, - outputExample: template.outputExampleUrl, - sortOrder: template.sortOrder, - isActive: template.isActive, - createdAt: template.createdAt, - updatedAt: template.updatedAt, - })), - }; + const data = templates.map((template) => ({ + id: template.id, + code: template.code, + name: template.name, + description: template.description, + creditCost: template.creditCost, + version: template.version, + templateType: template.templateType, + templateClass: template.templateClass, + tags: template.tags, + inputExample: template.inputExampleUrl, + outputExample: template.outputExampleUrl, + sortOrder: template.sortOrder, + isActive: template.isActive, + createdAt: template.createdAt, + updatedAt: template.updatedAt, + })); + return ResponseUtil.success(data, '获取模板列表成功'); } catch (error) { throw new HttpException( error.message || 'Failed to fetch templates', @@ -288,7 +284,7 @@ export class TemplateController { summary: '获取图片模板列表', description: '获取所有图片类型的AI生成模板', }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '获取成功', type: [TemplateListDto], @@ -313,7 +309,7 @@ export class TemplateController { summary: '获取视频模板列表', description: '获取所有视频类型的AI生成模板', }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '获取成功', type: [TemplateListDto], @@ -350,7 +346,7 @@ export class TemplateController { description: '推荐数量', example: 5, }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '推荐成功', schema: { @@ -395,12 +391,12 @@ export class TemplateController { description: '根据模板ID获取详细信息', }) @ApiParam({ name: 'templateId', description: '模板ID', example: 1 }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '获取成功', type: TemplateListDto, }) - @ApiResponse({ + @SwaggerApiResponse({ status: 404, description: '模板不存在', }) @@ -545,7 +541,7 @@ export class TemplateController { description: '创建一个新的AI生成模板', }) @ApiBody({ type: CreateTemplateDto }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '创建成功', schema: { @@ -559,7 +555,7 @@ export class TemplateController { }, }, }) - @ApiResponse({ + @SwaggerApiResponse({ status: 409, description: '模板代码已存在', }) @@ -601,16 +597,16 @@ export class TemplateController { }) @ApiParam({ name: 'templateId', description: '模板ID', example: 1 }) @ApiBody({ type: UpdateTemplateDto }) - @ApiResponse({ + @SwaggerApiResponse({ status: 200, description: '更新成功', type: TemplateListDto, }) - @ApiResponse({ + @SwaggerApiResponse({ status: 404, description: '模板不存在', }) - @ApiResponse({ + @SwaggerApiResponse({ status: 409, description: '模板代码已存在', }) diff --git a/src/platform/controllers/unified-user.controller.ts b/src/platform/controllers/unified-user.controller.ts index 39a33a5..6ee99b8 100644 --- a/src/platform/controllers/unified-user.controller.ts +++ b/src/platform/controllers/unified-user.controller.ts @@ -23,6 +23,7 @@ import { } from '../dto/platform-login.dto'; import { PlatformAuthGuard } from '../guards/platform-auth.guard'; import { PlatformType } from '../../entities/platform-user.entity'; +import { ResponseUtil, ApiResponse as ApiResponseType } from '../../utils/response.util'; @ApiTags('用户管理') @Controller('users') @@ -55,16 +56,12 @@ export class UnifiedUserController { }) @ApiResponse({ status: 400, description: '请求参数错误' }) @ApiResponse({ status: 401, description: '平台授权失败' }) - async login(@Body() loginDto: PlatformLoginDto) { + async login(@Body() loginDto: PlatformLoginDto): Promise> { const result = await this.unifiedUserService.login( loginDto.platform, loginDto, ); - return { - code: 200, - message: '登录成功', - data: result, - }; + return ResponseUtil.success(result, '登录成功'); } @Post('register') diff --git a/src/utils/response.util.ts b/src/utils/response.util.ts new file mode 100644 index 0000000..27ab596 --- /dev/null +++ b/src/utils/response.util.ts @@ -0,0 +1,102 @@ +import { HttpStatus } from '@nestjs/common'; +import * as crypto from 'crypto'; + +/** + * 统一响应格式工具类 + * 规范化API响应结构,提供一致的响应格式 + */ +export interface ApiResponse { + code: number; + message: string; + data?: T; + timestamp: number; + traceId: string; +} + +export class ResponseUtil { + /** + * 生成追踪ID + * @returns 随机字符串 + */ + private static generateTraceId(): string { + return crypto.randomUUID(); + } + + /** + * 成功响应 + * @param data 响应数据 + * @param message 响应消息 + * @param code HTTP状态码 + * @returns 标准化成功响应 + */ + static success( + data?: T, + message: string = 'success', + code: number = HttpStatus.OK, + ): ApiResponse { + return { + code, + message, + data, + timestamp: Date.now(), + traceId: this.generateTraceId(), + }; + } + + /** + * 错误响应(一般不直接使用,通过异常处理器处理) + * @param message 错误消息 + * @param code HTTP状态码 + * @returns 标准化错误响应 + */ + static error( + message: string = 'Internal Server Error', + code: number = HttpStatus.INTERNAL_SERVER_ERROR, + ): ApiResponse { + return { + code, + message, + data: null, + timestamp: Date.now(), + traceId: this.generateTraceId(), + }; + } + + /** + * 分页响应 + * @param items 数据项 + * @param total 总数 + * @param page 当前页 + * @param limit 每页数量 + * @param message 响应消息 + * @returns 标准化分页响应 + */ + static paginated( + items: T[], + total: number, + page: number, + limit: number, + message: string = 'success', + ): ApiResponse<{ + items: T[]; + pagination: { + total: number; + page: number; + limit: number; + totalPages: number; + }; + }> { + return this.success( + { + items, + pagination: { + total, + page, + limit, + totalPages: Math.ceil(total / limit), + }, + }, + message, + ); + } +} \ No newline at end of file