Files
leaudit-platform-frontend/docs/evaluation/evaluation_point_groups.md
T
TanWenyan d3b9403d64 feat(evaluation): 模块1.1 - 增强评查点分组查询接口
## 主要改进

### 1. 增强 getRuleGroups 函数
-  添加完整的分页参数支持 (page, pageSize)
-  添加筛选参数 (name, code, is_enabled, pid)
-  添加排序参数 (orderBy, order)
-  返回总数 (totalCount)
-  支持一级分组和二级分组查询

### 2. 优化 getChildGroups 函数
-  内部使用改进后的 getRuleGroups 函数
-  自动添加评查点数量统计
-  改进类型安全性

### 3. 优化 getRuleGroup 函数
-  确保评查点数量统计准确
-  改进错误处理
-  优化类型守卫逻辑

### 4. 类型定义改进
-  新增 RuleGroupQueryParams 接口
-  ApiRuleGroup.pid 类型支持 null
-  修复所有 TypeScript 类型错误

### 5. 创建对接计划文档
-  详细的 API 对接实施计划
-  分模块逐步实施策略
-  验收标准和风险评估

## 相关文件
- app/api/evaluation_points/rule-groups.ts
- docs/evaluation/API对接实施计划.md

## 验收清单
- [x] TypeScript 类型检查通过
- [x] 支持分页、筛选、排序
- [x] 返回评查点数量统计
- [x] 向后兼容现有代码

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 12:06:48 +08:00

855 lines
18 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.
# 评查点分组管理 API 文档 v3
> **版本**: v3
> **路由前缀**: `/api/v3/evaluation-point-groups`
> **数据库表**: `evaluation_point_groups`
> **认证方式**: JWT Bearer Token
---
## 📋 目录
1. [数据模型](#数据模型)
2. [查询接口](#查询接口)
3. [创建接口](#创建接口)
4. [更新接口](#更新接口)
5. [删除接口](#删除接口)
6. [批量操作接口](#批量操作接口)
7. [错误响应](#错误响应)
8. [使用示例](#使用示例)
---
## 数据模型
### 数据库表结构 (`evaluation_point_groups`)
| 字段名 | 类型 | 约束 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `id` | INTEGER | PRIMARY KEY | auto_increment | 分组ID(自增主键) |
| `pid` | INTEGER | NULLABLE | NULL | 父分组IDNULL/0 表示一级分组) |
| `code` | VARCHAR(50) | NOT NULL | - | 分组编码(唯一标识) |
| `name` | VARCHAR(100) | NOT NULL | - | 分组名称 |
| `description` | TEXT | NULLABLE | NULL | 分组描述 |
| `is_enabled` | BOOLEAN | NOT NULL | true | 启用状态 |
| `created_at` | TIMESTAMPTZ | NOT NULL | now() | 创建时间 |
| `updated_at` | TIMESTAMPTZ | NOT NULL | now() | 更新时间 |
### Pydantic 数据模型
#### `EvaluationPointGroupBase` - 基础模型
```python
class EvaluationPointGroupBase(BaseModel):
name: str = Field(..., min_length=1, max_length=100, description="分组名称")
code: str = Field(..., min_length=1, max_length=50, pattern=r"^[a-zA-Z0-9_-]+$", description="分组编码")
pid: Optional[int] = Field(None, description="父分组ID (NULL/0表示一级分组)")
description: Optional[str] = Field(None, description="分组描述")
is_enabled: bool = Field(True, description="启用状态")
```
#### `EvaluationPointGroupCreate` - 创建请求模型
```python
class EvaluationPointGroupCreate(EvaluationPointGroupBase):
pass
```
#### `EvaluationPointGroupUpdate` - 更新请求模型
```python
class EvaluationPointGroupUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=100)
code: Optional[str] = Field(None, min_length=1, max_length=50, pattern=r"^[a-zA-Z0-9_-]+$")
pid: Optional[int] = None
description: Optional[str] = None
is_enabled: Optional[bool] = None
```
#### `EvaluationPointGroupResponse` - 响应模型
```python
class EvaluationPointGroupResponse(EvaluationPointGroupBase):
id: int
created_at: datetime
updated_at: datetime
rule_count: Optional[int] = Field(None, description="评查点数量(子分组查询时返回)")
children: Optional[List['EvaluationPointGroupResponse']] = Field(None, description="子分组列表")
class Config:
from_attributes = True
```
#### `EvaluationPointGroupListResponse` - 列表响应模型
```python
class EvaluationPointGroupListResponse(BaseModel):
data: List[EvaluationPointGroupResponse]
total: int
page: int
page_size: int
```
---
## 查询接口
### 1. 获取一级分组列表
**接口**: `GET /api/v3/evaluation-point-groups`
**功能**: 获取所有一级分组(pid = 0 或 NULL
**请求参数** (Query):
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `page` | int | 否 | 1 | 页码 |
| `page_size` | int | 否 | 20 | 每页数量(最大100) |
| `name` | str | 否 | - | 分组名称(模糊搜索) |
| `code` | str | 否 | - | 分组编码(模糊搜索) |
| `is_enabled` | bool | 否 | - | 启用状态筛选 |
**响应示例**:
```json
{
"data": [
{
"id": 1,
"pid": null,
"name": "合同基本要素",
"code": "contract-basic",
"description": "合同基本信息检查",
"is_enabled": true,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z",
"rule_count": null,
"children": null
}
],
"total": 10,
"page": 1,
"page_size": 20
}
```
**SQL 等价**:
```sql
SELECT * FROM evaluation_point_groups
WHERE (pid = 0 OR pid IS NULL)
AND name ILIKE '%合同%' -- 可选
AND code ILIKE '%basic%' -- 可选
AND is_enabled = true -- 可选
ORDER BY created_at DESC
LIMIT 20 OFFSET 0;
```
---
### 2. 获取所有分组(树形结构)
**接口**: `GET /api/v3/evaluation-point-groups/all`
**功能**: 获取所有分组并构建父子树形结构
**请求参数** (Query):
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `include_disabled` | bool | 否 | false | 是否包含禁用的分组 |
| `with_rule_count` | bool | 否 | true | 是否返回评查点数量 |
**响应示例**:
```json
{
"data": [
{
"id": 1,
"pid": null,
"name": "合同基本要素",
"code": "contract-basic",
"description": "合同基本信息检查",
"is_enabled": true,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z",
"rule_count": 15,
"children": [
{
"id": 2,
"pid": 1,
"name": "合同主体信息",
"code": "contract-subject",
"description": "检查合同主体信息",
"is_enabled": true,
"created_at": "2024-01-01T11:00:00Z",
"updated_at": "2024-01-01T11:00:00Z",
"rule_count": 5,
"children": null
}
]
}
],
"total": 25,
"page": 1,
"page_size": 1000
}
```
**处理逻辑**:
1. 查询所有分组(可选过滤禁用状态)
2. 筛选一级分组(pid = NULL 或 0
3. 为每个一级分组查找子分组(pid = parent.id
4. 如果 `with_rule_count=true`,查询每个分组的评查点数量
---
### 3. 获取单个分组详情
**接口**: `GET /api/v3/evaluation-point-groups/{id}`
**功能**: 根据 ID 获取分组详情
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | int | 是 | 分组ID |
**查询参数** (Query):
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `with_rule_count` | bool | 否 | true | 是否返回评查点数量 |
**响应示例**:
```json
{
"id": 1,
"pid": null,
"name": "合同基本要素",
"code": "contract-basic",
"description": "合同基本信息检查",
"is_enabled": true,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z",
"rule_count": 15,
"children": null
}
```
**错误响应** (404):
```json
{
"detail": "评查点分组不存在"
}
```
---
### 4. 获取子分组列表
**接口**: `GET /api/v3/evaluation-point-groups/{parent_id}/children`
**功能**: 获取指定父分组下的所有子分组,并附带评查点数量
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `parent_id` | int | 是 | 父分组ID |
**查询参数** (Query):
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `page` | int | 否 | 1 | 页码 |
| `page_size` | int | 否 | 20 | 每页数量 |
| `is_enabled` | bool | 否 | - | 启用状态筛选 |
**响应示例**:
```json
{
"data": [
{
"id": 2,
"pid": 1,
"name": "合同主体信息",
"code": "contract-subject",
"description": "检查合同主体信息",
"is_enabled": true,
"created_at": "2024-01-01T11:00:00Z",
"updated_at": "2024-01-01T11:00:00Z",
"rule_count": 5,
"children": null
}
],
"total": 5,
"page": 1,
"page_size": 20
}
```
**SQL 等价**:
```sql
-- 查询子分组
SELECT * FROM evaluation_point_groups
WHERE pid = 1
AND is_enabled = true -- 可选
ORDER BY created_at DESC
LIMIT 20 OFFSET 0;
-- 查询每个子分组的评查点数量
SELECT COUNT(*) FROM evaluation_points
WHERE evaluation_point_groups_id = 2;
```
---
## 创建接口
### 5. 创建评查点分组
**接口**: `POST /api/v3/evaluation-point-groups`
**功能**: 创建新的评查点分组(一级或二级)
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体**:
```json
{
"name": "合同主体信息",
"code": "contract-subject",
"pid": 1,
"description": "检查合同主体信息的完整性",
"is_enabled": true
}
```
**字段说明**:
- `name`: 必填,1-100字符
- `code`: 必填,1-50字符,只能包含字母、数字、连字符和下划线
- `pid`: 可选,NULL/0 表示一级分组,其他值为父分组ID
- `description`: 可选,分组描述
- `is_enabled`: 可选,默认 true
**字段验证规则**:
1. `name``code` 不能为空
2. `code` 必须唯一(数据库约束)
3. `code` 格式:`^[a-zA-Z0-9_-]+$`
4. 如果 `pid` 不为 NULL/0,必须引用存在的分组ID
**响应示例** (201 Created):
```json
{
"id": 3,
"pid": 1,
"name": "合同主体信息",
"code": "contract-subject",
"description": "检查合同主体信息的完整性",
"is_enabled": true,
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T14:30:00Z",
"rule_count": 0,
"children": null
}
```
**错误响应** (400):
```json
{
"detail": "分组编码已存在"
}
```
**错误响应** (404):
```json
{
"detail": "父分组不存在"
}
```
---
## 更新接口
### 6. 更新评查点分组
**接口**: `PUT /api/v3/evaluation-point-groups/{id}`
**功能**: 更新指定分组的信息
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | int | 是 | 分组ID |
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体** (Partial Update):
```json
{
"name": "合同主体信息(更新)",
"code": "contract-subject-v2",
"description": "更新后的描述",
"is_enabled": false
}
```
**字段说明**:
- 所有字段均为可选
- 只更新提供的字段
- `updated_at` 自动更新为当前时间
**响应示例** (200 OK):
```json
{
"id": 3,
"pid": 1,
"name": "合同主体信息(更新)",
"code": "contract-subject-v2",
"description": "更新后的描述",
"is_enabled": false,
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T16:00:00Z",
"rule_count": 5,
"children": null
}
```
**错误响应** (404):
```json
{
"detail": "评查点分组不存在"
}
```
**错误响应** (400):
```json
{
"detail": "分组编码已被其他分组使用"
}
```
---
## 删除接口
### 7. 删除评查点分组
**接口**: `DELETE /api/v3/evaluation-point-groups/{id}`
**功能**: 删除指定分组(级联删除子分组和评查点)
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | int | 是 | 分组ID |
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
```
**删除逻辑**:
1. 查询分组信息,判断是一级还是二级分组
2. 如果是一级分组:
- 查询所有子分组
- 删除每个子分组的评查点(`evaluation_points` 表)
- 删除所有子分组
3. 删除当前分组的评查点
4. 删除当前分组
**响应示例** (200 OK):
```json
{
"success": true,
"message": "评查点分组删除成功",
"deleted_groups": 3,
"deleted_points": 15
}
```
**错误响应** (404):
```json
{
"detail": "评查点分组不存在"
}
```
**SQL 执行顺序** (伪代码):
```sql
-- 1. 查询分组信息
SELECT * FROM evaluation_point_groups WHERE id = ?;
-- 2. 如果是一级分组,查询所有子分组
SELECT * FROM evaluation_point_groups WHERE pid = ?;
-- 3. 删除所有子分组的评查点
DELETE FROM evaluation_points
WHERE evaluation_point_groups_id IN (
SELECT id FROM evaluation_point_groups WHERE pid = ?
);
-- 4. 删除所有子分组
DELETE FROM evaluation_point_groups WHERE pid = ?;
-- 5. 删除当前分组的评查点
DELETE FROM evaluation_points WHERE evaluation_point_groups_id = ?;
-- 6. 删除当前分组
DELETE FROM evaluation_point_groups WHERE id = ?;
```
---
## 批量操作接口
### 8. 批量更新启用状态
**接口**: `PATCH /api/v3/evaluation-point-groups/batch/status`
**功能**: 批量更新多个分组的启用状态
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体**:
```json
{
"ids": [1, 2, 3],
"is_enabled": false
}
```
**响应示例** (200 OK):
```json
{
"success": true,
"updated_count": 3,
"message": "批量更新成功"
}
```
---
### 9. 批量删除分组
**接口**: `DELETE /api/v3/evaluation-point-groups/batch`
**功能**: 批量删除多个分组(级联删除)
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体**:
```json
{
"ids": [1, 2, 3]
}
```
**响应示例** (200 OK):
```json
{
"success": true,
"deleted_groups": 5,
"deleted_points": 25,
"message": "批量删除成功"
}
```
---
## 错误响应
### 标准错误响应格式
```json
{
"detail": "错误描述信息"
}
```
### 常见错误码
| HTTP 状态码 | 错误场景 | 示例 |
|------------|---------|------|
| 400 | 请求参数验证失败 | `{"detail": "分组名称不能为空"}` |
| 401 | 未授权(JWT无效) | `{"detail": "未授权访问"}` |
| 404 | 资源不存在 | `{"detail": "评查点分组不存在"}` |
| 409 | 资源冲突 | `{"detail": "分组编码已存在"}` |
| 422 | 数据验证失败 | `{"detail": [{"loc": ["body", "code"], "msg": "格式不正确"}]}` |
| 500 | 服务器内部错误 | `{"detail": "服务器错误,请稍后重试"}` |
---
## 使用示例
### 示例 1: 获取一级分组(带分页和筛选)
**请求**:
```http
GET /api/v3/evaluation-point-groups?page=1&page_size=10&name=&is_enabled=true
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**响应**:
```json
{
"data": [
{
"id": 1,
"pid": null,
"name": "合同基本要素",
"code": "contract-basic",
"description": "合同基本信息检查",
"is_enabled": true,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z",
"rule_count": null,
"children": null
}
],
"total": 1,
"page": 1,
"page_size": 10
}
```
---
### 示例 2: 创建二级分组
**请求**:
```http
POST /api/v3/evaluation-point-groups
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"name": "",
"code": "contract-subject",
"pid": 1,
"description": "",
"is_enabled": true
}
```
**响应**:
```json
{
"id": 3,
"pid": 1,
"name": "合同主体信息",
"code": "contract-subject",
"description": "检查合同主体信息的完整性",
"is_enabled": true,
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T14:30:00Z",
"rule_count": 0,
"children": null
}
```
---
### 示例 3: 获取树形结构
**请求**:
```http
GET /api/v3/evaluation-point-groups/all?include_disabled=false&with_rule_count=true
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**响应**:
```json
{
"data": [
{
"id": 1,
"pid": null,
"name": "合同基本要素",
"code": "contract-basic",
"description": "合同基本信息检查",
"is_enabled": true,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z",
"rule_count": 15,
"children": [
{
"id": 2,
"pid": 1,
"name": "合同主体信息",
"code": "contract-subject",
"description": "检查合同主体信息",
"is_enabled": true,
"created_at": "2024-01-01T11:00:00Z",
"updated_at": "2024-01-01T11:00:00Z",
"rule_count": 5,
"children": null
}
]
}
],
"total": 25,
"page": 1,
"page_size": 1000
}
```
---
### 示例 4: 批量更新状态
**请求**:
```http
PATCH /api/v3/evaluation-point-groups/batch/status
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"ids": [1, 2, 3],
"is_enabled": false
}
```
**响应**:
```json
{
"success": true,
"updated_count": 3,
"message": "批量更新成功"
}
```
---
### 示例 5: 删除分组(级联删除)
**请求**:
```http
DELETE /api/v3/evaluation-point-groups/1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**响应**:
```json
{
"success": true,
"message": "评查点分组删除成功",
"deleted_groups": 3,
"deleted_points": 15
}
```
---
## 附录
### 性能优化建议
1. **查询优化**:
-`pid``code``is_enabled` 字段创建索引
- 使用分页避免一次性加载大量数据
- 树形结构查询时,使用递归查询或批量查询减少数据库往返
2. **缓存策略**:
- 对不常变化的分组列表进行缓存(Redis)
- 缓存键格式: `eval_groups:all`, `eval_groups:{id}`
- 创建/更新/删除操作时清除相关缓存
3. **批量操作**:
- 使用批量查询减少数据库连接开销
- 使用事务确保批量操作的原子性
### 数据库索引建议
```sql
-- 为常用查询字段创建索引
CREATE INDEX idx_evaluation_point_groups_pid ON evaluation_point_groups(pid);
CREATE INDEX idx_evaluation_point_groups_code ON evaluation_point_groups(code);
CREATE INDEX idx_evaluation_point_groups_is_enabled ON evaluation_point_groups(is_enabled);
CREATE INDEX idx_evaluation_point_groups_created_at ON evaluation_point_groups(created_at DESC);
-- 为外键创建索引(提升关联查询性能)
CREATE INDEX idx_evaluation_points_group_id ON evaluation_points(evaluation_point_groups_id);
CREATE INDEX idx_evaluation_points_parent_group_id ON evaluation_points(evaluation_point_groups_pid);
```
### 与 PostgREST 前端实现的对比
| 功能 | PostgREST 前端实现 | FastAPI 后端实现 |
|------|-------------------|-----------------|
| 认证方式 | 前端传递 JWT | 后端验证 JWT |
| 分页 | 前端手动实现 | 后端自动分页 |
| 树形结构 | 前端构建 | 后端构建(可选) |
| 评查点数量 | 前端并发查询 | 后端一次性返回 |
| 级联删除 | 前端多次调用 | 后端事务处理 |
| 数据验证 | 前端验证 | 前后端双重验证 |
| 错误处理 | 前端解析错误 | 后端统一错误格式 |
---
**文档版本**: v1.0
**最后更新**: 2025-01-21
**维护者**: DocAuditAI Team