20260904173136
This commit is contained in:
1 parent
0928437c67
commit
4e167df0f0
40 files changed
+3471
-2314
No files matched your search
@@ -0,0 +1,159 @@
|
||||
# 字段权限与字段个性化设计
|
||||
|
||||
> 状态:设计定稿,未实现。创建于 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 优先,默认全可见,用户级覆盖兜底)→ 个人偏好(仅列表的顺序/列宽/显隐,权限范围内生效,未设置走默认)。
|
||||
Reference in new issue
Block a user