Files
workspace/code/fms/字段权限与用户个性化设计.md
T
2026-09-07 22:45:21 +08:00

28 KiB
Raw Blame History

FMS 权限体系设计文档

1. 设计目标

本权限体系用于 FMS / ERP 元数据驱动架构,核心目标:

  1. 操作权限与数据权限分离。
  2. 权限直接绑定菜单、动作、模块、字段、页面、报表等资源。
  3. Power ID 不要求人工维护,直接由资源类型、资源 ID 和操作组成。
  4. 用户直接授权,不引入角色继承。
  5. 数据权限独立于菜单,不因为用户从哪个菜单进入而改变数据范围。
  6. 用户个性化设置不能突破权限。
  7. 权限默认拒绝(Default Deny)。

2. 权限模型总览

整个权限体系分为两条线:

        ┌──────────────┐
        │    资源定义   │
        └──────┬───────┘
               │
    ┌──────────┼──────────┐
    │          │          │
 菜单/动作   模块/字段   页面/报表
    │          │          │
    └──────────┼──────────┘
               ↓
            s_power
               ↓
         s_user_power
               ↓
          用户操作权限


        ┌──────────────┐
        │   数据模块    │
        └──────┬───────┘
               ↓
         s_user_data_scope
               ↓
       s_user_data_scope
               ↓
            数据范围

因此:

  • s_power:定义「能做什么」
  • s_user_power:定义「用户能做什么」
  • s_user_data_scope:定义「用户在某个模块、某个操作下可以作用于哪些数据」

3. Power ID 设计

3.1 核心原则

b_id 不再使用随机 ID,也不要求人工创建类似:

power_cw_fee_update
power_cw_fee_audit
power_cw_fee_amount_edit

而是直接使用稳定、可解析的权限编码。

统一格式:

menu.<MenuID>
action.<ActionID>
module.<ModuleID>.<Operation>
page.<PageID>
report.<ReportID>

3.2 Power ID 示例

菜单权限

menu.cw_fee

表示:可以进入 / 使用费用管理菜单。

动作权限

action.cw_fee_audit

表示:可以执行费用审核动作。

模块权限

module.cw_fee.read
module.cw_fee.create
module.cw_fee.update
module.cw_fee.delete
module.cw_fee.export

页面权限

page.cw_fee

报表权限

report.cw_fee_summary

4. Power 类型

b_power_type 用途 ID 格式
menu 菜单入口 menu.<MenuID>
action 业务动作 action.<ActionID>
module 数据模块操作 module.<ModuleID>.<Operation>
page 页面入口 page.<PageID>
report 报表入口 report.<ReportID>

5. 操作权限语义

5.1 menu

menu.cw_fee

用于判断用户是否拥有菜单入口权限。

菜单权限只解决:

  • 用户能不能进入这个菜单。

不负责:

  • 数据范围
  • 字段权限
  • 审核权限
  • 删除权限

5.2 action

例如:

action.cw_fee_audit
action.cw_fee_unaudit
action.cw_fee_writeoff

统一使用:

  • b_power_type = action
  • b_operation = execute

动作权限解决:用户能不能执行这个具体业务动作。

5.3 module

例如:

module.cw_fee.read
module.cw_fee.create
module.cw_fee.update
module.cw_fee.delete
module.cw_fee.export

模块权限解决:用户对该业务模块具有什么数据操作能力。

5.4 page

例如:

page.cw_fee

用于页面访问控制。

页面权限和菜单权限可以同时存在:

menu.cw_fee
page.cw_fee

菜单解决入口展示 / 进入菜单,页面解决具体页面访问。

5.5 report

例如:

report.cw_fee_summary

用于报表访问权限。

报表权限本身不等于数据权限。例如用户拥有 report.cw_fee_summary,还需要根据报表对应的数据模块执行数据范围控制。


6. 核心表结构

以下表结构暂时不加入索引、唯一约束、外键约束,后续根据实际运行情况再补充。

6.1 s_power

权限定义表。

create table dbo.s_power (
    b_id varchar(300) not null,

    b_name nvarchar(200) not null,
    b_i18n varchar(150) null,

    b_power_type varchar(20) not null,
    -- menu / action / module / page / report

    b_resource varchar(128) null,
    -- action / page / report 等资源 ID

    b_menu_id varchar(50) null,
    -- 所属菜单,主要用于 menu / action

    b_module_id varchar(50) null,
    -- 所属业务模块

    b_operation varchar(30) not null,
    -- menu/page/report: access
    -- action: execute
    -- module: read/create/update/delete/export

    b_canuse tinyint not null default 1,

    b_xh int not null default 0
);

b_id 示例:

menu.cw_fee
action.cw_fee_audit
module.cw_fee.read
module.cw_fee.update
page.cw_fee
report.cw_fee_summary

这里的 b_id 就是 Power 的业务编码。

不再需要 power_cw_fee_update、power_cw_fee_audit 这种额外编码。


7. s_user_power

用户权限授权表。

create table dbo.s_user_power (
    b_user_id varchar(50) not null,

    b_power_id varchar(300) not null,

    b_canuse tinyint not null default 1,

    b_updatedatetime datetime2 null
);

语义:

  • 存在有效记录 = 用户拥有权限
  • 不存在记录 = 用户没有权限
  • b_canuse = 0 = 当前授权无效

当前设计不增加 allow / deny,即采用:

默认拒绝,明确授权。


8. 数据权限

操作权限与数据权限必须分开。

例如:

module.cw_fee.read

只表示:用户具有读取费用数据的能力。

它并不表示:用户可以读取所有费用数据。

数据范围直接由 s_user_data_scope 控制。


9. s_user_data_scope

用户数据权限授权表。

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;default 使用 b_operation='*'

    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,

    b_updatedatetime datetime2 null
);

多个同级范围同时存在时:

Scope A OR Scope B OR Scope C

例如:

张三
cw_fee
* / read / update
    ├── department
    └── own

表示同一操作下多个范围按 OR 合并;具体操作没有 override 时回退到 b_operation='*' 的默认范围。


11. 完整示例

假设系统有:

  • 模块:cw_fee = 费用管理
  • 菜单:cw_fee = 费用管理
  • 动作:cw_fee_audit = 审核、cw_fee_unaudit = 反审核、cw_fee_writeoff = 核销
  • 字段:mx_amount = 金额

11.1 自动产生 Power

菜单:

menu.cw_fee

动作:

action.cw_fee_audit
action.cw_fee_unaudit
action.cw_fee_writeoff

模块:

module.cw_fee.read
module.cw_fee.create
module.cw_fee.update
module.cw_fee.delete
module.cw_fee.export

12. 用户授权示例

张三拥有:

  • menu.cw_fee
  • module.cw_fee.read
  • module.cw_fee.update
  • action.cw_fee_audit
insert into dbo.s_user_power (
    b_user_id,
    b_power_id,
    b_canuse
)
values
('zhangsan', 'menu.cw_fee', 1),
('zhangsan', 'module.cw_fee.read', 1),
('zhangsan', 'module.cw_fee.update', 1),
('zhangsan', 'action.cw_fee_audit', 1);

张三没有 module.cw_fee.delete,并且金额字段策略为 view,所以:

  • 不能删除费用
  • 不能修改金额字段

13. 数据范围示例

直接授权:

insert into dbo.s_user_data_scope (
    b_user_id,
    b_module_id,
    b_operation,
    b_scope_level,
    b_scope_no,
    b_scope_type,
    b_scope_field
)
values (
    'zhangsan',
    'cw_fee',
    '*',
    'default',
    1,
    'department',
    'b_department_id'
);

此时张三拥有 module.cw_fee.read,并且 read 数据范围回退为本部门。若再增加 update + override + own,则修改范围只限本人创建的数据。

最终不是「张三可以读取全部费用」,而是「张三可以读取自己有权限范围内的费用」。


14. 权限执行顺序

一个业务操作建议按照以下顺序判断:

① 用户是否有效
        ↓
② 菜单 / 页面入口权限
        ↓
③ Action 权限
        ↓
④ Module 数据操作权限
        ↓
⑤ Field 字段权限
        ↓
⑥ Data Scope 数据范围
        ↓
⑦ 业务状态 / 业务规则
        ↓
⑧ 执行操作

例如「审核费用」:

用户
 ↓
menu.cw_fee
 ↓
page.cw_fee
 ↓
action.cw_fee_audit
 ↓
module.cw_fee.update
 ↓
数据范围
 ↓
费用当前状态 = 送审
 ↓
执行审核

15. 不同权限解决不同问题

问题 权限
能不能看到菜单 menu.*
能不能进入页面 page.*
能不能执行审核 action.*
能不能修改费用 module.cw_fee.update
能不能看到金额 s_user_field_permission.b_access_mode in ('view','edit')
能不能修改金额 s_user_field_permission.b_access_mode = 'edit'
能不能查询金额 s_user_field_permission.b_allow_query = 1
能不能导出金额 s_user_field_permission.b_allow_export = 1
能不能看报表 report.*
能看哪些数据 s_user_data_scope

16. 与元数据体系的关系

Power 不应该成为另一套独立的资源体系,而应该从现有元数据自动生成。

s_menu
   ↓
menu.<MenuID>

Action 定义
   ↓
action.<ActionID>

s_module
   ↓
module.<ModuleID>.<Operation>

Page 定义
   ↓
page.<PageID>

Report 定义
   ↓
report.<ReportID>

因此新增模块 cw_air_fee,系统可以自动注册:

module.cw_air_fee.read
module.cw_air_fee.create
module.cw_air_fee.update
module.cw_air_fee.delete
module.cw_air_fee.export

新增字段 mx_tax 后,由模块字段元数据和用户字段策略直接控制,不生成 s_power 权限点。


17. 权限与用户个性化的关系

用户个性化配置(s_user_field_pref、s_user_query_field_pref)只能调整:

  • 显示
  • 排序
  • 宽度
  • 查询字段默认状态

不能增加权限。

最终优先级:

字段 b_canuse
        ↓
权限
        ↓
系统默认布局
        ↓
用户个性化

例如:用户字段策略为 hidden 时,即使 s_user_field_pref.b_visible = 1,也不能显示金额字段。


18. 最终推荐的核心关系

┌───────────────┐
│   s_module    │
└───────┬───────┘
        │
        ├──────────────┐
        ↓              ↓
   s_field
        │
        ├──────────────┐
        ↓              ↓
     s_power    s_user_data_scope
        │
        ↓
  s_user_power
        │
        ↓
      b_user

菜单和动作:

s_menu
   │
   ├── menu.<MenuID>
   │
   └── action.<ActionID>
          ↓
       s_power

页面和报表:

page / report
      ↓
   s_power

19. 最终结论

本设计的核心原则可以归纳为:

  • s_power.b_id 是内部主键,s_power.b_code 是系统生成的可读业务键;
  • 权限唯一性由资源类型、资源编码、owner 和能力字段共同保证;
  • 字段权限直接使用 s_user_field_permission 的访问策略;
  • 数据范围直接使用 s_user_data_scope,不再建立独立的范围模板表。

权限业务键示例:

menu.<MenuID>
action.<ActionID>
module.<ModuleID>.<Operation>
page.<PageID>
report.<ReportID>

其中:

  • s_power 是统一权限注册表。
  • s_user_power 是用户操作权限。
  • s_user_data_scope 是用户数据范围授权。
  • 操作权限和数据权限完全分离。
  • 菜单不负责数据范围。
  • 用户个性化不能突破权限。
  • 当前不引入角色继承。
  • 后续如果增加角色,可以在 s_user_power 之外增加角色授权层,而无需改变 Power 编码体系。

20. Demo 数据(4 张表)

以下为新权限模型的示例数据,沿用 cw_fee 费用模块。示例用户:张三(费用会计)、李四(财务经理)。数据范围直接保存在 s_user_data_scope,不再维护独立的范围模板表。

20.1 s_power(权限定义)

b_id b_code b_name b_power_type b_resource_id b_owner_type b_owner_id b_capability b_canuse b_xh
1001 menu.cw_fee.access 费用管理菜单 menu cw_fee null null access 1 10
1002 page.cw_fee.access 费用页面 page cw_fee null null access 1 20
1003 action.module.cw_fee.audit.execute 费用审核 action audit module cw_fee execute 1 30
1004 action.module.cw_fee.unaudit.execute 费用反审核 action unaudit module cw_fee execute 1 40
1005 module.cw_fee.read 费用读取 module cw_fee null null read 1 50
1006 module.cw_fee.create 费用新增 module cw_fee null null create 1 60
1007 module.cw_fee.update 费用修改 module cw_fee null null update 1 70
1008 module.cw_fee.delete 费用删除 module cw_fee null null delete 1 80
1009 module.cw_fee.export 费用导出 module cw_fee null null export 1 90
1010 report.cw_fee_summary.access 费用汇总报表 report cw_fee_summary null null access 1 100

b_id 是内部主键,b_code 是全局唯一业务键。动作的 b_resource_id 是动作编码,b_owner_type/b_owner_id 标识所属模块;因此不同模块可以同时拥有 audit 动作而不冲突。

20.2 s_user_power(用户授权)

b_user_id b_power_id b_canuse b_updatedatetime
zhangsan 1001 1 2026-02-01 09:00:00
zhangsan 1002 1 2026-02-01 09:00:00
zhangsan 1005 1 2026-02-01 09:00:00
zhangsan 1007 1 2026-02-01 09:00:00
zhangsan 1009 1 2026-02-01 09:00:00
zhangsan 1008 0 2026-02-10 14:30:00
zhangsan 1003 1 2026-02-01 09:00:00
zhangsan 1010 1 2026-02-01 09:00:00
lisi 1001 1 2026-01-15 10:00:00
lisi 1002 1 2026-01-15 10:00:00
lisi 1005 1 2026-01-15 10:00:00
lisi 1006 1 2026-01-15 10:00:00
lisi 1007 1 2026-01-15 10:00:00
lisi 1008 1 2026-01-15 10:00:00
lisi 1009 1 2026-01-15 10:00:00
lisi 1003 1 2026-01-15 10:00:00
lisi 1004 1 2026-01-15 10:00:00
lisi 1010 1 2026-01-15 10:00:00

张三的 1008 对应 module.cw_fee.delete,记录存在但已停用,因此仍然没有删除权限。

20.3 s_user_field_permission(字段访问策略)

b_user_id b_module_id b_field b_access_mode b_allow_query b_allow_export b_canuse
zhangsan cw_fee mx_amount view 1 0 1
zhangsan cw_fee mx_internal_cost hidden 0 0 1
lisi cw_fee mx_amount edit 1 1 1
lisi cw_fee mx_internal_cost view 1 0 1

张三对金额字段是“可见、只读、可查询、不可导出”;对内部成本字段完全不可见。李四可以编辑和导出金额,但内部成本字段仍然只读。

20.4 s_user_data_scope(用户数据范围授权)

b_user_id b_module_id b_operation b_scope_level b_scope_type b_scope_field b_scope_value b_scope_no b_updatedatetime
zhangsan cw_fee * default department b_department_id null 1 2026-02-01 09:00:00
zhangsan cw_fee update override own b_inputuser_id null 1 2026-02-01 09:00:00
lisi cw_fee * default department_tree b_department_id null 1 2026-01-15 10:00:00
lisi cw_fee delete override all null null 1 2026-01-15 10:00:00

要点:

  • 张三使用模块默认范围读取本部门数据,但 update 有操作级覆盖,只能修改本人录入的费用;
  • 李四使用默认范围处理一般操作,但 delete 有操作级覆盖为 all,经理可删全模块数据。

20.5 组合结果解读

能力 张三(费用会计) 李四(财务经理)
看菜单 / 页面 ✅ ✅
读取费用数据 ✅ 本部门 ✅ 本部门及下属部门
新增 ❌ 无 module.create ✅
修改 ✅ 仅本人录入的单据 ✅ 本部门及下属部门的单据
删除 ❌ 授权已停用(b_canuse=0) ✅ 全部数据
审核 / 反审核 ✅ 可审核,❌ 不可反审核 ✅ 都可以
金额字段 可见、只读、可查询、不可导出 可见、可编辑、可查询、可导出
内部成本字段 不可见 可见但只读
汇总报表 ✅ ✅(报表数据仍受 read 范围约束)

21. 权限模型重构(当前生效方案)

21.1 重构原因

旧方案有两个结构性问题:

  1. s_power.b_id 同时承担数据库主键和业务权限编码。权限编码一旦变化会影响授权记录;动作编码在不同菜单/模块下重复时,action.<ActionID> 也无法保证全局唯一。
  2. 字段权限被拆成多个彼此独立的 view/edit/query/export 权限点,不能直接表达“不可见”“可见但只读”“可见且可编辑”等实际权限状态,也容易出现 edit=1、view=0 这种无效组合。

新方案将“权限点身份”和“字段访问策略”分开:

  • s_power 只保存菜单、页面、报表、模块、动作等可执行能力;
  • s_user_field_permission 保存字段访问级别及查询/导出能力;
  • b_id 只做内部主键,业务侧使用不可变且全局唯一的 b_code;
  • 动作权限必须带上所属资源的命名空间,不再使用裸 action.<ActionID>。

21.2 s_power:内部主键与业务编码分离

create table dbo.s_power (
    b_id bigint not null,                 -- 内部主键,雪花/序列生成,不表达业务含义
    b_code varchar(300) not null,         -- 稳定、全局唯一的业务键,由系统生成
    b_name nvarchar(200) not null,
    b_i18n varchar(150) null,
    b_power_type varchar(20) not null,    -- menu/page/report/module/action
    b_resource_id varchar(128) not null,  -- 当前权限对应的资源编码
    b_owner_type varchar(20) null,        -- action 的 owner 类型
    b_owner_id varchar(128) null,         -- action 的 owner 编码
    b_capability varchar(30) not null,    -- access/execute/read/create/update/delete/export
    b_canuse tinyint not null default 1,
    b_xh int not null default 0,
    constraint PK_s_power primary key (b_id),
    constraint UQ_s_power_code unique (b_code),
    constraint CK_s_power_type check (b_power_type in ('menu','page','report','module','action')),
    constraint CK_s_power_shape check (
        (b_power_type in ('menu','page','report')
            and b_owner_type is null and b_owner_id is null
            and b_capability = 'access')
        or (b_power_type = 'module'
            and b_owner_type is null and b_owner_id is null
            and b_capability in ('read','create','update','delete','export'))
        or (b_power_type = 'action'
            and b_owner_type in ('menu','page','module')
            and b_owner_id is not null
            and b_capability = 'execute')
    )
);

create index IX_s_power_resource
    on dbo.s_power (b_power_type, b_owner_type, b_owner_id, b_resource_id, b_canuse);

b_code 是由结构化身份规范化生成的唯一键,不允许人工随意修改。资源编码应使用稳定的业务键(建议只允许字母、数字、_、-),更名应通过资源迁移完成,而不是直接改写已发布权限的身份。推荐格式:

menu.cw_fee.access
page.cw_fee.access
report.cw_fee_summary.access
module.cw_fee.read
action.module.cw_fee.audit.execute

动作至少包含 owner_type + owner_id + action_id 三段。两个模块都可以定义 audit,但它们会生成不同的 b_code。跨多个资源的动作必须为每个资源建立独立权限点,或指定明确的系统级 owner。

21.3 s_user_power:引用内部主键

create table dbo.s_user_power (
    b_user_id varchar(50) not null,
    b_power_id bigint not null,
    b_canuse tinyint not null default 1,
    b_updatedatetime datetime2 null,
    constraint PK_s_user_power 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);

授权、审计和关联查询使用 b_power_id;接口、缓存键、日志中需要可读标识时使用 s_power.b_code。权限名称或编码生成规则变化不会破坏数据库关联。

21.4 字段权限独立为访问策略

字段权限是有顺序的访问级别,不是四个互不相关的动作。新增用户字段策略表:

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,
    constraint PK_s_user_field_permission
        primary key (b_user_id, b_module_id, b_field),
    constraint CK_s_user_field_permission_mode
        check (b_access_mode in ('hidden','view','edit')),
    constraint CK_s_user_field_permission_capability
        check (b_access_mode <> 'hidden' or (b_allow_query = 0 and b_allow_export = 0))
);

create index IX_s_user_field_permission_module
    on dbo.s_user_field_permission (b_user_id, b_module_id, b_canuse, b_field);
b_access_mode 返回字段 页面显示 可编辑
hidden 否 否 否
view 是 是 否
edit 是 是 是

b_allow_query 和 b_allow_export 是附加能力,不能把 hidden 字段变成可查询或可导出字段。没有有效记录时按 hidden 处理。

系统元数据中的 s_field_view、s_field_edit、s_field_query 仍然只负责默认布局、只读、禁用和查询布局,不承担用户授权。最终字段状态按以下规则计算:

用户字段策略(hidden/view/edit)
    ↓
模块字段元数据:b_visible、b_readonly、b_disabled(只能收紧)
    ↓
业务状态与业务规则
    ↓
最终字段状态

因此 edit 遇到 b_readonly=1 或 b_disabled=1 时降为 view,b_visible=0 时最终为 hidden。用户个性化不能恢复 hidden 字段,也不能把 view 变成 edit。

21.5 字段授权示例

insert into dbo.s_user_field_permission
    (b_user_id, b_module_id, b_field, b_access_mode, b_allow_query, b_allow_export)
values
    ('zhangsan', 'cw_fee', 'mx_amount', 'view', 1, 0),
    ('lisi',     'cw_fee', 'mx_amount', 'edit', 1, 1);

写接口必须同时检查 module.<module>.update、字段最终为 edit、以及 update 数据范围。

21.6 权限判定顺序(重构后)

① 用户有效
② menu/page/report 入口权限(如适用)
③ action 权限(如适用)
④ module 操作权限
⑤ 字段策略:hidden / view / edit + query/export
⑥ 数据范围
⑦ 元数据只读/禁用、业务状态和业务规则
⑧ 执行操作

入口权限、模块权限、字段策略、数据范围是 AND 关系;同一用户多个数据范围仍按 OR 合并。

21.7 旧数据迁移规则

  1. 原 s_power.b_id 字符串迁移到新表的 b_code;新 b_id 重新生成,s_user_power.b_power_id 通过旧编码映射到新主键。
  2. 原 action.<ActionID> 根据 b_module_id 或菜单归属补全 owner,生成 action.<OwnerType>.<OwnerID>.<ActionID>.execute。无法唯一确定归属的记录不得自动合并。
  3. 原字段权限按用户、模块、字段聚合:有有效 edit 则为 edit,否则有有效 view 则为 view,否则为 hidden;query、export 映射到附加标志,并受 hidden 约束。
  4. 迁移完成后旧字段权限记录删除或归档,权限服务只读取新模型,避免新旧模型同时生效。

21.8 数据范围配置 UI:默认范围 + 操作级覆盖

数据范围底层仍按“模块 + 操作”保存,但管理界面不要求管理员一开始就配置每个操作。采用两层配置:

默认配置

用户选择一个模块后,先设置一个默认数据范围:

默认数据范围:仅本人 / 仅本部门 / 本部门及下属 / 全部 / 自定义

默认范围应用于该模块所有需要数据过滤的操作。底层只保存一条模块默认记录:

* -> 默认范围

对于不适用的操作(例如用户没有 module.<module>.delete),不生成数据范围记录也不会产生权限。

操作级覆盖

在默认范围旁提供“按操作单独设置”入口。管理员展开后,可以针对具体操作覆盖默认值:

查询 read   :跟随默认范围 = 本部门
新增 create :跟随默认范围
修改 update :仅本人
删除 delete :无权限或不配置
导出 export :跟随默认范围 = 本部门

操作级覆盖只改变该操作的数据过滤条件,不会授予操作权限。用户仍然必须拥有对应的 s_power 权限。

保存与读取规则

s_user_data_scope 使用来源标识和通配操作,区分默认值和覆盖值:

b_scope_level varchar(10) not null default 'default'
-- default = 来自模块默认范围
-- override = 操作级覆盖

b_operation = '*'
-- 仅 default 级别允许使用 '*'

同一用户、模块、操作最多保留一组生效配置:

  • 没有具体操作的 override 记录时,运行时回退到 b_operation='*' 的 default 范围;
  • 存在 override 记录时,只对该操作使用覆盖范围;
  • 一个操作可以配置多条范围,多条范围之间仍按 OR 合并;
  • UI 中的“无权限”表示不生成该操作的范围,同时仍以 s_user_power 为最终操作权限判断依据。

典型示例

管理员只配置:

cw_fee 默认数据范围 = 本部门

然后展开操作级配置,将修改覆盖为“仅本人”:

s_user_data_scope
    cw_fee + *      + department       (default)
    cw_fee + update + own              (override)

最终效果就是:张三可以查询和导出本部门费用,但只能修改本人创建的费用。这个例子也是保留操作级数据范围能力的主要原因。