权限模型
import { CommandManager } from 'ds-ui'
DirectSurface UI 的命令系统可以承载按钮权限、菜单权限、快捷键权限和启用状态。业务系统仍然需要自己定义权限编码、角色策略、数据权限和审计规则。
权限分层
建议把权限分成三层:
- 功能权限:是否能看到或执行某个命令,例如保存、删除、审核。
- 数据权限:是否能访问某个业务对象,例如某个科室、病区、患者。
- 状态权限:当前业务状态下是否允许操作,例如已归档病历不能直接修改。
命令的 permission 字段适合表达功能权限。数据权限和状态权限通常放在 canExecute 中结合页面上下文判断。
命令注册示例
const manager = new CommandManager({ permissionService: { has: permission => permission === 'record.save', },}) manager.register({ id: 'record.save', title: '保存病历', permission: 'record.save', execute: () => {},})
命令注册后,按钮、菜单和快捷键都可以绑定同一个命令。权限变化或页面状态变化后,调用命令管理器的刷新能力,让 UI 重新求值。
页面级命令
命令一般跟页面走。工作台可以提供全局命令,例如打开页面、切换主题、打开诊断面板。业务页面提供页面级命令,例如查询、保存、审核、打印。
页面关闭时,页面级命令也应该释放。这样可以避免关闭 tab 后工具栏仍然执行旧页面命令。
启用状态
canExecute 不是权限系统的替代品。它更适合表达实时状态:
- 当前没有选中行,删除按钮禁用。
- 当前文档只读,保存按钮禁用。
- 当前正在加载,查询按钮禁用。
- 当前表单校验失败,提交按钮禁用。
在多数业务页面里,启用状态可以在 UI 刷新或页面状态刷新时重新求值。不要在每个组件里重复写同一套禁用逻辑。
审计关系
权限控制的是“能不能做”。审计记录的是“谁在什么时候做了什么”。两者应该关联但不要混在一起。
推荐做法:
- 命令执行前通过权限和状态判断。
- 命令执行时传入操作上下文。
- 业务服务在保存、提交、审核等关键动作上写审计。
- 编辑器内部的留痕只记录文档内容变化,不替代业务操作审计。