菜单、路由与权限
资源类型常量
ts
export const RESOURCE_TYPE = {
MENU: 1,
PAGE: 2,
BUTTON: 3,
API: 4,
GROUP: 5,
} as const;判断资源类型使用精确等值,不使用 type <= 2 之类依赖数字顺序的逻辑。
侧栏生成
前端从 mineResources 得到资源树后:
- 过滤禁用资源。
- 展开辅助分组。
- 只保留菜单和页面资源。
- 过滤不可见节点。
- 规范化父子路径。
- 只展示当前角色已勾选的节点。
- 按
sort排序。
外链菜单根据 isLink 和 linkUrl 打开,不作为内部 Vue 路由。
固定与动态路由
系统核心页面有固定组件映射,例如:
ts
'system/user/index': UserManage
'system/role/index': RoleManage
'system/menu/index': ResourceManage后端新增的非系统页面可以通过 import.meta.glob 匹配组件并动态注册。无法解析的组件进入占位页,不应让整个路由初始化失败。
路由守卫
/login无需认证。- 没有 Token 时跳转登录并保留
redirect。 - 有 Token 时先初始化用户和资源。
- 初始化失败时清理会话并返回登录页。
- 首页和个人中心忽略资源路径访问控制。
- 普通业务页面不在可访问路径集合时,跳转第一个可访问页面;没有菜单时回到个人中心。
按钮权限
ts
const canCreate = computed(() =>
authStore.hasPermission("view:admin:sysUser:create"),
);后端可能同时在 mine.permissions 和资源树节点中返回权限,前端合并为一个 Set。*:*:* 表示通配权限。
页面展示只检查当前权限标识是否存在,不根据接口路径猜测权限,也不要求每个接口都必须有同名按钮。
状态显示
角色、组织、岗位或资源被禁用后:
- 新选择时显示“名称(禁用)”并置灰。
- 已绑定值允许回显。
- 已绑定禁用值允许取消。
- 保存原值时不应因为它已禁用而破坏回显。
常见错误
- 用接口权限直接控制按钮:应使用
view:权限。 - 只隐藏按钮但后端无权限注解:存在安全风险。
- 同一个挂载接口节点使用相同
resId作为 Tree Key:会导致多位置联动。 - 清空角色权限后没有刷新用户上下文:页面仍显示旧状态。
- 角色没有菜单时把登录页也当作无权访问:导致 404 循环。