vue-element-admin动态权限路由实现
vue-element-admin动态权限路由实现这次项目的需求有个需要实现动态权限管理,所以需要动态路由,结合网上看到的以及自己实践出来的,做个小总结。首先 vue-ele-admin 自带的权限管理是在路由表里写死的,在router/index.js中,asyncRoutes里通过roles属性可控制不同权限的人进入不同路由,但是我们现在得需求是动态的,路由是通过接口获取的,所以我们需要做些改
vue-element-admin动态权限路由实现
这次项目的需求有个需要实现动态权限管理,所以需要动态路由,结合网上看到的以及自己实践出来的,做个小总结。
首先 vue-ele-admin 自带的权限管理是在路由表里写死的,在router/index.js中,asyncRoutes里通过roles属性可控制不同权限的人进入不同路由,但是我们现在得需求是动态的,路由是通过接口获取的,所以我们需要做些改动,具体有以下几点
1.在router/index中,constantRoutes保持不变,因为这些路由是所有用户均可以访问的,把原来的asyncRoutes删掉,新建dynamicRoutes,dynamicRoutes是这个项目里所有的路由,后面我们通过hidden属性来控制它是否显示,给每个路由增添一个url属性,一会请求后台接口的时候会把接口返回的数据与我们设置的url对比。
export const constantRoutes = [
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index')
}
]
},
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/auth-redirect',
component: () => import('@/views/login/auth-redirect'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error-page/404'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error-page/401'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: '系统主页', icon: 'dashboard' }
}
]
},
{
path: '/personal',
component: Layout,
hidden: true,
children: [
{
path: 'person',
component: () => import('@/views/person/index')
}
]
},
]
export const dynamicRoutes = [
{
path: '/device',
component: Layout,
redirect: '/device/index',
name: 'Device',
url:'/device',//here
meta: {
title: '设备管理',
icon: 'lock',
},
children: [
{
path: 'index',
component: () => import('@/views/device/dataView'),
name: 'dataView',
url: '/device/index',//here
meta: {
title: '数据指标',
}
},
{
path: 'deviceType',
component: () => import('@/views/device/deviceType'),
name: 'deviceType',
url: '/device/deviceType',//here
meta: {
title: '设备类型',
}
},
{
path: 'deviceMonitor',
component: () => import('@/views/device/deviceMonitor'),
name: 'deviceMonitor',
url: '/device/deviceMonitor',//here
meta: {
title: '设备监控'
}
}
]
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
const createRouter = () => new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
//这里需要注意下,一开始动态路由是不注册的,后面请求接口页面再返回回去
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
2.在src/api下创建menu.js,请求后台数据
import request from '@/utils/request'
export function getMenus() {
return request({
url: '/api-user/func/my_menus',
method: 'get',
})
这个接口返回的数据即为我们能看到的页面,看不到的页面不返回,返回的数据格式如下
{"data":[{"id":1,"parentId":null,"funcName":"设备管理","url":"/device",,"childList":null},{"id":2,"parentId":null,"funcName":"数据指标","url":"/device/index",,"childList":null},{"id":3,"parentId":null,"funcName":"设备类型","url":"/device/deviceType",,"childList":null},{"id":4,"parentId":null,"funcName":"设备台账","url":"/device/deviceBook",,"childList":null},{"id":5,"parentId":null,"funcName":"设备监控","url":"/device/deviceMonitor",,"childList":null},{"id":6,"parentId":null,"funcName":"运维管理","url":"/management",,"childList":null},{"id":7,"parentId":null,"funcName":"报警列表","url":"/management/index",,"childList":null},{"id":8,"parentId":null,"funcName":"数据统计","url":"/management/dataToatl",,"childList":null},{"id":9,"parentId":null,"funcName":"客户管理","url":"/customer/index",,"childList":null},{"id":10,"parentId":null,"funcName":"系统设置","url":"/permission",,"childList":null},{"id":11,"parentId":null,"funcName":"用户管理","url":"/permission/page",,"childList":null},{"id":12,"parentId":null,"funcName":"角色管理","url":"/permission/role",,"childList":null},{"id":13,"parentId":null,"funcName":"操作日志","url":"/permission/directive",,"childList":null},{"id":14,"parentId":null,"funcName":"详情","url":"/device/deviceBook/detail",,"childList":null}],"code":0,"msg":"查询成功"}
3.在src/store/modules下新建menu.js,这个是为了把获得的路由表存进vuex中,并在里面对路由进行一些处理,menu.js内容如下
import { getMenus } from '@/api/menu'
import { getToken } from '@/utils/auth'
import { constantRoutes,dynamicRoutes } from '@/router/index'
const getDefaultState = () => {
return {
token: getToken(),
menuList: []
}
}
const state = getDefaultState()
const mutations = {
SET_MENUS: (state, menu) => {
state.menuList = menu
}
}
// 动态菜单还是定义在前端,后台只会返回有权限的菜单列表,通过遍历我们预先在路由表里定义好的菜单数据,没有的将对于菜单进行隐藏
export function generaMenu(routes, srvMenus) {
for (let i = 0; i < routes.length; i++) {
const routeItem = routes[i]
var showItem = false
for (let j = 0; j < srvMenus.length; j++) {
const srvItem = srvMenus[j]
// 前后端数据通过 url 属性来匹配
if (routeItem.url !== undefined && routeItem.url === srvItem.url) {
showItem = true
routes[i]['hidden'] = false
break
}
}
if (showItem === false) {
routes[i]['hidden'] = true
}
if (routeItem['children'] !== undefined && routeItem['children'].length > 0) {
generaMenu(routes[i]['children'], srvMenus)
}
}
}
const actions = {
getMenus({ commit }) {
return new Promise((resolve, reject) => {
getMenus(state.token).then(response => {
const { data } = response
console.log(response)
if (!data) {
reject('Verification failed, please Login again.')
}
const srvMenus = data
let pushRouter = dynamicRoutes
generaMenu(pushRouter, srvMenus)
commit('SET_MENUS', constantRoutes.concat(pushRouter))//将创建完成的路由表存在menuList中
resolve(pushRouter)
}).catch(error => {
reject(error)
})
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
4.在stroe/getters.js 新增menuList: state => state.menu.menuList
5.在src/permission.js 中
这样现在登录应该可以进入首页了,但是进入首页发现侧边栏为什么为空,逻辑应该没问题啊,经过排查,在src/layout/Sidebar/index.vue中,<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
这里permission_routes应该改为我们生成的路由,代码如下
<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 menuList" :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([
'menuList',
'sidebar'
]),
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if(path == '/device/deviceBook/detail' ){ //侧边栏选择三级路由时一二级路由高亮
return '/device/deviceBook'
}
if(path == '/management/index/detail'){
return '/management/index'
}
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
showLogo() {
return this.$store.state.settings.sidebarLogo
},
variables() {
return variables
},
isCollapse() {
return !this.sidebar.opened
}
}
}
</script>
到这,动态路由已经好了,因为第一次做动态路由。走了很多歪路,在此记录一下。
更多推荐
所有评论(0)