# FMS 模块架构 ## 目标 模块架构只解决五类稳定职责: ```text Module 可复用模块资源 FunctionNode 菜单目录和页面入口 PageNode 页面内部编排 Profile 数据模块的使用方式 Capability 字段、列表、表单、查询、操作等能力 ``` 业务表、业务数据和手写 Vue 页面不进入元数据模型。通用读写继续使用 `/data/loaddata`、`/data/page`、`/data/saveobjt`,不增加模块专用接口。 ## 设计规则 - 所有主键使用不可变 `bigint` 雪花 ID,前端按字符串处理。 - 技术编码创建后不可修改;显示名称可以修改。 - `s_module` 只保存资源公共属性,类型专属字段进入子类型表。 - 数据模块必须自动创建一个 `default` Profile。 - 字段和操作属于 Module;列表、表单、查询、导入、导出属于 Profile。 - 树结构使用明确父子外键和循环检测,不把树路径保存为 JSON。 - 关系和授权使用稳定 ID,不依赖名称或技术编码。 - 只有控件扩展参数、渲染器参数等不可预知属性使用 JSON。 - 不保留旧模块元数据兼容表、双写或页面专用模型。 ## 资源模型 ### `dbo.s_module` | 字段 | 类型 | 说明 | | --- | --- | --- | | `b_id` | `bigint` | 不可变雪花 ID | | `b_code` | `varchar(50)` | 全局唯一、不可变技术编码 | | `b_name` | `nvarchar(100)` | 默认名称 | | `b_i18n` | `varchar(150)` | `meta.module.` | | `b_module_type` | `varchar(20)` | `page/data/report/dashboard/workflow` | | `b_canuse` | `int` | 是否启用 | 每个 Module 必须且只能有一个对应子类型记录: | 子类型表 | 主要字段 | | --- | --- | | `s_module_page` | `b_route`、`b_page_mode`、`b_component_key` | | `s_module_data` | `b_viewtable`、`b_savetable`、`b_keyfield`、`b_orderfield` | | `s_module_report` | 来源数据模块/Profile、`b_renderer_key`、`b_options` | | `s_module_dashboard` | `b_component_key`、`b_options` | | `s_module_workflow` | `b_engine_key`、`b_options` | 报表、仪表盘和工作流只定义运行时契约,本阶段不提供报表引擎、设计器或流程引擎。 ### `dbo.s_module_profile` Profile 只属于数据模块。同一模块内 `b_code` 唯一,并且只能有一个 `b_default = 1`。 | 字段 | 说明 | | --- | --- | | `b_id` | 不可变雪花 ID | | `b_module_id` | 所属数据模块 | | `b_code` | 模块内唯一、不可变技术编码,如 `default`、`selector` | | `b_name` / `b_i18n` | 默认名称及 `meta.profile.` | | `b_default` / `b_canuse` / `b_xh` | 默认、启用和排序 | 运行时列表通过 `module_id + profile_id` 定位;手写页面可以通过模块/Profile 技术编码解析稳定 ID。 ## 功能结构 ### `dbo.s_function_node` 节点类型: - `directory`:只负责分组,不引用模块。 - `entry`:引用一个 `page` Module。 规则: - 技术编码全局唯一且不可修改。 - 子节点只能放在 `directory` 下。 - 入口节点不能包含子节点。 - 数据库触发器和维护界面同时阻止循环移动。 - 删除前必须清除角色和用户授权。 菜单运行时读取 `v_s_function_node`,路由组件仍由前端白名单显式注册。 ## 页面编排 ### `dbo.s_page_node` 节点类型:`group`、`tab`、`section`、`module_ref`。 - 所有节点属于一个 `page` Module。 - 容器节点不引用模块。 - `module_ref` 可以引用 `data/report/dashboard/workflow` Module。 - 引用数据模块时必须同时引用属于该模块的 Profile。 - `module_ref` 不能包含子节点。 - `b_permission_required = 1` 时需要页面节点授权。 - `b_fixed_condition` 与 `b_param_mapping` 只保存运行时组合参数。 页面运行时读取 `v_s_page_node`。`otherdata` 的分类和模块树迁入该表,不再保留 `b_other_bmfl`。 ## 能力模型 ### Module 级能力 | 表 | 职责 | | --- | --- | | `s_module_field` | 数据字段基础定义,`(module_id, field)` 唯一 | | `s_module_action` | 稳定操作定义,`(module_id, code)` 唯一 | | `s_module_relation` | 主子模块字段关系 | | `s_module_auto_code` | 模块业务编号规则 | | `s_module_file` | 模块文件能力契约 | | `s_module_workflow_binding` | 模块事件/操作与工作流资源绑定 | ### Profile 级能力 | 表 | 职责 | | --- | --- | | `s_module_layout_group` | Profile 内列表/表单布局分组 | | `s_module_field_list` | 列表列、分组、可见性、顺序、宽度 | | `s_module_field_form` | 表单必填、只读、禁用、可见性和顺序 | | `s_module_field_query` | 查询控件、操作符、默认值和顺序 | | `s_module_import` | 导入方式与扩展参数 | | `s_module_export` | 导出方式与扩展参数 | 字段同步按字段技术名合并:保留已有人工配置,新字段补默认列表/表单配置,数据源中失效的字段只停用、不删除。 ## 权限 角色是主授权,用户授权只做加法: ```text b_role -> b_role_function_node -> b_role_page_node -> b_role_action -> b_role_data_scope b_user -> b_user_role -> b_user_function_node -> b_user_page_node -> b_user_action ``` 有效权限视图: - `v_s_user_function_permission` - `v_s_user_page_permission` - `v_s_user_action_permission` 超级角色自动拥有全部启用权限。授权关系始终保存节点或操作 ID,不保存名称。当前由前端执行菜单、路由、页面节点和操作控制;后端数据范围和写操作拦截为后续扩展点。 `b_role_data_scope` 预留 `all/self/department/custom` 数据范围契约及扩展参数。本阶段不在查询接口中执行该规则。 ## 多语言 固定前端文案使用语义键,例如 `common.save`。动态元数据使用 ID 键: ```text meta.module. meta.node. meta.profile. meta.group. meta.field. meta.action. meta.role. ``` 动态实体保存 `b_name` 与 `b_i18n`,Vue 统一调用: ```js appStore.t(record.b_i18n, record.b_name); ``` 翻译缺失时回退 `b_name`,不会阻塞配置使用。 ## 运行时视图 `034_module_runtime_views.sql` 建立: - `v_s_function_node` - `v_s_page_node` - `v_s_module_profile` - `v_s_module_runtime` - `v_s_module_field_list` - `v_s_module_field_form` - `v_s_module_field_query` - `v_s_module_action` - 三个用户有效权限视图 视图只组合读取契约,不承载保存逻辑。所有多表配置仍通过一次 `/data/saveobjt` 在同一事务内提交。 ## 迁移与校验 按顺序人工执行: 1. `033_create_module_structure.sql`:一次性迁移有效旧元数据并删除旧模型。 2. `034_module_runtime_views.sql`:建立运行时视图和领域约束触发器。 3. `verify_module_architecture.sql`:只读检查子类型、Profile、父子规则、循环、旧表和多语言键。 执行前必须备份数据库。迁移脚本不由应用启动自动执行。