前端路由方案
1.router文件
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
/* Layout */
import Layout from "@/layout";
import store from "@/store";
// 通用路由,不需要配置权限
export const constRouter = [
{
path: "/login",
component: () => import("@/views/login/index"),
hidden: true,
meta: {
roles: [],
},
},
{
path: "/404",
component: () => import("@/views/404"),
hidden: true,
meta: {
roles: [],
},
},
{
path: "/",
component: Layout,
redirect: "/dashboard",
meta: {
title: "个人中心",
icon: "dashboard",
roles: [],
},
children: [
{
path: "dashboard",
name: "Dashboard",
component: () => import("@/views/grgl/person"),
meta: {
title: "个人信息",
icon: "dashboard",
roles: [],
},
},
{
path: "/spgl/goodType",
name: "GoodType",
component: () => import("@/views/spgl/goodType"),
meta: {
title: "商品类型",
icon: "nested",
roles: ["goodType:list"],
},
},
]
},
];
// 动态路由
export const constantRoutes = [
{
path: "/spgl",
component: Layout,
alwaysShow: true,
meta: {
title: "商品管理",
icon: "nested",
roles: ["goods:list","goodType:list"],
},
children: [
{
path: "/spgl/goods",
name: "Goods",
component: () => import("@/views/spgl/goods"),
meta: {
title: "商品列表",
icon: "nested",
roles: ["goods:list"],
},
},
],
},
];
const createRouter = () =>
new VueRouter({
scrollBehavior: () => ({ y: 0 }),
routes: constRouter,
});
const router = createRouter();
export function resetRouter() {
const newRouter = createRouter();
router.matcher = newRouter.matcher; // reset router
}
export default router;
2.在仓库创建路由操作文件 permiss.js
import { constRouter, constantRoutes } from "@/router";
import router from "@/router/index";
const context = require.context("@/views/", true, /\.vue$/);
const state = {
routes: [],
};
// 修改store
const mutations = {
SET_ROUTES(state, routesAA) {
state.routes = routesAA;
},
};
const actions = {
// 根据角色获取动态路由
generateRoutes({ commit }, menuInfo) {
return new Promise((resolve) => {
let accessedRoutes;
accessedRoutes = constantRoutes;
// 获取接口--个人的所有菜单
let arr = getFlatMenuList(menuInfo.menuList);
// 将菜单添加进路由
let newArr = filterAsyncRoutesEE(constantRoutes, arr);
// 判断权限
let lastArr = filterAsyncRoutes(newArr, menuInfo.permissions);
// 拼接 基础路由 + 接口路由
accessedRoutes = constRouter.concat(lastArr);
commit("SET_ROUTES", accessedRoutes);
resolve(accessedRoutes);
});
},
};
// 判断路由是否有权限
export const hasPermission = (roles, route) => {
if (route.meta && route.meta.roles) {
return roles.some((ele) => route.meta.roles.includes(ele));
} else {
return false;
}
};
// 判断是否拥有权限
export const filterAsyncRoutes = (routes, roles) => {
const res = [];
routes.forEach((route) => {
let temp = { ...route };
// 判断子集权限
if (hasPermission(roles, temp)) {
if (temp.children) {
temp.children = filterAsyncRoutes(temp.children, roles);
}
res.push(temp);
}
});
return res;
};
// 从全部路由中过滤出 和后端数据一样的 路由
export const filterAsyncRoutesEE = (routes, menuList) => {
const res = [];
routes.forEach((route) => {
let temp = { ...route };
// 判断后端路由和前端路路径相同后 使用前端路由
if (menuList.find((it) => it.path == temp.path)) {
router.addRoute(temp); // 将菜单路由 添加进 路由中
res.push(temp);
}
});
return res;
};
/**
* @description 使用递归扁平化菜单,方便添加动态路由
* @param {Array} menuList 菜单列表
* @returns {Array}
*/
export function getFlatMenuList(menuList) {
let newMenuList = JSON.parse(JSON.stringify(menuList));
return newMenuList.flatMap((item) => [
item,
...(item.children ? getFlatMenuList(item.children) : []),
]);
}
// export function loadView(view){
// return (resolve) => require(view, resolve)
// }
export default {
namespaced: true,
state,
mutations,
actions,
};
3.在登录后的 permission.js
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
const whiteList = ["/login"]; // no redirect whitelist
router.beforeEach(async (to, from, next) => {
// start progress bar
NProgress.start();
// set page title
document.title = getPageTitle(to.meta.title);
// 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();
} else {
const hasGetUserInfo = store.getters.name;
if (hasGetUserInfo) {
next();
} else {
try {
// 调用vuex方法
// 获取菜单信息
const menuInfo = await store.dispatch("user/getMenu");
// 获取用户信息
const data = await store.dispatch("user/getInfo");
// 根据角色生成动态路由
const accessRoutes = await store.dispatch( "permission/generateRoutes", menuInfo);
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();
});