Skip to content
On this page

权限

项目提供两种路由权限模式,以及独立的按钮级权限控制:

  1. FIXED(前端固定路由):路由在前端配置,登录后根据接口返回的权限集合过滤路由。
  2. BACK(后端动态菜单):菜单与路由由后端接口下发,前端按组件映射表动态生成。
  3. 按钮级权限:通过 usePermission / v-permission 指令控制页面内操作,与上述两种路由模式无关。

模式由 src/settings/projectSetting.ts 的 permissionMode 决定:

ts
const setting = {
  //菜单权限模式 FIXED 前端固定路由  BACK 动态获取
  permissionMode: 'FIXED',
};

FIXED:前端固定路由

实现原理: 路由写在前端(src/router/modules/*.ts),每条路由通过 meta.permissions 声明访问所需权限。登录后拿到用户的权限集合,过滤出可访问的路由,再通过 router.addRoute 添加到路由实例。

相关逻辑位于 src/store/modules/asyncRoute.ts 的 generateRoutes。

缺点: 权限相对不自由,后台调整角色后前端也需要同步调整。适合角色较固定的系统。

路由配置

ts
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 中的值同源):

vue
<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)必须拥有数组中的全部权限

指令方式

html
<!-- 无权限时移除元素 -->
<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。