Skip to content

路由设计

在本项目中,路由基于 Vue Router 实现,区分有两大类:常驻路由(静态路由)和异步路由(动态路由)。

常驻路由(静态路由)

静态路由是在 src/router/route.ts 文件中定义的,例如:登录、仪表盘、个人中心、消息中心等路由。

ts
import type { RouteRecordRaw } from 'vue-router'

/** 默认布局 */
const Layout = () => import('@/layout/index.vue')

/** 系统路由 */
export const systemRoutes: RouteRecordRaw[] = [
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/login/index.vue'),
    meta: { hidden: true },
  },
  {
    path: '/',
    name: 'Dashboard',
    component: Layout,
    redirect: '/dashboard/workplace',
    meta: { title: '仪表盘', icon: 'dashboard', hidden: false },
    children: [
      {
        path: '/dashboard/workplace',
        name: 'Workplace',
        component: () => import('@/views/dashboard/workplace/index.vue'),
        meta: { title: '工作台', icon: 'desktop', hidden: false, affix: true },
      },
      {
        path: '/dashboard/analysis',
        name: 'Analysis',
        component: () => import('@/views/dashboard/analysis/index.vue'),
        meta: { title: '分析页', icon: 'insert-chart', hidden: false },
      },
    ],
  },
  // 其他略...
]

异步路由(动态路由)

动态路由则是通过 系统管理/菜单管理 进行维护,在系统访问时通过调用后端接口 /auth/user/route 查询当前用户的菜单及权限,动态添加到系统中。

关键代码在 src/stores/modules/route.ts 文件的 generateRoutes 方法中,首先调用接口获取所有动态路由,处理后将常驻路由和动态路由进行合并生成路由树。

路由守卫

路由守卫在 src/router/guard.ts 文件中定义,包括全局前置守卫、全局后置守卫等。

ts
/** 初始化路由守卫 */
export const setupRouterGuard = (router: Router) => {
  router.beforeEach(async (to, from, next) => {
    NProgress.start()
    const userStore = useUserStore()
    const routeStore = useRouteStore()
    // 判断该用户是否登录
    if (getToken()) {
      if (to.path === '/login') {
        // 如果已经登录,并准备进入 Login 页面,则重定向到主页
        next()
      } else {
        if (!hasRouteFlag) {
          try {
            await userStore.getInfo()
            if (userStore.userInfo.pwdExpired && to.path !== '/pwdExpired') {
              Message.warning('密码已过期,请修改密码')
              next('/pwdExpired')
            }
            const accessRoutes = await routeStore.generateRoutes()
            accessRoutes.forEach((route) => {
              if (!isHttp(route.path)) {
                router.addRoute(route) // 动态添加可访问路由表
              }
            })
            hasRouteFlag = true
            // 确保添加路由已完成
            // 设置 replace: true, 因此导航将不会留下历史记录
            next({ ...to, replace: true })
          } catch (error: any) {
            // 过程中发生任何错误,都直接重置 Token,并重定向到登录页面
            await userStore.logoutCallBack()
            next(`/login?redirect=${to.path}`)
          }
        } else {
          next()
        }
      }
    } else {
      // 如果没有 Token
      if (whiteList.includes(to.path)) {
        // 如果在免登录的白名单中,则直接进入
        next()
      } else {
        // 其他没有访问权限的页面将被重定向到登录页面
        next('/login')
      }
    }

    // 生产环境开启检测版本更新
    const isProd = import.meta.env.PROD
    if (isProd) {
      await compareTag()
    }
  })

  router.onError(() => {
    NProgress.done()
  })

  router.afterEach(() => {
    NProgress.done()
  })
}

更换系统首页

默认情况下,系统首页为仪表盘/工作台页面,如果你需要调整系统首页,只需要几个步骤即可完成。

接下来演示一下,将默认首页调整为 仪表盘/分析页 的步骤:

  1. src/router/route.ts 中,将仪表盘路由的 redirect 地址调整为其子级路由分析页 path

    ts
      {
        path: '/',
        name: 'Dashboard',
        component: Layout,
        redirect: '/dashboard/analysis',
        meta: { title: '仪表盘', icon: 'dashboard', hidden: false },
        children: [
          {
            path: '/dashboard/workplace',
            name: 'Workplace',
            component: () => import('@/views/dashboard/workplace/index.vue'),
            meta: { title: '工作台', icon: 'desktop', hidden: false, affix: true },
          },
          {
            path: '/dashboard/analysis',
            name: 'Analysis',
            component: () => import('@/views/dashboard/analysis/index.vue'),
            meta: { title: '分析页', icon: 'insert-chart', hidden: false },
          },
        ],
      }
  2. 全局搜索 workplace,将相关代码进行调整

目前在 src/components/Breadcrumb/index.vue 中定义有一个 getHome 方法,修改下方高亮的路径为分析页路径。

ts
const getHome = () => {
  if (!home) {
    const cloneRoutes = JSON.parse(JSON.stringify(routes)) as RouteLocationMatched[]
    const obj = findTree(cloneRoutes, (i) => i.path === '/dashboard/analysis')
    home = obj.item
  }
}

如果你有更多的地方使用到了首页的代码,请同步进行调整

  1. 重启前端项目,正常访问页面

温馨提示

/ 是系统根路径,也就是系统首页 path,如果你不需要仪表盘下拆分多个菜单,可以只配一个子级路由即可,例如:可以把工作台路由直接删除,这样页面默认就只会显示一个一级菜单:分析页。

可参考常见问题:在目录下只添加了一个菜单,目录不显示

参考资料

  1. Vue Router:https://router.vuejs.org/zh/
  2. GiDemo:https://gitee.com/lin0716/gi-demo#项目规范