feat: migrate cross review to v3 leaudit flow

This commit is contained in:
wren
2026-05-07 18:18:59 +08:00
parent 35e0c45c42
commit 1c84209f38
23 changed files with 5172 additions and 39 deletions
@@ -0,0 +1,562 @@
# 新项目交叉评查实现方案设计稿
> 目标:基于 `leaudit-platform` 当前代码结构,给出交叉评查在新项目中的推荐实现方案,并明确数据模型、接口设计、目录落点、迁移顺序与实施边界。
## 1. 背景判断
结合当前仓库代码可以确认:
- 前端交叉评查页面已经存在于 `new_doc_review`
- RBAC 路由中已经存在 `/cross-checking`
- 新平台文档与评查底座已经切到 `leaudit_*`
- 但交叉评查协作层仍未完整迁入 `fastapi_modules/fastapi_leaudit`
当前现状更接近:
- 页面壳子是新的
- 文档与评查引擎底座是新的
- 交叉评查业务逻辑仍然大量沿用老系统思维和老接口口径
因此,交叉评查在新项目中的核心任务,不是“新做一个页面”,而是把“协作复核层”从老系统迁到新平台。
## 2. 总体设计原则
推荐遵循以下原则:
### 2.1 交叉评查是协作层,不是评查引擎层
交叉评查不负责:
- OCR
- 文本抽取
- 规则执行
- 原始机器评查结果生成
交叉评查只负责:
- 任务
- 参与人
- 文档挂载
- 提案
- 投票
- 完成确认
- 结果展示叠加
### 2.2 原始评查结果尽量不可变
不建议像老系统那样把通过提案直接回写到旧 `evaluation_results.final_score`
新平台里更合理的方式是:
- `leaudit_rule_results` 保留机器评查真相
- `leaudit_review_point_audits` 保留人工审核覆盖
- `leaudit_cross_review_proposals` 保留交叉评查加减分提案
- 页面展示时动态聚合出最终展示分数
### 2.3 交叉评查单独建模,不污染 LeAudit 核心表
推荐新增专属表:
- `leaudit_cross_review_tasks`
- `leaudit_cross_review_task_members`
- `leaudit_cross_review_task_documents`
- `leaudit_cross_review_proposals`
- `leaudit_cross_review_votes`
### 2.4 版本归纳使用新平台版本能力
不要继续使用老系统“同名 + 同类型推断版本”的方案作为主路径。
新平台已有:
- `leaudit_documents.versionGroupKey`
- `leaudit_documents.versionNo`
- `leaudit_documents.previousVersionId`
- `leaudit_documents.rootVersionId`
- `leaudit_documents.isLatestVersion`
交叉评查列表应优先基于这些字段实现版本归纳。
### 2.5 权限必须后端收口
前端可以决定是否显示按钮,但最终权限校验必须在后端 service 层完成。
不能继续依赖前端自己拼 PostgREST 查询判断权限。
## 3. 新项目里可直接复用的基础能力
## 3.1 文档主链路
现有能力:
- 上传文档:`fastapi_modules/fastapi_leaudit/controllers/documentController.py`
- 文档服务:`fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py`
- 文档主表:`fastapi_modules/fastapi_leaudit/models/leauditDocument.py`
- 文档文件表:`fastapi_modules/fastapi_leaudit/models/leauditDocumentFile.py`
可复用点:
- 文档上传
- OSS 存储
- 文档版本管理
- 附件追加
- 文档详情读取
## 3.2 评查运行与结果主链路
现有能力:
- 评查运行主表:`fastapi_modules/fastapi_leaudit/models/leauditAuditRun.py`
- 评查运行控制器:`fastapi_modules/fastapi_leaudit/controllers/auditController.py`
- 评查详情聚合:`DocumentServiceImpl.GetReviewPoints()`
可复用点:
- 评查运行追踪
- 详情页规则结果聚合
- 人工审核结果叠加
## 3.3 详情页结果聚合
现有 VO
- `fastapi_modules/fastapi_leaudit/domian/vo/reviewPointVo.py`
现有能力:
- `ReviewPointsAggregateVO`
- `scoring_proposals`
- `ReviewPointResultVO.finalScore`
- `ReviewPointResultVO.machineScore`
这意味着:
- 详情页主结构已经可承载交叉评查提案数据
- 只需把“提案来源”和“最终分数计算方式”替换为新模型
## 4. 目标架构
推荐架构分成两层:
### 4.1 LeAudit 评查结果层
职责:
- 文档上传
- 规则执行
- 机器评查结果生成
- 人工审核覆盖记录
主要表:
- `leaudit_documents`
- `leaudit_document_files`
- `leaudit_audit_runs`
- `leaudit_rule_results`
- `leaudit_review_point_audits`
### 4.2 Cross Review 协作层
职责:
- 交叉评查任务
- 成员管理
- 任务文档挂载
- 加减分提案
- 投票
- 文档完成确认
- 协作态进度管理
主要表:
- `leaudit_cross_review_tasks`
- `leaudit_cross_review_task_members`
- `leaudit_cross_review_task_documents`
- `leaudit_cross_review_proposals`
- `leaudit_cross_review_votes`
## 5. 新数据模型设计
## 5.1 `leaudit_cross_review_tasks`
任务主表。
建议字段:
- `id`
- `task_name`
- `task_type`
- `doc_type_id`
- `doc_type_code`
- `assigner_id`
- `status`
- `created_at`
- `updated_at`
- `deleted_at`
说明:
- `status` 建议值:`pending``in_progress``completed`
- `doc_type_id` 可用于快速关联新平台文档类型
- `doc_type_code` 用于兼容前端和历史口径
## 5.2 `leaudit_cross_review_task_members`
任务成员表。
建议字段:
- `id`
- `task_id`
- `user_id`
- `member_role`
- `created_at`
- `updated_at`
- `deleted_at`
说明:
- `member_role` 建议值:`participant``principal`
- 任务创建者不建议仅放数组,应显式保存在任务主表 `assigner_id`
## 5.3 `leaudit_cross_review_task_documents`
任务文档表。
建议字段:
- `id`
- `task_id`
- `document_id`
- `audit_status`
- `created_at`
- `updated_at`
- `deleted_at`
说明:
- `audit_status=0` 表示未完成
- `audit_status=1` 表示已确认完成
- 这是任务内状态,不是文档全局状态
## 5.4 `leaudit_cross_review_proposals`
提案表。
建议字段:
- `id`
- `task_id`
- `document_id`
- `rule_result_id`
- `proposer_id`
- `proposed_score_delta`
- `reason`
- `status`
- `created_at`
- `updated_at`
- `deleted_at`
说明:
- `rule_result_id` 应关联 `leaudit_rule_results.id`
- `proposed_score_delta` 使用增量值,正数加分,负数扣分
- `status` 建议值:`pending``approved``rejected``cancelled`
## 5.5 `leaudit_cross_review_votes`
投票表。
建议字段:
- `id`
- `proposal_id`
- `voter_id`
- `vote_type`
- `created_at`
- `updated_at`
- `deleted_at`
说明:
- `vote_type` 建议值:`agree``disagree`
- `cancel` 建议用软删除表示,不必单独存为最终值
## 6. 关键业务规则如何映射到新平台
## 6.1 创建任务
目标保留的老规则:
- 创建者强制加入任务成员
- 可指定普通参与人和主要负责人
- 任务创建时可同时挂一批文档
新实现建议:
- 创建任务时先写 `leaudit_cross_review_tasks`
- 再写 `leaudit_cross_review_task_members`
- 再写 `leaudit_cross_review_task_documents`
## 6.2 文档访问校验
目标保留的老规则:
- 只有任务成员才能看任务文档
- 提案必须绑定任务内文档
新实现建议:
- 不再让前端自己查 `cross_task_document_mapping`
- 提供统一后端方法:
- `CheckTaskMember(taskId, userId)`
- `CheckTaskDocument(taskId, documentId)`
- `CheckTaskDocumentRuleResult(documentId, ruleResultId)`
## 6.3 提案创建
目标保留的老规则:
- 必须是任务参与者
- 同一用户不能对同一评查点重复创建有效提案
- 不允许 0 分提案
- 当前分数为 0 时不能继续扣
- 当前已满分时不能继续加
新实现建议:
- 通过 `rule_result_id` 读取对应规则结果
- 计算当前展示分数
- 校验是否还能继续加减
- 写入 `leaudit_cross_review_proposals`
- 自动插入一条提案人同意票
## 6.4 投票与状态流转
目标保留的老规则:
- 采用绝对多数制
- 阈值为 `floor(n / 2) + 1`
新实现建议:
- `n` 基于 `leaudit_cross_review_task_members` 统计活跃成员
- 同意达到阈值 -> `approved`
- 反对达到阈值 -> `rejected`
- 剩余票全部同意也无法通过 -> `rejected`
## 6.5 文档完成确认
目标保留的老规则:
- 只有创建者或负责人可确认
- 文档完成改的是任务内状态
- 全部文档完成后任务才完成
新实现建议:
- 确认文档完成时更新 `leaudit_cross_review_task_documents.audit_status`
- 若同任务下所有未删除文档都为完成,则更新 `leaudit_cross_review_tasks.status = completed`
## 6.6 分数计算
这是新实现里最重要的变化。
### 不建议
- 直接更新 `leaudit_rule_results.score`
- 直接写回机器结果源字段
### 建议
按聚合方式计算展示分数:
- `machineScore`:来自 `leaudit_rule_results`
- `auditOverride`:来自 `leaudit_review_point_audits`
- `crossReviewDelta`:来自所有已通过的 `leaudit_cross_review_proposals`
- `finalScore`:在详情页聚合阶段动态计算
建议公式:
1. 先根据机器结果与人工审核确定基础结果
2. 基础结果换算出基础得分
3. 加上 `approved` 提案累计增量
4. 最终再做上下限裁剪:
- 不低于 0
- 不高于规则满分
## 7. 详情页如何接入新实现
当前详情页主入口已经存在:
- `fastapi_modules/fastapi_leaudit/controllers/documentController.py`
- `GET /v3/review-points/{DocumentId}`
建议做法:
### 7.1 保留 `GetReviewPoints()` 作为主入口
这样前端详情页无需大改。
### 7.2 修改 `_loadScoringProposals()`
当前只是兼容读取旧 `cross_scoring_proposals`
建议改为:
- 优先读取 `leaudit_cross_review_proposals`
- 若尚未迁移完成,可保留旧表兼容兜底一段时间
### 7.3 修改评查点聚合逻辑
`_loadReviewPointResults()` 或其上层聚合逻辑中:
- 读取单点所有已批准提案的分值增量
- 计算 `finalScore`
- 继续把提案列表放入 `scoring_proposals`
### 7.4 前端详情页不用重构为新的页面协议
保持 `ReviewPointsAggregateVO` 不变或小幅扩展即可。
## 8. 任务列表和任务文档列表如何实现
## 8.1 任务列表
返回建议字段:
- `task_id`
- `task_name`
- `task_status`
- `doc_type`
- `task_type`
- `task_created_at`
- `progress`
- `total_documents`
- `evaluation_region`
实现来源:
- 任务主表
- 成员表
- 任务文档表
## 8.2 任务文档列表
建议按以下逻辑组织:
1. 先取任务绑定文档
2. 通过 `leaudit_documents.versionGroupKey` 做版本归组
3. 当前版本优先取 `isLatestVersion = true`
4. 统计信息来自 `leaudit_rule_results`
5. 最终展示分数叠加 `approved` 提案增量
## 8.3 不建议继续使用旧版“同名同类型猜版本”
因为新平台已经有更稳定的版本链字段,不必再依赖脆弱的文件名规则。
## 9. 上传与追加附件的实现建议
## 9.1 推荐长期方案
采用“文档系统”和“交叉评查系统”解耦:
1. 先用通用文档接口上传
2. 拿到 `documentId`
3. 再把文档挂入交叉任务
优点:
- 复用现有 `DocumentServiceImpl.Upload`
- 文档生命周期统一
- 附件处理逻辑不重复
## 9.2 推荐短期兼容方案
为兼容当前前端,可先提供聚合接口:
- `UploadAndCreateTask`
- `UploadDocumentsToTask`
- `AppendTaskDocumentAttachments`
这些接口内部再调用:
- `DocumentService.Upload`
- `DocumentService.AppendAttachments`
这样前端先不需要大改。
## 10. 权限设计
建议保留现有 RBAC 权限点:
- `cross_review:task:read`
- `cross_review:task:create`
- `cross_review:progress:view`
- `cross_review:proposal:create`
- `cross_review:proposal:read`
- `cross_review:proposal:delete`
- `cross_review:proposal:vote`
- `cross_review:document:complete`
同时叠加业务层权限判断:
- 是否任务成员
- 是否创建者
- 是否主要负责人
- 文档是否属于任务
- 评查点结果是否属于该文档
## 11. 推荐实施顺序
### 第一阶段:先建协作层表和后端接口
目标:
- 新建 `leaudit_cross_review_*`
- 新建 `CrossReviewController / Service / DTO / VO`
- 打通任务、提案、投票、完成确认
### 第二阶段:详情页切新提案逻辑
目标:
- `GetReviewPoints()` 改读新提案表
- 动态计算最终分数
- 详情页不再依赖旧 `cross_scoring_proposals`
### 第三阶段:任务文档列表切新版本底座
目标:
- 改用 `leaudit_documents` 版本字段归组
- 任务内分数与统计改读新平台结果
### 第四阶段:前端路径和历史兼容收口
目标:
- 逐步下线 `/admin/v2/cross_review/*` 历史兼容口径
- 清理前端直查旧表逻辑
- 清理旧 `cross_*` 兼容读取
## 12. 风险与注意事项
### 12.1 最大风险:最终分数语义变化
如果继续沿用老系统“直接回写”的做法,会污染新平台结果底座。
建议统一改为聚合展示分数。
### 12.2 第二风险:前端隐式依赖旧接口字段
当前 `new_doc_review/app/api/cross-checking/*` 里仍存在很多历史字段名和旧路径假设。
新后端第一期最好兼容这些字段,避免前端同步改动过大。
### 12.3 第三风险:权限校验分散
当前部分前端仍尝试自行查表判断权限。
迁移时应尽快把权限判断收敛到后端。