7.2 KiB
sql —— 工作流模块 SQL 脚本
本目录是从原型 fms-api 迁移工作流引擎时一并带过来的 SQL Server 脚本,用于把工作流的
表、视图、模块/菜单/权限注册和示例数据建到目标库。
本目录不包含
fms_core.sql。 目标项目 g3soft-erp 的库已经具备核心表 (s_module/s_field/s_module_schema/s_menu/s_power/s_user_power/b_user/b_dept等)。如果目标库缺少这些核心表,本目录的脚本无法独立完成初始化, 请先建好核心表再执行。
执行顺序
按目录名前缀的数字顺序执行:
| 顺序 | 脚本 | 作用 | 幂等 |
|---|---|---|---|
| 1 | 00_core_companion/workflow_audit_tables.sql |
s_log_audit / s_log_audit_field(可选,用于 §11 审计) |
是 |
| 2 | 10_workflow/01_fms_workflow.sql |
13 张 wf_* 表 + 索引(只建表,不含数据) |
否(重复执行会报表已存在) |
| 3 | 10_workflow/02_fms_workflow_org_ext.sql |
组织主数据扩展:b_dept.b_manager_id、b_user.b_leader_id、b_position / b_user_position / b_org_role / b_user_org_role |
是 |
| 4 | 20_registration/10_fms_workflow_module.sql |
4 个只读视图 + s_module / s_field / s_module_schema / s_menu_module 注册 |
是(先删后建) |
| 5 | 20_registration/11_fms_workflow_menu.sql |
流程管理 / 审批中心菜单 + s_i18n |
是 |
| 6 | 20_registration/12_fms_workflow_power.sql |
菜单权限点 + 动作权限点 + 授予 g3soft |
是 |
| 6.5 | 20_registration/13_table_test_menu.sql |
表格测试根菜单(/table-test)+ s_i18n |
是 |
| 6.6 | 20_registration/14_dashboard_menu.sql |
首页根菜单(/dashboard)+ s_i18n |
是 |
| 7 | 30_patches/01_fms_workflow_index_patch.sql |
补充索引(见下) | 是 |
| 8 | 90_mock/01_fms_workflow_mock.sql |
示例流程定义 expense_approval(14 节点 / 17 连线 / 13 审批人规则) |
否 |
| 9 | 90_mock/02_fms_workflow_runtime_mock.sql |
示例运行数据:演示机构/用户 + 6 个实例 | 否 |
第 2 步不幂等:01_fms_workflow.sql 是纯 create table。表已存在时会报错,需要先 drop
(脚本头部有说明)。第 8、9 步是示例数据,生产环境不要执行。
第 6 步的顺序陷阱
12_fms_workflow_power.sql 的动作权限点是这样生成的:
select distinct b_module_id from dbo.wf_binding where b_canuse = 1
wf_binding 为空时,动作权限点会生成 0 条。 三个缓解手段,按需选用:
- 先跑 mock(第 8 步,它含一条 binding)再跑第 6 步;或先在应用里保存一条流程绑定;
- 应用侧本身会自愈——
WorkflowConfigService.saveBinding每次保存绑定都会调用ensureActionPowers(moduleId),按action.{模块}.{动作}幂等补点; - 该脚本可重复执行,binding 补上后再跑一次即可。
动作权限点写入 s_power (b_type='action', b_object_type='module', b_object_id=模块, b_action=动作),
与 SqlPermissionService.requireAction 的匹配列一致,两边天然对齐。
组织主数据扩展(第 3 步)不是可选项
02_fms_workflow_org_ext.sql 建的表/列是 8 种审批人里 4 种的前提:
| 审批人类型 | 依赖 |
|---|---|
dept_manager |
b_dept.b_manager_id |
initiator_manager |
b_user.b_leader_id |
position |
b_position / b_user_position |
org_role |
b_org_role / b_user_org_role |
不执行该脚本时,这 4 类审批人会静默解析为空,再由节点兜底策略(fallback / 置 error)接管。
mock 数据的模块依赖
90_mock/02_fms_workflow_runtime_mock.sql 使用模块 v_b_othercompany 作为绑定目标。
目标库若没有该 s_module 行,请把它替换为库里真实存在的业务模块,或先补建该模块。
运行时语义备忘(与本目录脚本相关的两条约定)
- 任务超时只标记、不自动改流程:超时任务会被置
expired并从待办列表过滤掉, 实例保持running,由管理员通过加签 / 转派处理。不自动提升串行后继、不置error、不自动通过。 因此串行会签链中若当前审批人超时,链路会停住等待人工介入。 - 审计探写:
WorkflowAuditWriter每事务探测s_log_audit是否存在;不存在时写一条wf_outbox(audit.skipped)并继续。库里没有审计表不算故障,不会阻断审批。
菜单现在是动态的(第 6.5 步的背景)
前端侧栏菜单已改为动态:读 s_menu 表构建菜单树(对照 fms-vue 的 stores/menus.js
AppSidebar),不再使用前端常量菜单。因此新增页面必须两步都做:
- 在前端加一条静态路由(
web/src/router/index.ts,数据库存不了 Vue 组件); - 在
s_menu里录一条菜单(决定是否出现在侧栏、叫什么、排第几)。
13_table_test_menu.sql 就是第 2 步的示例:把「表格测试」页挂成根菜单,路由 /table-test。
权限是白名单语义:s_power 里没有 menu.{菜单编码}、或用户未被授权,侧栏就不显示该菜单、
路由守卫也会拦到 /403。g3soft 超管前后端都提权、不受此限,调试时先用它登录最省事;
要给普通账号开放,用该脚本末尾注释掉的「可选:给普通账号授权」那段。
⚠️ 菜单与路由必须成对,否则点进去是 404
s_menu 里有 b_route 的每一条页面菜单,前端都必须有一条 path 完全相同的静态路由。
少一条,点击该菜单就会落到 router 末尾的 /:pathMatch(.*)* 通配路由 → 显示 404 缺省页。
实测过的坑:只给已实现的页面建路由、其余菜单不建,会表现为「菜单点进去全是 404」—— 而 Vite dev server 对任意路径都返回 HTTP 200(SPA fallback),所以浏览器网络面板里 看不到 404 状态码,容易误判成后端或代理问题。真正的判据是路由是否匹配,不是 HTTP 状态。
当前 s_menu 的 13 条页面菜单与前端路由已逐条对齐:
s_menu b_route |
页面 | 状态 |
|---|---|---|
/dashboard |
首页 | 占位(views/dashboard/index.vue) |
/table-test |
表格测试 | 已实现(G3Table 完整范例) |
/approval/todo、/initiated、/done、/cc |
审批中心 | 占位 |
/base/othercompany、/contact、/otherdata |
基础资料 | 占位 |
/system/user、/system/workflow、/system/log/login、/system/log/audit |
系统管理 | 占位 |
占位页统一复用 web/src/components/PlaceholderPage.vue:把真实页面写进对应视图文件即可,
路由与菜单都不用再改。
补充索引说明(第 7 步)
| 索引 | 解决什么 |
|---|---|
ix_wf_binding_version (b_version_id) |
发布校验与删除定义按 b_version_id 直查,原索引不以它打头 |
ix_wf_task_completed_by (b_completed_by, b_completed_at) |
「我已处理」列表过滤列原无索引 |
ix_wf_task_node_run (b_node_run_id, b_status, b_seq, b_id) |
串行会签提升、兄弟任务取消 |
行尾
本目录 *.sql 一律 LF(根 .gitattributes 已声明 *.sql text eol=lf)。
从 fms 仓拷贝时已做 LF 转换。