Files
workspace/code/g3soft-libs/docs/content/backend/schema.md
T
2026-10-13 22:32:50 +08:00

35 KiB
Raw Blame History

title, description
title description
数据表结构 核心元数据表、组织与权限表、日志表、工作流表的完整字段说明

数据表结构

本文记录 G3ERP 库的结构与约定,字段以真库为准。

按前缀分四类,本文只写系统级表(业务表详见各自业务域):

前缀 类别 本文是否覆盖
s_ 系统 / 元数据 / 权限 / 日志 ✅ 全部 20 张
wf_ 工作流 ✅ 全部 13 张
bf_ 文件附件 ✅ 2 张
b_ 业务与主数据 只写组织用户等基础表;业务字典表不写
v_ 视图 查询入口,见文末

1. 命名与字段约定

1.1 表名

  • 统一小写 snake_case,下划线分词。
  • 系统表 s_;业务与主数据 b_;业务域表用明确的域前缀(如 bf_files);工作流 wf_(属业务域前缀,不用 s_)。
  • 表名表达稳定的业务含义,不用页面名或路由名当表名。

1.2 字段命名

用途 约定
主键 业务编码主键 b_id;关系表用联合主键
关联 <对象>_id,如 b_module_id、b_dept_id
排序 b_xh,默认 0
启用 b_canuse,0/1,默认 1
备注 b_bz
名称 b_name
多语言 b_i18n(指向 s_i18n.b_key)
主表字段 b_ 前缀
明细 / 子表字段 mx_ 前缀

1.3 类型选择

用途 类型
名称、备注、多语言文本 nvarchar
编码、状态、类型、SQL 标识 varchar
日期时间 datetime2
启用、顺序标记 tinyint(0/1)
数量、金额 按业务精度设 precision / scale

1.4 审计字段

字段 含义
b_created_by / b_created_at 创建人(用户编码)/ 创建时间
b_updated_by / b_updated_at 最后修改人 / 最后修改时间

不建触发器,由写入方维护(通用保存在服务端统一填,前端不能指定)。

审计字段不是所有表都必须有:客户维护、需追溯变更的业务表才需要;系统内部关联表、字典表可省略。授权类表例外——s_user_power / s_user_field_power / s_user_data_power 由用户在授权界面操作,需追溯授权变更人,因此保留审计字段。s_power 是开发期维护的系统元数据,不设审计字段。

这些字段只表示系统层面的创建/修改信息,不替代业务字段里的录入人、审核人、负责人。

1.5 约束

  • 不依赖数据库外键、CHECK 约束和触发器保证业务规则,合法性由业务层校验。
  • 状态、类型、动作的取值写在列注释里,不用 CHECK 枚举——加值不需要改表。
  • 关联完整性与删除规则由业务层处理,删除策略见 s_relation.b_on_delete 与 s_delete_rule。

2. 键与 ID 策略

场景 策略 示例
配置表(模块、菜单、权限、流程定义) varchar 业务编码主键(人可读、跨环境稳定) s_module.b_id、wf_definition.b_id
业务数据 应用层生成的 bigint 雪花 ID bf_files.subid、业务表 b_id
工作流运行对象 UUIDv7(uniqueidentifier,按时间有序) wf_instance.b_id、wf_task.b_id
日志 UUIDv7 s_log_audit.b_id

跨表引用业务主键时统一按字符串保存(如 wf_instance.b_business_id、s_log_audit.b_data_id),不依赖业务表物理主键类型——业务表可能是 bigint,老表可能是 varchar。

3. 模块元数据

系统以「模块」为配置单元,五张表配合完成查询与界面配置。

3.1 s_module — 模块定义

列 类型 说明
b_id varchar(50) PK 模块编码
b_parent_id varchar(50) 父模块,NULL 为根
b_depth int 默认 0 树层级,根为 0
b_path varchar(1000) 根到当前节点路径,如 /sea/container/
b_name nvarchar(200) 模块名称
b_i18n varchar(150) 多语言资源键
b_module_type varchar(20) module / data / virtual
b_view_table varchar(128) 默认查询表或视图
b_save_table varchar(128) 默认保存目标表
b_key_field varchar(50) 主键字段
b_scope_field varchar(50) 数据范围判定字段(记录归属人字段)
b_order_sql varchar(500) 默认排序 SQL
b_query_sql nvarchar(max) 可选查询 SQL 或模板
b_config_json nvarchar(max) 低频扩展配置
b_canuse tinyint 默认 1 是否启用
b_xh int 默认 0 同级显示顺序
b_bz nvarchar(2000) 备注

索引:ix_s_module_parent(b_parent_id, b_canuse, b_depth, b_xh, b_id)、ix_s_module_path(b_path, b_canuse, b_id)、ix_s_module_type(b_module_type, b_canuse, b_xh, b_id)、ix_s_module_view_table、ix_s_module_save_table。

模块类型:

取值 含义
module 业务分组(海运、财务…),默认不配字段与表
data 具体数据对象,必须配 b_view_table 或 b_query_sql
virtual 不适合标准表表达的能力,由 SQL 或业务处理器实现

b_scope_field 是数据范围权限的唯一判定依据,配在模块上而非授权行上:同一模块的所有用户必须用同一字段判范围(如 b_inputuser_id)。

3.2 s_field — 模块字段

列 类型 说明
b_module_id varchar(50) PK 所属模块
b_field varchar(50) PK 字段编码 / 查询别名
b_name nvarchar(200) 字段名称
b_i18n varchar(150) 多语言资源键
b_type varchar(30) 业务类型
b_canuse tinyint 默认 1 是否启用
b_xh int 默认 0 默认顺序

主键 (b_module_id, b_field);索引 ix_s_field_module_order(b_module_id, b_canuse, b_xh, b_field)。

s_field 不保存数据库类型、长度、精度——这些由后端在运行时直接读表/视图结构(MetadataReader)。字段同步按来源结构对齐,但不覆盖人工维护的名称与业务类型。 b_type 的取值集合由业务层维护,本设计不做固定枚举。

3.3 s_module_schema — 界面配置

列表 / 表单 / 查询配置统一存 JSON,不再各建一张表。

列 类型 说明
b_module_id varchar(50) PK 模块编码
b_schema_type varchar(20) PK view / edit / query
b_schema_json nvarchar(max) 完整 JSON 配置
b_canuse tinyint 默认 1 是否启用
b_updated_by varchar(50) 最后修改人
b_updated_at datetime2 最后修改时间

主键 (b_module_id, b_schema_type)。JSON 顶层含 schemaVersion 便于结构升级。

3.4 s_relation — 模块关系

列 类型 说明
b_source_module_id varchar(50) PK 源模块
b_source_field varchar(50) PK 源字段
b_target_module_id varchar(50) PK 目标模块
b_target_field varchar(50) PK 目标字段
b_relation_type varchar(20) one_to_one / one_to_many / many_to_one
b_on_delete varchar(20) 默认 restrict 删除策略:restrict / cascade / set_null
b_canuse / b_xh — 启用 / 顺序

索引:ix_s_relation_source、ix_s_relation_target。

3.5 s_autocode — 自动编码

列 类型 默认 说明
b_module_id varchar(50) PK — 模块编码
b_field varchar(50) PK — 字段编码
b_prefix nvarchar(200) '' 前缀
b_dateformat varchar(30) yyyyMM 日期段格式
b_separator nvarchar(20) - 分隔符
b_seqwidth int 5 流水号位数
b_resettype varchar(10) month 重置周期
b_startvalue bigint 1 起始值
b_currentperiod varchar(20) — 当前周期
b_currentvalue bigint 0 当前值
b_canuse tinyint 1 是否启用

3.6 s_menu / s_menu_module

菜单树与模块挂载关系。

s_menu:b_id(PK) / b_parent_id / b_depth / b_path / b_name / b_i18n / b_menu_type / b_route(路由) / b_icon / b_xh / b_canuse。

s_menu_module:b_menu_id + b_module_id(联合 PK) / b_xh / b_canuse——把菜单挂到一个或多个模块上。

索引:ix_s_menu_parent、ix_s_menu_path、ix_s_menu_route、ix_s_menu_module_module。

3.7 多语言

表 结构
s_i18n b_key + b_locale(联合 PK) / b_value nvarchar(1000) / b_canuse
s_i18n_type b_id(PK, 如 zh-CN) / b_name / b_canuse / b_default(是否默认语言) / b_xh

3.8 s_user_module_pref — 用户个性化

用户对模块界面的个人偏好(列宽、顺序等),覆盖模块默认配置。

b_user_id + b_module_id + b_schema_type(联合 PK) / b_schema_json / b_updated_by / b_updated_at。

3.9 s_delete_rule — 删除规则

列 说明
b_id bigint 主键
b_module_id 模块编码
b_sql 删除前检查/处理的 SQL
b_message 不满足条件时给用户的提示
b_canuse / b_xh 启用 / 顺序
b_created_by / b_created_at / b_updated_by / b_updated_at 审计字段

4. 组织与用户

表 主键 说明
b_user b_id varchar(50) 用户账号
b_dept b_id varchar(50) 部门树
b_position b_id varchar(50) 岗位
b_org_role b_id varchar(50) 组织角色
b_user_position b_user_id + b_position_id 用户-岗位关联
b_user_org_role b_user_id + b_role_id 用户-组织角色关联

两个对工作流审批人解析至关重要的字段:

字段 含义 用于
b_dept.b_manager_id 部门负责人(用户编码) dept_manager 规则
b_user.b_leader_id 用户的直属领导(用户编码) initiator_manager 规则

部门树用 b_parent_id 作权威关系,b_depth / b_path 是派生字段;b_path 的节点编码前缀用于查下级部门(数据范围 dept_tree 依赖)。

关联表都有 b_canuse 与审计字段,并建了反向索引(如 ix_b_user_position_position)。

5. 权限

权限只保留四张表,分别回答四个问题:

5.1 s_power — 有哪些权限点

列 类型 说明
b_id varchar(150) PK 权限点编码,如 action.{模块}.{动作}
b_name nvarchar(200) 权限点名称
b_type varchar(20) 权限点类型
b_object_type varchar(20) 对象类型,动作权限为 module
b_object_id varchar(50) 对象编码(模块编码)
b_action varchar(30) 动作编码,如 submit / approve / export
b_canuse / b_xh / b_bz / b_i18n — —

唯一索引 ux_s_power_object_action(b_object_type, b_object_id, b_action) —— 保证同一对象同一动作只有一个权限点。 另有 ix_s_power_object、ix_s_power_type。

s_power 不设审计字段(开发期维护的系统元数据)。

5.2 s_user_power — 用户有哪些权限点

列 说明
b_user_id + b_power_id 联合主键
b_canuse 是否启用
b_created_by / b_created_at / b_updated_by / b_updated_at 审计字段(授权变更需可追溯)

索引 ix_s_user_power_power(b_power_id, b_user_id)。

5.3 s_user_field_power — 字段级权限

列 默认 说明
b_user_id + b_module_id + b_field_id 联合 PK —
b_view 1 是否可见
b_edit 0 是否可编辑
b_query 1 是否可作为查询条件
b_export 1 是否可导出
b_canuse 1 是否启用
b_created_by / b_created_at / b_updated_by / b_updated_at — 审计字段

无记录按模块默认(可看可导出)。b_view=0 或 b_export=0 的列会在导出时被移除。

5.4 s_user_data_power — 数据范围

列 类型 默认 说明
b_user_id varchar(50) PK — 用户编码
b_module_id varchar(50) PK — 模块编码
b_operation varchar(30) PK * 操作;* 表示适用于所有操作
b_xh int PK 0 同组内的排序 / 区分序号
b_scope_type varchar(20) — 范围类型,见下
b_scope_field varchar(50) — 判定字段(实际取值以模块配置 s_module.b_scope_field 为准)
b_condition_sql nvarchar(max) — custom 类型的条件片段
b_canuse tinyint 1 是否启用
审计字段 — — b_created_* / b_updated_*

主键 (b_user_id, b_module_id, b_operation, b_xh);索引 ix_s_user_data_power_module。

b_scope_type 含义
all 或空 全部数据,不追加条件
self 只本人:判定字段 = 当前用户
dept 只本部门:判定字段 = 当前用户所属部门
dept_tree 本部门及下级:按 b_dept.b_path 前缀匹配
custom 自定义:使用 b_condition_sql

判定规则:

  • 按操作精确匹配优先——命中精确规则就不再叠加 '*' 规则;没有精确规则时才用 '*'。
  • 多条规则之间 OR,整体再与其它条件 AND。
  • 判定字段取自模块配置而不是授权行:同一模块的所有用户必须用同一字段判范围。
  • 未归属部门时 dept / dept_tree 规则不生效(不报错,等于不追加条件)。
  • custom 的 b_condition_sql 只由管理员配置,运行时仅替换 {userId} / {deptId} 受控占位符,并做只读校验(禁分号、禁注释、禁写关键字)。

6. 日志

三张日志表都以 UUIDv7 为主键,都建了按时间与业务维度的索引。

6.1 s_log_audit — 数据变更审计

列 类型 默认 说明
b_id uniqueidentifier PK — UUIDv7
b_event_code varchar(50) — 事件编码
b_module_id varchar(50) — 模块编码
b_data_id varchar(50) — 业务主键(统一字符串保存)
b_business_no varchar(50) — 业务单号
b_operation varchar(100) — 操作名(如「审批状态投影」)
b_operator_id varchar(50) — 操作人
b_operator_name nvarchar(200) — 操作人姓名
b_source_type varchar(20) user 来源类型(user / system)
b_visibility varchar(20) internal 可见性
b_request_id / b_trace_id varchar(64) — 请求 / 链路 ID
b_payload_text nvarchar(max) — 事件载荷
b_occurdatetime datetime2 getdate() 发生时间

索引:ix_s_log_audit_module(b_module_id, b_data_id, b_occurdatetime)、ix_s_log_audit_occur(b_occurdatetime, b_id)。

6.2 s_log_audit_field — 字段级前后值

列 说明
b_id PK
b_event_id 关联 s_log_audit.b_id
b_module_id / b_data_id 冗余存储,便于直接按数据查
b_field 字段编码
b_field_label 字段名称
b_before_value / b_after_value 原始值
b_before_display / b_after_display 展示值(如枚举翻译后的文本)
b_visibility 可见性

索引 ix_s_log_audit_field_event(b_event_id, b_id)。

原始值与展示值分开存:原始值用于比对与回放,展示值用于界面直接呈现,避免查日志时再翻译一遍。

6.3 s_log_login — 登录日志

列 说明
b_id PK(UUIDv7)
b_user_id 用户账号(失败时也可能有值)
b_login_type 登录方式
b_login_result tinyint,0 失败 / 1 成功
b_fail_reason 失败原因(「账号不存在」/「密码错误」)
b_ip / b_ip_location 来源 IP 与归属地
b_browser / b_browser_version 浏览器
b_os / b_os_version 操作系统
b_device_type 设备类型
b_user_agent 原始 UA
b_session_id 会话 ID(成功时)
b_request_id / b_trace_id 请求 / 链路 ID
b_occurdatetime 发生时间

索引:ix_s_log_login_occur、ix_s_log_login_user(b_user_id, b_occurdatetime)。

对外提示不区分「账号不存在」与「密码错误」(都是 401 同一句),但日志里分别记录 —— 既能防账号探测,又能支撑排查。

6.4 s_log_technical — 技术日志

列 说明
b_id PK(UUIDv7)
b_user_id 用户编码
b_sourcetype 来源类型
b_loglevel 日志级别
b_logcategory 日志分类
b_operation 操作名
b_module_id 模块编码
b_request_id / b_trace_id 请求 / 链路 ID
b_server_node 服务节点
b_duration_ms 耗时(毫秒)
b_result_code 结果码
b_error_code / b_error_message 错误码与说明
b_exception_text 异常堆栈
b_context_text 上下文
b_occurdatetime 发生时间

索引:ix_s_log_technical_occur、ix_s_log_technical_trace(b_trace_id, b_occurdatetime)——按链路 ID 串起一次请求的全部日志。

7. 附件

7.1 bf_files — 文件记录

列 类型 说明
subid bigint PK 雪花 ID(应用层取号,非自增)
father bigint 宿主业务主键,不建外键
mx_filename nvarchar(500) 原始文件名
mx_filesize varchar(50) 文件大小
mx_fileext varchar(50) 扩展名
mx_mapfilename nvarchar(500) 访问地址(预览/下载直接用)
mx_moduleid varchar(50) 模块编码
mx_cate_id bigint 分类 ID(关联 bf_files_category.b_id)
mx_xh / mx_sh int / tinyint 顺序 / 审核标记(保留,当前未用)
mx_inputuser_id / mx_inputdatetime — 录入人 / 录入时间
mx_shuser_id / mx_shdatetime — 审核人 / 审核时间(保留)
mx_cutfilename / mx_cutfilesize — 缩略图文件名 / 大小(保留)
mx_updateuser_id / mx_updatedatetime — 最后修改人 / 时间(保留)
mx_orderid / mx_bz — 排序 / 备注(保留)

索引 ix_bf_files_host(father, mx_moduleid, mx_cate_id, mx_xh, subid) —— 列表查询按宿主 + 模块 + 分类过滤。

旧库遗留字段 mx_sh* / mx_cut* / mx_orderid / mx_bz / mx_update* 保留以兼容历史数据迁移,新代码不使用(写入 0 或空值)。但 subid / father / mx_* 的列名已被前后端实现引用,保持现状。

7.2 bf_files_category — 文件分类

列 类型 说明
b_id bigint PK 雪花 ID(与 bf_files.mx_cate_id 类型一致)
b_module_id varchar(50) 所属模块;为空表示跨模块通用分类
b_name nvarchar(50) 分类名称
b_i18n varchar(150) 多语言资源键
b_files_type varchar(50) 文件类型
b_xh / b_canuse int / tinyint 顺序 / 启用
b_bz nvarchar(200) 备注
审计字段 — b_created_* / b_updated_*

索引 ix_bf_files_category_module(b_module_id, b_canuse, b_xh, b_id)。

分类树按当前模块过滤:b_module_id IS NULL OR b_module_id = 当前模块。

8. 工作流

工作流是独立子系统:配置表用 varchar 业务编码主键,运行表用 UUIDv7。全部 13 张表。

配置:wf_definition → wf_version → { wf_node, wf_edge, wf_actor_rule }
                                  wf_binding(模块+事件 → 版本)
运行:wf_instance → wf_node_run → wf_task → wf_action
                   wf_cc(抄送)  wf_delegation(委托)  wf_outbox(通知)

8.1 wf_definition — 流程定义

稳定逻辑身份,执行内容在版本表。

b_id varchar(50) PK(编码,创建后不可修改)/ b_name nvarchar(200) / b_i18n / b_canuse / b_bz / 审计字段。 索引:ix_wf_definition_canuse(b_canuse, b_id)。

8.2 wf_version — 流程版本

列 类型 默认 说明
b_id varchar(50) PK — 版本 ID
b_definition_id varchar(50) — 所属定义
b_version_no int — 版本号(同流程内递增)
b_status varchar(20) draft draft / published / retired
b_schema_version int 1 配置结构版本
b_canvas_json nvarchar(max) — 设计器布局,不参与执行
b_checksum varchar(128) — 发布时计算的配置摘要
b_published_by / b_published_at — — 发布人与时间

四个索引,其中两个是筛选唯一索引:

索引 作用
ux_wf_version_draft(b_definition_id) WHERE b_status='draft' 同一定义只能有一条草稿
ux_wf_version_no(b_definition_id, b_version_no) 版本号不重复
ix_wf_version_status 按状态查询

已发布版本不可原地修改;运行中的实例固定引用提交时的 b_version_id。

8.3 wf_node — 节点

列 类型 说明
b_id varchar(50) PK 节点 ID
b_version_id varchar(50) 所属版本
b_node_key varchar(80) 版本内稳定编码(历史记录引用它)
b_name / b_i18n — 名称 / 多语言键
b_node_type varchar(30) 见下
b_approval_mode varchar(30) 见下
b_reject_mode varchar(30) 见下
b_due_hours decimal(10,2) 审批时限(小时);不配则该节点任务永不过期
b_config_json nvarchar(max) 扩展配置(requiredCount / requiredRatio / formPolicy 等)
b_xh / b_canuse — 顺序 / 启用
列 取值
b_node_type start / user_task / cc_task / service_task / exclusive_gateway / parallel_gateway / end
b_approval_mode single / any / all / serial / n_of_m / percentage
b_reject_mode terminate / return_initiator / return_previous

唯一索引 ux_wf_node_key(b_version_id, b_node_key)——同一版本内节点编码唯一。

8.4 wf_edge — 连线

列 说明
b_id 连线 ID(varchar(50) PK)
b_from_node_key / b_to_node_key 两端节点编码
b_condition_json 条件 AST,留空 = 无条件(默认边)
b_priority 判断优先级,小的先判断
b_name 连线名称(画布标签)
b_canuse / b_bz —

索引:ix_wf_edge_from、ix_wf_edge_to(都含 b_canuse, b_priority)。

8.5 wf_actor_rule — 审批人规则

列 说明
b_id 规则 ID
b_node_key 适用节点
b_actor_type 解析类型,见下
b_actor_ref 用户 / 岗位 / 角色 / 字段编码
b_resolve_json 解析参数
b_condition_json 规则适用条件 AST
b_fallback_type 解析为空时的兜底:none / admin / initiator / custom
b_fallback_ref 兜底引用
b_priority 优先级——串行会签的顺序来源
b_canuse / b_bz —
b_actor_type 含义 依赖字段
user 指定用户 b_actor_ref
initiator 发起人 —
initiator_manager 发起人直属领导 b_user.b_leader_id
dept_manager 部门负责人 b_dept.b_manager_id
position 岗位 b_user_position
org_role 组织角色 b_user_org_role
field_user 业务字段里的用户 b_actor_ref 指定的字段
custom 自定义解析器 —

索引 ix_wf_actor_rule_node(b_version_id, b_node_key, b_canuse, b_priority, b_actor_type)。

规则顺序即优先级顺序,也是串行会签的先后。组织主数据(岗位 / 角色表)不存在时对应类型会降级为空并记原因,由 b_fallback_type 兜底。

8.6 wf_binding — 模块绑定

决定「哪个模块的哪个业务事件走哪个流程版本」。

列 说明
b_module_id 模块编码(data / virtual 模块)
b_event submit / resubmit / change
b_version_id 必须是已发布版本
b_match_json 业务匹配条件 AST
b_org_scope_json 公司 / 组织范围
b_status_field 业务状态列名(状态投影写这一列)
b_status_map_json 流程状态 → 业务状态值映射
b_priority 匹配优先级,小的先匹配
b_effective_from / b_effective_to 生效区间
b_canuse / b_bz / 审计字段 —

关键筛选唯一索引:

ux_wf_binding_active_priority(b_module_id, b_event, b_priority) WHERE b_canuse = 1

→ 同一模块同一事件下不能有两条同优先级的启用绑定(否则无法确定用哪个流程)。

另有 ix_wf_binding_select、ix_wf_binding_version。

8.7 wf_instance — 流程实例

列 类型 说明
b_id uniqueidentifier PK UUIDv7
b_definition_id / b_version_id / b_binding_id varchar(50) 定义 / 版本(提交时固定)/ 命中的绑定
b_module_id / b_event varchar 业务模块与事件
b_business_id varchar(50) 业务主键,统一按字符串保存
b_business_no nvarchar(200) 业务单号(列表展示)
b_org_id varchar(50) 公司 / 组织编码
b_initiator_id / b_initiator_dept_id varchar(50) 发起人及其部门
b_status varchar(30) 见下
b_context_json nvarchar(max) 运行变量(条件分支与审批人解析的输入)
b_snapshot_json nvarchar(max) 提交时业务快照
b_current_summary_json nvarchar(max) 列表展示用当前节点摘要
b_row_version bigint 默认 0 乐观锁版本号
b_idempotency_key varchar(100) 幂等键
b_started_at / b_completed_at datetime2 开始 / 结束时间
b_status 含义
running 运行中
approved / rejected / returned 已通过 / 已驳回 / 已退回
withdrawn / cancelled 已撤回 / 已取消
error 异常待处理(审批人解析为空、路由走不通、配置损坏)

列注释里还列了 expired,但实现中实例从不进入该状态——超时只作用于任务(见 §8.9)。

关键筛选唯一索引:

ux_wf_instance_idempotency(b_module_id, b_business_id, b_idempotency_key)
    WHERE b_idempotency_key IS NOT NULL

→ 送审幂等的唯一保证。代码靠捕获唯一键冲突(SQL 2601/2627/23000)回查既有实例返回 duplicated,索引不存在则幂等完全失效。

另有 ix_wf_instance_business、ix_wf_instance_initiator、ix_wf_instance_version。

8.8 wf_node_run — 节点运行

列 类型 说明
b_id uniqueidentifier PK UUIDv7
b_instance_id uniqueidentifier 所属实例
b_node_key varchar(80) 节点编码
b_run_no int 默认 1 同一节点的第几次运行(退回、循环用)
b_status varchar(30) pending / running / completed / skipped
b_required_count int 应签人数(按比例时激活时换算)
b_completed_count / b_rejected_count int 默认 0 已通过 / 已驳回人数
b_entered_at / b_exited_at datetime2 进入 / 离开时间
b_actor_snapshot_json nvarchar(max) 审批人规则快照(含解析结果与说明)

节点状态是 completed,不是任务的 approved —— 若这里写 approved,并行汇合的「入线来源节点都已完成」判定与「退回上一节点」查找都会失效。

审批人快照必须落库:组织架构以后变了,也不能改动已产生的历史审批责任。

8.9 wf_task — 待办任务

列 类型 说明
b_id uniqueidentifier PK UUIDv7
b_instance_id / b_node_run_id uniqueidentifier 实例 / 节点运行(会签聚合判断用)
b_node_key varchar(80) 节点编码
b_actor_rule_id varchar(50) 命中的审批人规则
b_assignee_type varchar(30) user / position / role / delegate(委托物化)
b_assignee_id varchar(50) 实际受理人
b_seq int 默认 0 同节点内处理顺序(串行会签生效)
b_status varchar(30) 见下
b_due_at datetime2 应处理时间(由节点 b_due_hours 算出)
b_claimed_by / b_claimed_at — 抢占人与时间
b_completed_by / b_completed_at — 处理人与时间
b_rule_snapshot_json nvarchar(max) 审批人解析快照(委托时含原审批人与委托单号)
b_status 含义
waiting 串行会签排队中(未轮到)
pending / claimed 待处理 / 已抢占
approved / rejected 已通过 / 已驳回
cancelled 被撤回、取消,或同节点他人已处理而取消
expired 已超期(仅由超时扫描写入)

索引:ix_wf_task_assignee(b_assignee_id, b_status, b_due_at, b_id)(待办列表)、 ix_wf_task_due(b_status, b_due_at, b_id)(超时扫描)、 ix_wf_task_node_run(b_node_run_id, b_status, b_seq, b_id)(串行推进)、 ix_wf_task_instance、ix_wf_task_completed_by(已办列表)。

b_due_at 为空 = 永不超时:节点没配 b_due_hours 时不设应处理时间。

8.10 wf_action — 审批动作历史

列 说明
b_id PK(UUIDv7)
b_instance_id 实例
b_node_run_id / b_task_id 节点运行 / 任务(实例级动作为 null)
b_action 动作编码,见下
b_operator_id 操作人(系统动作为 null)
b_from_status / b_to_status 变更前后状态
b_comment 审批意见
b_payload_json 动作载荷(命中的条件、边、加签位置等)
b_request_id / b_trace_id 请求 / 链路 ID
b_occurdatetime 发生时间
b_action 含义
submit / approve / reject / return 送审 / 通过 / 驳回 / 退回
withdraw / cancel 撤回 / 取消
claim / transfer / add_approver / urge 抢占 / 转交 / 加签 / 催办
cc 抄送
activate 串行会签激活下一位
service 服务节点自动完成
route 分支点路由留痕
expire 任务超期(系统动作,操作人为 null)

筛选唯一索引:

ux_wf_action_request(b_request_id) WHERE b_request_id IS NOT NULL

→ 审批幂等的保证(与 wf_instance 的幂等键同理)。

该列无 CHECK 约束,加动作码不需要改表;但下游若按枚举过滤需同步。 wf_action 是不可变历史,与 s_log_audit 分工:前者记流程动作,后者记数据变更。

8.11 wf_cc — 抄送

b_id(PK) / b_instance_id / b_node_run_id / b_node_key / b_recipient_id / b_actor_rule_id / b_status(unread 默认 / read)/ b_read_at / b_rule_snapshot_json。

索引:ix_wf_cc_recipient(b_recipient_id, b_status, b_created_at, b_id)(抄送列表)、ix_wf_cc_instance。

抄送节点不产生待办,也不参与节点完成判定(写入即完成)。

8.12 wf_delegation — 委托

列 说明
b_id varchar(50) PK
b_from_user_id / b_to_user_id 委托 / 受托人
b_scope_json 委托范围:{moduleIds, actions, orgIds},空数组 = 不限
b_start_at / b_end_at 生效 / 失效时间
b_reason 委托原因
b_canuse / 审计字段 —

索引 ix_wf_delegation_user(b_from_user_id, b_canuse, b_start_at, b_end_at, b_to_user_id)。

委托在任务生成时就物化:候选人若有生效中的委托,任务直接建给代理人(b_assignee_type='delegate'),这样代理人能在待办里看到它。原审批人与委托单号进任务快照,动作期复核 actions 范围。

8.13 wf_outbox — 通知消息

列 默认 说明
b_id — PK(UUIDv7)
b_event_code — 事件编码
b_aggregate_type — instance / task
b_aggregate_id — 聚合 ID
b_payload_json — 消息载荷
b_status pending pending / sent / failed
b_retry_count 0 重试次数
b_next_retry_at — 下次重试时间
b_last_error — 最后错误
b_occurdatetime — 发生时间

索引 ix_wf_outbox_dispatch(b_status, b_next_retry_at, b_occurdatetime, b_id)。

事件码词表:

事件码 触发
instance.submitted / instance.withdrawn / instance.cancelled 实例级状态变化
instance.approved / instance.rejected / instance.returned 实例结束
instance.error 实例进入异常
task.created / task.activated 建任务 / 串行激活下一位
task.transferred / task.approver_added / task.urged 转交 / 加签 / 催办
task.expired 任务超期(超时扫描写)
cc.created 抄送产生
instance.projection_skipped 业务主键类型不匹配,跳过投影
instance.projection_missing 状态投影影响行数 ≠ 1(静默丢更新的留痕)
audit.skipped s_log_audit 不存在,审计无法落库

最后三个是降级留痕:出问题时不会阻断审批,但会在 outbox 里留下可追溯的记录。

9. 超时机制(与表结构的关系)

超时是唯一会主动改任务状态的后台行为,涉及 wf_task 与上述三张表:

节点 b_due_hours → 建任务时算出 b_due_at
       ↓
[后台扫描,默认 5 分钟]
  选出 b_status in ('pending','claimed') and b_due_at < sysutcdatetime()
       ↓
  wf_task.b_status = 'expired'
  wf_action      += 一条 expire(操作人为 null)
  wf_outbox      += task.expired

明确不做:不动 wf_node_run、不动 wf_instance(仍 running)、不自动通过/否决、不置 error、不提升串行后继。

几个由此而来的结论:

  • 到期任务从待办列表(只查 pending/claimed)自动消失,但实例仍在运行,需管理员加签或转派。
  • 没有「我的超期任务」出口:doneList 查的是 b_completed_by,超期任务没人处理过,所以也查不到。
  • 串行链上当前审批人超期会停住:那把唯一的 pending 失效后,waiting 的不会自动提升,整条链停在那里。
  • 配 erp.workflow.expire-sweep-interval: 0s 可完全关闭扫描。

10. 视图

查询入口以视图为主,业务模块通常指向视图而不是物理表:

视图 说明
v_wf_definition / v_wf_version / v_wf_binding / v_wf_instance 工作流配置与实例(配置侧列表用)
v_s_log_audit / v_s_log_login / v_s_log_technical 日志查询
v_b_othercompany / v_b_contact / v_b_user 业务与主数据