Files
workspace/code/fms/新数据库结构.md
T
2026-07-23 17:33:18 +08:00

326 lines
16 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.
# FMS 新数据库结构
## 设计原则
- `b_module` 是核心元数据对象,统一表示菜单目录、页面和数据模块。
- 字段来源于数据模块配置的查询视图。系统不创建业务字段,只同步视图字段,并维护其展示、编辑、查询和权限配置。
- 页面和业务逻辑不完全元数据化。海运等复杂业务页面由 Vue 页面显式组合多个数据模块,元数据只提供 Table、Form 和 Query 配置。
- 字段基础定义、列表、编辑、查询四个职责分离;一个字段可以只参与其中任一场景。
- 编辑规则与列表布局解耦:`b_module_field_edit` 是通用编辑配置,FmsForm 和 FmsTable 可按自身规则消费;`b_module_field_list` 只描述列表展示,不保存编辑状态。
- 模块权限控制访问,操作权限控制按钮动作;操作权限必须依赖模块访问权限。
- 表名和字段名沿用旧系统的 `b_` 风格。全部 `b_id` 使用 `bigint` 雪花 ID,返回前端时序列化为字符串。
- 布尔字段统一使用 `int`,`1` 表示是、`0` 表示否;`b_xh` 数值越小越靠前。
- 当前按机构使用独立数据库,表中不保存机构编号。表名、视图名和字段名必须由后端白名单校验,不能直接拼接 SQL。
## 整体关系
```text
b_module
|-- parent_id --> b_module
|-- 1:N --------> b_module_field
|-- 1:N --------> b_module_field_group -- parent_id --> b_module_field_group
|-- 1:N --------> b_module_power ---- 1:N ----> b_user_power
`-- 1:N --------> b_user_module
b_module_field
|-- 0:N --------> b_module_field_list -- group_id --> b_module_field_group
|-- 0:1 --------> b_module_field_edit -- group_id --> b_module_field_group
`-- 0:1 --------> b_module_field_query
b_module / b_module_field / b_module_field_list / b_module_field_group / b_module_power
`-- b_i18n --> b_i18n.b_key
```
## 模块
### `dbo.b_module`
统一保存目录、页面和数据模块。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 不可变雪花 ID 主键 |
| `b_code` | `varchar(50)` | 可修改的唯一模块编码,例如 `m_sea`、`d_container` |
| `b_parent_id` | `bigint` | 上级模块 ID;根节点为空 |
| `b_name` | `nvarchar(100)` | 默认中文名称 |
| `b_i18n` | `varchar(150)` | 多语言键 |
| `b_module_type` | `varchar(20)` | `directory`、`page` 或 `data` |
| `b_route` | `varchar(200)` | 页面路由,例如 `/sea/list` |
| `b_viewtable` | `varchar(128)` | 查询来源表或视图;数据模块字段从此处同步 |
| `b_savetable` | `varchar(128)` | 保存目标表 |
| `b_keyfield` | `varchar(50)` | 主键字段,例如 `b_id` |
| `b_orderfield` | `varchar(500)` | 默认排序,例如 `b_xh ASC, b_id DESC` |
| `b_canmenu` | `int` | 是否显示在菜单,默认 `0` |
| `b_canuse` | `int` | 是否启用,默认 `1` |
| `b_xh` | `int` | 同级显示顺序,默认 `0` |
约束:
- `b_parent_id` 外键引用 `b_module.b_id`;保存服务校验父节点不形成循环。
- `b_code` 唯一,格式为 `^[a-z][a-z0-9_]{1,49}$`;`b_route` 非空时唯一。
- `directory` 不能配置 `b_route`、`b_viewtable` 或 `b_savetable`。
- `page` 必须配置 `b_route`;其业务数据由页面组合的数据模块提供。
- `data` 不能显示菜单且不能配置 `b_route`;必须配置 `b_viewtable`,保存场景再按需配置 `b_savetable` 与 `b_keyfield`。
- `b_canmenu`、`b_canuse` 只能为 `0` 或 `1`。建议建立 `(b_parent_id, b_xh, b_id)` 索引。
## 字段来源与同步
### `dbo.b_module_field`
保存字段的基础定义。字段来自数据模块的 `b_viewtable`,并以 `(b_module_id, b_field)` 作为稳定标识;列表、编辑和查询场景属性均由独立配置表维护。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_module_id` | `bigint` | 所属数据模块 ID |
| `b_field` | `varchar(50)` | 视图字段名 |
| `b_name` | `nvarchar(100)` | 默认字段名称,由管理员维护 |
| `b_i18n` | `varchar(150)` | 多语言键 |
| `b_type` | `varchar(30)` | 字段控件类型:`input`、`textarea`、`number`、`money`、`date`、`datetime`、`switch` 或 `select` |
| `b_default_value` | `nvarchar(500)` | 新增记录时的默认值 |
| `b_options` | `nvarchar(max)` | 类型专属 JSON 配置,例如选择器来源、日期格式或金额精度 |
| `b_canuse` | `int` | 是否启用 |
约束:
- `b_module_id` 外键引用 `b_module.b_id`,`(b_module_id, b_field)` 唯一。
- `b_canuse` 只能为 `0` 或 `1`;`b_options` 非空时通过 `ISJSON` 校验。建议建立 `(b_module_id, b_canuse, b_id)` 索引。
- 字段没有 list、edit 或 query 配置记录时,不参与对应场景。
- `b_type` 是展示和编辑的唯一类型来源:Table 按它渲染默认显示器,Form 或可编辑 Table 按它选择控件。
- `select` 是否允许自由输入、选项来源、值字段和显示字段均由 `b_options` 控制。
### 视图同步规则
字段同步服务仅面向 `b_module_type = 'data'` 且配置了 `b_viewtable` 的模块执行:
1. 后端校验视图名并读取列名、SQL 类型和可空性等结构信息。
2. 按列名查找同模块的 `b_module_field`;新列创建字段基础记录。
3. 新字段按 SQL 类型初始化 `b_type`,例如字符串映射为 `input`、长文本映射为 `textarea`、数值映射为 `number`、日期映射为 `date` 或 `datetime`、位值映射为 `switch`。已有字段不覆盖管理员维护的 `b_type` 与 `b_options`;`select`、`money` 等业务类型由管理员按语义调整。
4. 本次视图中不存在的已有字段保留其记录和全部场景配置,但将 `b_canuse` 置为 `0`。
5. 不覆盖人工维护的 `b_name`、`b_i18n`、`b_default_value` 与 `b_options`,不物理删除字段或场景配置。
## 列表配置
### `dbo.b_module_field_list`
控制列表字段列。多级表头由 `b_module_field_group` 的 `list` 分组树表达;本表不保存编辑状态。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_module_id` | `bigint` | 所属模块 ID |
| `b_field_id` | `bigint` | 关联 `b_module_field.b_id` |
| `b_group_id` | `bigint` | 所属分组 ID;为空时为顶层列 |
| `b_title` | `nvarchar(100)` | 字段标题覆盖值;为空时使用默认字段名称 |
| `b_i18n` | `varchar(150)` | 字段标题多语言键覆盖值 |
| `b_visible` | `int` | 是否显示,默认 `1` |
| `b_xh` | `int` | 同一分组内的显示顺序,默认 `0` |
| `b_width` | `int` | 字段列宽 |
| `b_sortable` | `int` | 是否允许排序,默认 `0` |
约束:
- `b_module_id` 外键引用 `b_module.b_id`,`b_field_id` 外键引用 `b_module_field.b_id`,`b_group_id` 引用同模块的 `b_module_field_group`。
- `b_field_id` 必填;同一字段在同一模块的列表中最多出现一次,使用 `(b_module_id, b_field_id)` 唯一约束。
- `b_visible`、`b_sortable` 只能为 `0` 或 `1`。
- 字段列的显示器由关联字段的 `b_type` 与 `b_options` 决定,例如 `money`、`date`、`datetime` 均由前端按统一规则渲染。建议建立 `(b_module_id, b_group_id, b_xh, b_id)` 索引。
- 不保存 `level`、`colspan`、`rowspan`;前端加载 Table 分组树和字段列后,按分组的 `b_parent_id`、`b_xh` 组装嵌套表头。隐藏分组的后代不显示;没有可见字段后代的分组不渲染。
示例:
```text
费用(`b_module_field_group`)
|-- 人工费(`b_module_field_list.b_group_id` 指向费用)
`-- 海运费(`b_module_field_list.b_group_id` 指向费用)
```
## 编辑配置
### `dbo.b_module_field_edit`
控制字段的通用编辑属性与编辑分组。控件类型、显示规则和类型专属参数统一由 `b_module_field.b_type`、`b_options` 决定;FmsForm 与 FmsTable 自行决定何时使用本配置。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_module_id` | `bigint` | 所属模块 ID |
| `b_field_id` | `bigint` | 关联 `b_module_field.b_id` |
| `b_required` | `int` | 是否必填,默认 `0` |
| `b_readonly` | `int` | 是否只读,默认 `0` |
| `b_disabled` | `int` | 是否禁用,默认 `0` |
| `b_group_id` | `bigint` | 所属编辑分组 ID;不分组时为空 |
| `b_xh` | `int` | 编辑场景中的显示顺序,默认 `0` |
约束:
- `b_module_id` 外键引用 `b_module.b_id`,`b_field_id` 外键引用 `b_module_field.b_id`;`(b_module_id, b_field_id)` 唯一,保存服务校验字段属于同一模块。
- `b_required`、`b_readonly`、`b_disabled` 只能为 `0` 或 `1`。
- `b_group_id` 必须关联同模块的 `b_module_field_group`;分组为空时字段进入默认编辑区域。
- 已分组字段按分组的 `b_xh` 排列,组内按 `b_xh` 排列;默认区域字段按 `b_xh` 排列。
## 布局分组
### `dbo.b_module_field_group`
统一保存列表多级表头和编辑分组。分组只负责布局,不定义编辑能力;列表或编辑用途由引用它的配置表决定。
被 `b_module_field_list` 引用时,分组组成同一份 FmsTable 的多级表头;被 `b_module_field_edit` 引用时,分组组成同一份编辑界面中的业务区块,例如提单、订舱、报关、备注,不代表拆分为多个 Form。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_module_id` | `bigint` | 所属模块 ID |
| `b_parent_id` | `bigint` | 上级分组 ID;顶层为空 |
| `b_title` | `nvarchar(100)` | 默认分组标题 |
| `b_i18n` | `varchar(150)` | 分组标题多语言键 |
| `b_xh` | `int` | 分组显示顺序,默认 `0` |
| `b_canuse` | `int` | 是否启用,默认 `1` |
约束:
- `b_module_id` 外键引用 `b_module.b_id`;`b_id` 是分组的稳定关联键。
- `b_parent_id` 必须引用同模块的分组且不能形成循环。
- 多级分组可用于 FmsTable 表头;FmsForm 与 FmsTable 如何消费编辑分组由各自实现决定。
- `b_canuse` 只能为 `0` 或 `1`。建议建立 `(b_module_id, b_canuse, b_xh, b_id)` 索引。
- 无字段引用的分组不渲染;分组停用时,其关联字段或列不显示。
视图型选择器的 `b_options` 示例:
```json
{
"source": "view",
"view": "v_partner",
"valueField": "b_id",
"labelField": "b_name",
"allowInput": false
}
```
`select` 使用 `allowInput: false` 时保存 `valueField` 的值;设为 `true` 时可保存选择值或用户输入文本。视图名、值字段和标签字段均须由后端校验。
## 查询配置
### `dbo.b_module_field_query`
独立控制主列表查询条件,不依赖字段是否配置为可见列表列。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_module_id` | `bigint` | 所属模块 ID |
| `b_field_id` | `bigint` | 关联 `b_module_field.b_id` |
| `b_component` | `varchar(30)` | 查询组件 |
| `b_operator` | `varchar(20)` | `=`、`like`、`between` 或 `in` |
| `b_default_value` | `nvarchar(500)` | 默认查询值 |
| `b_xh` | `int` | 查询条件显示顺序,默认 `0` |
| `b_canuse` | `int` | 是否启用,默认 `1` |
约束:
- `b_module_id` 外键引用 `b_module.b_id`,`b_field_id` 外键引用 `b_module_field.b_id`;`(b_module_id, b_field_id)` 唯一,保存服务校验模块一致性。
- `b_canuse` 只能为 `0` 或 `1`;`b_operator` 必须属于定义的操作符集合。
- 查询组件与操作符由后端白名单校验;查询值必须参数化,不能由配置直接拼接 SQL。
- 建议建立 `(b_module_id, b_canuse, b_xh, b_id)` 索引。
## 权限与多语言
### `dbo.b_module_power`
定义模块内可授权的按钮操作。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_module_id` | `bigint` | 所属模块 ID |
| `b_code` | `varchar(50)` | 操作编码,例如 `create`、`update`、`delete`、`audit`、`export` |
| `b_name` | `nvarchar(100)` | 操作名称 |
| `b_i18n` | `varchar(150)` | 多语言键 |
| `b_xh` | `int` | 显示顺序 |
| `b_canuse` | `int` | 是否启用,默认 `1` |
约束:`b_module_id` 外键引用 `b_module.b_id`,`(b_module_id, b_code)` 唯一,`b_canuse` 只能为 `0` 或 `1`。
### `dbo.b_user_module`
控制用户能否查看、进入和调用模块。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_user_id` | `bigint` | 用户雪花 ID |
| `b_module_id` | `bigint` | 模块 ID |
| `b_inputuser_id` | `bigint` | 授权人雪花 ID |
| `b_inputdatetime` | `datetime` | 授权时间 |
约束:`b_module_id` 外键引用 `b_module.b_id`,`(b_user_id, b_module_id)` 唯一。目录不单独授权;用户拥有下级模块时自动显示上级目录。
### `dbo.b_user_power`
控制用户可执行的按钮操作。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_user_id` | `bigint` | 用户雪花 ID |
| `b_power_id` | `bigint` | `b_module_power.b_id` |
| `b_inputuser_id` | `bigint` | 授权人雪花 ID |
| `b_inputdatetime` | `datetime` | 授权时间 |
约束:`b_power_id` 外键引用 `b_module_power.b_id`,`(b_user_id, b_power_id)` 唯一。
权限规则:
1. 用户必须拥有 `b_user_module` 记录,才能进入或调用该模块。
2. 用户必须同时拥有模块权限和对应 `b_user_power` 记录,才能执行按钮动作。
3. 前端据此控制路由进入和按钮可用性;后端接口后续实施同等权限校验。
### `dbo.b_i18n`
统一保存菜单、模块、字段、权限、按钮、提示和校验信息等界面文案。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `b_id` | `bigint` | 雪花 ID 主键 |
| `b_key` | `varchar(150)` | 多语言键 |
| `b_locale` | `varchar(20)` | 语言编码,例如 `zh-CN` |
| `b_value` | `nvarchar(500)` | 翻译文本 |
约束:`(b_key, b_locale)` 唯一。
## 页面组合示例
海运业务页面由 Vue 显式组合数据模块,不通过字段配置创建动态页面区域:
```text
海运页面 m_sea(page:路由、菜单、权限、页面编排)
|-- 海运主单 d_sea(data)
|-- 费用 d_charge(data)
|-- 订舱 d_booking(data,独立表和主键时)
`-- 箱明细 d_container(data)
```
若订舱字段实际保存于海运主单表,不创建 `d_booking`,而在 `d_sea` 的编辑配置中用 `b_group_id` 和 `b_xh` 定义编辑分组与顺序,分组标题来自 `b_module_field_group`。主子表关联、加载时机、保存顺序和页面布局均由业务 Vue 页面明确实现。
## 现有字段迁移
当前 `b_module_field` 混合保存基础、列表、编辑和查询属性。迁移应分阶段实施:
| 当前字段 | 目标位置 |
| --- | --- |
| `b_type` | `b_module_field.b_type` |
| `b_canlist` | `b_module_field_list.b_visible` |
| `b_width` | `b_module_field_list.b_width` |
| `b_xh` | 初始化 `b_module_field_list.b_xh`、`b_module_field_edit.b_xh` 与 `b_module_field_query.b_xh` |
| `b_canform` | 为原 Form 字段创建 `b_module_field_edit` 记录 |
| `b_must` | `b_module_field_edit.b_required` |
| `b_readonly` | `b_module_field_edit.b_readonly` |
| `b_canquery` | 创建 `b_module_field_query` 记录 |
| `b_value` | 迁移为 `b_module_field.b_default_value` |
迁移步骤:
1. 新建 list、edit、group、query 表和必要索引,新增 `b_module.b_module_type` 与 `b_module_field.b_type` 的兼容列。
2. 为原有字段创建列表配置;根据原 `b_canform`、`b_canquery` 初始化编辑和查询配置。
3. 前端和后端改为读取新场景表,查询不再读取 list 配置;模块类型切换为读取 `b_module_type`。
4. 完成视图同步服务并验证新结构的读写稳定后,删除旧混合列和兼容字段。