253 lines
9.3 KiB
Markdown
253 lines
9.3 KiB
Markdown
# FMS 权限与功能实例简化设计
|
|
|
|
## 1. 设计原则
|
|
|
|
- 客户按菜单查找功能,但权限不绑定菜单位置。
|
|
- `s_feature` 表示客户能理解的业务功能或页面区域,是入口和显示权限边界。
|
|
- `s_module` 是技术数据对象,负责字段、数据范围和默认数据能力,不直接出现在客户菜单树中。
|
|
- 同一模块被多个功能使用时,模块默认能力只配置一次。
|
|
- 某个功能使用同一模块但权限更严时,增加功能-模块例外,只能收紧,不能扩大权限。
|
|
- 同一物理表但业务语义、字段或数据范围完全不同,拆成不同逻辑模块。
|
|
- 公共 Vue 页面、路由和组件可以复用,但不同业务场景使用不同 `s_feature`。
|
|
|
|
## 2. 对象关系
|
|
|
|
```text
|
|
菜单(既有表)
|
|
└── 引用 s_feature.b_code,只负责导航
|
|
|
|
s_feature
|
|
└── 技术配置:使用哪些 s_module、模板、页面区域或报表卡片
|
|
|
|
s_module
|
|
└── 字段、默认数据能力、默认数据范围
|
|
|
|
s_power
|
|
├── feature.* 功能入口、区域/卡片显示、功能专属动作
|
|
└── module.* 模块默认数据能力
|
|
|
|
s_user_power
|
|
└── 用户对 feature.* / module.* 的授权
|
|
|
|
s_user_feature_module_override
|
|
└── 某用户在某功能使用某模块时的收紧例外
|
|
```
|
|
|
|
## 3. 表结构
|
|
|
|
### 3.1 s_feature(业务功能实例)
|
|
|
|
```sql
|
|
create table dbo.s_feature (
|
|
b_code varchar(100) not null,
|
|
b_name nvarchar(200) not null,
|
|
b_feature_type varchar(20) not null, -- page / panel / report_card
|
|
b_parent_code varchar(100) null,
|
|
b_template_code varchar(100) null,
|
|
b_canuse tinyint not null default 1,
|
|
b_xh int not null default 0,
|
|
primary key (b_code)
|
|
);
|
|
```
|
|
|
|
菜单、模块及功能-模块关系属于既有技术配置表,本文件只约定语义,不重复定义其表结构。
|
|
|
|
### 3.2 s_power(权限点)
|
|
|
|
```sql
|
|
create table dbo.s_power (
|
|
b_code varchar(180) not null,
|
|
b_scope_type varchar(20) not null, -- feature / module
|
|
b_scope_code varchar(100) not null, -- feature_code 或 module_id
|
|
b_name nvarchar(200) not null,
|
|
b_capability varchar(30) not null, -- access/read/create/update/delete/export/业务动作
|
|
b_i18n varchar(220) null,
|
|
b_canuse tinyint not null default 1,
|
|
b_xh int not null default 0,
|
|
primary key (b_code)
|
|
);
|
|
```
|
|
|
|
业务层校验 `b_code`、`b_scope_type`、`b_scope_code` 和 `b_capability` 的组合关系。权限编码由系统生成,创建后不可修改。
|
|
|
|
### 3.3 s_user_power(用户默认授权)
|
|
|
|
```sql
|
|
create table dbo.s_user_power (
|
|
b_user_id varchar(50) not null,
|
|
b_power_code varchar(180) not null,
|
|
b_canuse tinyint not null default 1,
|
|
b_updatedatetime datetime2 null,
|
|
primary key (b_user_id, b_power_code),
|
|
foreign key (b_power_code) references dbo.s_power(b_code)
|
|
);
|
|
```
|
|
|
|
### 3.4 s_user_feature_module_override(功能-模块收紧例外)
|
|
|
|
```sql
|
|
create table dbo.s_user_feature_module_override (
|
|
b_user_id varchar(50) not null,
|
|
b_feature_code varchar(100) not null,
|
|
b_module_id varchar(50) not null,
|
|
b_capability varchar(30) not null, -- read/create/update/delete/export
|
|
b_canuse tinyint not null default 0, -- 0 表示在该场景禁止
|
|
b_updatedatetime datetime2 null,
|
|
primary key (b_user_id, b_feature_code, b_module_id, b_capability)
|
|
);
|
|
```
|
|
|
|
该表只保存例外限制,不保存默认允许记录,也不能用于突破 `s_user_power` 的模块权限。
|
|
|
|
字段和数据范围仍按逻辑模块配置:
|
|
|
|
```text
|
|
s_user_field_permission(user_id, module_id, field, ...)
|
|
s_user_data_scope(user_id, module_id, operation, ...)
|
|
```
|
|
|
|
如果某功能需要不同字段或数据范围,可将例外表扩展为功能-模块维度;仍只允许收紧权限。
|
|
|
|
## 4. 权限计算
|
|
|
|
### 4.1 入口和显示
|
|
|
|
```text
|
|
页面进入 = feature.<page>.access
|
|
页面区域显示 = 父页面已进入 + feature.<panel>.access
|
|
报表卡片显示 = 父看板已进入 + feature.<report_card>.access
|
|
```
|
|
|
|
### 4.2 模块操作
|
|
|
|
```text
|
|
模块读取 = feature.access + module.<module>.read
|
|
模块新增 = feature.access + module.<module>.create
|
|
模块修改 = feature.access + module.<module>.update
|
|
模块删除 = feature.access + module.<module>.delete
|
|
模块导出 = feature.access + module.<module>.export
|
|
```
|
|
|
|
如果存在 `s_user_feature_module_override` 对应的禁止记录,则该功能场景下的能力被收紧。
|
|
|
|
```text
|
|
最终模块能力 = 功能入口 ∩ 用户模块能力 ∩ 功能-模块例外
|
|
```
|
|
|
|
### 4.3 功能专属动作
|
|
|
|
审核、反审核、核销等不属于通用 CRUD 的动作,直接绑定功能实例:
|
|
|
|
```text
|
|
feature.sea_detail.audit
|
|
feature.cw_fee_list.settle
|
|
```
|
|
|
|
## 5. Demo 数据
|
|
|
|
### 5.1 功能实例
|
|
|
|
| b_code | b_name | b_feature_type | b_parent_code | b_template_code |
|
|
| --- | --- | --- | --- | --- |
|
|
| sea_detail | 海运详细 | page | null | DetailPage |
|
|
| sea_detail_container | 海运详细-装箱区域 | panel | sea_detail | DetailPanel |
|
|
| container_query | 装箱查询 | page | null | CommonListPage |
|
|
| cw_fee_list | 费用列表 | page | null | CommonListPage |
|
|
| finance_dashboard | 财务看板 | page | null | DashboardPage |
|
|
| ar_aging_card | 应收账龄 | report_card | finance_dashboard | ReportCard |
|
|
|
|
### 5.2 功能使用的模块
|
|
|
|
| b_feature_code | b_module_id | b_usage_type | b_required |
|
|
| --- | --- | --- | ---: |
|
|
| sea_detail | sea_main | main | 1 |
|
|
| sea_detail | cw_fee | detail | 0 |
|
|
| sea_detail_container | container_main | detail | 0 |
|
|
| container_query | container_main | main | 1 |
|
|
| cw_fee_list | cw_fee | main | 1 |
|
|
| ar_aging_card | finance_main | source | 1 |
|
|
|
|
### 5.3 权限点
|
|
|
|
| b_code | b_scope_type | b_scope_code | b_capability | b_name |
|
|
| --- | --- | --- | --- | --- |
|
|
| feature.sea_detail.access | feature | sea_detail | access | 进入海运详细 |
|
|
| feature.sea_detail.audit | feature | sea_detail | audit | 海运审核 |
|
|
| feature.sea_detail_container.access | feature | sea_detail_container | access | 显示装箱区域 |
|
|
| feature.container_query.access | feature | container_query | access | 进入装箱查询 |
|
|
| feature.cw_fee_list.access | feature | cw_fee_list | access | 进入费用列表 |
|
|
| feature.finance_dashboard.access | feature | finance_dashboard | access | 进入财务看板 |
|
|
| feature.ar_aging_card.access | feature | ar_aging_card | access | 显示应收账龄 |
|
|
| feature.ar_aging_card.export | feature | ar_aging_card | export | 导出应收账龄 |
|
|
| module.sea_main.read | module | sea_main | read | 查看海运主表 |
|
|
| module.cw_fee.read | module | cw_fee | read | 查看费用 |
|
|
| module.cw_fee.create | module | cw_fee | create | 新增费用 |
|
|
| module.cw_fee.update | module | cw_fee | update | 修改费用 |
|
|
| module.cw_fee.export | module | cw_fee | export | 导出费用 |
|
|
| module.container_main.read | module | container_main | read | 查看装箱 |
|
|
| module.container_main.export | module | container_main | export | 导出装箱 |
|
|
|
|
### 5.4 用户默认授权
|
|
|
|
| b_user_id | b_power_code | b_canuse |
|
|
| --- | --- | ---: |
|
|
| zhangsan | feature.sea_detail.access | 1 |
|
|
| zhangsan | feature.sea_detail_container.access | 1 |
|
|
| zhangsan | feature.container_query.access | 1 |
|
|
| zhangsan | feature.cw_fee_list.access | 1 |
|
|
| zhangsan | module.sea_main.read | 1 |
|
|
| zhangsan | module.container_main.read | 1 |
|
|
| zhangsan | module.cw_fee.read | 1 |
|
|
| zhangsan | module.cw_fee.create | 1 |
|
|
| zhangsan | module.cw_fee.update | 1 |
|
|
| lisi | feature.sea_detail.access | 1 |
|
|
| lisi | feature.sea_detail_container.access | 1 |
|
|
| lisi | feature.container_query.access | 1 |
|
|
| lisi | feature.cw_fee_list.access | 1 |
|
|
| lisi | feature.finance_dashboard.access | 1 |
|
|
| lisi | feature.ar_aging_card.access | 1 |
|
|
| lisi | module.sea_main.read | 1 |
|
|
| lisi | module.container_main.read | 1 |
|
|
| lisi | module.container_main.export | 1 |
|
|
| lisi | module.cw_fee.read | 1 |
|
|
| lisi | module.cw_fee.create | 1 |
|
|
| lisi | module.cw_fee.update | 1 |
|
|
| lisi | module.cw_fee.export | 1 |
|
|
|
|
### 5.5 功能-模块例外
|
|
|
|
李四可以在费用列表维护费用,但海运详细中的费用只读:
|
|
|
|
| b_user_id | b_feature_code | b_module_id | b_capability | b_canuse |
|
|
| --- | --- | --- | --- | ---: |
|
|
| lisi | sea_detail | cw_fee | create | 0 |
|
|
| lisi | sea_detail | cw_fee | update | 0 |
|
|
| lisi | sea_detail | cw_fee | export | 0 |
|
|
|
|
结果:
|
|
|
|
```text
|
|
费用列表:可查看、新增、修改、导出
|
|
海运详细:可查看费用,不可新增、修改、导出
|
|
```
|
|
|
|
## 6. 运行规则
|
|
|
|
```text
|
|
请求 -> 服务端确定 feature_code
|
|
-> 检查 feature.<feature>.access
|
|
-> 按功能配置取得允许的 module_id
|
|
-> 检查 module.<module>.<operation>
|
|
-> 检查功能-模块例外
|
|
-> 应用字段权限和数据范围
|
|
-> 执行查询、写入或导出
|
|
```
|
|
|
|
- 菜单只负责定位功能实例,同一功能挂在多个菜单时只授权一次。
|
|
- 同一公共页面模板对应不同功能实例时,权限按功能实例区分。
|
|
- 同一模块被多个功能使用时,模块默认能力只配置一次。
|
|
- 功能场景差异通过例外限制表达,例外只能收紧。
|
|
- 页面内可独立隐藏的区域定义为 `panel` 功能实例;看板卡片定义为 `report_card`。
|
|
- 前端传入的 `module_id` 必须经过当前功能的模块白名单校验。
|
|
- 后端接口必须重复校验 `access`、模块操作权限和例外限制,不能只依赖前端按钮隐藏。
|