20260823210241

This commit is contained in:
oneao committed 2026-08-23 21:02:41 +08:00
1 parent 5ff4583aeb
commit f4c7413dc6
2766 files changed
+1836409 -94689

No files matched your search

@@ -0,0 +1,333 @@
# 关系映射表
<cite>
**本文引用的文件**
- [100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql)
- [restore_fks.sql](file://.tmp-fkcheck/restore_fks.sql)
- [018_create_business_tables.sql](file://fms-api/config/migrations/018_create_business_tables.sql)
- [019_create_finance_tables.sql](file://fms-api/config/migrations/019_create_finance_tables.sql)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件聚焦 FMS 系统中的实体关系映射能力,围绕 s_relation(关系定义表)的设计与使用进行系统化说明。内容涵盖:
- 支持的关系类型:一对一、一对多、多对一、多对多
- 拥有者模式、外键侧配置与级联删除策略
- 多对多连接表的模块与字段映射方式
- 关系排序、数据验证与业务规则的集成点
- 典型复杂业务场景的建模示例(如订单与订单项、产品与分类等)
- 关系查询优化与性能调优建议
## 项目结构
FMS 通过元数据驱动的方式管理模块、字段与关系:
- s_module:模块定义(视图表、保存表、主键、排序、删除策略等)
- s_field:字段定义(类型、可空、默认值、写入模式等)
- s_relation:关系定义(关系类型、外键侧、拥有者、连接表、排序、删除策略等)
- 其他元数据表:s_field_view、s_field_edit、s_field_query 等用于界面与查询配置
```mermaid
graph TB
A["s_module<br/>模块定义"] --> B["s_field<br/>字段定义"]
A --> C["s_relation<br/>关系定义"]
B --> C
C --> D["业务表<br/>如 bs_business, cw_bill 等"]
C --> E["连接表<br/>如 cw_bill_business"]
```
图表来源
- [100_initialize_fms_new.sql:56-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L243)
- [019_create_finance_tables.sql:277-359](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L359)
章节来源
- [100_initialize_fms_new.sql:56-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L243)
## 核心组件
- s_relation(关系定义表)
- 关键字段与作用
- b_code:关系代码(唯一标识)
- b_module_id / b_target_module_id:源模块与目标模块
- b_relation_type:关系类型(one-to-one、one-to-many、many-to-one、many-to-many)
- b_module_field_id / b_target_field_id:源字段与目标字段
- b_foreign_side:外键侧(module 或 target),非多对多时必须指定
- b_junction_*:多对多时的连接表与字段映射
- b_ownership / b_owner_side:拥有者模式(reference 或 owned)及拥有方侧
- b_delete_policy:删除策略(restrict、set-null、cascade、archive)
- b_order_*:排序模块与排序字段
- b_canuse / b_xh:启用状态与顺序
- 约束校验要点
- 关系形状约束:多对多必须提供连接表与字段;非多对多必须指定外键侧且无连接表
- 拥有者约束:owned 时必须指定 owner_side,且不能是多对多
- 删除策略约束:仅允许枚举值
- 自引用限制:同一模块内不允许相同字段自关联
- 排序字段成对出现
章节来源
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
## 架构总览
s_relation 作为“关系元数据”的核心,驱动上层服务在运行时解析并生成 SQL、构建对象图、执行级联操作与排序。其关键交互如下:
```mermaid
sequenceDiagram
participant UI as "前端/表单"
participant API as "API 层"
participant RM as "关系解析器"
participant DB as "数据库"
participant MD as "元数据表(s_module/s_field/s_relation)"
UI->>API : 提交单据/列表请求
API->>MD : 读取模块/字段/关系定义
MD-->>API : 返回元数据
API->>RM : 根据 s_relation 解析关系
RM->>DB : 生成并执行查询/更新含连接表/外键/排序
DB-->>RM : 返回结果
RM-->>API : 组装对象图/分页/排序
API-->>UI : 返回数据
```
图表来源
- [100_initialize_fms_new.sql:56-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L243)
- [restore_fks.sql:65-90](file://.tmp-fkcheck/restore_fks.sql#L65-L90)
## 详细组件分析
### s_relation 设计详解
- 关系类型与外键侧
- one-to-one / one-to-many / many-to-one:b_foreign_side 必须为 module 或 target,表示外键落在哪一侧
- many-to-many:b_foreign_side 为空,必须提供 b_junction_module_id 以及对应的模块字段与目标字段映射
- 拥有者模式
- reference:弱引用,不控制生命周期
- owned:强拥有,需指定 b_owner_side,并在删除时按策略处理子记录
- 删除策略
- restrict:禁止删除(有依赖则拒绝)
- set-null:将外键置空
- cascade:级联删除
- archive:归档(逻辑删除)
- 排序
- 通过 b_order_module_id 与 b_order_field_id 指定排序维度,便于列表展示与导出
```mermaid
flowchart TD
Start(["开始"]) --> Type{"关系类型?"}
Type --> |多对多| JM["设置连接表与字段映射"]
Type --> |非多对多| FK["设置外键侧 foreign_side"]
JM --> Own{"是否拥有者?"}
FK --> Own
Own --> |是| OS["指定 owner_side"]
Own --> |否| Pol{"删除策略"}
OS --> Pol
Pol --> Sort{"是否需要排序?"}
Sort --> |是| OF["配置 order_module/order_field"]
Sort --> |否| End(["结束"])
OF --> End
```
图表来源
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
章节来源
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
### 多对多关系与连接表
- 连接表要求
- 必须提供 b_junction_module_id(连接表所属模块)
- 必须提供 b_junction_module_field_id(连接表中指向源模块的字段)
- 必须提供 b_junction_target_field_id(连接表中指向目标模块的字段)
- 物理外键
- 通过 restore_fks.sql 恢复 s_relation 与 s_module/s_field 之间的外键约束,确保连接表字段的有效性
```mermaid
classDiagram
class S_Module {
+bigint b_id
+varchar b_code
}
class S_Field {
+bigint b_id
+bigint b_module_id
+varchar b_field
}
class S_Relation {
+bigint b_id
+varchar b_code
+bigint b_module_id
+bigint b_target_module_id
+varchar b_relation_type
+bigint b_module_field_id
+bigint b_target_field_id
+varchar b_foreign_side
+bigint b_junction_module_id
+bigint b_junction_module_field_id
+bigint b_junction_target_field_id
+varchar b_ownership
+varchar b_owner_side
+varchar b_delete_policy
+bigint b_order_module_id
+bigint b_order_field_id
}
S_Relation --> S_Module : "source/target/junction"
S_Relation --> S_Field : "module/target/junction fields"
```
图表来源
- [100_initialize_fms_new.sql:56-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L243)
- [restore_fks.sql:65-90](file://.tmp-fkcheck/restore_fks.sql#L65-L90)
章节来源
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
- [restore_fks.sql:65-90](file://.tmp-fkcheck/restore_fks.sql#L65-L90)
### 关系排序与查询
- 排序字段由 b_order_module_id 与 b_order_field_id 共同决定
- 查询时可结合 s_field_query 的配置(条件、操作符、默认值)与 s_relation 的排序字段,实现高效过滤与排序
```mermaid
sequenceDiagram
participant Q as "查询入口"
participant M as "元数据加载"
participant R as "关系解析"
participant D as "数据库"
Q->>M : 获取模块/字段/关系
M-->>Q : 返回元数据
Q->>R : 传入查询条件与排序需求
R->>D : 生成带 JOIN/ORDER BY 的 SQL
D-->>R : 返回结果集
R-->>Q : 返回分页/排序后的数据
```
图表来源
- [100_initialize_fms_new.sql:184-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L184-L203)
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
章节来源
- [100_initialize_fms_new.sql:184-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L184-L203)
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
### 数据验证与业务规则集成
- 元数据约束
- s_relation 的形状约束确保多对多与非多对多的字段配置一致性
- 拥有者与删除策略的约束保证数据一致性与安全
- 业务表中的外键与索引
- 业务表(如 bs_business、cw_bill 及其子表)通过物理外键与索引保障数据完整性与查询性能
- 连接表(如 cw_bill_business)通过唯一约束避免重复关联
```mermaid
flowchart TD
V["输入数据"] --> Check{"校验 s_relation 约束"}
Check --> |通过| Apply["应用删除策略/排序/连接表映射"]
Check --> |失败| Error["返回错误信息"]
Apply --> Persist["持久化到业务表/连接表"]
Persist --> Done(["完成"])
Error --> Done
```
图表来源
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
- [019_create_finance_tables.sql:277-359](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L359)
章节来源
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
- [019_create_finance_tables.sql:277-359](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L359)
### 典型业务场景建模示例
- 订单与订单项(一对多)
- 父表:bs_business(订单头)
- 子表:bs_business_container / bs_business_cw / bs_business_hdbl / bs_business_transport(订单项)
- 关系:通过 father 字段建立父子关系;可在 s_relation 中配置为一对多,并设置删除策略(如 restrict/cascade/archive)
- 参考:[018_create_business_tables.sql:123-393](file://fms-api/config/migrations/018_create_business_tables.sql#L123-L393)
- 发票与账单(多对多)
- 连接表:cw_invoice_bill
- 关系:通过 cw_invoice_bill 关联 cw_invoice 与 cw_bill;在 s_relation 中配置为多对多,并映射连接表字段
- 参考:[019_create_finance_tables.sql:291-303](file://fms-api/config/migrations/019_create_finance_tables.sql#L291-L303)
- 账单与业务单(多对多)
- 连接表:cw_bill_business
- 关系:通过 cw_bill_business 关联 cw_bill 与 bs_business;在 s_relation 中配置为多对多
- 参考:[019_create_finance_tables.sql:277-289](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L289)
章节来源
- [018_create_business_tables.sql:123-393](file://fms-api/config/migrations/018_create_business_tables.sql#L123-L393)
- [019_create_finance_tables.sql:277-359](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L359)
## 依赖分析
- s_relation 对外键与模块/字段的依赖
- 通过 restore_fks.sql 恢复 s_relation 与 s_module/s_field 的外键约束,确保连接表与字段映射的正确性
- 业务表与连接表的外键
- 业务子表通过 father 字段与父表建立关系
- 连接表通过左右两侧的主键建立多对多关系
```mermaid
graph LR
SR["s_relation"] --> SM["s_module"]
SR --> SF["s_field"]
BB["bs_business"] --> BC["bs_business_container"]
BB --> BW["bs_business_cw"]
BB --> BH["bs_business_hdbl"]
BB --> BT["bs_business_transport"]
CB["cw_bill"] --> CBB["cw_bill_business"]
BI["cw_invoice"] --> CIB["cw_invoice_bill"]
SB["cw_sfd"] --> SBB["cw_sfd_business"]
```
图表来源
- [restore_fks.sql:65-90](file://.tmp-fkcheck/restore_fks.sql#L65-L90)
- [018_create_business_tables.sql:123-393](file://fms-api/config/migrations/018_create_business_tables.sql#L123-L393)
- [019_create_finance_tables.sql:277-359](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L359)
章节来源
- [restore_fks.sql:65-90](file://.tmp-fkcheck/restore_fks.sql#L65-L90)
- [018_create_business_tables.sql:123-393](file://fms-api/config/migrations/018_create_business_tables.sql#L123-L393)
- [019_create_finance_tables.sql:277-359](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L359)
## 性能考虑
- 索引与外键
- 业务子表普遍建立以 father 为主的前缀索引,提升父子查询效率
- 连接表建立联合唯一约束与常用查询列的索引,避免重复关联并加速关联查询
- 查询优化
- 利用 s_relation 的排序字段减少后端排序开销
- 合理选择 join 路径,优先使用已有索引的列
- 删除策略
- 谨慎使用 cascade,避免大规模级联删除带来的锁竞争与性能抖动
- 对于大表归档,建议使用 archive 策略配合异步任务
章节来源
- [018_create_business_tables.sql:123-393](file://fms-api/config/migrations/018_create_business_tables.sql#L123-L393)
- [019_create_finance_tables.sql:277-359](file://fms-api/config/migrations/019_create_finance_tables.sql#L277-L359)
## 故障排查指南
- 常见错误定位
- 外键约束冲突:检查 s_relation 的 foreign_side 与连接表字段映射是否正确
- 删除失败:确认 delete_policy 是否为 restrict,是否存在未解除的依赖
- 多对多配置错误:确认 junction_module_id 与对应字段是否齐全
- 排查步骤
- 核对 s_relation 的约束与业务表外键
- 查看连接表的唯一约束是否被违反
- 检查排序字段是否成对配置
章节来源
- [100_initialize_fms_new.sql:205-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L205-L243)
- [restore_fks.sql:65-90](file://.tmp-fkcheck/restore_fks.sql#L65-L90)
## 结论
s_relation 作为 FMS 的关系元数据中心,通过严格的约束与灵活的配置,支撑了一对一、一对多、多对一与多对多等多种关系建模。结合 s_module 与 s_field,系统实现了从元数据到 SQL 的自动化转换,并提供了排序、删除策略与连接表映射等高级能力。在生产环境中,应重点关注索引设计与删除策略的选择,以确保数据一致性与查询性能。
## 附录
- 关系类型速查
- one-to-one:双方各一条记录,通常通过外键+唯一约束实现
- one-to-many:一方多条记录,外键在多的一侧
- many-to-one:反向的一对多
- many-to-many:通过连接表实现,需配置连接模块与字段映射
- 删除策略速查
- restrict:有依赖则拒绝删除
- set-null:将外键置空
- cascade:级联删除
- archive:逻辑归档
@@ -0,0 +1,295 @@
# 核心表结构
<cite>
**本文引用的文件**
- [100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql)
- [035_restore_simple_module_tree.sql](file://fms-api/config/migrations/035_restore_simple_module_tree.sql)
- [restore_fks.sql](file://.tmp-fkcheck/restore_fks.sql)
- [backup_b_user.sql](file://.tmp-fkcheck/backup_b_user.sql)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构与数据来源](#项目结构与数据来源)
3. [核心组件总览](#核心组件总览)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系与索引设计](#依赖关系与索引设计)
7. [性能与查询优化建议](#性能与查询优化建议)
8. [典型业务场景数据操作示例](#典型业务场景数据操作示例)
9. [故障排查指南](#故障排查指南)
10. [结论](#结论)
## 简介
本文件面向FMS系统的核心元数据与权限体系,聚焦以下目标:
- 用户权限相关表(b_user、s_role、s_power、s_user_role、s_role_power)的设计理念与字段含义
- 业务模块配置表(s_module、s_field、s_field_group、s_field_view、s_field_edit、s_field_query)的元数据驱动设计,以及如何通过配置动态定义界面与表单
- 菜单系统表(s_menu)的结构设计与层级关系
- 表间关系图、索引设计原理与查询优化建议
- 典型业务场景下的数据操作示例
## 项目结构与数据来源
- 数据库迁移脚本位于 fms-api/config/migrations,其中 100_initialize_fms_new.sql 定义了当前新库的核心基础表;035_restore_simple_module_tree.sql 展示了旧版“简单模块树”模型及迁移逻辑,有助于理解 s_module 的演进。
- 外键约束参考 .tmp-fkcheck/restore_fks.sql,用于恢复或校验外键关系。
- b_user 初始数据备份样例见 .tmp-fkcheck/backup_b_user.sql,可用于理解字段取值与业务含义。
**章节来源**
- [100_initialize_fms_new.sql:9-514](file://fms-api/config/migrations/100_initialize_fms_new.sql#L9-L514)
- [035_restore_simple_module_tree.sql:357-380](file://fms-api/config/migrations/035_restore_simple_module_tree.sql#L357-L380)
- [restore_fks.sql:39-95](file://.tmp-fkcheck/restore_fks.sql#L39-L95)
- [backup_b_user.sql:1-11](file://.tmp-fkcheck/backup_b_user.sql#L1-L11)
## 核心组件总览
- 用户与角色权限
- b_user:用户主实体
- s_role:角色定义
- s_power:权限项(菜单/模块/动作/字段)
- s_user_role:用户-角色多对多
- s_role_power:角色-权限多对多
- 模块与字段元数据(元数据驱动)
- s_module:模块(目录/页面/数据分类/数据)
- s_field:字段元数据(类型、长度、可空、默认值、写入模式等)
- s_field_group:分组(支持水平/垂直布局)
- s_field_view:列表视图配置(可见性、排序、宽度)
- s_field_edit:编辑表单配置(必填、只读、禁用、跨度、高度、占位符)
- s_field_query:查询条件配置(组件、操作符、默认值、排序)
- 菜单系统
- s_menu:菜单树(目录/页面/数据/外链),支持图标、路由、关联模块与权限码
**章节来源**
- [100_initialize_fms_new.sql:56-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L394)
## 架构总览
下图展示核心表之间的主要关系:用户、角色、权限、模块、字段、视图、编辑、查询、菜单等。
```mermaid
erDiagram
b_user ||--o{ s_user_role : "拥有"
s_role ||--o{ s_user_role : "被分配"
s_role ||--o{ s_role_power : "包含"
s_power ||--o{ s_role_power : "被授权"
s_module ||--o{ s_field : "包含"
s_module ||--o{ s_field_group : "包含"
s_field_group ||--o{ s_field_view : "分组显示"
s_field_group ||--o{ s_field_edit : "分组编辑"
s_field ||--o{ s_field_view : "视图配置"
s_field ||--o{ s_field_edit : "编辑配置"
s_field ||--o{ s_field_query : "查询配置"
s_module ||--o{ s_menu : "菜单关联"
s_menu ||--|| s_menu : "父子层级"
```
**图表来源**
- [100_initialize_fms_new.sql:56-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L394)
- [restore_fks.sql:39-95](file://.tmp-fkcheck/restore_fks.sql#L39-L95)
## 详细组件分析
### 用户与权限模型(RBAC扩展)
- b_user:用户基本信息与开关标志(如是否启用、是否允许其他机器登录、销售/文档/交易员标识、可见范围等)。账户唯一。
- s_role:角色定义,支持国际化、系统内置标记、是否绕过权限检查、审计字段。
- s_power:统一权限抽象,区分四类:
- menu:菜单访问
- module:模块级读写/创建/更新/删除/导出
- action:模块内动作执行
- field:字段级查看/编辑
通过资源、模块、字段、操作组合表达细粒度权限。
- s_user_role:用户与角色的多对多,支持启用状态与时间戳。
- s_role_power:角色与权限的多对多,支持 allow/deny 效果控制。
```mermaid
classDiagram
class BUser {
+bigint b_id
+string b_account
+string b_name
+int b_canuse
+...其他用户标志字段
}
class SRole {
+bigint b_id
+string b_code
+string b_name
+int b_is_system
+int b_bypass_power
+int b_canuse
}
class SPower {
+bigint b_id
+string b_code
+string b_name
+string b_power_type
+string b_resource
+bigint b_module_id
+bigint b_field_id
+string b_operation
+int b_canuse
}
class SUserRole {
+bigint b_id
+bigint b_user_id
+bigint b_role_id
+int b_canuse
}
class SRolePower {
+bigint b_id
+bigint b_role_id
+bigint b_power_id
+string b_effect
+int b_canuse
}
BUser "1" -- "n" SUserRole : "拥有"
SRole "1" -- "n" SUserRole : "被分配"
SRole "1" -- "n" SRolePower : "包含"
SPower "1" -- "n" SRolePower : "被授权"
```
**图表来源**
- [100_initialize_fms_new.sql:9-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L9-L394)
**章节来源**
- [100_initialize_fms_new.sql:9-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L9-L394)
- [backup_b_user.sql:1-11](file://.tmp-fkcheck/backup_b_user.sql#L1-L11)
### 模块与字段元数据(元数据驱动)
- s_module:模块树节点,支持目录、页面、数据分类、数据四种类型;数据类模块绑定视图表、保存表、主键字段、排序字段、删除策略等;支持国际化与启用标记。
- s_field:字段元数据,定义字段名、显示名、国际化、数据类型、长度/精度/小数位、可空、默认值、写入模式(直写/仅创建/只读/计算/系统)、选项等。
- s_field_group:分组容器,支持水平/垂直布局、排序、启用。
- s_field_view:列表视图配置,控制字段在列表中的可见性、顺序、列宽。
- s_field_edit:编辑表单配置,控制必填、只读、禁用、分组、行跨度、高度、占位符等。
- s_field_query:查询条件配置,指定查询组件、操作符、默认值、排序与启用。
```mermaid
flowchart TD
Start(["开始"]) --> LoadModule["加载模块(s_module)"]
LoadModule --> LoadFields["加载字段(s_field)"]
LoadFields --> LoadGroups["加载分组(s_field_group)"]
LoadGroups --> BuildView["构建视图(s_field_view)"]
LoadGroups --> BuildEdit["构建编辑(s_field_edit)"]
LoadFields --> BuildQuery["构建查询(s_field_query)"]
BuildView --> RenderUI["渲染界面"]
BuildEdit --> RenderUI
BuildQuery --> RenderUI
RenderUI --> End(["结束"])
```
**图表来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
**章节来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
### 菜单系统(s_menu)
- s_menu:菜单树节点,支持目录、页面、数据、外链四种类型;可关联模块、设置路由、图标、权限码;支持父子层级与排序。
- 通过 b_parent_id 自引用实现层级;通过 b_module_id 与模块关联;通过 b_power_code 与权限项关联,实现菜单可见性与访问控制。
```mermaid
graph TB
A["s_menu(根)"] --> B["子目录"]
B --> C["页面"]
B --> D["数据"]
C --> E["外链"]
A -.->|"b_parent_id"| A
C -.->|"b_module_id"| M["s_module"]
C -.->|"b_power_code"| P["s_power"]
```
**图表来源**
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
**章节来源**
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
## 依赖关系与索引设计
- 外键关系
- s_field_view、s_field_edit、s_field_query 均通过 (b_module_id, b_field_id) 关联到 s_field
- s_field_view、s_field_edit 通过 (b_module_id, b_group_id) 关联到 s_field_group
- s_menu.b_module_id -> s_module
- s_menu.b_parent_id -> s_menu
- s_module.b_parent_id -> s_module
- s_role_power.b_role_id -> s_role,b_power_id -> s_power
- s_user_role.b_user_id -> b_user,b_role_id -> s_role
- 索引设计要点
- s_module:按父节点+排序+启用快速检索;按保存表加速反向查找
- s_field:按模块+启用+ID 快速拉取字段清单
- s_field_group:按模块+排序+启用快速分组
- s_field_view/edit/query:按排序+ID 保证界面渲染顺序
- s_power:按类型+资源+启用加速权限判定
- s_menu:按父节点+排序+启用快速构建树;按模块加速菜单-模块映射
- s_user_role/s_role_power:按角色/权限+启用加速权限聚合
**章节来源**
- [100_initialize_fms_new.sql:88-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L88-L203)
- [restore_fks.sql:39-95](file://.tmp-fkcheck/restore_fks.sql#L39-L95)
## 性能与查询优化建议
- 使用覆盖索引
- 常见查询如“获取某模块启用的字段列表”、“按父节点构建树”应优先命中 IX_s_field_module、IX_s_module_parent、IX_s_menu_parent 等复合索引。
- 避免全表扫描
- 权限判定尽量基于 s_power.b_power_type + b_resource + b_canuse 的组合索引进行过滤。
- 分页与排序
- 列表页使用 s_field_view.xh 作为排序依据,结合分页参数减少传输量。
- 缓存策略
- 模块元数据(s_module、s_field、s_field_group、s_field_view/edit/query)变化频率低,可在应用层缓存并按模块维度失效。
- 事务与一致性
- 批量导入模块/字段时,使用事务确保一致性;注意外键约束顺序。
[本节为通用性能建议,不直接分析具体代码]
## 典型业务场景数据操作示例
### 场景一:为用户分配角色并授予菜单访问权限
- 步骤
1) 在 s_user_role 中插入用户与角色的关联记录(b_user_id, b_role_id, b_canuse=1)
2) 在 s_role_power 中为该角色添加菜单权限(b_power_type='menu',b_resource=菜单资源,b_effect='allow')
3) 前端根据 s_menu 与 s_power 生成菜单树,结合用户角色进行可见性控制
- 关键表
- s_user_role、s_role_power、s_power、s_menu
**章节来源**
- [100_initialize_fms_new.sql:291-367](file://fms-api/config/migrations/100_initialize_fms_new.sql#L291-L367)
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
### 场景二:新增一个数据模块并配置表单与查询
- 步骤
1) 在 s_module 中新增数据模块(b_module_type='data',设置 viewtable、savetable、keyfield、delete_policy)
2) 在 s_field 中定义字段元数据(类型、长度、可空、默认值、写入模式)
3) 在 s_field_group 中创建分组(如“基本信息”、“扩展信息”),设置布局方向
4) 在 s_field_view 中配置列表显示(可见性、顺序、宽度)
5) 在 s_field_edit 中配置编辑表单(必填、只读、禁用、跨度、高度、占位符)
6) 在 s_field_query 中配置查询条件(组件、操作符、默认值、排序)
7) 可选:在 s_menu 中添加菜单入口,关联该模块
- 关键表
- s_module、s_field、s_field_group、s_field_view、s_field_edit、s_field_query、s_menu
**章节来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
### 场景三:字段级权限控制(查看/编辑)
- 步骤
1) 在 s_power 中为字段定义权限(b_power_type='field',b_operation='view'/'edit',关联 b_module_id、b_field_id)
2) 在 s_role_power 中将字段权限赋予角色(allow/deny)
3) 前端根据用户角色与 s_power 动态隐藏/禁用字段
- 关键表
- s_power、s_role_power、s_field
**章节来源**
- [100_initialize_fms_new.sql:326-367](file://fms-api/config/migrations/100_initialize_fms_new.sql#L326-L367)
## 故障排查指南
- 外键约束错误
- 若出现外键冲突,检查 restore_fks.sql 中定义的约束是否正确恢复,特别是 s_field_view/edit/query 与 s_field、s_field_group 的关系。
- 模块树循环或非法父节点
- 旧版简单树模型中包含触发器校验父节点类型与循环,升级或回滚时需遵循类型约束。
- 权限未生效
- 确认 s_role_power 的 effect 是否为 allow;确认 s_power 的 power_type、resource、operation 是否与菜单/模块/字段匹配;确认 s_user_role 已正确关联用户与角色。
- 菜单不显示
- 检查 s_menu 的 parent_id 与 route 是否正确;确认 s_menu.b_canuse=1;确认权限码与 s_power 对应。
**章节来源**
- [restore_fks.sql:39-95](file://.tmp-fkcheck/restore_fks.sql#L39-L95)
- [035_restore_simple_module_tree.sql:526-563](file://fms-api/config/migrations/035_restore_simple_module_tree.sql#L526-L563)
## 结论
FMS 的核心表结构以 RBAC 为基础,并通过模块与字段的元数据驱动实现“配置即界面”的能力。通过 s_module、s_field、s_field_group、s_field_view/edit/query 的组合,可以在不修改代码的情况下动态生成列表、表单与查询界面;通过 s_power 与 s_role_power 的灵活授权,可实现从菜单到字段级的细粒度权限控制;s_menu 则提供统一的导航入口并与模块和权限解耦。配合合理的索引设计与缓存策略,可在保证可扩展性的同时获得良好的查询性能。
@@ -0,0 +1,394 @@
# 模块配置表
<cite>
**本文引用的文件**
- [100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql)
- [035_restore_simple_module_tree.sql](file://fms-api/config/migrations/035_restore_simple_module_tree.sql)
- [ModuleEditConfigPanel.vue](file://fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue)
- [ModuleListConfigPanel.vue](file://fms-vue/src/views/system/module-management/components/ModuleListConfigPanel.vue)
- [ModuleQueryConfigPanel.vue](file://fms-vue/src/views/system/module-management/components/ModuleQueryConfigPanel.vue)
- [DbUtils.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/DbUtils.java)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录:典型业务配置示例与最佳实践](#附录典型业务配置示例与最佳实践)
## 简介
本文件面向FMS元数据驱动的模块配置体系,围绕以下目标展开:
- 说明 s_module(模块定义表)的结构设计,包括模块类型(category、data、query)、视图表映射、保存表映射和删除策略配置。
- 解释 s_field(字段定义表)、s_field_group(字段分组表)、s_field_view(视图字段配置表)、s_field_edit(编辑字段配置表)、s_field_query(查询字段配置表)的元数据驱动设计理念。
- 说明如何通过配置表动态生成表单界面、表格列和查询条件。
- 描述字段类型系统、编辑器组件映射和验证规则的配置方式。
- 提供典型业务模块的配置示例与最佳实践。
## 项目结构
本项目采用“后端元数据 + 前端可视化配置”的方式实现模块的动态化:
- 数据库层通过迁移脚本定义元数据表结构,约束了模块、字段、分组及三类视图配置的字段集与取值范围。
- 前端通过“模块管理”面板对 s_field_view、s_field_edit、s_field_query 进行可视化编辑,支持拖拽排序、栅格布局、分组管理等。
- 运行时根据这些元数据动态渲染表单、列表与查询界面,无需硬编码页面。
```mermaid
graph TB
A["数据库迁移脚本<br/>定义元数据表结构"] --> B["后端服务<br/>读取并校验元数据"]
B --> C["前端模块管理面板<br/>可视化编辑配置"]
C --> D["运行时渲染引擎<br/>动态生成表单/列表/查询"]
D --> E["业务数据表/视图<br/>CRUD 操作"]
```
**章节来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
- [ModuleEditConfigPanel.vue:1-120](file://fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue#L1-L120)
- [ModuleListConfigPanel.vue:1-60](file://fms-vue/src/views/system/module-management/components/ModuleListConfigPanel.vue#L1-L60)
- [ModuleQueryConfigPanel.vue:1-60](file://fms-vue/src/views/system/module-management/components/ModuleQueryConfigPanel.vue#L1-L60)
## 核心组件
本节聚焦元数据表与前端配置面板的核心职责与交互。
- s_module:模块定义,决定模块类型、关联的视图表/保存表、主键字段、排序字段、删除策略等。
- s_field:字段定义,声明字段名、显示名、数据类型、可空性、默认值、写入模式、选项等。
- s_field_group:字段分组,用于表单/列表/查询中的分组展示与布局方向控制。
- s_field_view:列表视图配置,控制列宽、是否显示、分组归属、排序号等。
- s_field_edit:编辑表单配置,控制必填、只读、禁用、栅格宽度、占位符、文本域高度等。
- s_field_query:查询条件配置,控制查询组件、操作符、默认值、启用状态、排序号等。
```mermaid
erDiagram
S_MODULE {
bigint b_id PK
varchar b_code
bigint b_parent_id
nvarchar b_name
varchar b_i18n
varchar b_module_type
varchar b_viewtable
varchar b_savetable
varchar b_keyfield
varchar b_orderfield
varchar b_delete_policy
int b_canuse
int b_xh
nvarchar b_bz
bigint b_inputuser_id
datetime2 b_inputdatetime
bigint b_updateuser_id
datetime2 b_updatedatetime
}
S_FIELD {
bigint b_id PK
bigint b_module_id FK
varchar b_field
nvarchar b_name
varchar b_i18n
varchar b_type
varchar b_dbtype
int b_length
int b_precision
int b_scale
int b_nullable
nvarchar b_default_value
nvarchar b_db_default
varchar b_writemode
nvarchar b_options
int b_canuse
bigint b_inputuser_id
datetime2 b_inputdatetime
bigint b_updateuser_id
datetime2 b_updatedatetime
}
S_FIELD_GROUP {
bigint b_id PK
bigint b_module_id FK
bigint b_parent_id
nvarchar b_title
varchar b_i18n
varchar b_layout_direction
int b_xh
int b_canuse
}
S_FIELD_VIEW {
bigint b_id PK
bigint b_module_id FK
bigint b_field_id FK
bigint b_group_id
varchar b_i18n
int b_visible
int b_xh
int b_width
}
S_FIELD_EDIT {
bigint b_id PK
bigint b_module_id FK
bigint b_field_id FK
bigint b_group_id
int b_visible
int b_required
int b_readonly
int b_disabled
int b_colspan
int b_height
nvarchar b_placeholder
int b_xh
}
S_FIELD_QUERY {
bigint b_id PK
bigint b_module_id FK
bigint b_field_module_id FK
bigint b_field_id FK
bigint b_relation_id
varchar b_component
int b_condition_no
varchar b_operator
nvarchar b_default_value
int b_canuse
int b_xh
}
S_MODULE ||--o{ S_FIELD : "包含"
S_MODULE ||--o{ S_FIELD_GROUP : "包含"
S_MODULE ||--o{ S_FIELD_VIEW : "列表视图"
S_MODULE ||--o{ S_FIELD_EDIT : "编辑表单"
S_MODULE ||--o{ S_FIELD_QUERY : "查询条件"
S_FIELD_GROUP ||--o{ S_FIELD_VIEW : "分组"
S_FIELD_GROUP ||--o{ S_FIELD_EDIT : "分组"
S_FIELD_GROUP ||--o{ S_FIELD_QUERY : "分组(可选)"
```
**图示来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
**章节来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
## 架构总览
下图展示了从元数据到运行时界面的完整流程:
```mermaid
sequenceDiagram
participant Admin as "管理员"
participant UI as "前端模块管理面板"
participant API as "后端服务"
participant DB as "数据库"
participant Runtime as "运行时渲染引擎"
Admin->>UI : 打开模块配置
UI->>API : 加载 s_module/s_field/s_field_group
API->>DB : 查询元数据
DB-->>API : 返回元数据
API-->>UI : 返回元数据
UI->>UI : 可视化编辑 s_field_view/s_field_edit/s_field_query
UI->>API : 保存配置变更
API->>DB : 更新配置表
Note over UI,Runtime : 运行时根据元数据动态生成界面
Runtime->>DB : 读取业务数据表/视图
Runtime-->>Admin : 渲染表单/列表/查询界面
```
**图示来源**
- [ModuleEditConfigPanel.vue:1-120](file://fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue#L1-L120)
- [ModuleListConfigPanel.vue:1-60](file://fms-vue/src/views/system/module-management/components/ModuleListConfigPanel.vue#L1-L60)
- [ModuleQueryConfigPanel.vue:1-60](file://fms-vue/src/views/system/module-management/components/ModuleQueryConfigPanel.vue#L1-L60)
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
## 详细组件分析
### s_module(模块定义表)
- 作用:定义一个业务模块及其行为特征。
- 关键字段:
- b_module_type:模块类型,限定为 category、data、query。
- b_viewtable:视图表名,data 类型必须填写;query 类型允许填写;category 类型不允许填写。
- b_savetable:保存表名,仅 data 类型需要填写。
- b_keyfield:主键字段,data 类型必须填写。
- b_orderfield:默认排序字段,data 类型常用。
- b_delete_policy:删除策略,限定 restrict、lifecycle、hard。
- 约束:通过检查约束保证不同模块类型的字段组合合法。
```mermaid
flowchart TD
Start(["新增/编辑模块"]) --> CheckType{"模块类型"}
CheckType --> |category| Cat["视图表/保存表/主键/排序/删除策略为空"]
CheckType --> |data| Data["视图表/保存表/主键/删除策略必填"]
CheckType --> |query| Query["视图表可选; 保存表/主键/删除策略为空"]
Cat --> Save["保存模块"]
Data --> Save
Query --> Save
```
**图示来源**
- [100_initialize_fms_new.sql:56-90](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L90)
**章节来源**
- [100_initialize_fms_new.sql:56-90](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L90)
### s_field(字段定义表)
- 作用:定义模块可用的字段及其基础属性。
- 关键字段:
- b_type:字段类型,限定 input、textarea、number、money、date、datetime、checkbox、select、selectId。
- b_dbtype:数据库类型,限定常见字符串、数值、日期时间、布尔等。
- b_writemode:写入模式,限定 direct、createOnly、readOnly、computed、system。
- b_options:字段选项(如下拉选项),以 JSON 或序列化形式存储。
- b_nullable、b_default_value、b_db_default:可空性与默认值。
- 索引:按模块+启用状态+ID建立索引,提升查询效率。
```mermaid
classDiagram
class Field {
+bigint b_id
+bigint b_module_id
+string b_field
+string b_name
+string b_type
+string b_dbtype
+int b_length
+int b_precision
+int b_scale
+int b_nullable
+string b_default_value
+string b_db_default
+string b_writemode
+string b_options
+int b_canuse
}
```
**图示来源**
- [100_initialize_fms_new.sql:92-123](file://fms-api/config/migrations/100_initialize_fms_new.sql#L92-L123)
**章节来源**
- [100_initialize_fms_new.sql:92-123](file://fms-api/config/migrations/100_initialize_fms_new.sql#L92-L123)
### s_field_group(字段分组表)
- 作用:将字段在表单/列表/查询中按分组组织,支持层级(父级分组)与布局方向(vertical/horizontal)。
- 关键字段:b_parent_id、b_title、b_layout_direction、b_xh、b_canuse。
- 用途:配合前端画布与栅格布局,形成清晰的表单分区与横向/纵向排列。
**章节来源**
- [100_initialize_fms_new.sql:125-142](file://fms-api/config/migrations/100_initialize_fms_new.sql#L125-L142)
### s_field_view(视图字段配置表)
- 作用:控制列表展示的列宽、是否显示、分组归属、排序号等。
- 关键字段:b_width、b_visible、b_group_id、b_xh。
- 前端能力:支持行拖拽排序、分组管理、同步到编辑/查询配置。
**章节来源**
- [100_initialize_fms_new.sql:144-159](file://fms-api/config/migrations/100_initialize_fms_new.sql#L144-L159)
- [ModuleListConfigPanel.vue:1-198](file://fms-vue/src/views/system/module-management/components/ModuleListConfigPanel.vue#L1-L198)
### s_field_edit(编辑字段配置表)
- 作用:控制编辑表单的字段可见性、必填、只读、禁用、栅格宽度、占位符、文本域高度等。
- 关键字段:b_visible、b_required、b_readonly、b_disabled、b_colspan、b_height、b_placeholder、b_xh。
- 前端能力:
- 设计视图:拖拽字段到画布,自动栅格分配,支持说明文字行。
- 数据视图:高密度表格编辑,支持同步到列表/查询配置。
- 栅格制:24 栅格,支持整行、半行、三分之一行等常用宽度。
**章节来源**
- [100_initialize_fms_new.sql:161-182](file://fms-api/config/migrations/100_initialize_fms_new.sql#L161-L182)
- [ModuleEditConfigPanel.vue:1-800](file://fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue#L1-L800)
### s_field_query(查询字段配置表)
- 作用:定义查询条件的控件类型、操作符、默认值、启用状态、排序号等。
- 关键字段:b_component、b_operator、b_default_value、b_canuse、b_xh、b_condition_no。
- 前端能力:支持新增查询条件、选择组件与操作符、设置默认值、拖拽排序。
**章节来源**
- [100_initialize_fms_new.sql:184-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L184-L203)
- [ModuleQueryConfigPanel.vue:1-161](file://fms-vue/src/views/system/module-management/components/ModuleQueryConfigPanel.vue#L1-L161)
## 依赖关系分析
- 模块与字段:s_module 与 s_field 通过 b_module_id 关联,字段属于特定模块。
- 字段与分组:s_field_view、s_field_edit、s_field_query 通过 b_group_id 关联到 s_field_group,实现分组展示与布局。
- 模块与分组:s_field_group 通过 b_module_id 关联到 s_module,确保分组属于特定模块。
- 查询条件与关系:s_field_query 支持 b_relation_id,用于跨模块/关系的查询条件。
```mermaid
graph LR
M["s_module"] --> F["s_field"]
M --> G["s_field_group"]
M --> V["s_field_view"]
M --> E["s_field_edit"]
M --> Q["s_field_query"]
G --> V
G --> E
G --> Q
```
**图示来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
**章节来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
## 性能考虑
- 索引优化:各配置表均按 b_xh、b_canuse、b_id 等建立索引,提升排序与过滤性能。
- 前端交互:使用拖拽与局部更新减少全量刷新,提高配置效率。
- 元数据缓存:建议在后端对元数据进行缓存,避免频繁查询数据库。
- 栅格计算:前端动态栅格分配算法需避免重复计算,必要时缓存行内字段集合。
[本节为通用性能建议,不直接分析具体文件]
## 故障排查指南
- 模块类型约束错误:若 s_module.b_module_type 与 b_viewtable/b_savetable/b_keyfield/b_delete_policy 的组合不符合约束,将导致保存失败。请检查模块类型与必填字段的匹配。
- 字段类型与数据库类型不匹配:s_field.b_type 与 b_dbtype 需合理对应,否则可能导致表单渲染或数据写入异常。
- 删除策略未配置:data 类型模块必须配置 b_delete_policy,否则无法正确执行删除逻辑。
- 前端配置不同步:若列表/编辑/查询配置不同步,可通过“同步到编辑显示/查询配置”功能保持一致。
**章节来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
- [ModuleListConfigPanel.vue:64-112](file://fms-vue/src/views/system/module-management/components/ModuleListConfigPanel.vue#L64-L112)
- [ModuleEditConfigPanel.vue:177-226](file://fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue#L177-L226)
## 结论
FMS 通过 s_module、s_field、s_field_group、s_field_view、s_field_edit、s_field_query 等元数据表,实现了模块、字段、分组以及三类视图配置的全面元数据驱动。前端提供可视化编辑能力,支持拖拽、栅格布局、分组管理与配置同步,从而在不修改代码的情况下动态生成表单、列表与查询界面。该设计提升了系统的灵活性与可维护性,适用于多业务场景的快速扩展。
[本节为总结性内容,不直接分析具体文件]
## 附录:典型业务配置示例与最佳实践
### 典型业务模块:订单管理(data 类型)
- 模块配置(s_module):
- b_module_type = data
- b_viewtable = 订单视图(如 v_order)
- b_savetable = 订单表(如 b_order)
- b_keyfield = 订单ID
- b_delete_policy = lifecycle(软删除)
- 字段定义(s_field):
- 订单号:input,b_writemode = computed(自动生成)
- 客户名称:select,b_options 包含客户列表
- 金额:money,b_dbtype = decimal
- 下单日期:datetime,b_nullable = 0
- 分组(s_field_group):
- 基本信息、商品信息、结算信息
- 列表配置(s_field_view):
- 显示字段:订单号、客户名称、金额、下单日期
- 列宽:根据内容调整
- 排序:按下单日期倒序
- 编辑配置(s_field_edit):
- 必填:订单号、客户名称、金额
- 栅格宽度:订单号整行,其他字段半行
- 占位符:输入提示
- 查询配置(s_field_query):
- 组件:输入框、下拉选择、日期选择
- 操作符:等于、模糊、范围
- 默认值:当前月份
**章节来源**
- [100_initialize_fms_new.sql:56-203](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L203)
- [ModuleEditConfigPanel.vue:1-800](file://fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue#L1-L800)
- [ModuleListConfigPanel.vue:1-198](file://fms-vue/src/views/system/module-management/components/ModuleListConfigPanel.vue#L1-L198)
- [ModuleQueryConfigPanel.vue:1-161](file://fms-vue/src/views/system/module-management/components/ModuleQueryConfigPanel.vue#L1-L161)
### 最佳实践
- 统一命名规范:模块代码、字段名、分组标题遵循统一命名约定,便于国际化与维护。
- 合理拆分分组:将相关字段放入同一分组,提升表单可读性。
- 谨慎使用复杂类型:对于 select/selectId,确保 b_options 数据源稳定且高效。
- 启用审计日志:结合 s_log_audit 记录关键操作,便于问题追溯。
- 定期清理无用配置:移除不再使用的字段与配置,保持系统简洁。
[本节为通用实践建议,不直接分析具体文件]
@@ -0,0 +1,321 @@
# 用户权限表
<cite>
**本文引用的文件**
- [100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql)
- [AuthService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java)
- [backup_b_user.sql](file://.tmp-fkcheck/backup_b_user.sql)
- [Fms旧系统表结构.md](file://Fms旧系统表结构.md)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向FMS系统的用户与权限体系,聚焦以下目标:
- 详细说明b_user(用户表)字段设计,涵盖基本信息、权限控制字段与业务角色标识。
- 解释s_role(角色表)、s_power(权限表)、s_user_role(用户角色关联表)、s_role_power(角色权限关联表)和s_role_scope(角色范围表)的设计理念与数据关系。
- 说明RBAC模型在系统中的实现方式,包括菜单权限、模块权限、操作权限与字段权限的控制机制。
- 提供用户授权、角色分配、权限验证的典型SQL示例与数据操作流程。
- 给出表间关系图与索引优化建议。
## 项目结构
权限相关的数据模型由数据库迁移脚本集中定义,服务层通过认证服务完成登录与鉴权流程。关键位置如下:
- 数据库DDL与约束:位于迁移脚本中,定义了用户、角色、权限、关联及范围等核心表。
- 认证服务:负责登录校验、会话管理与日志记录,为后续权限计算提供上下文(用户ID、组织ID)。
```mermaid
graph TB
A["前端/客户端"] --> B["认证服务 AuthService"]
B --> C["数据库: b_user / s_* 系列表"]
B --> D["JWT工具 JwtUtils"]
B --> E["会话注册 ActiveSessionRegistry"]
B --> F["登录日志 LoginLogService"]
```
图表来源
- [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84)
- [100_initialize_fms_new.sql:9-39](file://fms-api/config/migrations/100_initialize_fms_new.sql#L9-L39)
章节来源
- [100_initialize_fms_new.sql:9-39](file://fms-api/config/migrations/100_initialize_fms_new.sql#L9-L39)
- [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84)
## 核心组件
- b_user(用户表):存储用户账号、姓名、部门、密码、启用状态、多机登录开关以及若干业务角色标识位(如销售、文档、交易等),并包含可见性控制与登录策略相关字段。
- s_role(角色表):定义系统角色,支持系统内置角色与是否绕过权限检查的标记。
- s_power(权限表):统一抽象四类权限:菜单、模块、动作、字段;每种类型对资源、模块、字段与操作进行约束。
- s_user_role(用户角色关联表):将用户与角色建立多对多关系,支持启用标记与录入时间。
- s_role_power(角色权限关联表):将角色与权限建立多对多关系,支持允许/拒绝策略与启用标记。
- s_role_scope(角色范围表):为角色在特定模块的操作上配置数据范围(全部、创建者、所有者、部门、部门树、自定义),用于行级数据访问控制。
章节来源
- [100_initialize_fms_new.sql:291-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L291-L394)
## 架构总览
下图展示RBAC在FMS中的落地:用户通过角色获得权限,权限细分为菜单、模块、动作、字段;同时通过范围表限定数据可见范围。
```mermaid
erDiagram
b_user ||--o{ s_user_role : "拥有"
s_role ||--o{ s_user_role : "被赋予"
s_role ||--o{ s_role_power : "拥有"
s_power ||--o{ s_role_power : "被授权"
s_role ||--o{ s_role_scope : "数据范围"
s_module ||--o{ s_power : "模块权限"
s_menu ||--o{ s_power : "菜单权限"
s_field ||--o{ s_power : "字段权限"
```
图表来源
- [100_initialize_fms_new.sql:245-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L394)
## 详细组件分析
### b_user(用户表)字段设计
- 基本信息:b_id(自增主键)、b_account(唯一账号)、b_name(姓名)、b_department(部门)、b_subcode(子编码)、b_machineid(机器标识)、b_bz(备注)、b_phone(电话)。
- 安全与状态:b_password(密码)、b_canuse(是否启用)、b_othermachinelogin(是否允许多机登录)、b_logintime(登录策略位)、b_checkxy(审批策略位)、b_loginfee(计费策略位)。
- 业务角色标识:b_salesman(销售)、b_docman(文档)、b_dealman(交易)、b_receivelevel(接收级别)、b_paylevel(支付级别)。
- 可见性与来源:b_visible_customer(客户可见)、b_visible_supply(供应商可见)、b_levelvisible(层级可见)、b_fromcustomer(来自客户)。
设计要点
- 使用tinyint作为布尔型标志位,便于扩展多种业务角色与策略组合。
- 账号唯一约束保障登录识别的唯一性。
- 自增主键便于兼容旧系统;新系统其他表采用雪花主键,b_user保留历史兼容性。
章节来源
- [100_initialize_fms_new.sql:11-37](file://fms-api/config/migrations/100_initialize_fms_new.sql#L11-L37)
- [backup_b_user.sql:2-10](file://.tmp-fkcheck/backup_b_user.sql#L2-L10)
### s_role(角色表)
- 关键字段:b_code(角色编码,唯一)、b_name(名称)、b_i18n(国际化)、b_remark(备注)、b_is_system(是否系统内置)、b_bypass_power(是否绕过权限检查)、b_canuse(是否启用)。
- 设计意图:区分系统内置角色与自定义角色;系统角色可配置为绕过权限检查,用于特权场景或兼容旧逻辑。
章节来源
- [100_initialize_fms_new.sql:291-310](file://fms-api/config/migrations/100_initialize_fms_new.sql#L291-L310)
### s_power(权限表)
- 权限类型:menu(菜单)、module(模块)、action(动作)、field(字段)。
- 资源与粒度:
- 菜单:resource指向菜单资源,operation固定为access。
- 模块:module_id指向模块,operation支持read/create/update/delete/export。
- 动作:resource指向具体动作资源,operation固定为execute。
- 字段:module_id与field_id共同定位字段,operation支持view/edit。
- 设计意图:以统一的权限抽象承载不同粒度的访问控制,便于前端按钮/菜单/字段显隐与后端接口鉴权。
章节来源
- [100_initialize_fms_new.sql:326-351](file://fms-api/config/migrations/100_initialize_fms_new.sql#L326-L351)
### s_user_role(用户角色关联表)
- 关系:用户与角色的多对多映射,支持启用标记与录入时间。
- 设计意图:解耦用户与角色,便于批量授权与动态调整。
章节来源
- [100_initialize_fms_new.sql:312-324](file://fms-api/config/migrations/100_initialize_fms_new.sql#L312-L324)
### s_role_power(角色权限关联表)
- 关系:角色与权限的多对多映射,支持allow/deny策略与启用标记。
- 设计意图:通过显式允许/拒绝策略,实现精细化的权限覆盖与继承控制。
章节来源
- [100_initialize_fms_new.sql:353-367](file://fms-api/config/migrations/100_initialize_fms_new.sql#L353-L367)
### s_role_scope(角色范围表)
- 作用:为角色在指定模块的操作上配置数据范围,支持all(全部)、creator(创建者)、owner(所有者)、department(部门)、department-tree(部门树)、custom(自定义值)。
- 设计意图:实现行级数据访问控制,结合业务字段(如创建人、所属部门)实现数据隔离。
章节来源
- [100_initialize_fms_new.sql:369-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L369-L394)
### RBAC在系统中的实现方式
- 菜单权限:通过s_power.type=menu与s_menu.power_code关联,控制菜单可见性。
- 模块权限:通过s_power.type=module与s_module关联,控制模块的读/写/删/导出能力。
- 操作权限:通过s_power.type=action与resource绑定,控制具体动作执行。
- 字段权限:通过s_power.type=field与s_field关联,控制字段的查看/编辑能力。
- 数据范围:通过s_role_scope限制查询与更新的数据集范围。
章节来源
- [100_initialize_fms_new.sql:245-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L394)
## 依赖关系分析
- 认证流程依赖:AuthService从数据库加载用户信息,校验密码后生成JWT并激活会话,同时记录登录日志。
- 权限计算依赖:基于用户->角色->权限->资源的链路,结合范围表进行数据过滤。
- 外部依赖:JwtUtils用于令牌签发;ActiveSessionRegistry管理在线会话;LoginLogService记录登录事件。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Auth as "AuthService"
participant DB as "数据库(b_user/s_*)"
participant JWT as "JwtUtils"
participant Session as "ActiveSessionRegistry"
participant Log as "LoginLogService"
Client->>Auth : 提交登录(组织ID, 用户ID, 密码)
Auth->>DB : 查询用户信息
DB-->>Auth : 返回用户记录
Auth->>Auth : 校验密码
Auth->>JWT : 生成令牌
Auth->>Session : 激活会话
Auth->>Log : 记录登录结果
Auth-->>Client : 返回令牌与用户信息
```
图表来源
- [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84)
章节来源
- [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84)
## 性能考虑
- 索引优化建议:
- b_user:已具备主键与账号唯一索引;建议在常用查询条件(如部门、启用状态)上按需添加复合索引。
- s_user_role:已有按角色与启用状态的索引,利于快速查找用户角色集合。
- s_role_power:已有按权限与启用状态的索引,利于快速聚合角色权限。
- s_role_scope:已有按角色、模块、操作与启用状态的索引,利于数据范围过滤。
- s_power:已有按权限类型、资源与启用状态的索引,利于权限匹配。
- s_menu/s_module/s_field:已为常见查询路径建立索引(父节点、排序、模块关联等)。
- 查询优化:
- 权限计算尽量使用一次聚合查询,避免N+1问题。
- 数据范围过滤应在SQL层通过范围表与业务字段拼接WHERE条件,减少应用层过滤开销。
- 缓存建议:
- 对热点用户的角色与权限集合进行短期缓存,降低频繁查库压力。
- 菜单与模块元数据可缓存,减少重复构建。
[本节为通用性能指导,不直接分析具体文件]
## 故障排查指南
- 登录失败:
- 账号不存在:检查b_user是否存在对应账号,确认组织ID与账号大小写规范化。
- 密码错误:检查密码存储与比对逻辑,确保前后端一致。
- 会话未激活:检查ActiveSessionRegistry是否成功登记会话。
- 登录日志:通过LoginLogService记录的登录结果与失败原因定位问题。
- 权限异常:
- 菜单不可见:核对s_power.type=menu与s_menu.power_code关联是否正确。
- 模块无操作:核对s_power.type=module与s_module关联及operation是否匹配。
- 动作无法执行:核对s_power.type=action与resource绑定。
- 字段不可编辑:核对s_power.type=field与s_field关联及operation是否为edit。
- 数据范围不符:核对s_role_scope的范围类型与业务字段是否匹配。
章节来源
- [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84)
## 结论
FMS通过标准化的RBAC模型实现了细粒度的权限控制:以用户-角色-权限为核心,结合菜单、模块、动作、字段四类权限与数据范围,既满足功能访问控制,也支持行级数据隔离。配合完善的索引设计与合理的缓存策略,可在保证安全性的同时维持良好的性能表现。
[本节为总结性内容,不直接分析具体文件]
## 附录
### 典型SQL示例(参考路径)
- 用户授权(为用户分配角色)
- 参考路径:[100_initialize_fms_new.sql:312-324](file://fms-api/config/migrations/100_initialize_fms_new.sql#L312-L324)
- 角色分配(为角色授予权限)
- 参考路径:[100_initialize_fms_new.sql:353-367](file://fms-api/config/migrations/100_initialize_fms_new.sql#L353-L367)
- 权限验证(查询用户最终权限集合)
- 参考路径:[100_initialize_fms_new.sql:291-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L291-L394)
- 数据范围过滤(按角色范围限定数据集)
- 参考路径:[100_initialize_fms_new.sql:369-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L369-L394)
### 表间关系图(代码级)
```mermaid
classDiagram
class BUser {
+long b_id
+string b_account
+string b_name
+string b_department
+string b_subcode
+string b_machineid
+string b_bz
+string b_password
+int b_canuse
+int b_othermachinelogin
+int b_salesman
+int b_docman
+int b_dealman
+int b_receivelevel
+int b_paylevel
+int b_visible_customer
+int b_visible_supply
+int b_levelvisible
+int b_fromcustomer
+int b_logintime
+int b_checkxy
+int b_loginfee
+string b_phone
}
class SRole {
+long b_id
+string b_code
+string b_name
+string b_i18n
+string b_remark
+int b_is_system
+int b_bypass_power
+int b_canuse
}
class SPower {
+long b_id
+string b_code
+string b_name
+string b_i18n
+string b_power_type
+string b_resource
+long b_module_id
+long b_field_id
+string b_operation
+int b_canuse
+int b_xh
}
class SUserRole {
+long b_id
+long b_user_id
+long b_role_id
+int b_canuse
+datetime b_inputdatetime
}
class SRolePower {
+long b_id
+long b_role_id
+long b_power_id
+string b_effect
+int b_canuse
+datetime b_inputdatetime
}
class SRoleScope {
+long b_id
+long b_role_id
+long b_module_id
+string b_operation
+string b_scope_type
+int b_scope_no
+long b_scope_field_id
+string b_scope_value
+int b_canuse
+datetime b_inputdatetime
}
BUser "1" -- "*" SUserRole : "拥有"
SRole "1" -- "*" SUserRole : "被赋予"
SRole "1" -- "*" SRolePower : "拥有"
SPower "1" -- "*" SRolePower : "被授权"
SRole "1" -- "*" SRoleScope : "数据范围"
```
图表来源
- [100_initialize_fms_new.sql:291-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L291-L394)
### 旧系统对照
- 旧系统中存在b_user、b_user_power、b_user_module等表,新系统通过s_role、s_power、s_user_role、s_role_power等表重构权限模型,提升灵活性与可维护性。
- 参考路径:[Fms旧系统表结构.md:56-60](file://Fms旧系统表结构.md#L56-L60)
章节来源
- [Fms旧系统表结构.md:56-60](file://Fms旧系统表结构.md#L56-L60)
@@ -0,0 +1,349 @@
# 系统支撑表
<cite>
**本文引用的文件**
- [100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql)
- [001_add_i18n_type.sql](file://fms-api/config/migrations/001_add_i18n_type.sql)
- [006_add_i18n_module_id.sql](file://fms-api/config/migrations/006_add_i18n_module_id.sql)
- [009_add_module_auto_code.sql](file://fms-api/config/migrations/009_add_module_auto_code.sql)
- [010_normalize_auto_code_rule.sql](file://fms-api/config/migrations/010_normalize_auto_code_rule.sql)
- [003_create_login_log.sql](file://fms-api/config/migrations/003_create_login_log.sql)
- [LoginLogService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件聚焦FMS系统的“支撑表”设计与使用,覆盖以下主题:
- s_i18n(国际化表)的多语言支持机制、键值管理与语言包配置
- s_autocode(自动编号表)的编号生成规则:前缀、日期格式、分隔符、序列宽度与重置策略
- 日志表族(s_log_technical、s_log_login、s_log_audit、s_log_audit_field)的设计与记录规范
- 日志数据的查询分析与性能优化策略
- 系统配置管理的最佳实践与扩展开发指南
## 项目结构
支撑表定义集中在数据库迁移脚本中,登录日志写入由后端服务完成。关键位置如下:
- 初始化与基础支撑表定义:[100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql)
- 多语言类型与模块关联增强:[001_add_i18n_type.sql](file://fms-api/config/migrations/001_add_i18n_type.sql)、[006_add_i18n_module_id.sql](file://fms-api/config/migrations/006_add_i18n_module_id.sql)
- 自动编号表演进:[009_add_module_auto_code.sql](file://fms-api/config/migrations/009_add_module_auto_code.sql)、[010_normalize_auto_code_rule.sql](file://fms-api/config/migrations/010_normalize_auto_code_rule.sql)
- 登录日志表与索引:[003_create_login_log.sql](file://fms-api/config/migrations/003_create_login_log.sql)
- 登录日志写入服务:[LoginLogService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java)
```mermaid
graph TB
A["应用层服务<br/>LoginLogService"] --> B["通用数据保存接口<br/>DataSaveService"]
B --> C["数据库迁移与表结构<br/>100_initialize_fms_new.sql / 003_create_login_log.sql"]
C --> D["日志表<br/>s_log_login / s_log_technical / s_log_audit / s_log_audit_field"]
E["多语言与模块元数据<br/>s_i18n / b_i18n_type / s_module"] --> F["业务模块与菜单/字段/权限"]
G["自动编号规则<br/>s_autocode / s_module_auto_code"] --> H["业务单据编号生成"]
```
图表来源
- [100_initialize_fms_new.sql:396-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L396-L507)
- [003_create_login_log.sql:17-44](file://fms-api/config/migrations/003_create_login_log.sql#L17-L44)
- [LoginLogService.java:37-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java#L37-L84)
章节来源
- [100_initialize_fms_new.sql:396-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L396-L507)
- [003_create_login_log.sql:17-44](file://fms-api/config/migrations/003_create_login_log.sql#L17-L44)
- [LoginLogService.java:37-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java#L37-L84)
## 核心组件
- 国际化支撑:s_i18n、b_i18n_type、s_module(模块级联与键命名约定)
- 自动编号支撑:s_autocode、s_module_auto_code(规则标准化与历史迁移)
- 日志支撑:s_log_technical(技术日志)、s_log_login(登录日志)、s_log_audit(审计事件)、s_log_audit_field(审计字段明细)
章节来源
- [100_initialize_fms_new.sql:396-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L396-L507)
- [001_add_i18n_type.sql:26-45](file://fms-api/config/migrations/001_add_i18n_type.sql#L26-L45)
- [006_add_i18n_module_id.sql:15-27](file://fms-api/config/migrations/006_add_i18n_module_id.sql#L15-L27)
- [009_add_module_auto_code.sql:4-25](file://fms-api/config/migrations/009_add_module_auto_code.sql#L4-L25)
- [010_normalize_auto_code_rule.sql:4-52](file://fms-api/config/migrations/010_normalize_auto_code_rule.sql#L4-L52)
## 架构总览
支撑表通过统一的迁移脚本在数据库初始化时创建,并提供必要的约束与索引;业务侧通过通用数据保存接口写入日志等支撑数据,确保跨机构上下文隔离与一致性。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Auth as "认证流程"
participant LogSvc as "LoginLogService"
participant Save as "DataSaveService"
participant DB as "数据库(迁移脚本)"
Client->>Auth : "发起登录"
Auth-->>Client : "返回结果(成功/失败)"
Auth->>LogSvc : "recordLogin(...)"
LogSvc->>Save : "save([{table : 's_log_login', inserts : [...]}])"
Save->>DB : "INSERT INTO s_log_login"
Note over LogSvc,DB : "写日志失败不影响主流程"
```
图表来源
- [LoginLogService.java:37-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java#L37-L84)
- [003_create_login_log.sql:17-44](file://fms-api/config/migrations/003_create_login_log.sql#L17-L44)
## 详细组件分析
### 国际化表 s_i18n 与多语言机制
- 表结构与用途
- s_i18n:以(b_key, b_locale)为唯一键存储多语言文本,支持按语言环境检索与展示
- b_i18n_type:维护系统支持的语言清单(简称、名称、是否默认、是否启用、排序),并注册对应模块与权限
- 模块级联:通过为b_i18n增加b_module_id列,使删除模块时可级联清理其多语言数据,避免孤儿记录
- 键命名约定
- 键形如 module.<code> / menu.<code> / field.<code>.<item> / power.<code>.<item>,其中第二段为模块编码,用于回填b_module_id
- 索引与查询
- 针对b_locale与可启用状态建立索引,便于按语言快速检索
- 配置与管理
- 通过独立模块管理多语言类型,管理员可配置默认语言与可用语言
- 建议将界面文案统一纳入s_i18n,并通过模块维度进行分组与维护
```mermaid
erDiagram
S_I18N {
bigint b_id PK
varchar b_key UK
varchar b_locale
nvarchar b_value
varchar b_i18ntype
int b_canuse
}
B_I18N_TYPE {
bigint b_id PK
varchar b_code UK
nvarchar b_name
int b_canuse
int b_default
int b_xh
}
S_MODULE {
bigint b_id PK
varchar b_code UK
nvarchar b_name
}
S_I18N ||--o{ B_I18N_TYPE : "按类型组织"
S_I18N }o--|| S_MODULE : "b_module_id 关联(可选)"
```
图表来源
- [100_initialize_fms_new.sql:396-409](file://fms-api/config/migrations/100_initialize_fms_new.sql#L396-L409)
- [001_add_i18n_type.sql:26-45](file://fms-api/config/migrations/001_add_i18n_type.sql#L26-L45)
- [006_add_i18n_module_id.sql:15-27](file://fms-api/config/migrations/006_add_i18n_module_id.sql#L15-L27)
章节来源
- [100_initialize_fms_new.sql:396-409](file://fms-api/config/migrations/100_initialize_fms_new.sql#L396-L409)
- [001_add_i18n_type.sql:26-45](file://fms-api/config/migrations/001_add_i18n_type.sql#L26-L45)
- [006_add_i18n_module_id.sql:15-27](file://fms-api/config/migrations/006_add_i18n_module_id.sql#L15-L27)
### 自动编号表 s_autocode 与编号生成规则
- 表结构与规则字段
- s_autocode:定义每个模块字段的编号规则,包括前缀、日期格式、分隔符、序列宽度、重置策略、起始值、当前周期与当前值
- s_module_auto_code:早期版本或兼容表的规则定义,后续通过规范化迁移补齐字段并移除冗余JSON配置
- 编号生成流程(概念)
- 读取模块与字段的规则配置
- 根据当前周期(日/月/年/无)计算b_currentperiod
- 若周期变化则重置b_currentvalue至b_startvalue
- 拼接前缀+日期片段+分隔符+序号(按宽度补零)得到最终编号
- 原子递增b_currentvalue并持久化
- 重置策略
- none:不重置
- day/month/year:按周期重置序号
- 索引与查询
- 对b_field_id建立索引,便于按字段定位规则
```mermaid
flowchart TD
Start(["开始"]) --> ReadRule["读取模块/字段编号规则"]
ReadRule --> CalcPeriod{"计算当前周期"}
CalcPeriod --> |周期变化| Reset["重置当前值为起始值"]
CalcPeriod --> |周期未变| Keep["保持当前值"]
Reset --> Gen["生成编号: 前缀 + 日期片段 + 分隔符 + 序号(宽度补零)"]
Keep --> Gen
Gen --> Inc["原子递增当前值"]
Inc --> Persist["持久化到 s_autocode"]
Persist --> End(["结束"])
```
图表来源
- [100_initialize_fms_new.sql:269-289](file://fms-api/config/migrations/100_initialize_fms_new.sql#L269-L289)
- [009_add_module_auto_code.sql:4-25](file://fms-api/config/migrations/009_add_module_auto_code.sql#L4-L25)
- [010_normalize_auto_code_rule.sql:4-52](file://fms-api/config/migrations/010_normalize_auto_code_rule.sql#L4-L52)
章节来源
- [100_initialize_fms_new.sql:269-289](file://fms-api/config/migrations/100_initialize_fms_new.sql#L269-L289)
- [009_add_module_auto_code.sql:4-25](file://fms-api/config/migrations/009_add_module_auto_code.sql#L4-L25)
- [010_normalize_auto_code_rule.sql:4-52](file://fms-api/config/migrations/010_normalize_auto_code_rule.sql#L4-L52)
### 日志表族设计:技术日志、登录日志、审计日志
- 技术日志 s_log_technical
- 用途:记录系统运行过程中的技术事件、异常、耗时、请求追踪等
- 关键字段:日志级别、分类、操作、模块编码、请求ID、追踪ID、服务器节点、耗时、错误码/信息、异常堆栈、上下文
- 索引:按追踪ID与时间倒序、按日志级别与时间倒序,便于问题定位与过滤
- 登录日志 s_log_login
- 用途:记录每次登录尝试的结果与环境信息,用于安全审计
- 关键字段:用户ID/账号、登录类型、结果、失败原因、IP及归属地、浏览器/操作系统/设备类型、会话ID、请求/追踪ID、发生时间
- 索引:按用户/账号/结果与时间倒序,便于统计与排查
- 写入方式:通过LoginLogService采集客户端信息并使用通用保存接口写入,写失败不影响主流程
- 审计日志 s_log_audit 与 s_log_audit_field
- 用途:记录业务变更事件与字段级前后值对比,满足合规与追溯需求
- 关键字段:事件编码、模块编码、数据标识、业务单号、操作、操作者、来源类型、可见性、负载文本、追踪ID、发生时间
- 字段明细:事件ID、字段名、标签、变更前/后值与显示值、可见性
- 索引:按模块/数据/时间、追踪ID、事件ID、客户视角组合索引,提升查询效率
```mermaid
classDiagram
class S_LOG_TECHNICAL {
+bigint b_id
+varchar b_loglevel
+varchar b_logcategory
+varchar b_operation
+varchar b_module_code
+varchar b_request_id
+varchar b_trace_id
+bigint b_duration_ms
+datetime2 b_occurdatetime
}
class S_LOG_LOGIN {
+bigint b_id
+bigint b_user_id
+varchar b_account
+varchar b_login_type
+int b_login_result
+varchar b_ip
+varchar b_session_id
+varchar b_request_id
+varchar b_trace_id
+datetime2 b_occurdatetime
}
class S_LOG_AUDIT {
+bigint b_id
+varchar b_event_code
+varchar b_module_code
+varchar b_data_id
+varchar b_business_no
+varchar b_operation
+bigint b_operator_id
+varchar b_source_type
+varchar b_visibility
+varchar b_request_id
+varchar b_trace_id
+nvarchar b_payload_text
+datetime2 b_occurdatetime
}
class S_LOG_AUDIT_FIELD {
+bigint b_id
+bigint b_event_id
+varchar b_module_code
+varchar b_data_id
+varchar b_field
+varchar b_field_label
+nvarchar b_before_value
+nvarchar b_after_value
+varchar b_visibility
}
S_LOG_AUDIT "1" --> "many" S_LOG_AUDIT_FIELD : "b_event_id"
```
图表来源
- [100_initialize_fms_new.sql:411-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L411-L507)
- [003_create_login_log.sql:17-44](file://fms-api/config/migrations/003_create_login_log.sql#L17-L44)
章节来源
- [100_initialize_fms_new.sql:411-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L411-L507)
- [003_create_login_log.sql:17-44](file://fms-api/config/migrations/003_create_login_log.sql#L17-L44)
- [LoginLogService.java:37-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java#L37-L84)
## 依赖关系分析
- 多语言与模块
- s_i18n通过b_module_id与s_module关联,实现模块级联清理与按模块检索
- b_i18n_type提供语言清单,配合模块权限控制多语言类型的增删改
- 自动编号与模块/字段
- s_autocode/s_module_auto_code绑定到具体模块与字段,保证编号规则粒度可控
- 日志与追踪
- 各日志表均包含b_request_id与b_trace_id,便于跨服务链路追踪
- 登录日志通过LoginLogService统一采集客户端信息并写入,降低耦合
```mermaid
graph LR
M["s_module"] --> I18N["s_i18n (b_module_id)"]
M --> AC["s_autocode / s_module_auto_code"]
T["s_log_technical"] --> RQ["b_request_id / b_trace_id"]
L["s_log_login"] --> RQ
A["s_log_audit"] --> RQ
AF["s_log_audit_field"] --> A
```
图表来源
- [100_initialize_fms_new.sql:396-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L396-L507)
- [006_add_i18n_module_id.sql:15-27](file://fms-api/config/migrations/006_add_i18n_module_id.sql#L15-L27)
章节来源
- [100_initialize_fms_new.sql:396-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L396-L507)
- [006_add_i18n_module_id.sql:15-27](file://fms-api/config/migrations/006_add_i18n_module_id.sql#L15-L27)
## 性能考虑
- 索引策略
- s_i18n:按b_locale与可启用状态建索引,加速多语言检索
- s_log_technical:按b_trace_id与时间倒序、按日志级别与时间倒序,便于快速定位与过滤
- s_log_login:按用户/账号/结果与时间倒序,提高登录审计查询效率
- s_log_audit与s_log_audit_field:按模块/数据/时间、追踪ID、事件ID与客户视角组合索引,优化多维查询
- 写入与事务
- 登录日志写入采用try-catch包裹,失败不影响主流程,保障可用性
- 所有DDL与数据迁移脚本具备幂等性(存在性判断),可重复执行
- 查询优化建议
- 优先使用b_trace_id/b_request_id进行链路追踪
- 对高频查询条件(如b_module_code、b_data_id、b_loglevel)结合时间范围进行过滤
- 对大字段(如异常堆栈、上下文、负载文本)按需加载,避免全量扫描
章节来源
- [100_initialize_fms_new.sql:411-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L411-L507)
- [003_create_login_log.sql:17-44](file://fms-api/config/migrations/003_create_login_log.sql#L17-L44)
- [LoginLogService.java:37-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java#L37-L84)
## 故障排查指南
- 登录日志无法写入
- 检查OrgContext是否正确设置并在finally中清理
- 确认DataSaveService可用且目标库连接正常
- 查看LoginLogService中的异常日志输出
- 多语言数据缺失或孤儿
- 确认b_i18n.b_module_id已回填并与s_module关联
- 删除模块时确保级联逻辑生效,必要时手动清理孤儿记录
- 自动编号冲突或错乱
- 核对s_autocode的规则配置(前缀、日期格式、分隔符、宽度、重置策略)
- 检查并发场景下的原子递增与周期切换逻辑
- 日志查询缓慢
- 确认索引是否存在且有效
- 使用b_trace_id/b_request_id缩小范围,避免全表扫描
- 对大字段查询采用分页与投影
章节来源
- [LoginLogService.java:37-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java#L37-L84)
- [006_add_i18n_module_id.sql:30-70](file://fms-api/config/migrations/006_add_i18n_module_id.sql#L30-L70)
- [100_initialize_fms_new.sql:411-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L411-L507)
## 结论
- s_i18n提供了灵活的多语言支持,结合b_i18n_type与模块级联,实现了可配置、可治理的国际化能力
- s_autocode定义了标准化的编号生成规则,支持多种重置策略与格式化选项,满足复杂业务场景
- 日志表族覆盖了技术、登录与审计三类关键场景,配合完善的索引与追踪字段,便于问题定位与合规审计
- 通过迁移脚本的幂等性与服务的容错设计,系统在稳定性与可维护性方面具备良好基础
## 附录
- 扩展开发指南
- 新增多语言项:在s_i18n中插入键值,必要时在b_i18n_type中登记新语言
- 新增自动编号:在s_autocode中配置模块/字段规则,遵循前缀、日期、分隔符与宽度约定
- 新增审计点:在业务操作中记录s_log_audit与s_log_audit_field,填充事件编码、模块、数据标识与字段差异
- 日志接入:在关键路径记录s_log_technical,携带b_trace_id与b_request_id以便链路追踪
- 最佳实践
- 所有支撑表变更通过迁移脚本管理,保持幂等与可回滚
- 日志写入失败不应影响主流程,确保高可用
- 查询尽量基于索引字段,避免对大字段进行全表扫描
- 定期评估索引命中率与日志增长情况,必要时进行归档或分区
@@ -0,0 +1,392 @@
# 菜单系统表
<cite>
**本文引用的文件**
- [100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql)
- [restore_fks.sql](file://.tmp-fkcheck/restore_fks.sql)
- [migrate_identity_to_snowflake.sql](file://.tmp-fkcheck/migrate_identity_to_snowflake.sql)
- [AppSidebar.vue](file://fms-vue/src/layouts/components/AppSidebar.vue)
- [permissions.js](file://fms-vue/src/stores/permissions.js)
- [tree.js](file://fms-vue/src/utils/tree.js)
- [index.js](file://fms-vue/src/router/index.js)
- [MenuDetailPanel.vue](file://fms-vue/src/views/system/module-management/components/MenuDetailPanel.vue)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件围绕 FMS 菜单系统表 s_menu,系统性说明其层级结构设计、与模块和权限的关联、路由与图标配置、树形存储与查询优化、基于角色的可见性控制机制,以及前端渲染数据结构和常见配置场景。文档同时给出可操作的 SQL 示例与性能优化建议,帮助快速落地与维护。
## 项目结构
FMS 的菜单能力由“数据库表 + 后端迁移脚本 + 前端侧栏与权限状态”共同实现:
- 数据库层:s_menu 定义菜单元数据;s_module 提供模块维度;s_power/s_role/s_user_role 等支撑权限体系。
- 前端层:AppSidebar 根据权限状态构建动态导航;permissions store 负责加载并缓存授权结果;router 守卫在访问受保护页面时触发权限加载与校验。
```mermaid
graph TB
subgraph "数据库"
A["s_menu<br/>菜单表"]
B["s_module<br/>模块表"]
C["s_power / s_role / s_user_role<br/>权限与角色"]
end
subgraph "前端"
D["AppSidebar.vue<br/>动态侧边栏"]
E["permissions.js<br/>权限状态与缓存"]
F["router/index.js<br/>路由守卫"]
G["tree.js<br/>树构建与排序"]
end
D --> E
F --> E
D --> G
E --> |读取| B
D --> |展示| A
F --> |校验| E
```
图表来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
章节来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
## 核心组件
- 菜单表 s_menu:承载菜单节点的核心元数据,包括编码、名称、类型、路由、图标、排序、启用状态以及与模块、权限的关联字段。
- 模块表 s_module:作为菜单的归属维度,支持目录、页面、数据分类、数据四种类型,并提供路由与视图映射。
- 权限体系:通过 s_power(菜单级权限点)、s_role(角色)、s_user_role(用户-角色)组合实现基于角色的菜单可见性与功能点控制。
- 前端侧栏 AppSidebar:从权限状态中筛选可菜单化的模块,构建树并渲染为导航项。
- 权限状态 permissions.js:拉取模块与授权数据,按主体去重缓存,提供 canAccess/canPower 判断。
- 路由守卫 index.js:在进入受保护页面前统一加载权限,并按 moduleId 进行访问控制。
- 工具 tree.js:将一维列表构建为树并按 b_xh/b_id 稳定排序。
章节来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
- [100_initialize_fms_new.sql:326-367](file://fms-api/config/migrations/100_initialize_fms_new.sql#L326-L367)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)
## 架构总览
下图展示了从登录到侧边栏渲染的完整链路:路由守卫触发权限加载,权限状态拉取模块与授权数据,侧栏据此过滤并构建树,最终渲染菜单。
```mermaid
sequenceDiagram
participant U as "用户浏览器"
participant R as "路由守卫(index.js)"
participant P as "权限状态(permissions.js)"
participant S as "后端API"
participant L as "侧边栏(AppSidebar.vue)"
U->>R : 访问受保护页面
R->>P : 调用 load()
P->>S : 并发请求(s_module, b_user_module, b_user_power, s_module_power)
S-->>P : 返回模块与授权数据
P-->>R : 完成加载并缓存
R->>U : 允许进入或跳转
U->>L : 渲染侧边栏
L->>P : 读取 modules/grantedPageIds
L->>L : 过滤可菜单化模块并构建树
L-->>U : 输出菜单树
```
图表来源
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
## 详细组件分析
### s_menu 表结构与层级设计
- 主键与唯一约束:b_id 为主键;b_code 唯一,便于跨系统引用与多语言键派生。
- 层级关系:b_parent_id 自引用形成树;检查约束防止自环。
- 菜单类型:b_menu_type 限定为 directory/page/data/external,分别对应目录、页面、数据页面、外链。
- 路由与图标:b_route 用于页面或外链地址;b_icon 用于目录类菜单显示图标。
- 排序与启用:b_xh 控制同级顺序;b_canuse 控制是否启用。
- 关联:b_module_id 指向所属模块;b_power_code 绑定菜单级访问权限点。
```mermaid
erDiagram
S_MENU {
bigint b_id PK
bigint b_parent_id FK
varchar b_code UK
nvarchar b_name
varchar b_i18n
varchar b_menu_type
varchar b_route
bigint b_module_id FK
varchar b_power_code
varchar b_icon
int b_xh
int b_canuse
}
S_MODULE {
bigint b_id PK
varchar b_code UK
varchar b_module_type
varchar b_route
}
S_MENU ||--o{ S_MENU : "父-子(b_parent_id)"
S_MENU }o--|| S_MODULE : "归属(b_module_id)"
```
图表来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
章节来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
### 菜单与模块、权限的关联
- 菜单与模块:s_menu.b_module_id 关联 s_module,表示该菜单属于哪个业务模块;菜单类型 data 必须选择数据/查询模块。
- 菜单与权限:s_menu.b_power_code 对应 s_power.b_code(b_power_type=menu),用于控制菜单访问权限;前端通过权限状态判断是否可见。
- 角色与可见性:用户通过 s_user_role 获得角色,角色通过 s_role_power 拥有菜单权限点;最终由 permissions store 计算 grantedPageIds/powerCodes 并驱动 UI。
```mermaid
flowchart TD
A["用户登录"] --> B["加载权限(permissions.load)"]
B --> C{"管理员?"}
C -- 是 --> D["直接加载全部启用模块"]
C -- 否 --> E["并发拉取模块/用户模块/用户权限/模块权限"]
D --> F["构建 grantedPageIds/powerCodes"]
E --> F
F --> G["AppSidebar 过滤可菜单化模块"]
G --> H["构建树并渲染"]
```
图表来源
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
章节来源
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
### 菜单路由配置与图标设置
- 路由配置:page/external 类型需填写 b_route;data 类型需选择关联模块。
- 图标设置:目录类型菜单优先读取 b_icon;非目录仅显示文字。
- 前端处理:AppSidebar 在 toNavItem 中根据类型决定是否注入图标,并将 module 编码作为 moduleId 供后续权限校验使用。
```mermaid
flowchart TD
Start(["菜单节点"]) --> Type{"b_menu_type"}
Type --> |page/external| Route["填写 b_route"]
Type --> |data| Module["选择 b_module_id"]
Type --> |directory| Icon["可选 b_icon"]
Route --> Render["生成导航项"]
Module --> Render
Icon --> Render
```
图表来源
- [AppSidebar.vue:86-103](file://fms-vue/src/layouts/components/AppSidebar.vue#L86-L103)
- [MenuDetailPanel.vue:237-264](file://fms-vue/src/views/system/module-management/components/MenuDetailPanel.vue#L237-L264)
章节来源
- [AppSidebar.vue:86-103](file://fms-vue/src/layouts/components/AppSidebar.vue#L86-L103)
- [MenuDetailPanel.vue:237-264](file://fms-vue/src/views/system/module-management/components/MenuDetailPanel.vue#L237-L264)
### 菜单树形结构的存储方式与查询优化
- 存储方式:采用邻接表(parent_id)+ 排序字段(b_xh)+ 启用标记(b_canuse)。
- 索引优化:
- IX_s_menu_parent:以 (b_parent_id, b_xh, b_canuse) 复合索引,加速按父节点拉取同级菜单并按顺序过滤启用项。
- IX_s_menu_module:以 b_module_id 索引,便于按模块聚合菜单。
- 前端树构建:tree.js 使用 Map 一次遍历建立父子关系,再递归排序,时间复杂度 O(n)。
```mermaid
flowchart TD
Q["查询父节点下的菜单"] --> I["使用索引 IX_s_menu_parent"]
I --> F["按 b_xh 升序、b_id 兜底排序"]
F --> T["前端 buildTree 构建树"]
T --> S["sortTree 递归排序"]
```
图表来源
- [100_initialize_fms_new.sql:265-266](file://fms-api/config/migrations/100_initialize_fms_new.sql#L265-L266)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)
章节来源
- [100_initialize_fms_new.sql:265-266](file://fms-api/config/migrations/100_initialize_fms_new.sql#L265-L266)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)
### 菜单权限控制机制(基于角色)
- 权限模型:s_power 定义菜单级权限点(b_power_type=menu),s_role_power 将权限授予角色,s_user_role 将角色赋予用户。
- 前端判定:
- canAccess(moduleCode):判断当前用户是否可访问某模块(含父级 page 的继承)。
- canPower(scopeCode, powerCode):判断是否具备某功能点权限。
- 管理员提权:特定账号(g3soft)跳过授权表查询,直接可见全部启用模块。
```mermaid
classDiagram
class PermissionStore {
+load()
+canAccess(code) bool
+canPower(scope, power) bool
+modules[]
+grantedPageIds[]
+powerCodes[]
}
class RouterGuard {
+beforeEach()
}
class Sidebar {
+navMain computed
}
RouterGuard --> PermissionStore : "加载权限"
Sidebar --> PermissionStore : "读取授权"
```
图表来源
- [permissions.js:111-153](file://fms-vue/src/stores/permissions.js#L111-L153)
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
章节来源
- [permissions.js:111-153](file://fms-vue/src/stores/permissions.js#L111-L153)
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
### 前端菜单渲染的数据结构
- 输入:permissionStore.modules(已过滤 b_canmenu=1、b_canuse=1、类型为 directory/page)。
- 处理:buildTree 构建树,sortTree 按 b_xh/b_id 排序,toNavItem 转换为导航项(title/url/icon/moduleId)。
- 输出:NavMain 接收 items 数组,支持分组与嵌套。
```mermaid
flowchart TD
M["modules[]"] --> B["buildTree()"]
B --> S["sortTree()"]
S --> N["toNavItem()"]
N --> V["NavMain(items)"]
```
图表来源
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)
章节来源
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)
## 依赖关系分析
- 数据库依赖:
- s_menu 自引用 b_parent_id 形成树;外键约束保证父子关系合法。
- s_menu.b_module_id 关联 s_module,确保菜单归属明确。
- 权限相关表 s_power/s_role/s_user_role 构成 RBAC 基础。
- 前端依赖:
- router 守卫依赖 permissions.store.load 完成首屏权限加载。
- AppSidebar 依赖 permissions.store.modules 与 tree.js 工具函数。
- MenuDetailPanel 依赖表单校验与 i18n 面板,维护菜单元数据编辑体验。
```mermaid
graph LR
DB["数据库表(s_menu/s_module/s_power...)"] --> FE["前端应用"]
FE --> RS["路由守卫(index.js)"]
FE --> PS["权限状态(permissions.js)"]
FE --> SB["侧边栏(AppSidebar.vue)"]
PS --> |缓存| FE
SB --> |渲染| FE
```
图表来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
章节来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
- [index.js:109-133](file://fms-vue/src/router/index.js#L109-L133)
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
## 性能考虑
- 数据库层面
- 利用 IX_s_menu_parent 复合索引,按父节点批量拉取菜单并按顺序过滤启用项,减少网络与前端处理开销。
- 对 s_menu.b_module_id 建立索引,便于按模块聚合菜单。
- 避免在 SQL 中对 b_canuse 做复杂函数运算,保持索引有效。
- 前端层面
- 权限状态按主体去重缓存,避免重复请求;首次加载后本地 Map/Set 查找 O(1)。
- 树构建与排序为 O(n),适合中等规模菜单;若菜单规模增长,可考虑分页或懒加载子树。
- 仅在目录类型菜单渲染图标,减少不必要的图标解析。
- 路由层面
- 路由守卫统一加载权限,避免多次重复请求;未授权直接跳转,减少无效渲染。
[本节为通用性能建议,不直接分析具体代码行]
## 故障排查指南
- 菜单不显示
- 检查 s_menu.b_canuse 是否为启用;检查 s_module.b_canmenu 与 b_module_type 是否符合目录/页面要求。
- 确认权限状态是否正确加载(permissions.store.load),必要时查看控制台错误。
- 菜单点击无响应
- 检查 b_route 是否填写正确;外链需完整 URL,页面需匹配路由路径。
- 权限异常
- 核对 s_power.b_code 与 s_menu.b_power_code 是否一致;检查 s_role_power 与 s_user_role 配置。
- 管理员账号(g3soft)应跳过授权表,如仍受限,检查账号标识。
- 树顺序错乱
- 检查 b_xh 与 b_id 的设置;确认前端 sortTree 生效。
章节来源
- [permissions.js:41-108](file://fms-vue/src/stores/permissions.js#L41-L108)
- [AppSidebar.vue:62-83](file://fms-vue/src/layouts/components/AppSidebar.vue#L62-L83)
- [MenuDetailPanel.vue:237-264](file://fms-vue/src/views/system/module-management/components/MenuDetailPanel.vue#L237-L264)
## 结论
s_menu 作为 FMS 菜单系统的核心表,通过清晰的类型划分、严格的约束与索引设计,结合前端的权限状态与树构建工具,实现了灵活、可扩展且高性能的菜单体系。配合 RBAC 权限模型与路由守卫,既能满足细粒度访问控制,又能保障用户体验。建议在新增菜单时遵循类型规范、完善路由与权限配置,并利用现有索引与工具函数提升性能。
## 附录
### 菜单类型与用途对照
- directory:目录型菜单,用于分组与组织下级菜单;可配置图标。
- page:页面型菜单,指向固定路由;可配置访问权限编码。
- data:数据页面型菜单,需关联数据/查询模块;可配置访问权限编码。
- external:外链型菜单,直接跳转到外部地址;可配置访问权限编码。
章节来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
- [MenuDetailPanel.vue:48-68](file://fms-vue/src/views/system/module-management/components/MenuDetailPanel.vue#L48-L68)
### 菜单配置的 SQL 示例
- 创建目录菜单
- 插入 s_menu 记录,设置 b_menu_type='directory',b_parent_id 指向父节点,b_xh 控制排序,b_canuse=1。
- 创建页面菜单
- 设置 b_menu_type='page',填写 b_route 与 b_power_code(可选),关联 b_module_id(可选)。
- 创建数据菜单
- 设置 b_menu_type='data',必填 b_module_id,可选 b_power_code。
- 创建外链菜单
- 设置 b_menu_type='external',填写 b_route 与 b_power_code(可选)。
- 索引与约束
- 确保存在 IX_s_menu_parent 与 IX_s_menu_module;检查 CK_s_menu_type 与 CK_s_menu_parent 约束生效。
章节来源
- [100_initialize_fms_new.sql:245-267](file://fms-api/config/migrations/100_initialize_fms_new.sql#L245-L267)
- [restore_fks.sql:50-54](file://.tmp-fkcheck/restore_fks.sql#L50-L54)
- [migrate_identity_to_snowflake.sql:150-162](file://.tmp-fkcheck/migrate_identity_to_snowflake.sql#L150-L162)
### 前端菜单渲染数据结构要点
- 输入数组元素包含:b_id、b_parent_id、b_code、b_name、b_menu_type、b_route、b_module_id、b_icon、b_xh、b_canuse。
- 转换规则:
- 仅目录类型渲染图标;非目录仅显示文字。
- url 优先使用 b_route,否则回退到 #b_code。
- 非目录节点携带 moduleId 用于权限校验。
- 排序与树:
- 使用 buildTree 构建父子关系;sortTree 按 b_xh/b_id 稳定排序。
章节来源
- [AppSidebar.vue:86-103](file://fms-vue/src/layouts/components/AppSidebar.vue#L86-L103)
- [tree.js:8-55](file://fms-vue/src/utils/tree.js#L8-L55)