Skip to content

🧭 动态路由与权限管理指南

🔑 权限配置流程

1️⃣ 中台权限配置

在业务中台-系统设置-应用管理页面添加应用、菜单、功能按钮:

应用管理

2️⃣ 角色授权配置

在业务中台-用户中心-角色管理页面选择角色并进行权限授权:

角色授权

📁 路由文件配置

⚙️ 主路由文件 (index.ts)

创建 routers/index.ts 文件,配置路由实例和路由守卫:

ts
import { AuthStore, initDynamicRouter } from '@pt/common-ui';
import { createRouter, createWebHashHistory } from 'vue-router';
import { staticRouter } from './staticRouter';
import { storage } from '@pt/utils';
import { LOGIN_URL, ROUTER_WHITE_LIST } from '@/config';

// 🔄 创建路由实例
const router = createRouter({
  history: createWebHashHistory(),
  routes: [...staticRouter],
  strict: false,
  scrollBehavior: () => ({ left: 0, top: 0 }),
});

/**
 * @description 重置路由
 * */
export const resetRouter = () => {
  const authStore = AuthStore();
  authStore.flatMenuListGet.forEach((route) => {
    const { name } = route;
    if (name && router.hasRoute(name)) router.removeRoute(name);
  });
};

// 🔍 引入 views 文件夹下所有 vue 文件
// @ts-ignore
const modules = import.meta.glob('@example/views/**/*.vue');

// 🛡️ 路由守卫配置
router.beforeEach(async (to, from, next) => {
  const cookie_token = storage.get('token');
  const cookie_userInfoStr = storage.get('userInfo');
  const authStore = AuthStore();
  authStore.setRouteName(to.name as string);

  // 2.动态设置标题
  // const title = import.meta.env.VITE_GLOB_APP_TITLE;
  // document.title = to.meta.title ? `${to.meta.title} - ${title}` : title;

  // 3.判断是访问登陆页,有 Token 就在当前页面,没有 Token 重置路由并放行到登陆页
  if (to.path.toLocaleLowerCase() === LOGIN_URL) {
    if (cookie_token && cookie_userInfoStr) return next(from.fullPath);

    storage.clear();
    resetRouter();
    return next();
  }

  // 4. 白名单可以直接访问
  if (ROUTER_WHITE_LIST.includes(to.path)) {
    return next();
  }

  // 5.判断是否有 Token,没有重定向到 login
  if (!cookie_token || !cookie_userInfoStr)
    return next({ path: LOGIN_URL, replace: true });

  // 6.如果没有菜单列表,就重新请求菜单列表并添加动态路由
  authStore.setRouteName(to.name as string);
  if (!authStore.authMenuListGet.length) {
    await initDynamicRouter(router, {
      parentRouteName: 'layout',
      resolveComponent: (path: string) => {
        return () => modules['/example/src/views' + path + '.vue']?.();
      },
      goLogin: () => {
        next({ path: LOGIN_URL, replace: true });
      },
    });
    return next({ ...to, replace: true });
  }

  // 7.正常访问页面
  next();
});

export default router;

📊 静态路由文件 (staticRouter.ts)

创建 src/routers/staticRouter.ts 文件,配置基础路由结构:

ts
import { RouteRecordRaw } from 'vue-router';
import { HOME_URL, LOGIN_URL } from '../config';

/**
 * staticRouter(静态路由)
 */
export const staticRouter: RouteRecordRaw[] = [
  {
    path: '/',
    redirect: HOME_URL,
  },
  {
    path: LOGIN_URL,
    name: 'login',
    component: () => import('../views/login/index.vue'),
  },
  {
    path: '/layout',
    name: 'layout',
    component: () => import('../layouts/index.vue'),
    redirect: HOME_URL,
    children: [
      /* {
        path: '/components',
        component: () => import('../views/ComponentsDemo.vue'),
        name: 'components',
      },
      {
        path: '/auth',
        component: () => import('../views/AuthDemo.vue'),
        name: 'auth',
      }, */
    ],
  },
];

⚓ 基础配置文件 (config/index.ts)

创建 src/config/index.ts 文件,定义基础路由配置:

ts
// * 首页地址(默认)
export const HOME_URL: string = '/components';

// * 登录页地址(默认)
export const LOGIN_URL: string = '/login';

// * Tabs(白名单地址,不需要添加到 tabs 的路由地址)
export const TABS_WHITE_LIST: string[] = ['/403', '/404', '/500', LOGIN_URL];

// * 路由白名单地址,不需要权限就可以访问(必须是本地存在的路由 staticRouter.ts)
export const ROUTER_WHITE_LIST: string[] = [
  '/register',
  '/forgotPassword',
  '/login/agreement',
  '/login/privacy',
  '/svg-preview/index',
  '/demo2',
  '/demo3',
];

🌟 主要功能说明

  • 🔐 权限控制:通过业务中台配置菜单和功能权限
  • 🔄 动态路由:使用 initDynamicRouter 方法动态加载路由
  • 🛡️ 路由守卫:自动处理登录状态、权限检查和路由跳转
  • 🗂️ 代码组织:将路由配置拆分为主文件、静态路由和基础配置

📝 最佳实践

  1. 将所有页面组件放在 views 目录下,便于动态路由自动加载
  2. 使用约定式路径命名,保持与后台权限配置的一致性
  3. 合理配置白名单,避免公共页面也需要权限验证
  4. 使用路由懒加载提高性能

Released under the MIT License.