本项目采用的模板为vue-element-admin i18n分支
在网上看了很多教程,发现都写的很复杂(本人比较菜) , 用尽千辛万苦终于实现了这个功能
首先修改src/store/modules目录下的permission.js文件
为了区分,下面先附上原文件代码
import { asyncRoutes, constantRoutes } from '@/router'
/**
* Use meta.role to determine if the current user has permission
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
下面附上修改后的代码
import { asyncRoutes, constantRoutes } from '@/router'
import { getMenu } from '@/api/menu'
import Layout from '@/layout'
/**
* Use meta.role to determine if the current user has permission
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
/**
* 后台查询的菜单数据拼装成路由格式的数据
* @param routes
* @param data
*/
export function generaMenu(routes, data) {
const len = data.length
// eslint-disable-next-line no-const-assign
for (let i = 0; i < len; i++) {
/* alert(data[i].path)
alert(data[i].meta.title)*/
const menu = {
path: data[i].path + '',
// component: () => import(`${item.component}`),
component: Layout,
alwaysShow: data[i].alwaysShow,
redirect: data[i].redirect + '',
name: data[i].name + '',
// hidden: true,
meta: { title: data[i].meta.title + '', icon: data[i].meta.icon },
children: []
}
// alert('data[i].children' + data[i].children)
if (data[i].children) {
const children = data[i].children
for (let j = 0; j < children.length; j++) {
const viewPath = children[j].component
const childrenList = {
path: children[j].path + '',
component: (resolve) => require([`@/views/${viewPath}`], resolve),
name: children[j].name + '',
// hidden: true,
// component: () => import(`@/views/${viewPath}`),
meta: { title: children[j].meta.title + '', icon: children[j].meta.icon }
}
menu.children.push(childrenList)
}
}
routes.push(menu)
/* data.forEach(item => {
alert(JSON.stringify(item))
const menu = {
path: item.path + '',
// component: () => import(`${item.component}`),
component: Layout,
name: item.name + '',
// hidden: true,
meta: { title: item.title + '', icon: item.icon, roles: ['admin'] },
children: []
}
if (item.children) {
const children = data.children
children.forEach(item1 => {
const childrenList = {
path: item1.path + '',
component: () => import(`${item1.component}`),
name: item1.name + '',
// hidden: true,
meta: { title: item1.title + '', icon: item1.icon, roles: ['admin'] }
}
menu.children.push(childrenList)
})
}
routes.push(menu)
})*/
}
}
/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
// 先查询后台并返回左侧菜单数据并把数据添加到路由
getMenu().then(response => {
const data = response.data
// Object.assign(loadMenuData, data)
generaMenu(asyncRoutes, data)
let accessedRoutes
if (roles.includes('admin')) {
// alert(JSON.stringify(asyncRoutes))
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
// generaMenu(asyncRoutes, data)
}).catch(error => {
console.log(error)
})
})
}
}
/* const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
console.log('asyncRoutes' + asyncRoutes)
accessedRoutes = asyncRoutes || []
console.log('accessedRoutes' + accessedRoutes)
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}*/
export default {
namespaced: true,
state,
mutations,
actions
}
代码详细介绍
- 引入后台接口的方法(也就是封装好的axios,然后把接口统一写在一个js文件里,用的时候直接引入,方便后期维护)
首先在@/api
目录下(也就是src/api
目录)新建menu.js
文件,定义一个方法用来获取数据
import request from '@/utils/request'
export function getMenu() {
return request({
url: '/menu/selectMenu',
method: 'post',
})
}
然后在@/store/moudles
下的permission.js
中引入
import { getMenu } from '@/api/menu'
- 改写
actions.generateRoutes
方法
思路: 首先调用接口getMenu
从后台获取数据,利generaMenu(asyncRoutes, data)
方法组织数据结构为routes的数据结构(generaMenu为自定义的方法)
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
// 先查询后台并返回左侧菜单数据并把数据添加到路由
getMenu().then(response => {
const data = response.data
// Object.assign(loadMenuData, data)
generaMenu(asyncRoutes, data)
let accessedRoutes
if (roles.includes('admin')) {
// alert(JSON.stringify(asyncRoutes))
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
// generaMenu(asyncRoutes, data)
}).catch(error => {
console.log(error)
})
})
}
}
3.编写generaMenu
方法
思路: 就是把获取的数据转换为routes的格式,如下,更加详细的请看目录@/router/index.js
下的数据结构
这里只给出示例,因为我的数据当时在编写的时候就在后台进行转换了,所以我的转换方法并不适用你们自己的!
请自行编写转换方法思路!!!!
请自行编写转换方法思路!!!!
请自行编写转换方法思路!!!!
数据结构:
{
path: '/documentation',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/documentation/index'),
name: 'Documentation',
meta: { title: 'documentation', icon: 'documentation', affix: true }
}
]
}
generaMenu方法代码
export function generaMenu(routes, data) {
const len = data.length
// eslint-disable-next-line no-const-assign
for (let i = 0; i < len; i++) {
/* alert(data[i].path)
alert(data[i].meta.title)*/
const menu = {
path: data[i].path + '',
// component: () => import(`${item.component}`),
component: Layout,
alwaysShow: data[i].alwaysShow,
redirect: data[i].redirect + '',
name: data[i].name + '',
// hidden: true,
meta: { title: data[i].meta.title + '', icon: data[i].meta.icon },
children: []
}
// alert('data[i].children' + data[i].children)
if (data[i].children) {
const children = data[i].children
for (let j = 0; j < children.length; j++) {
const viewPath = children[j].component
const childrenList = {
path: children[j].path + '',
component: (resolve) => require([`@/views/${viewPath}`], resolve),
name: children[j].name + '',
// hidden: true,
// component: () => import(`@/views/${viewPath}`),
meta: { title: children[j].meta.title + '', icon: children[j].meta.icon }
}
menu.children.push(childrenList)
}
}
routes.push(menu)
}
}
对应的数据库表结构
请自行编写转换方法思路!!!!
请自行编写转换方法思路!!!!
请自行编写转换方法思路!!!!
需要引入Layoutimport Layout from '@/layout'
只要可以把数据转换为规定的结构即可!!
根据角色权限动态生成路由菜单
在以上基础上只需要修改接口接收role参数,然后把参数传入后台,后台根据角色信息返回该角色可访问的菜单列表即可
export function getMenu(data) {
return request({
url: '/menu/selectMenu',
method: 'post',
params: data
})
}
const roleName = roles[0]
getMenu({ roleName: roleName }).then(response => {