library-picturebook-activity/.claude/skills/backend-api.md
2026-01-15 16:35:00 +08:00

262 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 后端接口生成规范
## 概述
本规范用于快速生成 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<XxxListResponse> {
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
功能描述:获取赛事的作品列表(用于赛果发布)
查询参数:
- pagenumber选填默认1
- pageSizenumber选填默认10
- workNostring选填作品编号模糊搜索
- accountNostring选填报名账号模糊搜索
返回字段:
- id, workNo, title, finalScore作品表
- registration.user.nickname, username用户表
- registration.user.tenant.name租户表
- registration.user.student.class.name, grade.name班级年级
- registration.teachers[].user.nickname指导老师
关联查询:
- ContestWork -> ContestRegistrationregistrationId
- ContestRegistration -> UseruserId
- User -> TenanttenantId
- 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 内置异常