# 新项目交叉评查实现方案设计稿

> 目标：基于 `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 第三风险：权限校验分散

当前部分前端仍尝试自行查表判断权限。

迁移时应尽快把权限判断收敛到后端。

