# 后端接口生成规范 ## 概述 本规范用于快速生成 NestJS 后端接口,包含: - Controller(路由定义) - Service(业务逻辑) - DTO(参数校验) - 前端 API 调用 ## 快速生成指令格式 ``` 请生成后端接口: 模块名称:xxx 接口路径:GET/POST /api/xxx 功能描述:xxx 查询参数: - 参数1(类型,必填/选填) - 参数2(类型,必填/选填) 返回字段: - 字段1(来源表.字段) - 字段2(关联表.字段) 关联查询: - 表1 -> 表2(关联字段) 排序:字段名 + 排序方式 分页:是/否 ``` ## 文件结构 ``` backend/src/模块名/ ├── 模块名.module.ts # 模块定义 ├── 模块名.controller.ts # 路由控制器 ├── 模块名.service.ts # 业务逻辑 └── dto/ ├── query-xxx.dto.ts # 查询参数 DTO └── create-xxx.dto.ts # 创建参数 DTO frontend/src/api/ └── 模块名.ts # 前端 API 调用 ``` ## Controller 模板 ```typescript import { Controller, Get, Query, Param, UseGuards } from '@nestjs/common'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { XxxService } from './xxx.service'; import { QueryXxxDto } from './dto/query-xxx.dto'; @Controller('api/xxx') @UseGuards(JwtAuthGuard) export class XxxController { constructor(private readonly xxxService: XxxService) {} @Get(':id/list') async getList( @Param('id') id: string, @Query() queryDto: QueryXxxDto, ) { return this.xxxService.findAll(+id, queryDto); } } ``` ## Service 模板 ```typescript import { Injectable } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import { QueryXxxDto } from './dto/query-xxx.dto'; @Injectable() export class XxxService { constructor(private prisma: PrismaService) {} async findAll(parentId: number, queryDto: QueryXxxDto) { const { page = 1, pageSize = 10, ...filters } = queryDto; const skip = (page - 1) * pageSize; // 构建查询条件 const where: any = { parentId }; if (filters.field1) { where.field1 = { contains: filters.field1 }; } const [list, total] = await Promise.all([ this.prisma.table.findMany({ where, skip, take: pageSize, orderBy: { sortField: 'desc' }, include: { // 关联查询 }, }), this.prisma.table.count({ where }), ]); return { list, total, page, pageSize }; } } ``` ## DTO 模板 ```typescript import { IsOptional, IsString, IsInt, Min } from 'class-validator'; import { Type } from 'class-transformer'; export class QueryXxxDto { @IsOptional() @Type(() => Number) @IsInt() @Min(1) page?: number = 1; @IsOptional() @Type(() => Number) @IsInt() @Min(1) pageSize?: number = 10; @IsOptional() @IsString() field1?: string; @IsOptional() @IsString() field2?: string; } ``` ## 前端 API 模板 ```typescript import request from '@/utils/request' export interface QueryXxxParams { page?: number pageSize?: number field1?: string field2?: string } export interface XxxItem { id: number // ... 其他字段 } export interface XxxListResponse { list: XxxItem[] total: number page: number pageSize: number } export const xxxApi = { getList(parentId: number, params: QueryXxxParams): Promise { return request.get(`/api/xxx/${parentId}/list`, { params }) }, } ``` ## Prisma 关联查询示例 ### 常用关联模式 ```typescript // 用户信息 + 租户 + 学生班级年级 user: { include: { tenant: { select: { id: true, name: true }, }, student: { include: { class: { include: { grade: { select: { id: true, name: true }, }, }, }, }, }, }, } // 指导老师列表 teachers: { include: { user: { select: { id: true, username: true, nickname: true }, }, }, } // 报名信息 + 用户 + 团队 registration: { include: { user: { select: { id: true, username: true, nickname: true }, }, team: { select: { id: true, teamName: true }, }, }, } ``` ## 示例:赛果发布详情接口 ``` 请生成后端接口: 模块名称:results(已存在,需修改) 接口路径:GET /api/contests/:id/results/works 功能描述:获取赛事的作品列表(用于赛果发布) 查询参数: - page(number,选填,默认1) - pageSize(number,选填,默认10) - workNo(string,选填,作品编号模糊搜索) - accountNo(string,选填,报名账号模糊搜索) 返回字段: - id, workNo, title, finalScore(作品表) - registration.user.nickname, username(用户表) - registration.user.tenant.name(租户表) - registration.user.student.class.name, grade.name(班级年级) - registration.teachers[].user.nickname(指导老师) 关联查询: - ContestWork -> ContestRegistration(registrationId) - ContestRegistration -> User(userId) - User -> Tenant(tenantId) - User -> Student -> Class -> Grade - ContestRegistration -> ContestRegistrationTeacher -> User 排序:finalScore DESC 分页:是 ``` ## 注意事项 1. **权限控制**:Controller 需要添加 `@UseGuards(JwtAuthGuard)` 和权限装饰器 2. **参数校验**:DTO 使用 class-validator 进行校验 3. **分页处理**:统一使用 page/pageSize 参数 4. **空值处理**:查询条件为空时不添加到 where 条件 5. **关联数据**:使用 Prisma 的 include 进行关联查询 6. **性能优化**:只 select 需要的字段,避免查询过多数据 7. **错误处理**:Service 层抛出 NestJS 内置异常