Files
workspace/code/fms/字段权限与字段个性化设计.md
T
2026-09-04 17:31:36 +08:00

160 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 字段权限与字段个性化设计
> 状态:设计定稿,未实现。创建于 2026-09-04。
> 关联文档:[FMS新系统核心表结构设计.md](./FMS新系统核心表结构设计.md)(其中 s_power / s_role_power 部分)
## 1. 背景与目标
系统已有全局的字段显示配置(`s_field_view` / `s_field_edit`,在模块设计器中维护,对所有人生效)。本设计解决两个新需求:
1. **字段权限**:管理员(高权限角色)控制某个人/某些人**能不能看到**某些字段;
2. **字段个性化**:用户自己调整列表的**字段顺序、列宽、显示/隐藏**,且只影响自己、跨设备持久化。
范围约定:
- 个性化只作用于**列表**(查看态列表 + 可编辑列表两套配置),**表单不参与**顺序/布局个性化;
- 单公司系统(无多租户维度),后续如需多公司再扩展;
- 不考虑旧数据迁移难度。
## 2. 三层模型
```
第 1 层 默认配置(模板) s_field_view / s_field_edit 模块设计器维护,管理员设定
第 2 层 字段权限(谁能看) s_power(field型) + s_role_power 管理员按角色控制可见性
第 3 层 个人偏好(怎么摆) s_user_field_pref(新表) 用户自己拖拽,只影响自己
```
职责边界是本设计的核心原则:
- **权限决定"全集"**:deny 的字段对用户不存在(列表不渲染、后端不返回);
- **偏好只决定"排列"**:顺序、宽度、个人显隐,永远在权限允许的范围内生效,无法越过权限;
- 终端用户能控制的只有自己的布局,可见性的控制权始终在管理员手里。
两层独立演化:将来权限规则变化,偏好数据不需要清洗(偏好里残留无权限字段只是无效数据,不构成越权)。
## 3. 数据结构
### 3.1 新表:s_user_field_pref(个人偏好)
一人 × 一模块 × 一字段 × 一模式 一行。每字段一行(而非 JSON 快照),可直接复用现有通用 CRUD(DataService)。
```sql
CREATE TABLE s_user_field_pref (
b_id VARCHAR(32) PRIMARY KEY,
b_user_id VARCHAR(32) NOT NULL,
b_module_id VARCHAR(32) NOT NULL,
b_field_id VARCHAR(32) NOT NULL,
b_mode VARCHAR(10) NOT NULL, -- 'view' 查看列表 / 'edit' 可编辑列表
b_visible TINYINT DEFAULT 1, -- 个人显隐(1 显示,0 隐藏)
b_xh INT, -- 个人顺序号
b_width INT, -- 个人列宽
b_update_time DATETIME,
UNIQUE KEY uk_user_field (b_user_id, b_module_id, b_field_id, b_mode)
);
```
说明:
- 用户**没有**保存过偏好的字段不产生行,解析时落回默认配置(`s_field_view` / `s_field_edit`);
- 保存过布局 = 该用户该模块该 mode 存在偏好行,此后**默认布局变更对该用户不再生效**(保持用户自主摆放的稳定性),可通过"恢复默认"删除偏好行回到跟随默认;
- "恢复默认" = 删除该用户 + 该模块 + 该 mode 的全部行。
### 3.2 权限层:复用已有表 + 一张用户级覆盖表
- `s_power`(field 型:`b_module_id + b_field_id + b_operation`[view/edit])与 `s_role_power`(`b_effect` allow/deny)沿用现有表结构,见 [FMS新系统核心表结构设计.md](./FMS新系统核心表结构设计.md);
- 新增用户级覆盖表,用于个别用户的特例(平时应为空表,只为"开小灶"使用,不值得建角色时用它):
```sql
CREATE TABLE s_user_power (
b_id VARCHAR(32) PRIMARY KEY,
b_user_id VARCHAR(32) NOT NULL,
b_module_id VARCHAR(32) NOT NULL,
b_field_id VARCHAR(32) NOT NULL,
b_operation VARCHAR(10) NOT NULL, -- 'view' / 'edit'
b_effect VARCHAR(10) NOT NULL, -- 'allow' / 'deny'
UNIQUE KEY uk_user_field_op (b_user_id, b_module_id, b_field_id, b_operation)
);
```
## 4. 解析算法
### 4.1 字段可见性(权限链)
```
可见性 = 用户级覆盖(s_user_power,有配置则生效,优先级最高)
↓ 该用户该字段无配置
角色合并(该用户所有角色的 s_role_power,deny 优先:任一角色 deny 即 deny)
↓ 无任何角色配置
默认可见(allow)
```
要点:
- **默认全部可见,黑名单式配置**:只为敏感字段配 deny,不为普通字段配 allow,维护量最小;
- deny 优先(而非 allow 优先):敏感字段场景下更安全。
### 4.2 列表最终配置(合并链)
对查看列表和可编辑列表分别执行(mode = view / edit):
```
最终配置 = 默认配置(s_field_view / s_field_edit,含 b_canuse 过滤)
→ 剔除权限 deny 的字段
→ 用个人偏好覆盖 b_xh / b_width / b_visible
→ 偏好中没有的字段,按默认配置的顺序追加补全
```
有效显示 = `权限可见 && 字段可用(b_canuse=1) && 个人未隐藏`。
补全规则保证:新增字段、默认配置新启用的字段,即使用户保存过布局也会按默认顺序出现在列表尾部,不会"消失"。
### 4.3 顺序合并细节
偏好只覆盖出现过的字段;用户保存布局后管理员再调默认顺序,对已保存用户无效(见 3.1)。
## 5. 边界场景约定
| 场景 | 行为 |
|---|---|
| 字段 `b_canuse=0`(下架) | 不进入候选集,即使偏好表里有该字段的行也不显示(偏好行成无效数据,暂不清理,量大后在字段下架入口顺带删除) |
| 新增字段 | 所有用户可见:无偏好则按默认顺序出现在尾部 |
| 权限从 allow 变 deny | 字段对用户消失;偏好数据保留,权限恢复后用户的自定义布局自动恢复 |
| 用户隐藏字段 vs 权限隐藏字段 | 是两回事:个人隐藏 = 有权看但暂时不显示,"栏位设置"弹窗可随时勾回;权限隐藏 = 对该用户不存在,弹窗中**不展示**无权限字段 |
| 必填字段被用户隐藏(可编辑列表) | **待定**,见第 8 节 |
## 6. 交互设计
- 列表列头拖拽排序、拖拽调宽(能力已有:`FmsTable.vue`);
- 拖拽结束后防抖保存(约 500ms)upsert 到 `s_user_field_pref`;
- 菜单保留"保存/恢复栏位设置",语义从全局改为个人:"恢复"即删除偏好行;
- "栏位设置"弹窗:排序 + 个人显隐 + 列宽统一管理;不展示无权限字段;
- 可选:管理员入口"保存为全局默认",仍写 `s_field_view` / `s_field_edit`。
## 7. 改动范围(实现清单)
| 位置 | 改动 |
|---|---|
| migration | 新增 `s_user_field_pref`、`s_user_power` 建表 |
| 后端 DataService | ① 字段权限过滤:deny 字段从查询结果中剔除(设计文档既定要求,目前后端零过滤)② 偏好表 CRUD 复用现有通用机制 |
| 前端 `stores/permissions.js` | 新增 `canField(moduleId, fieldId, operation)`:用户级 → 角色合并(deny 优先)→ 默认 allow |
| 前端 `FmsModuleListPage.vue` | `loadData` 中实现合并链(默认 → 权限过滤 → 偏好覆盖 → 补全);`saveColumnSettings` 保存目标从 `s_field_view/s_field_edit` 改为 `s_user_field_pref` |
| 权限管理 UI | 模块管理 `ModuleFieldsPanel` 旁新增"字段权限"页签:选角色 × 勾字段(view/edit);入口本身由现有模块/按钮权限(`canPower`)控制,实现"高权限的人才能配" |
| 用户级覆盖 UI | 可后置:先支持直接改 `s_user_power` 数据,界面后续补 |
关键实现纪律:**合并偏好的代码必须在权限过滤之后执行**,保证偏好永远无法越过权限。
## 8. 待定事项
**必填字段被用户隐藏后的校验策略**(可编辑列表场景):
| 方案 | 规则 | 适用 |
|---|---|---|
| A. 所见即所验 | 隐藏后跳过必填校验 | "必填"只是引导性要求,空值可接受;且权限隐藏与用户隐藏行为天然统一,无需特殊分支 |
| B. 必填不可藏 | 可编辑列表中必填字段置灰、禁止隐藏 | "必填"是业务硬规则,字段空值会损害下游使用 |
判断标准:该字段空着,会不会有人受害。会 → B;不会 → A。权限隐藏(管理员 deny)场景下无论选哪个方案,行为都与 A 一致(用户"没有这个字段",天然不校验)。
---
**结论摘要**:默认配置(全局模板)→ 字段权限(管理员按角色控制可见性,deny 优先,默认全可见,用户级覆盖兜底)→ 个人偏好(仅列表的顺序/列宽/显隐,权限范围内生效,未设置走默认)。