权限
项目提供两种路由权限模式,以及独立的按钮级权限控制:
- FIXED(前端固定路由):路由在前端配置,登录后根据接口返回的权限集合过滤路由。
- BACK(后端动态菜单):菜单与路由由后端接口下发,前端按组件映射表动态生成。
- 按钮级权限:通过
usePermission/v-permission指令控制页面内操作,与上述两种路由模式无关。
模式由 src/settings/projectSetting.ts 的 permissionMode 决定:
const setting = {
//菜单权限模式 FIXED 前端固定路由 BACK 动态获取
permissionMode: 'FIXED',
};
FIXED:前端固定路由
实现原理: 路由写在前端(src/router/modules/*.ts),每条路由通过 meta.permissions 声明访问所需权限。登录后拿到用户的权限集合,过滤出可访问的路由,再通过 router.addRoute 添加到路由实例。
相关逻辑位于 src/store/modules/asyncRoute.ts 的 generateRoutes。
缺点: 权限相对不自由,后台调整角色后前端也需要同步调整。适合角色较固定的系统。
路由配置
import { RouteRecordRaw } from 'vue-router';
import { Layout } from '@/router/constant';
import { DashboardOutlined } from '@vicons/antd';
import { renderIcon } from '@/utils/index';
const routeName = 'dashboard';
const routes: Array<RouteRecordRaw> = [
{
path: '/dashboard',
name: routeName,
redirect: '/dashboard/console',
component: Layout,
meta: {
// i18n key,词条位于 src/locales/lang/<locale>/route.ts
title: 'route.dashboard',
icon: renderIcon(DashboardOutlined),
// 父级路由需要任一子路由的权限即可访问
permissions: ['dashboard_console', 'dashboard_workplace'],
sort: 0,
},
children: [
{
path: 'console',
name: `${routeName}_console`,
meta: {
title: 'route.dashboard_console',
permissions: ['dashboard_console'],
},
component: () => import('@/views/dashboard/console/console.vue'),
},
],
},
];
export default routes;
3.0.0 变更
meta.title 由中文文案改为 i18n key(如 '主控台' → 'route.dashboard_console')。自定义路由需要同步调整,或在 src/locales/lang/<locale>/route.ts 中补齐词条;未命中语言包时会原样显示 key。
BACK:后端动态菜单
实现原理: 后端返回路由表,前端在 src/router/generator.ts 中把 component 字符串映射为实际组件,再通过 router.addRoute 添加:
LAYOUT/IFRAME由LayoutMap直接映射- 其他值按路径匹配
src/views下的文件,例如'/dashboard/console/console'对应src/views/dashboard/console/console.vue - 未提供
component但有子路由时使用ParentLayout
缺点: 后端返回的 component 路径需要与 src/views 下的文件结构保持一致。
提示: 多级路由未配置 redirect 时,默认重定向到第一个子路由。
注意
后端接口返回的数据结构请参考 mock/user/menus.ts 中的 menusList。
3.0.0 起后端返回的 meta.title 会保留原值,在菜单/面包屑渲染时再翻译:返回 i18n key 可跟随语言切换,返回纯中文标题则原样显示(不会暴露 key)。
按钮级权限
usePermission 提供三个函数,参数均为权限标识数组(与路由 meta.permissions 中的值同源):
<template>
<n-button v-if="hasPermission(['dashboard_console'])">拥有 dashboard_console 权限可见</n-button>
</template>
<script setup lang="ts">
import { usePermission } from '@/hooks/web/usePermission';
const { hasPermission, hasEveryPermission, hasSomePermission } = usePermission();
</script>
| 函数 | 含义 |
|---|---|
hasPermission(accesses) | 拥有其中任意一个权限;传入空数组时返回 true |
hasSomePermission(accesses) | 同 hasPermission,语义更明确的别名 |
hasEveryPermission(accesses) | 必须拥有数组中的全部权限 |
指令方式
<!-- 无权限时移除元素 -->
<n-button v-permission="{ action: ['dashboard_console'] }">仅演示</n-button>
<!-- 无权限时禁用元素 -->
<n-button v-permission="{ action: ['dashboard_console'], effect: 'disabled' }">仅演示</n-button>
TIP
指令在 mounted 时判断一次,不能动态更改权限;权限会变化时请使用 v-if + usePermission。
Naive Ui Admin