Files
workspace/code/fms/FMS新系统核心表结构设计.md
T
2026-09-08 22:39:22 +08:00

20 KiB
Raw Blame History

FMS 新系统核心表结构

目标结构基于 2026-09-04 只读拉取的 FMS-NEW 数据库整理。 平台配置使用字符串业务键;未来业务数据表使用 bigint 雪花 ID。

0. SQL 驱动与动态配置

本系统是 SQL 驱动的内部 ERP。能通过 SQL 完成的查询、关联、过滤、排序、分页、聚合、权限过滤和数据范围过滤,优先在 SQL 层完成,不在业务代码中加载大量数据后再处理。

  • 模块、字段、查询条件、排序、字段权限和数据范围等规则,优先从本文件定义的配置表读取,由通用查询逻辑动态生成 SQL;
  • 动态 SQL 的表名、字段名和操作符只能来自受控的模块元数据、字段定义和白名单,业务值使用参数传递;
  • 配置驱动的动态 SQL 不等于保存任意 SQL 字符串。不得把未审查的前端字符串或整段 SQL 直接保存后执行;
  • 固定 SQL 仅用于稳定且明确的特殊业务逻辑,且应保持通用,不为单个页面或单个用户复制一套查询接口;
  • 前端权限控制只负责界面展示,模块操作、字段访问和数据范围必须在后端查询或写入 SQL 中落实;用户个性化只能调整布局,不能放宽权限。

1. 用户表

create table dbo.b_user (
    b_id varchar(50) not null primary key, -- 用户账号本身
    b_name nvarchar(100) null,
    b_bz nvarchar(400) null,
    b_password nvarchar(255) not null,
    b_canuse tinyint not null default 1,
    b_logintime tinyint not null default 0
);

2. 模块

create table dbo.s_module (
    b_id varchar(50) not null primary key, -- 模块编码本身,创建后不可修改
    b_parent_id varchar(50) null,
    b_name nvarchar(200) not null,
    b_i18n varchar(150) null,
    b_module_type varchar(20) not null,
    b_viewtable varchar(128) null,
    b_savetable varchar(128) null,
    b_keyfield varchar(50) null,
    b_orderfield varchar(500) null,
    b_delete_policy varchar(20) null,
    b_canuse tinyint not null default 1,
    b_xh int not null default 0,
    b_bz nvarchar(2000) null,
    b_edit_mode varchar(10) null
);

create index ix_s_module_parent
    on dbo.s_module (b_parent_id, b_xh, b_canuse, b_id);

create index ix_s_module_order
    on dbo.s_module (b_xh, b_id);

create index ix_s_module_savetable
    on dbo.s_module (b_savetable);

3. 字段和字段布局

状态字段统一使用 tinyint 保存 0/1,由业务层负责校验取值。b_canuse 表示记录或配置是否启用、是否参与运行;b_visible 表示当前列表或编辑场景是否展示,二者语义不同,不互相替代。

create table dbo.s_field (
    b_module_id varchar(50) not null,
    b_field varchar(50) not null,
    b_name nvarchar(200) not null,
    b_i18n varchar(150) null,
    b_type varchar(30) not null,
    b_dbtype varchar(30) not null,
    b_length int null,
    b_precision int null,
    b_scale int null,
    b_nullable tinyint not null default 1,
    b_default_value nvarchar(1000) null,
    b_db_default nvarchar(1000) null,
    b_writemode varchar(20) not null default 'direct',
    b_options nvarchar(max) null,
    b_canuse tinyint not null default 1,
    b_xh int not null default 0, -- 字段定义顺序:模块「同步字段」时按查询视图列序(10 起步)重排
    primary key (b_module_id, b_field)
);

create index ix_s_field_module_order
    on dbo.s_field (b_module_id, b_xh, b_field);

create table dbo.s_field_group (
    b_id varchar(50) not null, -- 分组编码本身,模块内唯一,创建后不可修改
    b_module_id varchar(50) not null,
    b_parent_id varchar(50) null, -- 父分组编码,NULL 表示根分组
    b_title nvarchar(200) not null,
    b_i18n varchar(150) null,
    b_xh int not null default 0,
    b_canuse tinyint not null default 1,
    b_colspan int not null default 48,
    b_layout_direction varchar(10) null default 'vertical',
    primary key (b_module_id, b_id)
);

create index ix_s_field_group_parent
    on dbo.s_field_group (b_module_id, b_parent_id, b_xh, b_id);

create index ix_s_field_group_order
    on dbo.s_field_group (b_module_id, b_xh, b_id);

create table dbo.s_field_view (
    b_module_id varchar(50) not null,
    b_field varchar(50) not null,
    b_group_id varchar(50) null, -- 引用同模块 s_field_group.b_id
    b_visible tinyint not null default 1,
    b_xh int not null default 0,
    b_width int null,
    primary key (b_module_id, b_field)
);

create index ix_s_field_view_order
    on dbo.s_field_view (b_module_id, b_xh, b_field);

create table dbo.s_field_edit (
    b_module_id varchar(50) not null,
    b_field varchar(50) not null,
    b_group_id varchar(50) null, -- 引用同模块 s_field_group.b_id
    b_visible tinyint not null default 1,
    b_required tinyint not null default 0,
    b_readonly tinyint not null default 0,
    b_disabled tinyint not null default 0,
    b_xh int not null default 0,
    b_width int null,
    b_placeholder nvarchar(400) null,
    b_colspan int not null default 12,
    b_height int null,
    primary key (b_module_id, b_field)
);

create index ix_s_field_edit_order
    on dbo.s_field_edit (b_module_id, b_xh, b_field);

create table dbo.s_field_query (
    b_module_id varchar(50) not null,
    b_field varchar(50) not null,
    b_component varchar(30) null,
    b_condition_no int not null default 1,
    b_operator varchar(20) not null,
    b_default_value nvarchar(1000) null,
    b_canuse tinyint not null default 1,
    b_xh int not null default 0,
    primary key (b_module_id, b_field, b_condition_no)
);

create index ix_s_field_query_order
    on dbo.s_field_query (b_module_id, b_xh, b_field, b_condition_no);

4. 用户个性化

用户个性化只作用于列表布局和普通查询收起态,不改变模块级默认配置。权限过滤优先于个人偏好,个人偏好不能越过字段权限或字段 b_canuse 限制。

create table dbo.s_user_field_pref (
    b_user_id varchar(50) not null,
    b_module_id varchar(50) not null,
    b_field varchar(50) not null,
    b_mode varchar(10) not null, -- 'view' 查看列表 / 'edit' 可编辑列表
    b_visible tinyint not null default 1,
    b_xh int not null default 0,
    b_width int null,
    b_updatedatetime datetime2 null,
    primary key (b_user_id, b_module_id, b_field, b_mode)
);

create index ix_s_user_field_pref_order
    on dbo.s_user_field_pref (b_user_id, b_module_id, b_mode, b_xh, b_field);

create table dbo.s_user_query_field_pref (
    b_user_id varchar(50) not null,
    b_module_id varchar(50) not null,
    b_field varchar(50) not null,
    b_quick_visible tinyint not null default 1, -- 普通查询收起态是否显示
    b_xh int not null default 0,                -- 普通查询字段顺序
    b_updatedatetime datetime2 null,
    primary key (b_user_id, b_module_id, b_field)
);

create index ix_s_user_query_field_pref_order
    on dbo.s_user_query_field_pref (b_user_id, b_module_id, b_xh, b_field);

说明:

  • s_user_field_pref 的 b_mode 区分查看列表和可编辑列表两套个人布局;
  • s_user_query_field_pref 不区分普通查询/高级查询模式,因为两者使用同一批查询字段;
  • 查询偏好只影响普通查询收起态,展开态和高级查询仍展示所有有权限且启用的查询字段;
  • 没有个人偏好时回落到对应的 s_field_view / s_field_edit / s_field_query 默认配置;
  • “恢复默认”删除当前用户、当前模块对应的个人偏好记录。

5. 自动编码

create table dbo.s_autocode (
    b_module_id varchar(50) not null,
    b_field varchar(50) not null,
    b_prefix nvarchar(200) not null default N'',
    b_dateformat varchar(30) not null default 'yyyyMM',
    b_separator nvarchar(20) not null default N'-',
    b_seqwidth int not null default 5,
    b_resettype varchar(10) not null default 'month',
    b_startvalue bigint not null default 1,
    b_currentperiod varchar(8) null,
    b_currentvalue bigint not null default 0,
    b_canuse tinyint not null default 1,
    primary key (b_module_id, b_field)
);

6. 模块关系

create table dbo.s_relation (
    b_module_id varchar(50) not null,
    b_target_module_id varchar(50) not null,
    b_relation_type varchar(20) not null,
    b_field varchar(50) not null,
    b_target_field varchar(50) not null,
    b_foreign_side varchar(10) null,
    b_junction_module_id varchar(50) null,
    b_junction_field varchar(50) null,
    b_junction_target_field varchar(50) null,
    b_ownership varchar(20) not null default 'reference',
    b_owner_side varchar(10) null,
    b_delete_policy varchar(20) null,
    b_order_module_id varchar(50) null,
    b_order_field varchar(50) null,
    b_canuse tinyint not null default 1,
    b_xh int not null default 0,
    primary key (b_module_id, b_field, b_target_module_id, b_target_field)
);

create index ix_s_relation_module
    on dbo.s_relation (b_module_id, b_canuse, b_xh, b_field, b_target_module_id);

create index ix_s_relation_target
    on dbo.s_relation (b_target_module_id);

7. 菜单

create table dbo.s_menu (
    b_id varchar(50) not null primary key, -- 菜单编码本身
    b_parent_id varchar(50) null,
    b_name nvarchar(200) not null,
    b_i18n varchar(150) null,
    b_menu_type varchar(20) not null,
    b_route varchar(200) null,
    b_module_id varchar(50) null,
    b_icon varchar(50) null,
    b_xh int not null default 0,
    b_canuse tinyint not null default 1
);

create index ix_s_menu_parent
    on dbo.s_menu (b_parent_id, b_xh, b_canuse, b_id);

create index ix_s_menu_order
    on dbo.s_menu (b_xh, b_id);

create index ix_s_menu_module
    on dbo.s_menu (b_module_id);

create index ix_s_menu_route
    on dbo.s_menu (b_route, b_canuse, b_id);

8. 权限

权限直接授予用户,不引入角色继承。s_power.b_id 是权限编码本身(业务键即主键),格式 类型.对象[.能力],例如 menu.cw_fee、module.cw_fee、action.cw_fee.audit;完整规范见《字段权限与用户个性化设计.md》「权限编码规范」。字段授权使用独立的字段访问策略表。

create table dbo.s_power (
    b_id varchar(100) not null,           -- 权限编码即主键:menu.cw_fee / module.cw_fee / action.cw_fee.audit
    b_name nvarchar(200) not null,
    b_i18n varchar(150) null,
    b_power_type varchar(20) not null,    -- page/menu/module/action/report
    b_owner_type varchar(20) not null,    -- 归属对象类型:page/menu/module/report;action 时为所属模块或页面
    b_owner_id varchar(50) not null,      -- 归属对象编码:菜单/模块/页面/报表编码
    b_capability varchar(30) null,        -- action 的操作或动作编码:create/update/delete/export/audit...;入口类为 null
    b_operation varchar(30) null,         -- 兼容列:access/execute,由 b_power_type 派生
    b_canuse tinyint not null default 1,
    b_xh int not null default 0,
    primary key (b_id)
);

create index ix_s_power_owner
    on dbo.s_power (b_power_type, b_owner_type, b_owner_id, b_capability, b_canuse);

create table dbo.s_user_power (
    b_user_id varchar(50) not null,
    b_power_id varchar(100) not null,     -- s_power.b_id,即权限编码
    b_canuse tinyint not null default 1,
    b_updatedatetime datetime2 null,
    primary key (b_user_id, b_power_id)
);

create index ix_s_user_power_user
    on dbo.s_user_power (b_user_id, b_canuse, b_power_id);

create table dbo.s_user_field_permission (
    b_user_id varchar(50) not null,
    b_module_id varchar(50) not null,
    b_field varchar(128) not null,
    b_access_mode varchar(10) not null,   -- hidden / view / edit
    b_allow_query tinyint not null default 0,
    b_allow_export tinyint not null default 0,
    b_canuse tinyint not null default 1,
    b_updatedatetime datetime2 null,
    primary key (b_user_id, b_module_id, b_field)
);

create index ix_s_user_field_permission_module
    on dbo.s_user_field_permission (b_user_id, b_module_id, b_canuse, b_field);

create table dbo.s_user_data_scope (
    b_user_id varchar(50) not null,
    b_module_id varchar(50) not null,
    b_operation varchar(30) not null, -- * / read / create / update / delete / export;* 表示模块默认范围
    b_scope_level varchar(10) not null default 'default', -- default / override
    b_scope_no int not null default 1,
    b_scope_type varchar(30) not null, -- own / department / department_tree / all / custom
    b_scope_field varchar(50) null,     -- 业务数据中的归属用户/部门字段
    b_scope_value varchar(100) null,    -- custom 时每个用户/部门值一行
    b_updatedatetime datetime2 null,
    primary key (b_user_id, b_module_id, b_operation, b_scope_level, b_scope_no),
    constraint ck_s_user_data_scope_level check (b_scope_level in ('default','override')),
    constraint ck_s_user_data_scope_operation check (
        (b_scope_level = 'default' and b_operation = '*')
        or (b_scope_level = 'override' and b_operation in ('read','create','update','delete','export'))
    )
);

create index ix_s_user_data_scope_module
    on dbo.s_user_data_scope (b_user_id, b_module_id, b_operation, b_scope_level, b_scope_type);

权限点约定:

  • page.<页面编码> / menu.<菜单编码> / report.<报表编码>:入口访问权限,报表列表中的每个报表可作为一个资源;
  • module.<模块编码>:模块访问(≈ read,能否查看该模块数据);
  • action.<模块编码>.<操作或动作>:数据操作(create / update / delete / export)与业务动作(audit / settle 等)统一为动作权限;
  • s_user_field_permission:字段 hidden/view/edit 访问级别,以及独立的查询/导出能力;
  • b_power_type 和 b_capability 是可扩展编码,新增资源类型不新增权限表,但需要补充权限定义和前端/后端校验规则;
  • 动作必须带所属模块命名空间,例如 action.cw_fee.audit,不得使用裸 action.audit;动作归属模块而非菜单,避免同一个动作在不同菜单下被重复配置。

权限计算约定:

  • 入口权限默认拒绝:page.*、menu.*、report.* 与 action.* 必须存在有效的 s_user_power 授权记录;停用的权限点或授权记录不生效;
  • 模块操作 action.<模块编码>.<操作> 在没有授权记录时默认放行还是默认拒绝尚未最终确定,见《字段权限与用户个性化设计.md》「待确认事项」第 1 条;s_power 权限点或用户授权记录存在 b_canuse = 0 时视为明确禁用;
  • 字段没有有效用户策略记录时不增加限制,按 s_field、s_field_view、s_field_edit、s_field_query 等模块默认配置执行;有效的 s_user_field_permission 只能收紧权限;hidden 表示不可见,view 表示可见只读,edit 表示可见可编辑;
  • hidden 字段不可查询、不可导出;b_allow_query / b_allow_export 不能突破字段访问级别;
  • 模块数据操作权限与数据范围同时生效:先判断操作权限,再按 s_user_data_scope 限制数据行;数据范围没有配置时视为 all;
  • 数据范围优先使用当前操作的 override,没有 override 时使用 operation = '*' 的 default;同一层级的多条范围按 OR 合并;
  • read、export、update、delete 在 SQL 行条件中应用数据范围;create 在写入前校验新增数据是否符合数据范围;
  • 菜单/页面/报表访问权限只控制入口和访问,不能替代模块、字段或数据范围权限。

9. 多语言

-- b_i18n / b_key 保存完整资源键,不追加 .name 或 .title 后缀:
-- s_module.b_i18n      = module.<module_id>
-- s_field.b_i18n      = field.<module_id>.<b_field>
-- s_field_group.b_i18n = field_group.<module_id>.<b_id>
-- s_menu.b_i18n       = menu.<b_id>

create table dbo.s_i18n_type (
    b_id varchar(20) not null primary key, -- 语言编码本身
    b_name nvarchar(200) not null,
    b_canuse tinyint not null default 1,
    b_default tinyint not null default 0,
    b_xh int not null default 0
);

create table dbo.s_i18n (
    b_id varchar(200) not null primary key, -- b_key + ':' + b_locale
    b_key varchar(150) not null,
    b_locale varchar(20) not null,
    b_value nvarchar(1000) not null,
    b_i18ntype varchar(20) null,
    b_canuse tinyint not null default 1,
    b_module_id varchar(50) null,
    unique (b_key, b_locale)
);

create index ix_s_i18n_module_key
    on dbo.s_i18n (b_module_id, b_key, b_locale);

create index ix_s_i18n_locale
    on dbo.s_i18n (b_locale, b_canuse);

10. 日志

日志主键由业务层统一生成 UUIDv7。UUID 主键使用非聚集索引;技术、登录、审计日志按发生时间建立聚集索引,审计字段明细按审计事件建立聚集索引。日志顺序以 b_occurdatetime 为准,不依赖 UUID 排序。

create table dbo.s_log_technical (
    b_id uniqueidentifier not null, -- 业务层生成的 UUIDv7
    b_user_id varchar(50) null, -- 稳定用户/账号标识;未认证请求时为 NULL
    b_sourcetype varchar(20) null,
    b_loglevel varchar(16) not null,
    b_logcategory varchar(64) null,
    b_operation varchar(100) null,	
    b_module_id varchar(50) null,
    b_request_id varchar(64) null,
    b_trace_id varchar(64) null,
    b_server_node varchar(128) null,
    b_duration_ms bigint null,
    b_result_code varchar(50) null,
    b_error_code varchar(50) null,
    b_error_message nvarchar(4000) null,
    b_exception_text nvarchar(max) null,
    b_context_text nvarchar(max) null,
    b_occurdatetime datetime2 default sysutcdatetime(),
    constraint pk_s_log_technical primary key nonclustered (b_id)
);

create table dbo.s_log_login (
    b_id uniqueidentifier not null, -- 业务层生成的 UUIDv7
    b_user_id varchar(50) null, -- 当前系统中账号即用户稳定标识;登录失败且账号不存在时为 NULL
    b_login_type varchar(20) not null,
    b_login_result tinyint not null default 0,
    b_fail_reason nvarchar(400) null,
    b_ip varchar(50) null,
    b_ip_location nvarchar(400) null,
    b_browser varchar(100) null,
    b_browser_version varchar(50) null,
    b_os varchar(100) null,
    b_os_version varchar(50) null,
    b_device_type varchar(20) null,
    b_user_agent nvarchar(max) null,
    b_session_id varchar(50) null,
    b_request_id varchar(64) null,
    b_trace_id varchar(64) null,
    b_occurdatetime datetime2 default sysutcdatetime(),
    constraint pk_s_log_login primary key nonclustered (b_id)
);

create table dbo.s_log_audit (
    b_id uniqueidentifier not null, -- 业务层生成的 UUIDv7
    b_event_code varchar(50) not null,
    b_module_id varchar(50) null,
    b_data_id varchar(50) null,
    b_business_no varchar(50) null,
    b_operation varchar(100) null,
    b_operator_id varchar(50) null,
    b_operator_name nvarchar(200) null,
    b_source_type varchar(20) not null default 'user',
    b_visibility varchar(20) not null default 'internal',
    b_request_id varchar(64) null,
    b_trace_id varchar(64) null,
    b_payload_text nvarchar(max) null,
    b_occurdatetime datetime2 default sysutcdatetime(),
    constraint pk_s_log_audit primary key nonclustered (b_id)
);

create table dbo.s_log_audit_field (
    b_id uniqueidentifier not null, -- 业务层生成的 UUIDv7
    b_event_id uniqueidentifier not null,
    b_module_id varchar(50) null,
    b_data_id varchar(50) null,
    b_field varchar(50) not null,
    b_field_label nvarchar(200) null,
    b_before_value nvarchar(max) null,
    b_after_value nvarchar(max) null,
    b_before_display nvarchar(1000) null,
    b_after_display nvarchar(1000) null,
    b_visibility varchar(20) not null default 'internal',
    constraint pk_s_log_audit_field primary key nonclustered (b_id)
);

create clustered index cx_s_log_technical_occur
    on dbo.s_log_technical (b_occurdatetime, b_id);

create clustered index cx_s_log_login_occur
    on dbo.s_log_login (b_occurdatetime, b_id);

create clustered index cx_s_log_audit_occur
    on dbo.s_log_audit (b_occurdatetime, b_id);

create clustered index cx_s_log_audit_field_event
    on dbo.s_log_audit_field (b_event_id, b_id);

create index ix_s_log_technical_trace
    on dbo.s_log_technical (b_trace_id, b_occurdatetime);

create index ix_s_log_login_user
    on dbo.s_log_login (b_user_id, b_occurdatetime);

create index ix_s_log_audit_module
    on dbo.s_log_audit (b_module_id, b_data_id, b_occurdatetime);

11. 业务表主键约定

create table dbo.b_example (
    b_id bigint not null primary key, -- 应用层雪花 ID
    b_inputuser_id varchar(50) null,  -- 引用 b_user.b_id
    b_inputdatetime datetime2 default sysutcdatetime()
);