# 字段权限与字段个性化设计 > 状态:设计定稿,未实现。创建于 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 优先,默认全可见,用户级覆盖兜底)→ 个人偏好(仅列表的顺序/列宽/显隐,权限范围内生效,未设置走默认)。