功能描述
根据后端给到的菜单权限code来判断该用户拥有哪些菜单权限,并将该用户有权限的菜单显示出来,没有权限的则隐藏;其次,因为每个菜单是通过路由加载,如果该用户没有某个菜单的权限,不仅不显示该菜单而且也不能访问该菜单下的路由(即在浏览器地址栏输入没有权限的菜单路由会直接跳转到404页面)
代码实现
@/router/routes.js文件是用来存所有菜单的所有路由信息
import Base from "../../views/base.vue"; //基础布局,上左右结构
/**
* @type { import("vue-router").RouteRecordRaw[] }
*/
export default [
{
path: "/test",
name: "base",
component: Base,
redirect: "/test/page1",
children: [
{
path: "/test/page1", //一级菜单
name: "Page1",
meta: {
permissionCode: "menu_page1"
},
redirect: "/test/page1/page11"
},
{
path: "/test/page1/page11", //二级菜单
name: "Page11",
meta: {
permissionCode: "menu_page1_page11"
},
component: () => import("@/views/page1/page11")
},
{
path: "/test/page2", //一级菜单
name: "Page2",
meta: {
permissionCode: "menu_page2"
},
redirect: "/test/page1/page22"
},
{
path: "/test/page2/page22", //二级菜单
name: "Page22",
meta: {
permissionCode: "menu_page2_page22"
},
component: () => import("@/views/page2/page2")
}
......
]
}
];
@/router/index.js 路由文件
import { createRouter, createWebHistory } from "vue-router";
import setRouterGuards from "./guards";
const systemRoutes = [];
export const resetRouter = (systemRoutes) => {
const routes = [
{
path: "/",
redirect: "/login"
},
{
path: "/login",
name: "mainLogin",
component: () => import("@/views/login")
},
{
path: "/logout",
name: "mainLogout",
component: () => import("@/views/logout")
},
{
path: "/404",
name: "main404",
component: () => import("@/views/error/404")
},
{
path: "/:catchAll(.*)",
redirect: "/404"
},
...systemRoutes
];
const router = createRouter({
history: createWebHistory("/"),
routes
});
setRouterGuards(router);
return router;
};
export default resetRouter(systemRoutes);
登录获取权限后组装动态路由
import router, { resetRouter } from "@/router";
import routes from "@/router/routes";
import { cloneDeep } from "lodash";
function GetUserInfo () {
//用户密码登录后获取权限菜单
//menuAuth = ["menu_page1","menu_page1_page11","menu_page2","menu_page2_page22"...]
.....
//动态路由组装
let tempRoutes = cloneDeep(routes[0].children);
let newRoutes = cloneDeep(routes);
tempRoutes?.map((m) => {
if (m.meta?.permissionCode) {
let isExist = menuAuth.some((p) => m.meta?.permissionCode === p);
if (!isExist) {
let index = newRoutes[0].children.findIndex((r) => m.path === r.path);
index > -1 ? newRoutes[0].children.splice(index, 1) : null;
}
}
});
newRoutes[0].redirect = newRoutes[0].children[0].path;
//添加路由前先重置路由
router.matcher = resetRouter([]).matcher;
newRoutes.forEach((m) => router.addRoute(m));
......
//存储用户信息及权限后进入系统
}
OK,这样动态路由就加载完成了。
注意
问题:刷新页面后,有权限访问的页面也变成了404,原因是登录时对已有权限的路由进行添加到系统路由中,但刷新页面后main.js文件也会重新加载,路由就会恢复默认没有添加routes的状态,导致访问所有的菜单都是404。
解决方法:在main.js实例化路由之前,首先判断当前系统是否已登录,如果已经登录那么就直接从store中取出已经持久化存储的权限菜单menuAuth,进行再次添加相关的路由信息。
main.js
import store from "./store";
import router, { resetRouter } from "@/router";
import routes from "@/router/routes";
import { cloneDeep } from "lodash";
......
let instance = null;
function checkRouter() {
let menuAuth = store?.state?.user?.menuAuth || [];
if (menuAuth?.length) {
//动态路由组装
let tempRoutes = cloneDeep(routes[0].children);
let newRoutes = cloneDeep(routes);
tempRoutes?.map((m) => {
if (m.meta?.permissionCode) {
let isExist = menuAuth.some((p) => m.meta?.permissionCode === p);
if (!isExist) {
let index = newRoutes[0].children.findIndex((r) => m.path === r.path);
index > -1 ? newRoutes[0].children.splice(index, 1) : null;
}
}
});
newRoutes[0].redirect = newRoutes[0].children[0].path;
//添加路由前先重置路由
router.matcher = resetRouter([]).matcher;
newRoutes.forEach((m) => router.addRoute(m));
}
}
function render(props = {}) {
const { container } = props;
instance = plugin(createApp(App));
checkRouter(); //重新鉴权路由
instance
.use(store)
.use(router)
.use(i18n)
.use(Table)
.use(Button)
.use(Input)
.mount(container ? container.querySelector("#app") : "#app");
}
......