feat: 统一API响应格式规范
- 创建 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,避免外部依赖
This commit is contained in:
parent
0e33292d7a
commit
e261cb027d
|
|
@ -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<T = any> {
|
||||
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<TemplateExecutionEntity>,
|
||||
) {}
|
||||
@Post('callback')
|
||||
async callback(@Body() body: any): Promise<ApiResponse<any>> {
|
||||
async callback(@Body() body: any): Promise<ApiResponse<string | null>> {
|
||||
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, '回调处理成功');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ApiResponse<number>> {
|
||||
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<ApiResponse<any[]>> {
|
||||
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: '模板代码已存在',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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<ApiResponseType<any>> {
|
||||
const result = await this.unifiedUserService.login(
|
||||
loginDto.platform,
|
||||
loginDto,
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '登录成功',
|
||||
data: result,
|
||||
};
|
||||
return ResponseUtil.success(result, '登录成功');
|
||||
}
|
||||
|
||||
@Post('register')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
import { HttpStatus } from '@nestjs/common';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
/**
|
||||
* 统一响应格式工具类
|
||||
* 规范化API响应结构,提供一致的响应格式
|
||||
*/
|
||||
export interface ApiResponse<T = any> {
|
||||
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<T>(
|
||||
data?: T,
|
||||
message: string = 'success',
|
||||
code: number = HttpStatus.OK,
|
||||
): ApiResponse<T> {
|
||||
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<null> {
|
||||
return {
|
||||
code,
|
||||
message,
|
||||
data: null,
|
||||
timestamp: Date.now(),
|
||||
traceId: this.generateTraceId(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页响应
|
||||
* @param items 数据项
|
||||
* @param total 总数
|
||||
* @param page 当前页
|
||||
* @param limit 每页数量
|
||||
* @param message 响应消息
|
||||
* @returns 标准化分页响应
|
||||
*/
|
||||
static paginated<T>(
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue