菜单权限store\modules\permisstion.ts -> generateRoutes()
按钮权限directive\permission\index.ts
路由权限plugins\permission.ts
permission.ts 修改如下
import type { NavigationGuardNext, RouteLocationNormalized, RouteRecordRaw } from "vue-router";
import NProgress from "@/utils/nprogress";
import { getAccessToken } from "@/utils/auth";
import router from "@/router";
import { usePermissionStore, useUserStore } from "@/store";
export function setupPermission() {
// 白名单路由
const whiteList = ["/login", "/datav"];
const constantPathList = ["/redirect", "/dashboard", "/401", "/404", "/profile", "/myNotice"];
router.beforeEach(async (to, from, next) => {
// 开始进度条
NProgress.start();
const isLogin = !!getAccessToken(); // 判断是否登录
if (isLogin) {
if (to.path === "/login") {
// 已登录,访问登录页,跳转到首页
next({ path: "/" });
} else {
const permissionStore = usePermissionStore();
//console.log("permissionStore", permissionStore);
// 判断路由是否加载完成
if (permissionStore.isRoutesLoaded) {
if (to.matched.length === 0) {
// 路由未匹配,跳转到404
console.log("Route 加载完成后,路由未匹配 => ", to.path);
next("/404");
} else if (whiteList.includes(to.path)) {
console.log("Route 加载完成后,白名单 => ", to.path);
next();
} else {
const routeExists = constantPathList.some((path) => to.path.includes(path));
if (!routeExists) {
//有权限的 + 白名单 = 可访问
//console.log("Route 加载【后】 => ", to.path);
permissionCheck(permissionStore, to, next);
}
// 动态设置页面标题
const title = (to.params.title as string) || (to.query.title as string);
if (title) {
to.meta.title = title;
}
next();
}
} else {
try {
// 生成动态路由 -- 直接游览器里输入地址会走到这边
const dynamicRoutes = await permissionStore.generateRoutes();
const routeExists = constantPathList.some((path) => to.path.includes(path));
if (!routeExists) {
//有权限的 + 白名单 = 可访问
//console.log("Route 加载【前】 => ", to.path);
permissionCheck(permissionStore, to, next);
}
// console.log("dynamicRoutes", dynamicRoutes);
// console.log("router", router);
dynamicRoutes.forEach((route: RouteRecordRaw) => {
//console.log("route", route);
router.addRoute(route);
});
// console.log("router", router);
// console.log("to", to);
next({ ...to, replace: true });
} catch (error) {
console.error(error);
// 路由加载失败,重置 token 并重定向到登录页
await useUserStore().clearUserData();
redirectToLogin(to, next);
NProgress.done();
}
}
}
} else {
// 未登录,判断是否在白名单中
if (whiteList.includes(to.path)) {
next();
} else {
// 不在白名单,重定向到登录页
redirectToLogin(to, next);
NProgress.done();
}
}
});
// 后置守卫,保证每次路由跳转结束时关闭进度条
router.afterEach(() => {
NProgress.done();
});
}
function permissionCheck(permissionStore: any, to: any, next: NavigationGuardNext) {
console.log("permissionStore.routes", permissionStore.routes);
let found = false;
permissionStore.routes.forEach((route: RouteRecordRaw) => {
console.log("permissionStore.route", route.path);
if (to.path.includes(route.path) && route.path != "/") {
console.log("to.path => ", to.path);
console.log("route.path => ", route.path);
found = true;
}
});
if (!found) {
console.log("无权 => ", to.path);
next("/401");
}
}
// 重定向到登录页
function redirectToLogin(to: RouteLocationNormalized, next: NavigationGuardNext) {
const params = new URLSearchParams(to.query as Record<string, string>);
const queryString = params.toString();
const redirect = queryString ? `${to.path}?${queryString}` : to.path;
next(`/login?redirect=${encodeURIComponent(redirect)}`);
}
/** 判断是否有权限 */
export function hasAuth(value: string | string[], type: "button" | "role" = "button") {
const { roles, perms } = useUserStore().userInfo;
// 超级管理员 拥有所有权限
if (type === "button" && roles.includes("ROOT")) {
return true;
}
const auths = type === "button" ? perms : roles;
return typeof value === "string"
? auths.includes(value)
: value.some((perm) => auths.includes(perm));
}
console.log("to", to.path);
let found = false;
permissionStore.routes.forEach((route: RouteRecordRaw) => {
console.log("permissionStore.route", route.path);
if (route.path.includes(to.path)) {
found = true;
}
});
if (!found) {
next("/404");
}
不能用 some 优化,优化后值就变少了
console.log("to", to.path);
const routeExists = permissionStore.routes.some((route: RouteRecordRaw) => {
console.log("permissionStore.route", route.path);
return route.path.includes(to.path);
});
if (!routeExists) {
next("/404");
}