【Vue】 vue-element-admin 路由菜单配置

 

路由说明见官方文档:

https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/essentials/router-and-nav.html

 

 

组件渲染的数据来源

这里先说明侧边栏组件获取的路由:

src\layout\components\Sidebar\index.vue

 

路由是通过这个permission_routers获取的

<template>
  <div :class="{'has-logo':showLogo}">
    <logo v-if="showLogo" :collapse="isCollapse" />
    <el-scrollbar wrap-class="scrollbar-wrapper">
      <el-menu
        :default-active="activeMenu"
        :collapse="isCollapse"
        :background-color="variables.menuBg"
        :text-color="variables.menuText"
        :unique-opened="false"
        :active-text-color="variables.menuActiveText"
        :collapse-transition="false"
        mode="vertical"
      >
        <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
      </el-menu>
    </el-scrollbar>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'

export default {
  components: { SidebarItem, Logo },
  computed: {
    ...mapGetters([
      'permission_routes',
      'sidebar'
    ]),
    activeMenu() {
      const route = this.$route
      const { meta, path } = route
      // if set path, the sidebar will highlight the path you set
      if (meta.activeMenu) {
        return meta.activeMenu
      }
      return path
    },
    showLogo() {
      return this.$store.state.settings.sidebarLogo
    },
    variables() {
      return variables
    },
    isCollapse() {
      return !this.sidebar.opened
    }
  }
}
</script>

  

访问到Gettter.js可以看到Vuex是区分了命名空间的,对应的空间是permission

const getters = {
  sidebar: state => state.app.sidebar,
  size: state => state.app.size,
  device: state => state.app.device,
  visitedViews: state => state.tagsView.visitedViews,
  cachedViews: state => state.tagsView.cachedViews,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,
  introduction: state => state.user.introduction,
  roles: state => state.user.roles,
  // permission_routes: state => state.permission.routes,
  permission_routes: state => state.menu.routes,
  errorLogs: state => state.errorLog.logs
}
export default getters

所以说,默认是从permission模块里的routes获取的

如果我们新开的Vuex写路由获取逻辑,这里不改的话就拿不到我们自己获取的路由了

 

路由权限控制

在main.js下面的permission里面:

每次跳转路由,都要从VueX拿令牌,判断用户是否有效

自己定义校验规则 和 路由获取规则即可, 

这段参考Open-his来做的,路由还是前端配置,控制只展示哪些,交给后端来完成

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

/**
 * no redirect whitelist
 * 白名单,没有权限控制的路由地址
 * @type {string[]}
 */
const whiteList = ['/login', '/auth-redirect']

/**
 * 在路由跳转之前,勾子函数的控制
 */
router.beforeEach(async(to, from, next) => {
  /* 启动进度条 start progress bar */
  NProgress.start()

  /* 设置系统标签文本信息 set page title  */
  document.title = getPageTitle(to.meta.title)

  /* 从Cookie里面提取令牌 determine whether the user has logged in */
  const hasToken = getToken()

  /* 令牌存在 */
  if (hasToken) {
    /* 访问登录页时直接放行 */
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
    } else {
      /**
       * 判断当前用户的角色集合是否存在
       * determine whether the user has obtained his permission roles through getInfo
       * @type {any}
       */
      // const hasRoles = store.getters.roles && store.getters.roles.length > 0
      /* 存在则放行路由 */

      // 确定用户是否已通过getInfo获得其用户
      const hasName = !!store.getters.name

      if (hasName) {
        next()
      } else {
        /* 没有则重新获取用户信息 */
        try {
          /**
           * // get user info
           * // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
           * 根据令牌重新获取用户信息,只要角色集合
           */
          const { menus } = await store.dispatch('user/getInfo')

          /**
           * generate accessible routes map based on roles
           * 创建可访问的路由表
           * @type {any}
           */
          // const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
          const accessRoutes = await store.dispatch('menu/getAccessMenus', menus)

          /**
           * dynamically add accessible routes
           * 动态添加路由
           */
          router.addRoutes(accessRoutes)

          /**
           * 如果用户状态持续,保持路由不会丢掉历史记录
           * // hack method to ensure that addRoutes is complete
           * // set the replace: true, so the navigation will not leave a history record
           */
          next({ ...to, replace: true })
        } catch (error) {
          /**
           * 如果用户信息无法获取,重定向,要求用户重新登录
           * remove token and go to login page to re-login
           */
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* 如果没有令牌,检查是否是白名单的路由 has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      /* 没有权限,也不是白名单,重定向到登录页面 */
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

/* 每次跳转之后的回调勾子 */
router.afterEach(() => {
  /* finish progress bar 进度条加载完成 */
  NProgress.done()
})

  

路由获取规则Menu.js

import { asyncRoutes, constantRoutes, lastRoute } from '@/router/index'

const state = {
  routes: []
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = routes
  }
}

/**
 * 递归路由集合,和用户的菜单进行比较,符合则打开,反之关闭
 * @param routes
 * @param srvMenus
 */
function generateMenus(routes, srvMenus) {
  for (let i = 0; i < routes.length; i++) {
    const routeItem = routes[i]
    let showItem = false
    for (let j = 0; j < srvMenus.length; j++) {
      const srvItem = srvMenus[j]

      // 前后端数据通过 serPath 属性来匹配
      if (routeItem.name !== undefined && routeItem.name === srvItem['menuRoute'] && srvItem['isShow'] === true) {
        showItem = true
        routes[i]['hidden'] = false
        break
      }
    }
    if (showItem === false) {
      routes[i]['hidden'] = true
    }

    if (routeItem['children'] !== undefined && routeItem['children'].length > 0) {
      generateMenus(routes[i]['children'], srvMenus)
    }
  }
}

const actions = {
  getAccessMenus({ commit }, menus) {
    return new Promise(resolve => {
      const pushRouter = asyncRoutes
      generateMenus(pushRouter, menus)
      const routeArr = []
      console.log(constantRoutes)
      routeArr.push(...constantRoutes)
      routeArr.push(...pushRouter)
      routeArr.push(...lastRoute)
      commit('SET_ROUTES', routeArr)
      console.log(routeArr)

      /* 返回全部匹配的路由 */
      resolve(routeArr)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

  

前端路由表配置:

我想弄三层菜单,需要第二层再单开组件放路由才可以,这个可以查看文档说明

https://panjiachen.github.io/vue-element-admin-site/zh/guide/essentials/router-and-nav.html#侧边栏

 

 

这里我就只放异步路由的配置,常量路由是所有人都能看的,没啥可表达的

/**
 * 异步路由,根据用户的角色集合动态加载
 * asyncRoutes
 * the routes that need to be dynamically loaded based on user roles
 */
export const asyncRoutes = [
  {
    path: '/system',
    component: Layout,
    redirect: 'noRedirect',
    name: '/system',
    alwaysShow: true,
    meta: { title: '系统管理', icon: 'lock' },
    children: [
      {
        path: 'rbac',
        component: () => import('@/views/tt-server/system/rbac/index'),
        name: '/system/rbac',
        meta: { title: '权限维护', icon: 'lock' },
        children: [
          {
            path: 'user-info',
            component: () => import('@/views/tt-server/system/rbac/user-info/index'),
            name: '/system/rbac/user-info',
            meta: { title: '用户管理', icon: 'edit' }
          },
          {
            path: 'role-info',
            component: () => import('@/views/tt-server/system/rbac/role-info/index'),
            name: '/system/rbac/role-info',
            meta: { title: '角色管理', icon: 'edit' }
          },
          {
            path: 'menu-info',
            component: () => import('@/views/tt-server/system/rbac/menu-info/index'),
            name: '/system/rbac/menu-info',
            meta: { title: '菜单管理', icon: 'edit' }
          },
          {
            path: 'privilege-info',
            component: () => import('@/views/tt-server/system/rbac/privilege-info/index'),
            name: '/system/rbac/privilege-info',
            meta: { title: '权限管理', icon: 'edit' }
          }
        ]
      },
      {
        path: 'common',
        component: () => import('@/views/tt-server/system/common/index'),
        name: '/system/common',
        alwaysShow: true,
        meta: { title: '通用管理', icon: 'lock' },
        children: [
          {
            path: 'dict-info',
            component: () => import('@/views/tt-server/system/common/dict-info/index'),
            name: '/system/common/dict-info',
            meta: { title: '字典管理', icon: 'edit' }
          },
          {
            path: 'area-info',
            component: () => import('@/views/tt-server/system/common/area-info/index'),
            name: '/system/common/area-info',
            meta: { title: '区域管理', icon: 'edit' }
          },
          {
            path: 'system-param',
            component: () => import('@/views/tt-server/system/common/system-param/index'),
            name: '/system/common/system-param',
            meta: { title: '系统参数', icon: 'edit' }
          },
          {
            path: 'system-log',
            component: () => import('@/views/tt-server/system/common/system-log/index'),
            name: '/system/common/system-log',
            meta: { title: '系统日志', icon: 'edit' }
          }
        ]
      }
    ]
  }
]

  

后台数据设计:

表结构 

CREATE TABLE `sys_menu` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '菜单主键',
  `app_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '应用编号',
  `menu_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称',
  `menu_value` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单值',
  `menu_icon` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单图标',
  `menu_level` int NOT NULL DEFAULT '1' COMMENT '菜单层级',
  `menu_type` varchar(12) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单类型',
  `menu_sort` int NOT NULL COMMENT '菜单排序',
  `menu_route` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单路由',
  `is_show` tinyint(1) DEFAULT '1' COMMENT '是否展示 1展示 0隐藏',
  `menu_path` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单主键路径',
  `parent_id` int NOT NULL DEFAULT '0' COMMENT '父级菜单,顶级菜单默认为0',
  `creator` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `updater` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100200401 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统菜单表';

 

菜单记录:

【菜单路由】和【是否展示】是前端路由展示的判断条件

mysql> SELECT * FROM sys_menu;
+-----------+-----------+-----------+--------------+-----------+------------+-----------+-----------+-----------------------------+---------+---------------------------------+-----------+---------+---------------------+---------+---------------------+
| id        | app_code  | menu_name | menu_value   | menu_icon | menu_level | menu_type | menu_sort | menu_route                  | is_show | menu_path                       | parent_id | creator | create_time         | updater | update_time         |
+-----------+-----------+-----------+--------------+-----------+------------+-----------+-----------+-----------------------------+---------+---------------------------------+-----------+---------+---------------------+---------+---------------------+
| 100000000 | tt-server | 系统管理  | system       |           |          1 | Directory |         1 | /system                     |       1 | 0,100000000                     |         0 | admin   | 2022-12-07 23:46:49 | admin   | 2022-12-07 23:46:51 |
| 100100000 | tt-server | 权限维护  | privileges   |           |          2 | Directory |         1 | /system/rbac                |       1 | 0,100000000,100100000           | 100000000 | admin   | 2022-12-07 23:41:14 | admin   | 2022-12-07 23:41:16 |
| 100100100 | tt-server | 用户管理  | user-info    |           |          3 | Function  |         1 | /system/rbac/user-info      |       1 | 0,100000000,100100000,100100100 | 100100000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
| 100100200 | tt-server | 角色管理  | role-info    |           |          3 | Function  |         2 | /system/rbac/role-info      |       1 | 0,100000000,100100000,100100200 | 100100000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
| 100100300 | tt-server | 菜单管理  | menu-info    |           |          3 | Function  |         3 | /system/rbac/menu-info      |       1 | 0,100000000,100100000,100100300 | 100100000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
| 100100400 | tt-server | 权限管理  | permit-info  |           |          3 | Function  |         4 | /system/rbac/privilege-info |       1 | 0,100000000,100100000,100100400 | 100100000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
| 100200000 | tt-server | 通用管理  | common       |           |          2 | Directory |         2 | /system/common              |       1 | 0,100000000,100200000           | 100000000 | admin   | 2022-12-07 23:42:03 | admin   | 2022-12-07 23:42:03 |
| 100200100 | tt-server | 字典管理  | dict-info    |           |          3 | Function  |         1 | /system/common/dict-info    |       1 | 0,100000000,100200000,100200100 | 100200000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
| 100200200 | tt-server | 行政区域  | area-info    |           |          3 | Function  |         2 | /system/common/area-info    |       1 | 0,100000000,100200000,100200200 | 100200000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
| 100200300 | tt-server | 系统参数  | system-param |           |          3 | Function  |         3 | /system/common/system-param |       1 | 0,100000000,100200000,100200300 | 100200000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
| 100200400 | tt-server | 系统日志  | system-log   |           |          3 | Function  |         4 | /system/common/system-log   |       1 | 0,100000000,100200000,100200400 | 100200000 | admin   | 2022-12-07 23:44:12 | admin   | 2022-12-07 23:44:12 |
+-----------+-----------+-----------+--------------+-----------+------------+-----------+-----------+-----------------------------+---------+---------------------------------+-----------+---------+---------------------+---------+---------------------+

  

展示效果

 

posted @ 2022-12-11 00:23  emdzz  阅读(2254)  评论(0编辑  收藏  举报