Files
workspace/code/g3soft-erp/sql/README.md
T
2026-10-13 22:32:50 +08:00

124 lines
7.2 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.
# 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` 的动作权限点是这样生成的:
```sql
select distinct b_module_id from dbo.wf_binding where b_canuse = 1
```
**`wf_binding` 为空时,动作权限点会生成 0 条。** 三个缓解手段,按需选用:
1. 先跑 mock(第 8 步,它含一条 binding)再跑第 6 步;或先在应用里保存一条流程绑定;
2. 应用侧本身会自愈——`WorkflowConfigService.saveBinding` 每次保存绑定都会调用
`ensureActionPowers(moduleId)`,按 `action.{模块}.{动作}` 幂等补点;
3. 该脚本可重复执行,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`),不再使用前端常量菜单。因此**新增页面必须两步都做**:
1. 在前端加一条静态路由(`web/src/router/index.ts`,数据库存不了 Vue 组件);
2. 在 `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 转换。