【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 | +-----------+-----------+-----------+--------------+-----------+------------+-----------+-----------+-----------------------------+---------+---------------------------------+-----------+---------+---------------------+---------+---------------------+
展示效果