4. 变更记录数据模型:操作人、操作时间、操作类型、变更前内容、变更后内容、变更原因

变更记录是审批工作流中实现可追溯性与合规审计的核心资产。一个完整且严谨的变更记录数据模型,必须能够回答“谁、在何时、做了什么、改了什么、为什么改”这五个关键问题。本章将详细定义该模型的字段规范、类型枚举与存储策略。

4.1 核心字段定义

变更记录表(change_log)应包含以下六个必填字段,构成审计追踪的最小完备集:

字段名 数据类型 约束 说明
operator VARCHAR(64) NOT NULL 操作人唯一标识(用户ID或用户名)
operate_time DATETIME(3) NOT NULL, DEFAULT CURRENT_TIMESTAMP(3) 操作发生的精确时间,精确到毫秒
operate_type VARCHAR(32) NOT NULL 操作类型枚举值(见4.2节)
before_content JSON / TEXT NULLABLE 变更前的完整数据快照或差异字段集
after_content JSON / TEXT NULLABLE 变更后的完整数据快照或差异字段集
change_reason VARCHAR(512) NOT NULL 操作人填写的变更原因或系统自动生成的摘要
设计要点:建议将 before_content 与 after_content 设计为 JSON 类型,便于存储结构化差异数据,同时支持未来扩展字段级对比查询。对于非结构化审批单,可使用 TEXT 类型存储序列化后的完整快照。

4.2 操作类型枚举

操作类型(operate_type)应使用受控枚举值,避免自由文本带来的分析混乱。标准枚举集如下:

  • CREATE — 创建审批单或流程实例
  • SUBMIT — 提交审批(从草稿进入流转)
  • APPROVE — 审批通过
  • REJECT — 审批驳回
  • REVOKE — 发起人撤回
  • TRANSFER — 转办/委托
  • ADD_SIGN — 加签
  • UPDATE — 修改表单内容(非流程操作)
  • COMMENT — 仅添加审批意见,未改变状态
最佳实践:在数据库层面使用 ENUM 或 CHECK 约束强制枚举值合法;在应用层使用常量类或枚举类统一引用,避免硬编码字符串。

4.3 变更记录数据模型架构图

下图展示了变更记录在审批工作流中的位置及其与核心实体之间的关系:

变更记录数据模型架构图 变更记录数据模型与实体关系 审批单 approval_id, form_data, status 流程实例 instance_id, node_id, assignee 变更记录 (change_log) operator | operate_time | operate_type before_content | after_content | change_reason 外键: approval_id, instance_id 用户/操作人 user_id, name, role 操作类型字典 枚举值: CREATE, APPROVE... 每条变更记录必须 关联一个审批单或流程实例 before_content 在 CREATE 操作时为 NULL

4.4 变更内容存储策略

针对 before_content 与 after_content 的存储,推荐以下两种策略,可根据业务场景选择:

策略 存储方式 优点 缺点 适用场景
全量快照 每次变更存储完整表单 JSON 查询简单,无需关联计算;历史版本独立 存储冗余大;大表单时性能开销高 表单字段少、变更频率低、审计要求严格的场景
差异字段 仅存储发生变化的字段键值对 存储空间小;便于字段级对比分析 查询历史全貌需逐条合并;实现复杂度高 表单字段多、变更频繁、关注字段级追溯的场景
注意:无论采用哪种策略,change_reason 字段都不应留空。对于系统自动触发的变更(如超时自动驳回),应生成标准化的原因文本,例如:“审批超时,系统自动驳回”。严禁将 change_reason 设为 NULL 或空字符串。

4.5 变更记录查询与索引设计

为支撑高效的审计查询与报表分析,建议在 change_log 表上建立以下索引:

  • 复合索引 (approval_id, operate_time) — 按审批单查询变更历史,按时间排序
  • 复合索引 (operator, operate_time) — 按操作人查询操作记录,用于用户行为审计
  • 单列索引 (operate_type) — 按操作类型统计,如统计驳回率、转办次数

典型查询示例:

-- 查询某审批单的完整变更历史
SELECT operator, operate_time, operate_type, change_reason
FROM change_log
WHERE approval_id = 'AP-2024-00123'
ORDER BY operate_time ASC;

-- 查询某用户在最近30天内的所有驳回操作
SELECT cl.*, a.form_data
FROM change_log cl
JOIN approval a ON cl.approval_id = a.approval_id
WHERE cl.operator = 'user_zhang'
  AND cl.operate_type = 'REJECT'
  AND cl.operate_time >= NOW() - INTERVAL 30 DAY
ORDER BY cl.operate_time DESC;

4.6 变更原因填写规范

为保证审计质量,change_reason 的填写应遵循以下规范:

操作类型 原因填写要求 示例
CREATE / SUBMIT 必填,简述发起事由 “申请采购开发服务器,用于新项目环境搭建”
APPROVE 必填,说明通过依据 “预算已确认,符合采购流程,同意”
REJECT 必填,说明驳回理由 “预算超出部门额度,请重新调整后提交”
REVOKE 必填,说明撤回原因 “发现附件上传错误,撤回后重新提交”
TRANSFER 可选,可填写转办原因 “原审批人请假,转办至代理审批人”
UPDATE 必填,说明修改内容 “修改预算金额从50000变更为45000”
工程落地建议:在前端审批表单中,将 change_reason 设置为必填文本框,并给出字数提示(建议 10-200 字)。对于驳回和撤回操作,可提供常用原因模板供用户选择,降低填写门槛同时保证质量。