writeOff/docs/审核流程优化.md
haomingming db10401b13 0529
2026-05-29 10:38:34 +08:00

282 lines
18 KiB
Markdown
Raw 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.

优先级 ToDoList
P0先做不做后面的方案立不住
- [ ] 审核任务改为绑定“提交版本”而不是 `meetingId/current material`
状态:已完成
说明:`audit_task` 已绑定 `submission_version_id`;审核详情、材料抽屉、差异摘要、问题闭环等新任务读取链路均优先消费绑定的提交版本快照,不再读取申请人当前草稿,旧任务仅在缺少版本绑定时走兼容兜底。
- [ ] 提交后版本不可变,申请人只允许编辑草稿,重新提交生成新版本
状态:已完成
说明:已为 `meeting_material` 增加草稿字段,申请端模块保存/模块提交只更新草稿;整单提交时才把草稿固化为新的提交版本并同步 `meeting_submission_version``meeting_material_history`,已提交版本不再被后续编辑覆盖。
- [ ] 驳回改为结构化问题数组,禁止仅提交自由文本驳回意见
状态:已完成
说明:单任务驳回现已强制要求提交非空 `issues[]`,且每条结构化问题必须包含模块、定位、标签、原因等必填字段;自由文本 `opinion` 仅保留为可选补充说明,不能再单独作为驳回依据。批量驳回仍明确禁用,避免绕过结构化问题闭环。
- [ ] 建立 `audit_issue / issue_response / version_change_set / version_change_item` 核心表结构
状态:部分完成
说明:已落 `audit_issue / issue_response` 基础表并接入问题写入/回应闭环;同时新增 `version_change_set / version_change_item` 表结构与会议提交后的差异持久化链路,但差异粒度仍以当前模块级 `itemKey` 为主,尚未升级到文档目标里的统一字段/行/附件模型。
- [ ] 审核详情聚合接口一次返回版本、问题、回应、差异、完整快照
状态:已完成
说明:整单级审核详情接口已可一次返回审核任务、绑定提交版本、完整快照、问题列表、回应结果、差异摘要与模块详情;新任务统一读取绑定版本快照,旧任务仅在历史数据缺版本绑定时做兼容回退。
P1核心流程闭环
- [ ] 申请端支持逐条填写问题处理说明,并落库到 `issue_response`
状态:已完成
说明:会议级与模块级重新提交均支持逐条填写问题处理说明,申请端“去修改”跳转与字段高亮链路已接入;提交后会把回应按提交版本写入 `issue_response`,并回写问题当前处理说明。
- [ ] 重新提交时强制校验未关闭问题都已响应,否则不允许提交
状态:已完成
说明:会议级与模块级重新提交均已在前后端双重校验未关闭问题必须逐条响应;待处理问题读取范围已统一覆盖 `OPEN / PENDING_CONFIRM`,避免遗漏“已回复待确认”的问题。
- [ ] 审核端问题闭环支持三态:已修改待确认、未修改、已确认解决
状态:已完成
说明:审核端复审摘要已稳定区分“已修改待确认 / 未修改 / 已确认解决”三态;审核人确认解决时会按问题真实归属记录更新状态,不再受当前待审任务与原驳回任务 ID 不一致影响。
- [ ] 审核通过时自动关闭当前任务及关联未关闭问题;再次驳回时挂到新版本
状态:已完成
说明:终审通过时会自动关闭会议下未关闭问题;再次驳回前会先收口旧版本未关闭问题,再按当前提交版本重新生成新的结构化问题,确保问题生命周期按版本闭环流转。
- [ ] 审核处理逻辑校验“只能处理分配给自己的任务”
状态:已完成
说明:后端审核主入口和资料审核入口已统一增加处理人硬校验;除未分配任务外,非当前处理人无法执行通过、驳回、退回、转审及资料项审核动作。
P2差异引擎与规则完善
- [ ] 差异结果从“模块 itemKey 对比”升级为“字段/行/附件”统一 ChangeSet
状态:已完成
说明:`version_change_set / version_change_item` 已升级为统一的字段 / 行 / 附件差异模型,并持久化 `target_kind / target_row_key / attachment_identity / attachment_hash`;会议重新提交后会沉淀跨版本差异,审核详情聚合接口、审核抽屉“本次修改”、申请端复审预览均已优先消费持久化 `changeSet`
- [ ] 实现问题命中规则:精确命中、父子路径命中、模块内额外修改识别
状态:已完成
说明:已支持精确命中、父子路径命中和模块内额外修改识别;审核复审摘要、持久化 `version_change_item`、审核抽屉高亮定位与申请端“去修改”链路均会优先关联命中的驳回问题,并兼容 `agenda / invitation / profileFile / meeting_invoice:OTHER / invoice:*` 等历史别名。
- [ ] 附件比对改为 `asset_id/hash` 维度,避免仅按文件名或当前结构判断
状态:已完成
说明:当前已按工程化附件身份实现稳定比对:优先使用 `ossKey/objectKey` 作为附件 identity缺失时回退到 `fileName|size|contentType` 的短 hash并持久化 `attachment_identity / attachment_hash`;尚未引入独立 `attachment_asset` 实体,但已不再依赖纯文件名或当前数组结构判断。
- [ ] 明细数组建立稳定行主键,避免只靠数组下标做差异
状态:已完成
说明:明细数组已按业务稳定键建模差异与审核项:专家资料优先用 `expertId`,专家发票优先用 `invoiceNo`,会议发票按 `sectionCode + fieldKey`,文档附件优先用 `ossKey`,仅在历史或异常数据缺少稳定键时才回退到顺序索引,避免常态场景只靠数组下标做差异。
P3审核端页面
- [ ] 审核列表完整显示:重新提交、本次修改数、驳回项处理进度、额外修改数
状态:已完成
说明:审核列表已完整展示“重新提交 / 本次修改数 / 驳回项处理进度 / 额外修改数 / 未解决项 / 高风险复审”等核心标签;同时补齐复审快速筛选、后端级 `reviewFocus` 查询过滤,以及待我处理列表按 `riskScore` 的服务端风险优先排序,避免列表结果继续依赖前端二次筛选。
- [ ] 审核详情页固定为四块:本次摘要、驳回问题闭环、仅看修改、完整资料
状态:已完成
说明:审核详情抽屉已改为整单级四区固定布局:`本次摘要 / 驳回问题闭环 / 仅看修改 / 完整资料`;顶部摘要统一消费 `fetchAuditTaskDetail` 聚合结果,完整资料保留模块 tabs 作为第四区内部导航,不再以模块级抽屉替代整单视图。
- [ ] 完整资料页支持变更高亮,并可从字段跳回对应 ChangeItem
状态:已完成
说明:完整资料区已覆盖基础信息、核销材料、专家简介、专家资料、会议发票等模块的变更高亮;支持从整单“仅看修改”点击后自动切换到目标模块并滚动定位到对应字段/材料卡片,也支持从高亮字段反向回跳到对应 ChangeItem。
- [ ] 审核端优先展示“驳回相关修改”,其次展示“额外修改”
状态:已完成
说明:整单“仅看修改”区已固定拆分为“驳回相关修改 / 额外修改”两个分组,并默认先展示驳回相关修改;同时补齐整单级 ChangeItem 与完整资料字段之间的双向跳转和跨模块切换。
P4申请端页面
- [ ] 驳回后进入“修改并重新提交”模式,顶部固定展示上次驳回问题清单
状态:已完成
说明:驳回后进入资料页会明确进入“修改并重新提交模式”;侧栏持续展示上次驳回问题与本次修改摘要,主内容顶部提供统一 sticky 复审头部,集中展示问题总数、未解决数、驳回相关修改、额外修改及待处理模块入口,形成稳定的整页复审模式。
- [ ] 每条问题增加“去修改”跳转,直达对应模块/字段
状态:已完成
说明:会议级待回应弹窗、模块级提交复审预览、资料页顶部/侧栏问题清单都已支持“去修改”;点击后可直接切到对应模块,并结合字段高亮、滚动定位、专家子模块切换与历史别名兼容,已覆盖基础信息、核销材料、专家简介、专家现场照片/劳务协议、会议发票及 `agenda / invitation / profileFile / meeting_invoice:OTHER / invoice:*` 等关键路径。
- [ ] 提交前展示标准化变更预览:驳回项相关修改 / 额外修改 / 未处理问题
状态:已完成
说明:模块提交前的“提交复审预览”已标准化拆分为“上次驳回项 / 未处理问题 / 驳回项相关修改 / 额外修改”四块,并新增逐条提交状态、处理说明缺失提示与表格高亮;未完成修改或未填写处理说明的问题会在预览中显式暴露,并继续阻断提交。
P5审计与治理
- [ ] 关键动作全链路留痕:谁提交了哪个版本、谁创建了问题、谁回应、谁确认解决
状态:已完成
说明:会议提交版本、结构化问题创建、申请人回应、审核确认解决、审核通过/驳回/退回/转审动作均已纳入统一留痕链路;审核详情现可直接返回版本链、问题闭环留痕、审核动作时间线与操作者信息,形成端到端审计追溯视图。
- [ ] 任意审核结论都能追溯到具体版本和具体差异
状态:已完成
说明:审核详情已固定绑定 `submission_version_id`,并优先返回该版本对应的持久化 `version_change_set / version_change_item`;对历史旧任务,读取详情时会按版本链自动补建缺失的 ChangeSet使审核结论可继续追溯到具体版本与具体差异而不再仅依赖当前草稿或人工推断。
- [ ] 补充迁移与回填方案,兼容当前 `meeting_material_history``audit_material_item_review`
状态:已完成
说明:已明确并落地兼容策略:新数据继续写入 `meeting_submission_version / version_change_set / version_change_item`;旧任务读取详情时,若缺少持久化差异,则基于 `meeting_material_history` 的提交快照与 `audit_material_item_review` 的历史审核项自动回填 ChangeSet并在追溯信息中标记“读取时自动回填/兼容旧任务”,避免历史记录断层。
最终方案
结论先定下来:把审核对象从“当前表单”改成“提交版本”,把驳回原因从“自由文本”改成“结构化问题”,把重新提交后的复审入口从“整单重看”改成“问题闭环 + 自动差异审核”。这样审核人打开后先看“这次改了什么、是否改到了上次驳回点”,而不是重新读全量资料。
一、整体架构
Application申请单主实体只承载申请编号、申请人、当前草稿、最新状态。
ApplicationVersion每次“提交审核”生成一份不可变版本审核永远针对 version_id不针对可变草稿。
AuditTask某个版本对应的一次审核任务。
AuditIssue审核不通过时产生的问题项必须结构化记录到模块/字段/明细行/附件。
IssueResponse申请人对每条问题项的处理说明。
VersionChangeSet重新提交时系统自动生成的版本差异汇总。
VersionChangeItem字段级/行级/附件级差异明细。
AttachmentAsset附件资源独立存储用 asset_id/hash 做稳定比对。
二、核心业务规则
所有审核都基于版本,版本一旦提交不可修改。
申请人编辑的是草稿,重新提交时生成新版本,不覆盖旧版本。
驳回时不能只写一句“请完善资料”,必须至少创建 1 条 AuditIssue。
AuditIssue 必须挂到具体位置,至少精确到模块,理想情况精确到字段或明细行。
重新提交时,申请人必须对每条未关闭问题填写处理说明。
审核人再次审核时,默认只看“本次修改”和“问题闭环”,完整资料作为第二层查看。
如果申请人除了驳回项外还改了别的内容,系统单独标红提示“额外修改”。
三、标准流程
申请人填写草稿,点击提交,系统生成 V1 快照并创建审核任务。
审核人审核 V1若不通过创建若干 AuditIssue例如
basic.meetingTime会议时间与通知不一致
budget.items[itemId=3].amount预算金额计算错误
attachments.agenda缺少议程附件
申请人查看驳回问题,修改草稿,并逐条填写“本次如何处理”。
申请人重新提交,系统生成 V2并自动计算 V1 -> V2 的 ChangeSet。
审核人打开 V2 时,页面顶部先展示:
本次共修改 8 处,涉及 3 个模块
上次驳回 5 条,已命中修改 4 条,未修改 1 条
另有 2 处非驳回项修改
审核人先处理“问题闭环”,确认每条问题是否已改到位,再决定通过或再次驳回。
若再次驳回,生成新的问题项并挂到 V2若通过关闭当前审核任务和所有未关闭问题项。
四、数据模型
application
id, code, applicant_id, current_draft_json, latest_version_id, status
application_version
id, application_id, version_no, snapshot_json, snapshot_hash, submit_note, submitted_by, submitted_at, base_version_id
audit_task
id, application_version_id, status, auditor_id, started_at, decided_at, decision_comment
audit_issue
id, audit_task_id, issue_no, module_code, target_path, target_label, target_row_key, reason, severity, status
issue_response
id, issue_id, application_version_id, response_text, response_status, responded_at
version_change_set
id, from_version_id, to_version_id, changed_module_count, changed_item_count, issue_related_count, extra_change_count
version_change_item
id, change_set_id, module_code, target_path, target_label, target_row_key, change_type, old_value, new_value, related_issue_id, is_extra_change
attachment_asset
id, file_name, file_hash, storage_key, mime_type, file_size
version_attachment_ref
id, version_id, target_path, asset_id
五、字段路径规范
普通字段basic.meetingName
嵌套对象schedule.startTime
明细行budget.items[itemId=3].amount
参会人participants[userId=1001].title
附件attachments.noticeFile
路径必须稳定,不能靠前端展示文案比对;明细表必须有稳定行主键,不能靠数组下标。
六、差异引擎规则
标量字段:直接比较前后值。
对象字段:递归比较。
明细数组:按稳定主键判断 新增/删除/修改。
附件:按 asset_id 或 file_hash 判断变化,不能只看文件名。
忽略字段:更新时间、操作人、系统流水号等非业务字段。
值展示规则:长文本截断展示,支持展开;金额保留格式化前后值;附件显示文件名和预览入口。
问题命中规则:
路径完全相同:直接命中
当前字段是问题字段的子路径或父路径:视为相关命中
同模块但不同字段:视为“模块内额外修改”
输出结果分三类:
已按驳回项修改
未命中驳回项
额外修改
七、审核端页面设计
审核列表页增加字段:
重新提交 标记
本次修改 x 处
驳回项已处理 y/z
额外修改 n 处
审核详情页固定四个区域:
本次摘要
驳回问题闭环
仅看修改
完整资料
本次摘要
显示版本链V1 驳回 -> V2 待审
显示修改统计和风险提示
驳回问题闭环
每条问题展示:问题内容、定位字段、上次值、本次值、申请人处理说明、审核结论
状态只有:已修改待确认、未修改、已确认解决
仅看修改
按模块分组展示所有 ChangeItem
默认先显示“驳回相关修改”,再显示“额外修改”
支持前后值并排对比
完整资料
仍展示整单
所有变更字段高亮
点击字段可跳回对应 ChangeItem
八、申请端页面设计
驳回后进入“修改并重新提交”模式。
页面顶部固定显示“上次驳回问题清单”。
每条问题旁边有“去修改”按钮,直接跳转到对应字段/模块。
每条问题必须填写“处理说明”,例如“已按会议通知修改时间为 2026-05-22 09:00”。
提交前显示“本次变更预览”,让申请人确认:
驳回项相关修改
额外修改
未处理问题
若存在未响应的问题,不允许提交。
九、接口设计
POST /applications
创建申请草稿
PUT /applications/{id}/draft
保存草稿
POST /applications/{id}/submit
生成新版本并提交审核
GET /audit-tasks/{taskId}
返回审核详情聚合数据:版本信息、问题项、问题回应、变更集、完整快照
POST /audit-tasks/{taskId}/reject
入参为结构化问题项数组和总评
POST /audit-tasks/{taskId}/approve
审核通过
GET /versions/{versionId}/diff?baseVersionId=xxx
获取版本差异
POST /issues/{issueId}/response
申请人填写问题处理说明
十、审核入参与出参约束
驳回入参必须包含:
target_path
target_label
module_code
reason
重新提交时必须包含:
base_version_id
submit_note
issue_responses[]
审核详情聚合接口一次返回前端所需全部信息,前端不要自己拼多接口。
十一、权限与审计
申请人只能编辑草稿,不能改已提交版本。
审核人只能审核分配给自己的 AuditTask。
所有关键动作留痕:
谁在何时提交了哪个版本
谁创建了哪条驳回问题
谁对问题做了什么回应
谁最终确认问题已解决
任意审核结论都能追溯到具体版本和具体差异。
十二、必须落地的两个强约束
审核针对版本,不针对当前表
驳回必须结构化,不允许只有自由文本
如果这两个不做,后面的“只看修改、不重看整单”就做不稳。
十三、最终效果
审核人再次打开时,先看到的是“改了什么”和“是否改到了上次问题”,不是整页资料。
申请人无法模糊处理驳回意见,必须逐条回应。
系统能明确区分“问题修复”和“额外修改”,减少复审成本和漏审风险。
整个流程天然可审计、可追溯、可统计。