14 KiB
新项目交叉评查详细业务逻辑定稿
目标:把新项目交叉评查的业务逻辑收敛成一份“可直接指导实现”的定稿,重点避免实现阶段把任务状态、评分语义、权限边界、版本逻辑和完成条件做错。
1. 定位
交叉评查在新项目中必须被视为:
- 一层独立的“协作复核业务”
- 建立在
leaudit已有文档、评查运行、规则结果之上 - 不负责重新生成底层规则结果
- 只负责任务协作、提案、投票、完成确认和展示分数叠加
因此,交叉评查不是评查引擎的一部分,而是评查结果之上的二次协作层。
2. 核心业务对象
新项目中交叉评查至少包含五类核心对象:
2.1 任务
任务是交叉评查的协作容器,负责绑定:
- 一组参与人
- 一组主要负责人
- 一批文档
- 一个文档类型语义
- 一个任务状态
任务是交叉评查权限判断的顶层边界。
2.2 任务成员
任务成员分为两类:
participant:普通参与人principal:主要负责人
另有一个特殊角色:
assigner:任务创建者
实现上建议:
assigner保存在任务主表participant/principal保存在成员表
2.3 任务文档
任务文档表示:
- 哪些文档进入了交叉评查任务
- 每个文档在该任务内的完成状态
注意:
- 任务文档状态是“任务内状态”
- 不等于文档全局状态
- 不等于底层评查运行状态
2.4 提案
提案表示:
- 某个参与人针对某个“规则结果”提出的分数调整建议
提案的本质是:
- 绑定到具体
rule_result - 以“增量分值”表达加分或扣分
2.5 投票
投票表示:
- 任务成员对某条提案的同意或反对
投票只作用于提案状态流转,不直接改文档状态。
3. 不可搞错的几个真相源
实现阶段最容易尴尬的就是“到底哪张表是真相源”。
这里必须定死:
3.1 文档真相源
leaudit_documents
3.2 文档文件与版本真相源
leaudit_document_filesleaudit_documents.versionGroupKeyleaudit_documents.versionNoleaudit_documents.previousVersionIdleaudit_documents.rootVersionIdleaudit_documents.isLatestVersion
3.3 机器评查结果真相源
leaudit_rule_results
3.4 人工审核覆盖真相源
leaudit_review_point_audits
3.5 交叉评查协作真相源
leaudit_cross_review_tasksleaudit_cross_review_task_membersleaudit_cross_review_task_documentsleaudit_cross_review_proposalsleaudit_cross_review_votes
4. 明确禁止的实现方式
以下做法不要再用:
4.1 不要直接修改 leaudit_rule_results 原始分数
原因:
- 会污染机器评查原始结果
- 会让重新跑批、调试、审计对账变得混乱
4.2 不要把交叉评查完成状态写回文档全局状态
原因:
- 交叉评查完成只是任务内完成
- 同一文档可能同时出现在多个任务或多个业务视角下
4.3 不要靠前端自行拼表判断权限
原因:
- 字段口径容易漂移
- 任务成员、负责人和创建者语义容易搞混
- 前端无法作为权限真相源
4.4 不要再用“同名同类型猜版本”作为主逻辑
原因:
- 新平台已经有正式版本字段
- 同名同类型只能作为兼容或兜底
5. 任务业务逻辑定稿
5.1 创建任务
输入
- 文档 ID 列表
- 参与人 ID 列表
- 主要负责人 ID 列表
- 任务名称
- 任务类型
- 文档类型信息
必须规则
assigner_id必须自动加入任务成员集合- 成员列表必须去重
- 主要负责人必须同时是任务成员
- 所有文档必须真实存在
- 所有文档必须可被当前用户纳入交叉评查
- 初始状态必须是
in_progress
输出
- 任务主记录
- 任务成员记录
- 任务文档记录
注意
- 创建任务不等于重新跑评查
- 默认不触发新的机器评查
- 如果文档上传接口内包含自动评查,是上传链路行为,不是任务创建行为
5.2 任务列表
任务列表只返回当前用户参与的任务。
当前用户可见任务的判定
用户满足以下任一条件即可见:
- 是
assigner - 是成员表里的
participant - 是成员表里的
principal
返回字段必须稳定
task_idtask_nametask_statusdoc_typetask_typetask_created_atprogresstotal_documentsevaluation_region
进度定义
progress = 已完成任务文档数 / 任务文档总数 * 100
这里的“已完成”只看:
leaudit_cross_review_task_documents.audit_status
不看:
leaudit_documents.audit_statusleaudit_audit_runs.statusleaudit_rule_results
5.3 任务状态
任务状态建议保留三态:
pendingin_progresscompleted
但如果当前产品没有明确“待启动”态,实际上可以只使用:
in_progresscompleted
状态流转规则
- 创建任务 ->
in_progress - 所有任务内文档完成 ->
completed - 只要还有未完成文档 -> 保持
in_progress
禁止的隐式流转
不要因为:
- 提案全部投完
- 文档所有规则点都看过
- 有人上传了附件
就自动把任务置完成。
任务完成只能由“所有任务内文档被确认完成”推导出来。
6. 任务文档业务逻辑定稿
6.1 文档进入任务
文档进入任务只有两种方式:
- 创建任务时挂入
- 向已有任务追加文档
文档进入任务后默认状态
audit_status = 0
即:
- 新纳入任务的文档,默认都还未完成交叉评查
6.2 文档完成的真正含义
任务内文档“完成”表示:
- 负责人或创建者确认:该文档在这个任务内的交叉评查工作结束
它不表示:
- 文档机器评查已完成
- 所有人都看过
- 所有提案都被通过
- 文档在全局业务上彻底完结
6.3 谁可以确认文档完成
只有:
- 任务创建者
assigner - 主要负责人
principal
普通 participant 不可确认完成。
6.4 确认完成前的业务建议
建议在后端允许确认前做提醒型校验,而不是强阻断:
- 文档下是否还有
pending提案 - 是否存在未投票成员
推荐策略:
- 默认允许负责人确认完成
- 如果仍有
pending提案,返回告警信息给前端二次确认
这样更贴近真实业务,不会因为个别滞后投票把流程卡死。
7. 提案业务逻辑定稿
7.1 提案的最小绑定单位
提案必须绑定到:
- 一个任务
- 一个文档
- 一个规则结果
rule_result_id
不要只绑定:
- 文档 + 评查点名称
- 文档 + 规则名
因为这些都不够稳定。
7.2 谁可以提案
只有该任务成员可以提案。
必须满足
- 用户是任务成员
- 文档属于该任务
rule_result_id属于该文档- 当前提案目标不是已删除/无效结果
7.3 提案唯一性规则
建议规则:
- 同一用户对同一任务下同一文档的同一
rule_result_id - 同时只能存在一条“有效提案”
有效提案指:
pendingapprovedrejected
如果需要允许历史重提,建议前提是:
- 原提案已
cancelled - 或被软删
7.4 提案分值规则
必须禁止
0分提案
必须校验
- 当前分值已为
0时,不允许继续扣分 - 当前分值已达该规则满分时,不允许继续加分
- 提案增量应用后,理论结果不能越界
边界是:
- 最低
0 - 最高该规则满分
7.5 提案创建后的自动动作
提案创建成功后:
- 自动写入一条提案人
agree投票 - 立刻触发提案状态判定
8. 投票业务逻辑定稿
8.1 谁可以投票
只有该任务成员可以投票。
额外限制
- 非成员不能投
- 已删除提案不能投
- 已结束提案不能投
8.2 提案人能否投票
建议保留老逻辑:
- 提案创建后自动算提案人一票同意
这意味着:
- 提案人不需要再手动投一次
- 后续若要改票,只能通过显式撤销/重投逻辑支持
8.3 投票值
推荐只保留:
agreedisagree
“取消投票”不作为状态值保存,而是:
- 将该投票软删
8.4 一人一票
同一提案、同一成员:
- 同一时刻只能存在一条有效投票
如重复投票:
- 覆盖旧投票类型
9. 提案状态机定稿
提案状态建议固定为:
pendingapprovedrejectedcancelled
9.1 创建后的初始状态
pending
9.2 通过规则
设任务有效成员数为 n
通过阈值:
threshold = floor(n / 2) + 1
若:
agree >= threshold
则:
proposal.status = approved
9.3 否决规则
若:
disagree >= threshold
则:
proposal.status = rejected
9.4 提前否决规则
若:
- 即使所有剩余未投票者都改投同意,
agree也达不到threshold
则:
proposal.status = rejected
9.5 撤销规则
只有提案人可撤销,且只允许撤销:
pending
撤销后:
status = cancelled- 同时软删或停用关联投票
9.6 提案终态不可再操作
对于:
approvedrejectedcancelled
不允许再继续投票或修改状态。
10. 分数语义定稿
这是实现中最容易“做着做着又回到老系统”的地方,必须说清楚。
10.1 三层分数
新项目详情页涉及三层分数:
机器分
来自:
leaudit_rule_results
含义:
- 规则执行后机器给出的原始结果分值
人工审核分
来自:
leaudit_review_point_audits
含义:
- 人工对规则结果的覆盖性判断
交叉评查调整分
来自:
- 所有已通过的
leaudit_cross_review_proposals
含义:
- 协作层加减分累计值
10.2 推荐最终展示分数计算
建议按以下顺序:
- 先计算基础分
baseScore - 再叠加交叉评查增量
crossDelta - 再做边界裁剪
baseScore 计算建议
若存在人工审核覆盖:
- 按人工审核后的通过/不通过结果计算基础分
否则:
- 按机器结果计算基础分
crossDelta
取该 rule_result_id 下所有:
status = approveddeleted_at is null
提案的 proposed_score_delta 累加值
finalScore
finalScore = clamp(baseScore + crossDelta, 0, ruleMaxScore)
10.3 绝对禁止
不要:
- 直接更新
leaudit_rule_results.score - 直接把聚合后的最终分落回机器结果表
11. 详情页聚合逻辑定稿
当前详情页主入口已经是:
DocumentServiceImpl.GetReviewPoints()
这条主链路可以保留。
11.1 详情页返回内容应包含
- 规则点列表
- 单点机器分
- 单点人工审核覆盖结果
- 单点最终展示分
- 交叉评查提案列表
- 文档级统计信息
11.2 提案列表读取规则
提案列表优先从:
leaudit_cross_review_proposals
读取。
如果需要历史兼容,可短期允许:
- 新表优先
- 旧
cross_scoring_proposals兜底
但这必须是过渡方案,不是长期方案。
11.3 文档总分统计
文档总分建议由每个规则点的最终展示分累加得到。
即:
- 总分不是单独存储字段
- 而是聚合计算结果
12. 版本归纳逻辑定稿
12.1 主规则
任务文档列表必须优先基于:
versionGroupKey
归组。
当前版本判定
优先使用:
isLatestVersion = true
历史版本排序
按:
versionNo desc
或时间倒序
12.2 兜底规则
只有在极端兼容场景下,才允许用:
normalizedName + typeId
做辅助兜底。
12.3 追加附件后的语义
追加附件如果产生新文档,则该新文档:
- 应进入同一版本链
- 自动挂到当前任务
- 默认
audit_status = 0
原因:
- 新版本进入任务后,需要重新做交叉评查确认
13. 权限逻辑定稿
13.1 权限判断分两层
第一层:RBAC 权限点
例如:
cross_review:task:readcross_review:task:createcross_review:proposal:createcross_review:proposal:votecross_review:document:complete
第二层:业务归属校验
例如:
- 是否是该任务成员
- 是否是负责人
- 文档是否属于该任务
- 规则结果是否属于该文档
两层都通过,才允许操作。
13.2 读权限
用户可读某任务,当且仅当:
- 是
assigner - 或是任务成员
13.3 写权限
创建提案
- 任务成员即可
投票
- 任务成员即可
撤销提案
- 仅提案人
确认文档完成
- 仅
assigner或principal
上传任务文档 / 追加附件
- 建议仅
assigner或principal
14. 实施时的接口行为定稿
14.1 后端必须兜住这些错误
- 文档不存在
- 文档不属于任务
- 规则结果不属于文档
- 用户不是任务成员
- 用户不是负责人
- 提案重复
- 提案已结束
- 分值越界
14.2 后端返回建议
每个关键接口尽量返回:
successmessage- 必要结果对象
- 必要告警信息
例如确认完成时可以带:
has_pending_proposalspending_proposal_counthas_pending_votes
15. 推荐开发顺序
为了避免做到一半逻辑漂移,建议严格按以下顺序:
第一步
先落表结构和状态定义。
第二步
实现 service 层纯业务逻辑:
- 任务
- 提案
- 投票
- 完成确认
第三步
实现 controller 接口。
第四步
把详情页聚合接到新提案表。
第五步
再做上传、附件、版本链整合。
16. 最终一句话定稿
新项目交叉评查的正确实现方式应该是:
- 用
leaudit_*作为文档与评查结果底座 - 用
leaudit_cross_review_*承接协作层 - 用聚合计算得到最终展示分
- 用任务内状态管理完成进度
- 用后端统一收口权限和状态流转
只要这五点不偏,整体实现就不会跑歪。