From e91fd1d8de5890eef95a5d24b422bf0395db50b8 Mon Sep 17 00:00:00 2001 From: oneao Date: Tue, 18 Aug 2026 22:33:54 +0800 Subject: [PATCH] 20260818223354 --- code/fms/FMS新系统核心表结构设计.md | 196 ++++++---------------------- code/fms/fms-demo/index.html | 131 +++++++++++-------- 2 files changed, 117 insertions(+), 210 deletions(-) diff --git a/code/fms/FMS新系统核心表结构设计.md b/code/fms/FMS新系统核心表结构设计.md index d1f7fd49..b3c6df8c 100644 --- a/code/fms/FMS新系统核心表结构设计.md +++ b/code/fms/FMS新系统核心表结构设计.md @@ -2,7 +2,7 @@ ## 1. 说明 -本文档给出 FMS 新系统核心平台表的 SQL Server 建表语句,范围包括元数据中心(模块、实体、字段、关系、页面菜单、视图、表单、多语言)、Schema Compiler、权限中心、技术日志、登录日志与业务审计。 +本文档给出 FMS 新系统核心平台表的 SQL Server 建表语句,范围包括元数据中心(模块、实体、字段、字段分组、关系、页面菜单、多语言)、Schema Compiler、权限中心、技术日志、登录日志与业务审计。 设计原则: @@ -83,7 +83,7 @@ create index ix_s_module_dependency_depends_on ### 2.3 实体 -实体是数据和字段的所有者,映射一张真实物理表。页面、列表、表单都只是实体的展示方式。 +实体是数据和字段的所有者,同时声明"查询数据源"和"保存数据源"。查询源可以是真实表,也可以是带关联/聚合的 SQL 视图(视图只读,用于列表展示);保存目标必须是真实表。 ```sql create table dbo.s_module_entity ( @@ -92,7 +92,9 @@ create table dbo.s_module_entity ( b_module_key nvarchar(128) not null, -- 所属模块 key b_name_key nvarchar(256) not null, -- 实体显示名多语言 key b_description nvarchar(1000) null, -- 实体描述 - b_physical_table sysname not null, -- 真实物理表名(如 ocean_booking) + b_view_table sysname not null, -- 查询数据源:真实表或 SQL 视图(如 ocean_booking / v_booking_with_fee) + b_save_table sysname null, -- 保存目标:真实表(查询源为视图时必填,只读实体可为空) + b_key_field sysname null, -- 保存对象主键字段(如 b_id) b_delete_policy nvarchar(32) not null -- 删除策略(默认 lifecycle) constraint df_s_module_entity_delete_policy default N'lifecycle', b_origin nvarchar(32) not null -- 来源:platform / tenant @@ -109,6 +111,17 @@ create table dbo.s_module_entity ( create index ix_s_module_entity_module_key on dbo.s_module_entity (b_module_key, b_enabled); + +create index ix_s_module_entity_save_table + on dbo.s_module_entity (b_save_table); +``` + +实体的"查/存"配置方式: + +```text +简单实体: b_view_table = b_save_table = 同一张真实表 +复杂列表: b_view_table = 带关联/聚合的 SQL 视图(只读), b_save_table = 真实表 +纯查询实体: b_view_table = 视图或表, b_save_table = 空(只读,不可保存) ``` 删除策略取值(`b_delete_policy`): @@ -153,6 +166,7 @@ create table dbo.s_module_field ( constraint df_s_module_field_readonly default 0, b_sort_no int not null -- 列表/表单默认排序 constraint df_s_module_field_sort_no default 0, + b_group_key nvarchar(128) null, -- 所属分组 key(逻辑外键,空为未分组) b_width int null, -- 列表列宽(px) b_component_type nvarchar(64) null, -- 固定表单组件类型(input/select/date) b_auditable tinyint not null -- 是否记录字段级审计 @@ -253,8 +267,6 @@ create table dbo.s_module_menu ( b_menu_type nvarchar(32) not null, -- 菜单类型:directory/page/data_category/data/external b_route nvarchar(256) null, -- 固定页面或外链路由 b_entity_key nvarchar(192) null, -- data 类型绑定的实体 key - b_view_key nvarchar(192) null, -- 绑定的列表视图 key - b_form_key nvarchar(192) null, -- 绑定的表单 key b_permission_key nvarchar(192) null, -- 页面访问权限 key b_icon_key nvarchar(128) null, -- 菜单图标 key b_sort_no int not null -- 菜单排序号 @@ -284,153 +296,40 @@ create index ix_s_module_menu_entity_key on dbo.s_module_menu (b_entity_key, b_enabled); ``` -约束由元数据校验器执行:`directory` 节点不能填写业务表或外链路由;`page` 节点必须填写 `b_route`,并绑定 `b_view_key`/`b_form_key`;`data` 节点必须填写 `b_entity_key` 和 `b_view_key`(列表)、`b_form_key`(表单);`external` 节点必须填写 `b_route` 和 `b_permission_key`。固定页面组件负责布局,表中只保存实体与视图/表单引用和导航配置。目录仅在至少存在一个可访问子页面时显示。 +约束由元数据校验器执行:`directory` 节点不能填写业务表或外链路由;`page` 节点必须填写 `b_route`;`data` 节点必须填写 `b_entity_key`(查询走实体 `b_view_table`,保存走实体 `b_save_table`);`external` 节点必须填写 `b_route` 和 `b_permission_key`。固定页面组件负责布局,表中只保存实体引用和导航配置。目录仅在至少存在一个可访问子页面时显示。 -### 2.7 视图(列表) +### 2.7 字段分组 -视图定义"一个实体的一种列表展示方式",一个实体可以有多个视图。列表字段配置在 `s_module_view_field`。 +字段分组是实体级独立定义,用于表单/编辑页面按分组展示字段。分组定义集中在 `s_module_field_group`,字段通过 `s_module_field.b_group_key` 引用分组,避免在每个字段上重复维护分组标题与排序。 ```sql -create table dbo.s_module_view ( +create table dbo.s_module_field_group ( b_id bigint identity(1, 1) not null, -- 内部自增主键 - b_view_key nvarchar(192) not null, -- 视图稳定业务标识(如 ocean.booking.default-list) b_entity_key nvarchar(192) not null, -- 所属实体 key - b_name_key nvarchar(256) not null, -- 视图显示名多语言 key - b_queryable tinyint not null -- 是否提供查询条件区 - constraint df_s_module_view_queryable default 1, - b_exportable tinyint not null -- 是否允许导出 - constraint df_s_module_view_exportable default 1, - b_page_size int null, -- 默认分页大小 - b_config_text nvarchar(max) null, -- 视图扩展配置 - b_enabled tinyint not null -- 是否启用 - constraint df_s_module_view_enabled default 1, + b_group_key nvarchar(128) not null, -- 分组稳定标识(如 basic/transport/finance) + b_name_key nvarchar(256) not null, -- 分组标题多语言 key + b_sort_no int not null -- 分组排序号(0,1,2...) + constraint df_s_module_field_group_sort_no default 0, + b_enabled tinyint not null -- 是否启用(停用则整组隐藏) + constraint df_s_module_field_group_enabled default 1, + b_config_text nvarchar(max) null, -- 分组扩展配置 b_created_at datetime2(3) not null -- 创建时间(UTC) - constraint df_s_module_view_created_at default sysutcdatetime(), + constraint df_s_module_field_group_created_at default sysutcdatetime(), b_created_by nvarchar(128) not null, -- 创建人 - constraint pk_s_module_view primary key (b_id), - constraint ux_s_module_view_key unique (b_view_key) -); - -create index ix_s_module_view_entity_key - on dbo.s_module_view (b_entity_key, b_enabled); - -create table dbo.s_module_view_field ( - b_id bigint identity(1, 1) not null, -- 内部自增主键 - b_view_key nvarchar(192) not null, -- 所属视图 key - b_field_key nvarchar(128) not null, -- 引用的字段 key - b_sort_no int not null -- 列排序号 - constraint df_s_module_view_field_sort_no default 0, - b_width int null, -- 列宽(px) - b_visible tinyint not null -- 是否显示 - constraint df_s_module_view_field_visible default 1, - b_frozen tinyint not null -- 是否固定列 - constraint df_s_module_view_field_frozen default 0, - b_align nvarchar(16) null, -- 对齐方式(left/center/right) - b_format_text nvarchar(256) null, -- 显示格式(如日期、千分位) - b_queryable tinyint not null -- 是否作为查询条件 - constraint df_s_module_view_field_queryable default 0, - b_query_operator nvarchar(32) null, -- 查询运算符(eq/contains/gte/...) - b_created_at datetime2(3) not null -- 创建时间(UTC) - constraint df_s_module_view_field_created_at default sysutcdatetime(), - b_created_by nvarchar(128) not null, -- 创建人 - constraint pk_s_module_view_field primary key (b_id), - constraint ux_s_module_view_field_key unique ( - b_view_key, - b_field_key + constraint pk_s_module_field_group primary key (b_id), + constraint ux_s_module_field_group_key unique ( + b_entity_key, + b_group_key ) ); -create index ix_s_module_view_field_view_key - on dbo.s_module_view_field (b_view_key, b_sort_no); +create index ix_s_module_field_group_entity_key + on dbo.s_module_field_group (b_entity_key, b_enabled, b_sort_no); ``` -### 2.8 表单 +表单渲染时按 `b_sort_no` 排序分组,组内字段按 `s_module_field.b_sort_no` 排序;`s_module_field.b_group_key` 为空的字段显示在"未分组"区。新增/调整/停用分组只改 `s_module_field_group`,不需要逐个修改字段。 -表单定义"一个实体的一种编辑展示方式",一个实体可以有多个表单(默认编辑表单、详情表单)。子表区域通过 `s_module_form_relation` 引用关系并绑定子表视图/表单。 - -```sql -create table dbo.s_module_form ( - b_id bigint identity(1, 1) not null, -- 内部自增主键 - b_form_key nvarchar(192) not null, -- 表单稳定业务标识(如 ocean.booking.default-form) - b_entity_key nvarchar(192) not null, -- 所属实体 key - b_name_key nvarchar(256) not null, -- 表单显示名多语言 key - b_form_type nvarchar(32) not null -- 表单类型(默认 default) - constraint df_s_module_form_form_type default N'default', - b_config_text nvarchar(max) null, -- 表单扩展配置(控件特有属性与布局 JSON) - b_enabled tinyint not null -- 是否启用 - constraint df_s_module_form_enabled default 1, - b_created_at datetime2(3) not null -- 创建时间(UTC) - constraint df_s_module_form_created_at default sysutcdatetime(), - b_created_by nvarchar(128) not null, -- 创建人 - constraint pk_s_module_form primary key (b_id), - constraint ux_s_module_form_key unique (b_form_key) -); - -create index ix_s_module_form_entity_key - on dbo.s_module_form (b_entity_key, b_enabled); - -create table dbo.s_module_form_field ( - b_id bigint identity(1, 1) not null, -- 内部自增主键 - b_form_key nvarchar(192) not null, -- 所属表单 key - b_field_key nvarchar(128) not null, -- 引用的字段 key - b_group_key nvarchar(128) null, -- 所属分组 key(逻辑分组) - b_sort_no int not null -- 表单内排序号 - constraint df_s_module_form_field_sort_no default 0, - b_required tinyint not null -- 是否必填(覆盖字段默认) - constraint df_s_module_form_field_required default 0, - b_readonly tinyint not null -- 是否只读(覆盖字段默认) - constraint df_s_module_form_field_readonly default 0, - b_visible tinyint not null -- 是否显示 - constraint df_s_module_form_field_visible default 1, - b_span int null, -- 布局占宽(栅格) - b_component_type nvarchar(64) null, -- 控件类型(覆盖字段默认) - b_config_text nvarchar(max) null, -- 控件扩展配置 - b_created_at datetime2(3) not null -- 创建时间(UTC) - constraint df_s_module_form_field_created_at default sysutcdatetime(), - b_created_by nvarchar(128) not null, -- 创建人 - constraint pk_s_module_form_field primary key (b_id), - constraint ux_s_module_form_field_key unique ( - b_form_key, - b_field_key - ) -); - -create index ix_s_module_form_field_form_key - on dbo.s_module_form_field (b_form_key, b_sort_no); - -create table dbo.s_module_form_relation ( - b_id bigint identity(1, 1) not null, -- 内部自增主键 - b_form_key nvarchar(192) not null, -- 所属表单 key - b_relation_key nvarchar(192) not null, -- 引用的主子关系 key - b_child_view_key nvarchar(192) null, -- 子表列表配置 key - b_child_form_key nvarchar(192) null, -- 子表编辑配置 key(可选) - b_display_mode nvarchar(16) not null -- 子表显示模式(默认 table) - constraint df_s_module_form_relation_display_mode default N'table', - b_editable tinyint not null -- 是否可编辑 - constraint df_s_module_form_relation_editable default 1, - b_allow_add tinyint not null -- 是否允许新增行 - constraint df_s_module_form_relation_allow_add default 1, - b_allow_delete tinyint not null -- 是否允许删除行 - constraint df_s_module_form_relation_allow_delete default 1, - b_allow_sort tinyint not null -- 是否允许排序行 - constraint df_s_module_form_relation_allow_sort default 1, - b_sort_no int not null -- 子表区域排序号 - constraint df_s_module_form_relation_sort_no default 0, - b_created_at datetime2(3) not null -- 创建时间(UTC) - constraint df_s_module_form_relation_created_at default sysutcdatetime(), - b_created_by nvarchar(128) not null, -- 创建人 - constraint pk_s_module_form_relation primary key (b_id), - constraint ux_s_module_form_relation_key unique ( - b_form_key, - b_relation_key - ) -); - -create index ix_s_module_form_relation_form_key - on dbo.s_module_form_relation (b_form_key, b_sort_no); -``` - -### 2.9 多语言 +### 2.8 多语言 多语言是元数据运行时的一部分,统一解析模块、菜单、实体、字段、动作和主数据的显示名称。 @@ -461,7 +360,7 @@ create index ix_s_module_i18n_resource_key ## 3. Schema Compiler -元数据变更通过服务层校验后立即生效。Schema Compiler 根据 `s_module_entity` 的物理表配置和 `s_module_field` 的物理字段配置生成所需的 `CREATE TABLE`、`ALTER TABLE`、索引和约束语句,并由应用服务直接执行;执行成功后提交元数据变更,失败则回滚本次操作并返回错误。 +元数据变更通过服务层校验后立即生效。Schema Compiler 根据 `s_module_entity` 的保存数据源(`b_save_table`)配置和 `s_module_field` 的物理字段配置生成所需的 `CREATE TABLE`、`ALTER TABLE`、索引和约束语句,并由应用服务直接执行;执行成功后提交元数据变更,失败则回滚本次操作并返回错误。查询数据源(`b_view_table`)为 SQL 视图时,由运维或售后在数据库中维护视图定义,Schema Compiler 不生成视图 DDL。 执行机制: @@ -700,24 +599,14 @@ create index ix_s_log_audit_field_audit_event_id | `s_module_dependency` | `b_depends_on_module_key` | `s_module.b_module_key` | | `s_module_entity` | `b_module_key` | `s_module.b_module_key` | | `s_module_field` | `b_entity_key` | `s_module_entity.b_entity_key` | +| `s_module_field` | `b_group_key` | 实体范围内的 `s_module_field_group.b_group_key` | +| `s_module_field_group` | `b_entity_key` | `s_module_entity.b_entity_key` | | `s_module_relation` | `b_entity_key` | `s_module_entity.b_entity_key` | | `s_module_relation` | `b_target_entity_key` | `s_module_entity.b_entity_key` | | `s_module_menu` | `b_module_key` | `s_module.b_module_key` | | `s_module_menu` | `b_parent_menu_key` | `s_module_menu.b_menu_key` | | `s_module_menu` | `b_entity_key` | `s_module_entity.b_entity_key` | -| `s_module_menu` | `b_view_key` | `s_module_view.b_view_key` | -| `s_module_menu` | `b_form_key` | `s_module_form.b_form_key` | | `s_module_menu` | `b_permission_key` | `s_auth_permission.b_permission_key` | -| `s_module_view` | `b_entity_key` | `s_module_entity.b_entity_key` | -| `s_module_view_field` | `b_view_key` | `s_module_view.b_view_key` | -| `s_module_view_field` | `b_field_key` | 实体范围内的 `s_module_field.b_field_key` | -| `s_module_form` | `b_entity_key` | `s_module_entity.b_entity_key` | -| `s_module_form_field` | `b_form_key` | `s_module_form.b_form_key` | -| `s_module_form_field` | `b_field_key` | 实体范围内的 `s_module_field.b_field_key` | -| `s_module_form_relation` | `b_form_key` | `s_module_form.b_form_key` | -| `s_module_form_relation` | `b_relation_key` | `s_module_relation.b_relation_key` | -| `s_module_form_relation` | `b_child_view_key` | `s_module_view.b_view_key` | -| `s_module_form_relation` | `b_child_form_key` | `s_module_form.b_form_key` | | `s_auth_user_role` | `b_role_key` | `s_auth_role.b_role_key` | | `s_auth_role_permission` | `b_permission_key` | `s_auth_permission.b_permission_key` | | `s_log_audit_field` | `b_event_id` | `s_log_audit.b_id` | @@ -730,7 +619,7 @@ create index ix_s_log_audit_field_audit_event_id 稳定 key 是否存在 -> 目标资源是否启用 -> 跨模块引用是否合法(依赖图中可达) --> 字段、实体类型和视图/表单配置是否匹配 +-> 字段、实体类型和分组配置是否匹配 -> 删除或停用前是否仍被其他资源引用 ``` @@ -739,8 +628,7 @@ create index ix_s_log_audit_field_audit_event_id 建议按以下顺序创建和启用这些表: ```text -元数据基础表(模块/依赖/实体/字段/关系) --> 视图与表单表 +元数据基础表(模块/依赖/实体/字段/字段分组/关系) -> 页面菜单入口表 -> 多语言表 -> 权限表 diff --git a/code/fms/fms-demo/index.html b/code/fms/fms-demo/index.html index ad44af3d..8687d962 100644 --- a/code/fms/fms-demo/index.html +++ b/code/fms/fms-demo/index.html @@ -196,7 +196,7 @@ const MODULES = [ desc: '海运出口全流程:订舱、海运单、集装箱、提单、船期。典型的"一模块多实体多菜单"形态。', deps: ['platform', 'master-data'], entities: [ - { key: 'ocean.booking', table: 'ocean_booking', policy: 'lifecycle', desc: '订舱主单' }, + { key: 'ocean.booking', table: 'ocean_booking', view: 'v_booking_with_fee', policy: 'lifecycle', desc: '订舱主单' }, { key: 'ocean.container', table: 'ocean_container', policy: 'cascadeOwned', desc: '箱信息(订舱的子表)' }, { key: 'ocean.shipment', table: 'ocean_shipment', policy: 'lifecycle', desc: '海运单' }, { key: 'ocean.bill_of_lading', table: 'ocean_bill_of_lading', policy: 'lifecycle', desc: '提单' }, @@ -204,7 +204,7 @@ const MODULES = [ ], menus: [ { key: 'ocean.booking.cat', name: '订舱管理', type: 'data_category', children: [ - { key: 'ocean.booking.list', name: '订舱列表', type: 'data', entity: 'ocean.booking', view: 'ocean.booking.default-list', form: 'ocean.booking.default-form', route: '/ocean/bookings', permission: 'ocean.booking.view' }, + { key: 'ocean.booking.list', name: '订舱列表', type: 'data', entity: 'ocean.booking', route: '/ocean/bookings', permission: 'ocean.booking.view' }, ]}, { key: 'ocean.shipment.cat', name: '海运单', type: 'data_category', children: [ { key: 'ocean.shipment.list', name: '海运单列表', type: 'data', entity: 'ocean.shipment', route: '/ocean/shipments', permission: 'ocean.shipment.view' }, @@ -274,16 +274,16 @@ const MODULES = [ const ENTITY_FIELDS = { 'ocean.booking': [ - { key: 'booking_no', label: '订舱号', type: 'varchar(50)', write: 'direct', req: 1, qry: 1, list: 1, edit: 1 }, - { key: 'customer_id', label: '客户', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1 }, - { key: 'carrier_id', label: '船公司', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1 }, - { key: 'etd', label: '预计离港日', type: 'date', write: 'direct', req: 0, qry: 1, list: 1, edit: 1 }, - { key: 'load_port', label: '起运港', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1 }, - { key: 'discharge_port', label: '目的港', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1 }, - { key: 'freight_payment',label: '运费支付', type: 'varchar(32)', write: 'direct', req: 0, qry: 1, list: 1, edit: 1 }, - { key: 'gross_weight', label: '毛重', type: 'decimal(18,3)', write: 'direct', req: 0, qry: 0, list: 1, edit: 1 }, - { key: 'volume', label: '体积', type: 'decimal(18,3)', write: 'direct', req: 0, qry: 0, list: 1, edit: 1 }, - { key: 'container_count',label: '箱量', type: 'int', write: 'computed', req: 0, qry: 0, list: 1, edit: 0 }, + { key: 'booking_no', label: '订舱号', type: 'varchar(50)', write: 'direct', req: 1, qry: 1, list: 1, edit: 1, group: 'basic' }, + { key: 'customer_id', label: '客户', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1, group: 'basic' }, + { key: 'carrier_id', label: '船公司', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1, group: 'basic' }, + { key: 'etd', label: '预计离港日', type: 'date', write: 'direct', req: 0, qry: 1, list: 1, edit: 1, group: 'transport' }, + { key: 'load_port', label: '起运港', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1, group: 'transport' }, + { key: 'discharge_port', label: '目的港', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1, group: 'transport' }, + { key: 'freight_payment',label: '运费支付', type: 'varchar(32)', write: 'direct', req: 0, qry: 1, list: 1, edit: 1, group: 'transport' }, + { key: 'gross_weight', label: '毛重', type: 'decimal(18,3)', write: 'direct', req: 0, qry: 0, list: 1, edit: 1, group: 'cargo' }, + { key: 'volume', label: '体积', type: 'decimal(18,3)', write: 'direct', req: 0, qry: 0, list: 1, edit: 1, group: 'cargo' }, + { key: 'container_count',label: '箱量', type: 'int', write: 'computed', req: 0, qry: 0, list: 1, edit: 0, group: 'cargo' }, { key: 'status', label: '状态', type: 'varchar(32)', write: 'actionOnly', req: 0, qry: 1, list: 1, edit: 0 }, { key: 'remark', label: '备注', type: 'nvarchar(1000)', write: 'direct', req: 0, qry: 0, list: 0, edit: 1 }, { key: 'created_by', label: '创建人', type: 'nvarchar(128)', write: 'system', req: 0, qry: 0, list: 0, edit: 0 }, @@ -297,15 +297,27 @@ const ENTITY_FIELDS = { { key: 'vgm', label: 'VGM', type: 'decimal(18,3)', write: 'direct', req: 0, qry: 0, list: 1, edit: 1 }, ], 'finance.invoice': [ - { key: 'invoice_no', label: '发票号', type: 'varchar(50)', write: 'direct', req: 1, qry: 1, list: 1, edit: 0 }, - { key: 'direction', label: '方向', type: 'varchar(16)', write: 'createOnly', req: 1, qry: 1, list: 1, edit: 0 }, - { key: 'customer_id', label: '往来单位', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1 }, - { key: 'amount', label: '含税金额', type: 'decimal(18,2)', write: 'computed', req: 0, qry: 0, list: 1, edit: 0 }, - { key: 'currency', label: '币种', type: 'varchar(8)', write: 'direct', req: 1, qry: 1, list: 1, edit: 1 }, + { key: 'invoice_no', label: '发票号', type: 'varchar(50)', write: 'direct', req: 1, qry: 1, list: 1, edit: 0, group: 'basic' }, + { key: 'direction', label: '方向', type: 'varchar(16)', write: 'createOnly', req: 1, qry: 1, list: 1, edit: 0, group: 'basic' }, + { key: 'customer_id', label: '往来单位', type: 'bigint', write: 'direct', req: 1, qry: 1, list: 1, edit: 1, group: 'basic' }, + { key: 'amount', label: '含税金额', type: 'decimal(18,2)', write: 'computed', req: 0, qry: 0, list: 1, edit: 0, group: 'amount' }, + { key: 'currency', label: '币种', type: 'varchar(8)', write: 'direct', req: 1, qry: 1, list: 1, edit: 1, group: 'amount' }, { key: 'status', label: '状态', type: 'varchar(32)', write: 'actionOnly', req: 0, qry: 1, list: 1, edit: 0 }, ], }; +const ENTITY_GROUPS = { + 'ocean.booking': [ + { key: 'basic', name: '基本信息', sort: 0 }, + { key: 'transport', name: '运输信息', sort: 1 }, + { key: 'cargo', name: '货物信息', sort: 2 }, + ], + 'finance.invoice': [ + { key: 'basic', name: '基本信息', sort: 0 }, + { key: 'amount', name: '金额信息', sort: 1 }, + ], +}; + const ENTITY_RELATIONS = { 'ocean.booking': [ { key: 'ocean.booking.containers', type: 'one-to-many', target: 'ocean.container', ownership: 'composition', delete: 'cascade', save: 'with-parent' }, @@ -314,19 +326,6 @@ const ENTITY_RELATIONS = { ], }; -const ENTITY_VIEWS = { - 'ocean.booking': [ - { key: 'ocean.booking.default-list', queryable: 1, exportable: 1, pageSize: 50 }, - { key: 'ocean.booking.query-simple', queryable: 1, exportable: 1, pageSize: 20 }, - ], -}; -const ENTITY_FORMS = { - 'ocean.booking': [ - { key: 'ocean.booking.default-form', type: 'default', relations: ['ocean.booking.containers'] }, - { key: 'ocean.booking.readonly-form', type: 'readonly', relations: [] }, - ], -}; - /* ============ 状态与工具 ============ */ const state = { selectedModule: null, selectedMenu: null, selectedEntity: null, openModules: new Set(['ocean']) }; @@ -340,7 +339,11 @@ function findMenuByKey(k) { function menuOwner(k) { return MODULES.find(m => m.menus.some(mm => mm.key === k || (mm.children && mm.children.some(c => c.key === k)))); } -function entityTable(ek) { +function entityViewTable(ek) { + for (const m of MODULES) { const e = m.entities.find(x => x.key === ek); if (e) return e.view || e.table; } + return '—'; +} +function entitySaveTable(ek) { for (const m of MODULES) { const e = m.entities.find(x => x.key === ek); if (e) return e.table; } return '—'; } @@ -473,14 +476,14 @@ function renderModule() {
包含实体(s_module_entity)点击实体查看字段元数据
- + ${m.entities.map(e => ` + - `).join('')} @@ -517,10 +520,12 @@ function renderMenu() { const t = MENU_TYPES[menu.type]; const owner = menuOwner(menu.key); const entity = menu.entity ? { - key: menu.entity, table: entityTable(menu.entity), + key: menu.entity, + viewTable: entityViewTable(menu.entity), + saveTable: entitySaveTable(menu.entity), fields: ENTITY_FIELDS[menu.entity] ? ENTITY_FIELDS[menu.entity].length : 0, - views: ENTITY_VIEWS[menu.entity] ? ENTITY_VIEWS[menu.entity].length : 0, - forms: ENTITY_FORMS[menu.entity] ? ENTITY_FORMS[menu.entity].length : 0, + groups: ENTITY_GROUPS[menu.entity] ? ENTITY_GROUPS[menu.entity].length : 0, + rels: ENTITY_RELATIONS[menu.entity] ? ENTITY_RELATIONS[menu.entity].length : 0, } : null; return ` @@ -542,13 +547,12 @@ function renderMenu() { ${entity ? `
-
绑定的实体 / 视图 / 表单 data 类型
+
绑定的实体 查询走 view_table,保存走 save_table
实体 entity_key
-
物理表
${entity.table}
-
字段 / 视图 / 表单
${entity.fields} / ${entity.views} / ${entity.forms}
-
视图 key
${menu.view || '—'}
-
表单 key
${menu.form || '—'}
+
查询源 view_table
${entity.viewTable}${entity.viewTable !== entity.saveTable ? '(视图)' : ''}
+
保存目标 save_table
${entity.saveTable}
+
字段 / 分组 / 关系
${entity.fields} / ${entity.groups} / ${entity.rels}
` : ''} @@ -569,26 +573,50 @@ function renderEntity() { const ek = ent.key; const fields = ENTITY_FIELDS[ek] || []; const rels = ENTITY_RELATIONS[ek] || []; - const views = ENTITY_VIEWS[ek] || []; - const forms = ENTITY_FORMS[ek] || []; + const groups = ENTITY_GROUPS[ek] || []; + const viewTable = ent.view || ent.table; + const isView = !!ent.view; + const groupName = gk => (groups.find(g => g.key === gk) || {}).name || '未分组'; return `
-
${ent.desc} ${ent.policy}
+
${ent.desc} ${ent.policy}${isView ? ' 视图查询' : ''}
实体是数据和字段的所有者,字段挂实体(s_module_field.b_entity_key)。返回${mod.name} 模块。
-
entity_key: ${ek} · 物理表: ${ent.table} · module: ${mod.key}
+
entity_key: ${ek} · 查询源: ${viewTable} · 保存目标: ${ent.table} · module: ${mod.key}
-
字段元数据(s_module_field)写入模式 / 必填 / 查询 / 列表 / 编辑
+
查询 / 保存数据源 s_module_entity
+
+
查询源 view_table
${viewTable}${isView ? '(SQL 视图,带关联/聚合)' : ''}
+
保存目标 save_table
${ent.table}
+
主键字段 key_field
b_id
+
+
+ +
+
字段分组(s_module_field_group)分组独立定义,字段引用 group_key
+ ${groups.length ? `
实体 key物理表删除策略描述字段数
实体 key查询源 view_table保存目标 save_table删除策略字段数
${e.key}${e.view || e.table}${e.view ? '(视图)' : ''} ${e.table} ${e.policy}${e.desc} ${ENTITY_FIELDS[e.key] ? ENTITY_FIELDS[e.key].length : 0}
+ + ${groups.map(g => ` + + + + `).join('')} +
分组 key标题 name_key排序
${g.key}${g.name}${g.sort}
` : '
无分组(字段直接平铺)
'} +
+ +
+
字段元数据(s_module_field)写入模式 / 分组 / 必填 / 查询 / 列表 / 编辑
- + ${fields.map(f => ` + @@ -615,15 +643,6 @@ function renderEntity() { `).join('')}
字段 key标签数据类型写入模式必填查询列表编辑
字段 key标签数据类型写入模式分组必填查询列表编辑
${f.key} ${f.label} ${f.type} ${f.write}${f.group ? groupName(f.group) : '—'} ${f.req ? '必填' : '—'} ${f.qry ? '✓' : ''} ${f.list ? '✓' : ''}
` : '
无
'}
- -
-
视图与表单 一个实体可有多视图/多表单
-
-
视图 s_module_view
${views.map(v => v.key).join('、') || '—'}
-
表单 s_module_form
${forms.map(v => v.key).join('、') || '—'}
-
- ${forms.some(f => f.relations.length) ? `
主子表区域(s_module_form_relation):${forms.find(f => f.relations.length).relations.join('、')} 以 table 模式内嵌于表单
` : ''} -
`; }