Files
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

1308 lines
33 KiB
Markdown
Raw Permalink 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-points`
> **数据库表**: `evaluation_points`
> **认证方式**: JWT Bearer Token
---
## 📋 目录
1. [数据模型](#数据模型)
2. [查询接口](#查询接口)
3. [创建接口](#创建接口)
4. [更新接口](#更新接口)
5. [删除接口](#删除接口)
6. [批量操作接口](#批量操作接口)
7. [错误响应](#错误响应)
8. [使用示例](#使用示例)
---
## 数据模型
### 数据库表结构 (`evaluation_points`)
| 字段名 | 类型 | 约束 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `id` | INTEGER | PRIMARY KEY | auto_increment | 评查点ID(自增主键) |
| `code` | VARCHAR(100) | UNIQUE, NOT NULL | - | 评查点编码(唯一标识) |
| `name` | VARCHAR(100) | NOT NULL | - | 评查点名称 |
| `evaluation_point_groups_id` | INTEGER | FOREIGN KEY | NULL | 所属二级分组ID |
| `evaluation_point_groups_pid` | INTEGER | FOREIGN KEY | NULL | 所属一级分组ID |
| `risk` | VARCHAR(10) | NOT NULL | - | 风险等级(high/medium/low |
| `description` | TEXT | NULLABLE | NULL | 评查点描述 |
| `is_enabled` | BOOLEAN | NOT NULL | true | 启用状态 |
| `references_laws` | JSONB | NOT NULL | - | 引用法典(JSON结构) |
| `extraction_config` | JSONB | NOT NULL | - | 抽取配置(JSON结构) |
| `evaluation_config` | JSONB | NOT NULL | - | 评查设置(JSON结构) |
| `pass_message` | TEXT | NULLABLE | NULL | 通过提示 |
| `fail_message` | TEXT | NULLABLE | NULL | 不通过提示 |
| `suggestion_message` | TEXT | NULLABLE | NULL | 建议信息 |
| `suggestion_message_type` | VARCHAR(20) | NOT NULL | 'warning' | 建议信息类型(info/warning/error |
| `post_action` | VARCHAR(50) | NULLABLE | NULL | 评查后动作类型(none/manual/replace |
| `action_config` | TEXT | NULLABLE | NULL | 动作配置 |
| `score` | NUMERIC(5,2) | NOT NULL | 0.00 | 评查点得分 |
| `area` | VARCHAR(20) | NULLABLE | NULL | 所属地区 |
| `created_at` | TIMESTAMPTZ | NOT NULL | now() | 创建时间 |
| `updated_at` | TIMESTAMPTZ | NOT NULL | now() | 更新时间 |
### 外键关系
```sql
-- 二级分组外键
FOREIGN KEY (evaluation_point_groups_id)
REFERENCES evaluation_point_groups(id)
ON UPDATE CASCADE ON DELETE SET NULL
-- 一级分组外键
FOREIGN KEY (evaluation_point_groups_pid)
REFERENCES evaluation_point_groups(id)
ON UPDATE CASCADE ON DELETE SET NULL
```
---
## JSONB 字段结构详解
### 1. `references_laws` - 引用法典
**数据结构**:
```typescript
{
"name": string, // 法律法规名称
"content": string, // 法律法规内容
"articles": string[] // 条款列表
}
```
**示例**:
```json
{
"name": "中华人民共和国合同法",
"content": "第十条 当事人订立合同,有书面形式、口头形式和其他形式。",
"articles": ["第十条", "第十一条"]
}
```
---
### 2. `extraction_config` - 抽取配置
**数据结构**:
```typescript
{
"llm": { // LLM抽取配置
"fields": string[], // 抽取字段列表
"prompt_setting": {
"type": string, // 提示词类型:"system" 或 "llm_default_prompt"
"template": "" // 固定为空字符串
}
},
"vlm": { // VLM视觉抽取配置
"fields": Array<{
"name": string, // 字段名称
"type": string // 字段级提示词类型 (vlm_default_prompt/vlm_handwriting_prompt/等)
}>,
"prompt_setting": {
"type": string, // 提示词类型:"system" 或 "vlm_default_prompt"
"template": "" // 固定为空字符串
}
},
"regex": { // 正则表达式抽取配置
"fields": Array<{
"field": string, // 字段名称(完整路径,如:文书名-章节-字段名)
"pattern": string // 正则表达式
}>
}
}
```
**重要说明**:
- **prompt_setting.type 支持两种值**
- `"system"` - 旧格式,后端抽取模块识别并处理(推荐)
- `"llm_default_prompt"` / `"vlm_default_prompt"` - 前端新格式,**后端不处理**
- ⚠️ **兼容性警告**:如果使用 `llm_default_prompt` / `vlm_default_prompt`,抽取模块将**忽略该配置**
- **推荐使用** `"system"` 确保后端正确处理
- `vlm.fields[].type` 是字段级的提示词类型,与 `prompt_setting.type` 不同
- `template` 字段固定为空字符串 `""`
- 前端界面保存时使用 `llm_default_prompt` / `vlm_default_prompt`,但建议改为 `system`
**示例1:推荐格式(使用 "system",后端可处理)**:
```json
{
"llm": {
"fields": ["合同封面-合同名称", "合同封面-合同编号", "合同正文-合同名称"],
"prompt_setting": {
"type": "system",
"template": ""
}
},
"vlm": {
"fields": [
{
"name": "证据复制(提取)单-居民身份证-姓名",
"type": "vlm_default_prompt"
},
{
"name": "立案报告表-负责人意见-签名(有/无)",
"type": "vlm_handwriting_prompt"
}
],
"prompt_setting": {
"type": "system",
"template": ""
}
},
"regex": {
"fields": [
{
"field": "行政处罚事先告知书-正文-权利告知",
"pattern": "(?:享有|陈述|权|申辩|权).{0,40}(日).{0,40}(?:视为|放弃|权利)"
}
]
}
}
```
**示例2:前端新格式(使用 "llm_default_prompt",后端不处理⚠️**:
```json
{
"llm": {
"fields": ["test-llm"],
"prompt_setting": {
"type": "llm_default_prompt",
"template": ""
}
},
"vlm": {
"fields": [
{
"name": "test-vlm",
"type": "vlm_default_prompt"
}
],
"prompt_setting": {
"type": "vlm_default_prompt",
"template": ""
}
},
"regex": {
"fields": [
{
"field": "test-zz",
"pattern": "\\d{4}[-/年](0?[1-9]|1[0-2])[-/月](0?[1-9]|[12][0-9]|3[01])[日]?"
}
]
}
}
```
⚠️ **注意**:示例2的格式虽然可以保存到数据库,但抽取模块会忽略 `prompt_setting.type != "system"` 的配置,导致这些字段不会被抽取!
---
### 3. `evaluation_config` - 评查设置
**数据结构**:
```typescript
{
"logicType": string, // 逻辑类型 (and/or/custom)
"customLogic": string, // 自定义逻辑表达式
"rules": Array<{ // 评查规则列表
"id": string, // 规则ID
"type": string, // 规则类型 (exists/consistency/logic/regex/ai)
"config": {
// exists 规则配置
"logic"?: string, // 逻辑运算符 (and/or)
"fields"?: string[], // 字段列表
// consistency 规则配置
"pairs"?: Array<{ // 字段对列表
"sourceField": string,
"targetField": string,
"compareMethod": string // 比较方法 (exact/fuzzy/contains)
}>,
// logic 规则配置
"conditions"?: Array<{ // 条件列表
"field": string, // 字段名
"operator": string, // 运算符 (eq/neq/gt/lt/contains等)
"value": any // 比较值
}>,
// regex 规则配置
"field"?: string, // 目标字段
"pattern"?: string, // 正则表达式
"matchType"?: string, // 匹配类型 (match/search/fullmatch)
// ai 规则配置
"model"?: string, // AI模型标识 (deepseek/qwen14b/qwen32b等) - 仅用于前端显示,后端使用统一配置的LLM模型
"prompt"?: string, // AI提示词(支持字段占位符 {字段名})
"temperature"?: number, // 温度参数 (0.0-1.0) - 仅用于前端显示,后端使用默认配置
// 通用配置
"selectedFields"?: string[] // 选中的字段列表(可选)
}
}>
}
```
**评查规则类型说明**:
| 规则类型 | 说明 | config字段 | 界面显示 |
|---------|------|-----------|----------|
| `exists` | 字段存在性检查 | `logic`, `fields` | 字段存在性 |
| `consistency` | 字段一致性检查 | `logic`, `pairs` (sourceField, targetField, compareMethod) | 字段一致性 |
| `logic` | 逻辑条件判断 | `logic`, `conditions` (field, operator, value) | 逻辑判断 |
| `regex` | 正则表达式匹配 | `field`, `pattern`, `matchType` | 正则匹配 |
| `ai` | AI智能评查 | `model`(仅标识), `prompt`, `temperature`(仅标识), `selectedFields` | AI评查(大模型) |
**重要说明**:
- `ai` 规则中的 `model``temperature` 字段**仅用于前端界面显示和标识**
- 后端实际使用环境配置中的 `DEFAULT_LLM_MODEL` 和默认温度参数(0.6)
- 如需切换AI模型,需修改后端配置文件,而非评查点配置
**示例1:综合规则配置**:
```json
{
"logicType": "and",
"customLogic": "",
"rules": [
{
"id": "1",
"type": "exists",
"config": {
"logic": "and",
"fields": ["合同封面-有效期限", "合同封面-签订日期", "合同正文-合同生效"]
}
},
{
"id": "2",
"type": "consistency",
"config": {
"logic": "and",
"pairs": [
{
"sourceField": "合同封面-合同名称",
"targetField": "合同正文-合同名称",
"compareMethod": "exact"
}
]
}
},
{
"id": "3",
"type": "ai",
"config": {
"model": "deepseek",
"prompt": "请判断{合同落款-甲方-签订日期}和{合同落款-乙方-签订日期}中较晚的日期即为{合同正文-合同生效}起始日期,{合同封面-有效期限}有明确日期范围的情况下,{合同落款-甲方-签订日期}和{合同落款-乙方-签订日期}与{合同封面-有效期限}明确日期范围上限差值是否小于3天,小于3天为不符合,若{合同落款-甲方-签订日期}或{合同落款-乙方-签订日期}大于{合同封面-有效期限}明确日期范围上限,则提示""\n仅回答\"符合\"、\"不符合\"或"",并简要说明理由。",
"temperature": 0.1,
"selectedFields": []
}
}
]
}
```
**示例2:纯AI评查**:
```json
{
"logicType": "and",
"customLogic": "",
"rules": [
{
"id": "1",
"type": "ai",
"config": {
"model": "qwen14b",
"prompt": "请判断以下{文本、印刷体大模型评查-正文-内容}是否包含了时间地点人物事情工具的四要素,仅回答\"符合\"或\"不符合\",并简要说明理由。",
"temperature": 0.1
}
}
]
}
```
---
## Pydantic 数据模型
### `EvaluationPointBase` - 基础模型
```python
class ReferencesLaw(BaseModel):
"""法律法规引用"""
name: str = Field(default="", description="法律法规名称")
content: str = Field(default="", description="法律法规内容")
articles: List[str] = Field(default_factory=list, description="条款列表")
class LLMExtractionConfig(BaseModel):
"""LLM抽取配置"""
fields: List[str] = Field(default_factory=list, description="抽取字段列表")
prompt_setting: Dict[str, str] = Field(
default_factory=lambda: {"type": "llm_default_prompt", "template": ""}
)
class VLMField(BaseModel):
"""VLM字段配置"""
name: str
type: str = "vlm_default_prompt"
class VLMExtractionConfig(BaseModel):
"""VLM抽取配置"""
fields: List[VLMField] = Field(default_factory=list)
prompt_setting: Dict[str, str] = Field(
default_factory=lambda: {"type": "vlm_default_prompt", "template": ""}
)
class RegexField(BaseModel):
"""正则表达式字段"""
field: str
pattern: str
class RegexExtractionConfig(BaseModel):
"""正则表达式抽取配置"""
fields: List[RegexField] = Field(default_factory=list)
class ExtractionConfig(BaseModel):
"""完整抽取配置"""
llm: LLMExtractionConfig = Field(default_factory=LLMExtractionConfig)
vlm: VLMExtractionConfig = Field(default_factory=VLMExtractionConfig)
regex: RegexExtractionConfig = Field(default_factory=RegexExtractionConfig)
class EvaluationRule(BaseModel):
"""评查规则"""
id: str
type: str # exists/consistency/range/format/ai
config: Dict[str, Any]
class EvaluationConfig(BaseModel):
"""评查配置"""
logicType: str = Field("and", description="逻辑类型 (and/or/custom)")
customLogic: str = Field("", description="自定义逻辑表达式")
rules: List[EvaluationRule] = Field(default_factory=list)
class EvaluationPointBase(BaseModel):
"""评查点基础模型"""
name: str = Field(..., min_length=1, max_length=100)
code: str = Field(..., min_length=1, max_length=100, pattern=r"^[a-zA-Z0-9_-]+$")
risk: str = Field(..., pattern=r"^(high|medium|low)$")
is_enabled: bool = Field(True)
description: Optional[str] = None
evaluation_point_groups_id: int = Field(..., description="二级分组ID")
evaluation_point_groups_pid: int = Field(..., description="一级分组ID")
references_laws: ReferencesLaw = Field(default_factory=ReferencesLaw)
extraction_config: ExtractionConfig = Field(default_factory=ExtractionConfig)
evaluation_config: EvaluationConfig = Field(default_factory=EvaluationConfig)
pass_message: str = Field(default="文档检查通过,符合规范要求。")
fail_message: str = Field(default="文档存在以下问题,请修改后重新提交。")
suggestion_message: Optional[str] = None
suggestion_message_type: str = Field(default="warning", pattern=r"^(info|warning|error)$")
post_action: Optional[str] = Field(None, pattern=r"^(none|manual|replace)$")
action_config: Optional[str] = None
score: float = Field(default=0.00, ge=0, le=100)
```
### `EvaluationPointCreate` - 创建请求模型
```python
class EvaluationPointCreate(EvaluationPointBase):
"""创建评查点请求"""
pass
```
### `EvaluationPointUpdate` - 更新请求模型
```python
class EvaluationPointUpdate(BaseModel):
"""更新评查点请求(所有字段可选)"""
name: Optional[str] = Field(None, min_length=1, max_length=100)
code: Optional[str] = Field(None, min_length=1, max_length=100)
risk: Optional[str] = Field(None, pattern=r"^(high|medium|low)$")
is_enabled: Optional[bool] = None
description: Optional[str] = None
evaluation_point_groups_id: Optional[int] = None
evaluation_point_groups_pid: Optional[int] = None
references_laws: Optional[ReferencesLaw] = None
extraction_config: Optional[ExtractionConfig] = None
evaluation_config: Optional[EvaluationConfig] = None
pass_message: Optional[str] = None
fail_message: Optional[str] = None
suggestion_message: Optional[str] = None
suggestion_message_type: Optional[str] = Field(None, pattern=r"^(info|warning|error)$")
post_action: Optional[str] = Field(None, pattern=r"^(none|manual|replace)$")
action_config: Optional[str] = None
score: Optional[float] = Field(None, ge=0, le=100)
```
### `EvaluationPointResponse` - 响应模型
```python
class EvaluationPointResponse(BaseModel):
"""评查点响应"""
id: int
name: str
code: str
risk: str
is_enabled: bool
description: Optional[str]
evaluation_point_groups_id: int
evaluation_point_groups_pid: int
references_laws: Dict[str, Any]
extraction_config: Dict[str, Any]
evaluation_config: Dict[str, Any]
pass_message: str
fail_message: str
suggestion_message: Optional[str]
suggestion_message_type: str
post_action: Optional[str]
action_config: Optional[str]
score: float
area: Optional[str]
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
```
### `EvaluationPointListResponse` - 列表响应模型
```python
class EvaluationPointListResponse(BaseModel):
"""评查点列表响应"""
data: List[EvaluationPointResponse]
total: int
page: int
page_size: int
```
---
## 查询接口
### 1. 获取评查点列表
**接口**: `GET /api/v3/evaluation-points`
**功能**: 获取评查点列表,支持分页和多条件筛选
**请求参数** (Query):
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `page` | int | 否 | 1 | 页码 |
| `page_size` | int | 否 | 20 | 每页数量(最大100) |
| `name` | str | 否 | - | 评查点名称(模糊搜索) |
| `code` | str | 否 | - | 评查点编码(模糊搜索) |
| `risk` | str | 否 | - | 风险等级(high/medium/low |
| `is_enabled` | bool | 否 | - | 启用状态 |
| `evaluation_point_groups_id` | int | 否 | - | 二级分组ID |
| `evaluation_point_groups_pid` | int | 否 | - | 一级分组ID |
| `area` | str | 否 | - | 所属地区 |
**响应示例**:
```json
{
"data": [
{
"id": 693,
"name": "测试评查点-test",
"code": "test-test",
"risk": "low",
"is_enabled": true,
"description": "",
"evaluation_point_groups_pid": 1,
"evaluation_point_groups_id": 40,
"references_laws": {
"name": "",
"content": "",
"articles": []
},
"extraction_config": {
"llm": {
"fields": ["test-llm"],
"prompt_setting": {
"type": "llm_default_prompt",
"template": ""
}
},
"vlm": {
"fields": [
{
"name": "test-vlm",
"type": "vlm_default_prompt"
}
],
"prompt_setting": {
"type": "vlm_default_prompt",
"template": ""
}
},
"regex": {
"fields": [
{
"field": "test-zz",
"pattern": "\\d{4}[-/年](0?[1-9]|1[0-2])[-/月](0?[1-9]|[12][0-9]|3[01])[日]?"
}
]
}
},
"evaluation_config": {
"logicType": "and",
"customLogic": "",
"rules": [
{
"id": "1",
"type": "exists",
"config": {
"logic": "and",
"fields": ["test-llm"]
}
},
{
"id": "2",
"type": "consistency",
"config": {
"logic": "and",
"pairs": [
{
"sourceField": "test-vlm",
"targetField": "test-zz",
"compareMethod": "exact"
}
]
}
}
]
},
"pass_message": "文档检查通过,符合规范要求。",
"fail_message": "文档存在以下问题,请修改后重新提交。",
"suggestion_message": "你觉得呢",
"suggestion_message_type": "warning",
"post_action": "manual",
"action_config": "测试评查后动作的文本输入",
"score": 1.00,
"area": null,
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T14:30:00Z"
}
],
"total": 50,
"page": 1,
"page_size": 20
}
```
**SQL 等价**:
```sql
SELECT * FROM evaluation_points
WHERE name ILIKE '%test%' -- 可选
AND code ILIKE '%test%' -- 可选
AND risk = 'low' -- 可选
AND is_enabled = true -- 可选
AND evaluation_point_groups_id = 40 -- 可选
AND evaluation_point_groups_pid = 1 -- 可选
AND area = '梅州' -- 可选
ORDER BY created_at DESC
LIMIT 20 OFFSET 0;
```
---
### 2. 获取单个评查点详情
**接口**: `GET /api/v3/evaluation-points/{id}`
**功能**: 根据 ID 获取评查点详情
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | int | 是 | 评查点ID |
**响应示例**: 同上(单个对象)
**错误响应** (404):
```json
{
"detail": "评查点不存在"
}
```
---
### 3. 获取指定分组的评查点列表
**接口**: `GET /api/v3/evaluation-points/group/{group_id}`
**功能**: 获取指定分组下的所有评查点
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `group_id` | int | 是 | 分组ID(可以是一级或二级分组) |
**查询参数** (Query):
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `page` | int | 否 | 1 | 页码 |
| `page_size` | int | 否 | 20 | 每页数量 |
| `is_enabled` | bool | 否 | - | 启用状态筛选 |
**响应示例**: 同第1个接口
---
### 4. 获取评查点数量统计
**接口**: `GET /api/v3/evaluation-points/count/{group_id}`
**功能**: 获取指定分组的评查点数量
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `group_id` | int | 是 | 分组ID |
**响应示例**:
```json
{
"group_id": 40,
"count": 15
}
```
---
## 创建接口
### 5. 创建评查点
**接口**: `POST /api/v3/evaluation-points`
**功能**: 创建新的评查点
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体**:
```json
{
"name": "测试评查点-test",
"code": "test-test",
"risk": "low",
"is_enabled": true,
"description": "",
"evaluation_point_groups_pid": 1,
"evaluation_point_groups_id": 40,
"references_laws": {
"name": "",
"content": "",
"articles": []
},
"extraction_config": {
"llm": {
"fields": ["test-llm"],
"prompt_setting": {
"type": "llm_default_prompt",
"template": ""
}
},
"vlm": {
"fields": [
{
"name": "test-vlm",
"type": "vlm_default_prompt"
}
],
"prompt_setting": {
"type": "vlm_default_prompt",
"template": ""
}
},
"regex": {
"fields": [
{
"field": "test-zz",
"pattern": "\\d{4}[-/年](0?[1-9]|1[0-2])[-/月](0?[1-9]|[12][0-9]|3[01])[日]?"
}
]
}
},
"evaluation_config": {
"logicType": "and",
"customLogic": "",
"rules": [
{
"id": "1",
"type": "exists",
"config": {
"logic": "and",
"fields": ["test-llm"]
}
},
{
"id": "2",
"type": "consistency",
"config": {
"logic": "and",
"pairs": [
{
"sourceField": "test-vlm",
"targetField": "test-zz",
"compareMethod": "exact"
}
]
}
}
]
},
"pass_message": "文档检查通过,符合规范要求。",
"fail_message": "文档存在以下问题,请修改后重新提交。",
"suggestion_message": "你觉得呢",
"suggestion_message_type": "warning",
"post_action": "manual",
"action_config": "测试评查后动作的文本输入",
"score": 1
}
```
**字段验证规则**:
1. **必填字段**: `name`, `code`, `risk`, `evaluation_point_groups_id`, `evaluation_point_groups_pid`
2. **唯一性约束**: `code` 必须唯一
3. **枚举值验证**:
- `risk`: `high` | `medium` | `low`
- `suggestion_message_type`: `info` | `warning` | `error`
- `post_action`: `none` | `manual` | `replace`
4. **外键验证**:
- `evaluation_point_groups_id` 必须存在于 `evaluation_point_groups`
- `evaluation_point_groups_pid` 必须存在于 `evaluation_point_groups`
5. **JSONB默认值**:
- `references_laws`: `{"name": "", "content": "", "articles": []}`
- `extraction_config`: 完整的默认结构
- `evaluation_config`: `{"logicType": "and", "customLogic": "", "rules": []}`
**响应示例** (201 Created):
```json
{
"id": 694,
"name": "测试评查点-test",
"code": "test-test",
...
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T14:30:00Z"
}
```
**错误响应** (400):
```json
{
"detail": "评查点编码已存在"
}
```
**错误响应** (404):
```json
{
"detail": "评查点分组不存在"
}
```
---
## 更新接口
### 6. 更新评查点
**接口**: `PUT /api/v3/evaluation-points/{id}`
**功能**: 更新指定评查点的信息
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | int | 是 | 评查点ID |
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体** (Partial Update):
```json
{
"name": "测试评查点-test(更新)",
"suggestion_message": "更新后的建议",
"is_enabled": false
}
```
**字段说明**:
- 所有字段均为可选
- 只更新提供的字段
- `updated_at` 自动更新为当前时间
**响应示例** (200 OK):
```json
{
"id": 693,
"name": "测试评查点-test(更新)",
"code": "test-test",
...
"suggestion_message": "更新后的建议",
"is_enabled": false,
"updated_at": "2024-01-15T16:00:00Z"
}
```
**错误响应** (404):
```json
{
"detail": "评查点不存在"
}
```
**错误响应** (400):
```json
{
"detail": "评查点编码已被其他评查点使用"
}
```
---
## 删除接口
### 7. 删除评查点
**接口**: `DELETE /api/v3/evaluation-points/{id}`
**功能**: 删除指定评查点
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | int | 是 | 评查点ID |
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
```
**响应示例** (200 OK):
```json
{
"success": true,
"message": "评查点删除成功"
}
```
**错误响应** (404):
```json
{
"detail": "评查点不存在"
}
```
---
## 批量操作接口
### 8. 批量更新启用状态
**接口**: `PATCH /api/v3/evaluation-points/batch/status`
**功能**: 批量更新多个评查点的启用状态
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体**:
```json
{
"ids": [693, 694, 695],
"is_enabled": false
}
```
**响应示例** (200 OK):
```json
{
"success": true,
"updated_count": 3,
"message": "批量更新成功"
}
```
---
### 9. 批量删除评查点
**接口**: `DELETE /api/v3/evaluation-points/batch`
**功能**: 批量删除多个评查点
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体**:
```json
{
"ids": [693, 694, 695]
}
```
**响应示例** (200 OK):
```json
{
"success": true,
"deleted_count": 3,
"message": "批量删除成功"
}
```
---
### 10. 批量更新分组
**接口**: `PATCH /api/v3/evaluation-points/batch/group`
**功能**: 批量移动评查点到其他分组
**请求头**:
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```
**请求体**:
```json
{
"ids": [693, 694, 695],
"evaluation_point_groups_id": 50,
"evaluation_point_groups_pid": 2
}
```
**响应示例** (200 OK):
```json
{
"success": true,
"updated_count": 3,
"message": "批量移动成功"
}
```
---
### 11. 复制评查点
**接口**: `POST /api/v3/evaluation-points/{id}/copy`
**功能**: 复制现有评查点并创建新的评查点
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | int | 是 | 源评查点ID |
**请求体**:
```json
{
"code": "test-test-copy",
"name": "测试评查点-test(副本)",
"evaluation_point_groups_id": 40,
"evaluation_point_groups_pid": 1
}
```
**响应示例** (201 Created):
```json
{
"id": 700,
"name": "测试评查点-test(副本)",
"code": "test-test-copy",
...
"created_at": "2024-01-15T17:00:00Z"
}
```
---
## 错误响应
### 标准错误响应格式
```json
{
"detail": "错误描述信息"
}
```
### 常见错误码
| HTTP 状态码 | 错误场景 | 示例 |
|------------|---------|------|
| 400 | 请求参数验证失败 | `{"detail": "评查点名称不能为空"}` |
| 401 | 未授权(JWT无效) | `{"detail": "未授权访问"}` |
| 404 | 资源不存在 | `{"detail": "评查点不存在"}` |
| 409 | 资源冲突 | `{"detail": "评查点编码已存在"}` |
| 422 | 数据验证失败 | `{"detail": [{"loc": ["body", "risk"], "msg": "必须是high/medium/low"}]}` |
| 500 | 服务器内部错误 | `{"detail": "服务器错误,请稍后重试"}` |
---
## 使用示例
### 示例 1: 获取评查点列表(带筛选)
**请求**:
```http
GET /api/v3/evaluation-points?page=1&page_size=10&risk=low&is_enabled=true&evaluation_point_groups_id=40
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
---
### 示例 2: 创建评查点
**请求**:
```http
POST /api/v3/evaluation-points
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"name": "",
"code": "contract-name-consistency",
"risk": "medium",
"is_enabled": true,
"description": "",
"evaluation_point_groups_pid": 1,
"evaluation_point_groups_id": 33,
"references_laws": {
"name": "",
"content": " ",
"articles": [""]
},
"extraction_config": {
"llm": {
"fields": ["-", "-"],
"prompt_setting": {
"type": "llm_default_prompt",
"template": ""
}
},
"vlm": {
"fields": [],
"prompt_setting": {
"type": "vlm_default_prompt",
"template": ""
}
},
"regex": {
"fields": []
}
},
"evaluation_config": {
"logicType": "and",
"customLogic": "",
"rules": [
{
"id": "1",
"type": "exists",
"config": {
"logic": "and",
"fields": ["-", "-"]
}
},
{
"id": "2",
"type": "consistency",
"config": {
"logic": "and",
"pairs": [
{
"sourceField": "-",
"targetField": "-",
"compareMethod": "exact"
}
]
}
}
]
},
"pass_message": "",
"fail_message": "",
"suggestion_message": "",
"suggestion_message_type": "warning",
"post_action": "manual",
"action_config": "",
"score": 2
}
```
---
### 示例 3: 批量更新状态
**请求**:
```http
PATCH /api/v3/evaluation-points/batch/status
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"ids": [693, 694, 695],
"is_enabled": false
}
```
---
### 示例 4: 复制评查点
**请求**:
```http
POST /api/v3/evaluation-points/693/copy
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"code": "test-test-copy",
"name": "-test",
"evaluation_point_groups_id": 40,
"evaluation_point_groups_pid": 1
}
```
---
## 附录
### 性能优化建议
1. **查询优化**:
-`code``evaluation_point_groups_id``evaluation_point_groups_pid``risk``is_enabled``area` 创建索引
- 使用分页避免一次性加载大量数据
- JSONB字段查询使用 GIN 索引
2. **缓存策略**:
- 对不常变化的评查点列表进行缓存(Redis)
- 缓存键格式: `eval_points:group:{group_id}`, `eval_points:{id}`
- 创建/更新/删除操作时清除相关缓存
3. **批量操作**:
- 使用批量查询减少数据库连接开销
- 使用事务确保批量操作的原子性
### 数据库索引建议
```sql
-- 基础索引(已存在)
CREATE UNIQUE INDEX evaluation_points_code_key ON evaluation_points(code);
CREATE INDEX idx_evaluation_points_area ON evaluation_points(area);
-- 推荐新增索引
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);
CREATE INDEX idx_evaluation_points_risk ON evaluation_points(risk);
CREATE INDEX idx_evaluation_points_is_enabled ON evaluation_points(is_enabled);
CREATE INDEX idx_evaluation_points_created_at ON evaluation_points(created_at DESC);
-- JSONB字段索引(用于复杂查询)
CREATE INDEX idx_evaluation_points_extraction_config ON evaluation_points USING GIN (extraction_config);
CREATE INDEX idx_evaluation_points_evaluation_config ON evaluation_points USING GIN (evaluation_config);
CREATE INDEX idx_evaluation_points_references_laws ON evaluation_points USING GIN (references_laws);
```
### 前端PostgREST vs 后端FastAPI对比
| 功能 | PostgREST 前端实现 | FastAPI 后端实现 |
|------|-------------------|-----------------|
| 认证方式 | 前端传递 JWT | 后端验证 JWT |
| 数据验证 | 前端验证 | 前后端双重验证 |
| JSONB处理 | 前端序列化 | 后端自动处理 |
| 批量操作 | 前端多次调用 | 后端事务处理 |
| 复制功能 | 前端实现 | 后端一次性完成 |
| 错误处理 | 前端解析错误 | 后端统一错误格式 |
| 分组验证 | 前端验证 | 后端外键约束验证 |
---
**文档版本**: v1.0
**最后更新**: 2025-01-21
**维护者**: DocAuditAI Team