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

18 KiB
Raw Blame History

评查点分组管理 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 父分组ID(NULL/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 - 基础模型

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 - 创建请求模型

class EvaluationPointGroupCreate(EvaluationPointGroupBase):
    pass

EvaluationPointGroupUpdate - 更新请求模型

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 - 响应模型

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 - 列表响应模型

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 - 启用状态筛选

响应示例:

{
  "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 等价:

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 是否返回评查点数量

响应示例:

{
  "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 是否返回评查点数量

响应示例:

{
  "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):

{
  "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 - 启用状态筛选

响应示例:

{
  "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 等价:

-- 查询子分组
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

请求体:

{
  "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. namecode 不能为空
  2. code 必须唯一(数据库约束)
  3. code 格式:^[a-zA-Z0-9_-]+$
  4. 如果 pid 不为 NULL/0,必须引用存在的分组ID

响应示例 (201 Created):

{
  "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):

{
  "detail": "分组编码已存在"
}

错误响应 (404):

{
  "detail": "父分组不存在"
}

更新接口

6. 更新评查点分组

接口: PUT /api/v3/evaluation-point-groups/{id}

功能: 更新指定分组的信息

路径参数:

参数名 类型 必填 说明
id int 分组ID

请求头:

Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

请求体 (Partial Update):

{
  "name": "合同主体信息(更新)",
  "code": "contract-subject-v2",
  "description": "更新后的描述",
  "is_enabled": false
}

字段说明:

  • 所有字段均为可选
  • 只更新提供的字段
  • updated_at 自动更新为当前时间

响应示例 (200 OK):

{
  "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):

{
  "detail": "评查点分组不存在"
}

错误响应 (400):

{
  "detail": "分组编码已被其他分组使用"
}

删除接口

7. 删除评查点分组

接口: DELETE /api/v3/evaluation-point-groups/{id}

功能: 删除指定分组(级联删除子分组和评查点)

路径参数:

参数名 类型 必填 说明
id int 分组ID

请求头:

Authorization: Bearer <JWT_TOKEN>

删除逻辑:

  1. 查询分组信息,判断是一级还是二级分组
  2. 如果是一级分组:
    • 查询所有子分组
    • 删除每个子分组的评查点(evaluation_points 表)
    • 删除所有子分组
  3. 删除当前分组的评查点
  4. 删除当前分组

响应示例 (200 OK):

{
  "success": true,
  "message": "评查点分组删除成功",
  "deleted_groups": 3,
  "deleted_points": 15
}

错误响应 (404):

{
  "detail": "评查点分组不存在"
}

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

请求体:

{
  "ids": [1, 2, 3],
  "is_enabled": false
}

响应示例 (200 OK):

{
  "success": true,
  "updated_count": 3,
  "message": "批量更新成功"
}

9. 批量删除分组

接口: DELETE /api/v3/evaluation-point-groups/batch

功能: 批量删除多个分组(级联删除)

请求头:

Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

请求体:

{
  "ids": [1, 2, 3]
}

响应示例 (200 OK):

{
  "success": true,
  "deleted_groups": 5,
  "deleted_points": 25,
  "message": "批量删除成功"
}

错误响应

标准错误响应格式

{
  "detail": "错误描述信息"
}

常见错误码

HTTP 状态码 错误场景 示例
400 请求参数验证失败 {"detail": "分组名称不能为空"}
401 未授权(JWT无效) {"detail": "未授权访问"}
404 资源不存在 {"detail": "评查点分组不存在"}
409 资源冲突 {"detail": "分组编码已存在"}
422 数据验证失败 {"detail": [{"loc": ["body", "code"], "msg": "格式不正确"}]}
500 服务器内部错误 {"detail": "服务器错误,请稍后重试"}

使用示例

示例 1: 获取一级分组(带分页和筛选)

请求:

GET /api/v3/evaluation-point-groups?page=1&page_size=10&name=合同&is_enabled=true
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

响应:

{
  "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: 创建二级分组

请求:

POST /api/v3/evaluation-point-groups
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "name": "合同主体信息",
  "code": "contract-subject",
  "pid": 1,
  "description": "检查合同主体信息的完整性",
  "is_enabled": true
}

响应:

{
  "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: 获取树形结构

请求:

GET /api/v3/evaluation-point-groups/all?include_disabled=false&with_rule_count=true
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

响应:

{
  "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: 批量更新状态

请求:

PATCH /api/v3/evaluation-point-groups/batch/status
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "ids": [1, 2, 3],
  "is_enabled": false
}

响应:

{
  "success": true,
  "updated_count": 3,
  "message": "批量更新成功"
}

示例 5: 删除分组(级联删除)

请求:

DELETE /api/v3/evaluation-point-groups/1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

响应:

{
  "success": true,
  "message": "评查点分组删除成功",
  "deleted_groups": 3,
  "deleted_points": 15
}

附录

性能优化建议

  1. 查询优化:

    • pidcodeis_enabled 字段创建索引
    • 使用分页避免一次性加载大量数据
    • 树形结构查询时,使用递归查询或批量查询减少数据库往返
  2. 缓存策略:

    • 对不常变化的分组列表进行缓存(Redis)
    • 缓存键格式: eval_groups:all, eval_groups:{id}
    • 创建/更新/删除操作时清除相关缓存
  3. 批量操作:

    • 使用批量查询减少数据库连接开销
    • 使用事务确保批量操作的原子性

数据库索引建议

-- 为常用查询字段创建索引
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