一、项目主体
- 管理平台(代称为ManagePlatform、MP)
- 一级菜单(代称M)
- 二级菜单(代称m)
结构图:
二、应用场景
不同用户拥有不同的菜单权限:
- 管理员(manageUser)拥有可见全部菜单的权限
- 用户1(user1)拥有可见M1下的全部菜单的权限
- 用户2(user2)拥有可见M1和M2下的全部菜单的权限
- 用户3(user3)拥有可见M1、M2下全部及M3的m31菜单权限
三、实现思路
权限控制:
- 导航栏菜单是否可见
- 校验url能否跳转
服务端:
- 接口返回当前用户的权限数据,并实际菜单结构保持一致(MP中包含M1、M2、M3,M1中包含m11、m12,...)
- 其中每个菜单包含id(菜单id)、name(菜单名称)、children(子集菜单)等必要属性
前端:
- 路由默认配置全部的菜单,但均为隐藏状态(登录和首页无权限,无需限制)
- 通过接口获取到该用户的权限数据,并与默认路由进行比对,将对应菜单部分设置为可显示(有权限)
- 将菜单所有id存储到本地list,在路由跳转之前校验此路由的id是否包含在list中,如果有,则执行跳转,否则进入到首页(表示没有权限)
四、代码模拟
默认路由routes:
export default [
{
path: '/M1',
redirect: '/M1/m11',
component: Layout,
name: 'M1菜单',
meta: {
extraMenuId: 1,
hidden: true
},
children: [{
path: '/M1/m11',
name: 'm11菜单',
component(resolve) {
require(['@views/M1/m11'], resolve);
},
meta: {
extraMenuId: 2,
hidden: true,
}
}, {
path: '/M1/m12',
name: 'm12菜单',
component(resolve) {
require(['@views/M1/m12'], resolve);
},
meta: {
extraMenuId: 3,
hidden: true,
}
}]
},
{
path: '/M2',
redirect: '/M2/m21',
component: Layout,
name: 'M2菜单',
meta: {
extraMenuId: 4,
hidden: true
},
children: [{
path: '/M2/m11',
name: 'm21菜单',
component(resolve) {
require(['@views/M2/m21'], resolve);
},
meta: {
extraMenuId: 5,
hidden: true,
}
}, {
path: '/M2/m22',
name: 'm22菜单',
component(resolve) {
require(['@views/M2/m22'], resolve);
},
meta: {
extraMenuId: 6,
hidden: true,
}
}]
},
{
path: '/M3',
redirect: '/M3/m31',
component: Layout,
name: 'M3菜单',
meta: {
extraMenuId: 7,
hidden: true
},
children: [{
path: '/M3/m31',
name: 'm31菜单',
component(resolve) {
require(['@views/M3/m31'], resolve);
},
meta: {
extraMenuId: 8,
hidden: true,
}
}, {
path: '/M3/m32',
name: 'm32菜单',
component(resolve) {
require(['@views/M3/m32'], resolve);
},
meta: {
extraMenuId: 9,
hidden: true,
}
}, {
path: '/M3/m33',
name: 'm33菜单',
component(resolve) {
require(['@views/M3/m33'], resolve);
},
meta: {
extraMenuId: 9,
hidden: true,
}
}]
},
{
path: '/login',
name: '登录',
component(resolve) {
require(['@views/login'], resolve);
},
meta: {
hidden: true
}
},
{
path: '/home',
name: '首页',
component(resolve) {
require(['@views/home'], resolve);
},
meta: {
hidden: true
}
},
{
path: '*',
redirect: '/home',
meta: {
hidden: true
}
}
]
复制代码
菜单id数据menuIdList与路由routes匹配:
// 因管理端菜单展示只展示两层,故只需遍历前两层路由
routes.forEach((item) => {
if (menuIdList.indexOf(item.meta.extraMenuId) >= 0) {
item.meta.hidden = false;
if (item.children && item.children.length) {
item.children.forEach((child) => {
if (menuIdList.indexOf(child.meta.extraMenuId) >= 0) {
child.meta.hidden = false;
}
})
}
}
});
复制代码
公共方法判断id是否存在:
/**
* 判断menuId是否存在与Localtorage中
* @param menuId
*/
export function getMenuAuth(menuId) {
const menuIdList = JSON.parse(getMenuIdList());
return menuIdList.indexOf(menuId) >= 0;
}
复制代码
路由守卫校验:
router.beforeEach((to, from, next) => {
// 判断是否已登录,未登录则进入登录页面
if (getToken()) {
if (to.path === '/login') {
next();
} else {
if (to.path === '/' || to.path === '/home') {
next();
return;
}
// url路由权限校验,没有权限则进入home页面
if (getMenuAuth(to.meta.extraMenuId)) {
next();
} else {
next('/home');
}
}
} else {
next('/login');
}
})
复制代码
以上仅为项目开发过程中的个人思路,如有更好的想法思路请在评论区留言,谢谢!