From 605d87b3a7f6a47fdc78268e6923e273e93aedc8 Mon Sep 17 00:00:00 2001 From: ray <1490493387@qq.com> Date: Fri, 18 Oct 2024 22:04:18 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20:bug:=20=E4=BF=AE=E5=A4=8D=E6=B3=A8?= =?UTF-8?q?=E9=94=80=E7=99=BB=E5=BD=95location.reload=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=97=A0=E5=93=8D=E5=BA=94=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/permission.ts | 47 ++++++++++++++--------------- src/store/modules/permission.ts | 25 +++++++++++++++- src/store/modules/user.ts | 53 +++++++++++++++++++-------------- 3 files changed, 76 insertions(+), 49 deletions(-) diff --git a/src/plugins/permission.ts b/src/plugins/permission.ts index 34056fe6..f93db995 100644 --- a/src/plugins/permission.ts +++ b/src/plugins/permission.ts @@ -3,10 +3,8 @@ import type { RouteLocationNormalized, RouteRecordRaw, } from "vue-router"; - import NProgress from "@/utils/nprogress"; -import { isLogin } from "@/utils/auth"; - +import { getToken } from "@/utils/auth"; import router from "@/router"; import { usePermissionStore, useUserStore } from "@/store"; @@ -16,22 +14,21 @@ export function setupPermission() { router.beforeEach(async (to, from, next) => { NProgress.start(); - if (isLogin()) { - if (to.path === "/login") { - // 如果已登录,跳转到首页 - next({ path: "/" }); - NProgress.done(); - } else { - const userStore = useUserStore(); - const hasRoles = - userStore.user.roles && userStore.user.roles.length > 0; - if (hasRoles) { - // 如果未匹配到任何路由,跳转到404页面 + const isLogin = !!getToken(); // 判断是否登录 + if (isLogin) { + if (to.path === "/login") { + // 已登录,访问登录页,跳转到首页 + next({ path: "/" }); + } else { + const permissionStore = usePermissionStore(); + // 判断路由是否加载过 + if (permissionStore.isRoutesLoaded) { if (to.matched.length === 0) { - next(from.name ? { name: from.name } : "/404"); + // 路由未匹配,跳转到404 + next("/404"); } else { - // 如果路由参数中有 title,覆盖路由元信息中的 title + // 动态设置页面标题 const title = (to.params.title as string) || (to.query.title as string); if (title) { @@ -40,35 +37,35 @@ export function setupPermission() { next(); } } else { - const permissionStore = usePermissionStore(); try { - await userStore.getUserInfo(); + // 生成动态路由 const dynamicRoutes = await permissionStore.generateRoutes(); dynamicRoutes.forEach((route: RouteRecordRaw) => router.addRoute(route) ); - next({ ...to, replace: true }); + next({ ...to, replace: true }); // 添加动态路由后重新导航 } catch (error) { console.error(error); - // 移除 token 并重定向到登录页,携带当前页面路由作为跳转参数 - await userStore.resetToken(); + // 路由加载失败,重置 token 并重定向到登录页 + await useUserStore().clearUserSession(); redirectToLogin(to, next); NProgress.done(); } } } } else { - // 未登录 + // 未登录,判断是否在白名单中 if (whiteList.includes(to.path)) { - next(); // 在白名单,直接进入 + next(); } else { // 不在白名单,重定向到登录页 redirectToLogin(to, next); - NProgress.done(); + NProgress.done(); // 关闭进度条 } } }); + // 后置守卫,保证每次路由跳转结束时关闭进度条 router.afterEach(() => { NProgress.done(); }); @@ -90,7 +87,7 @@ export function hasAuth( value: string | string[], type: "button" | "role" = "button" ) { - const { roles, perms } = useUserStore().user; + const { roles, perms } = useUserStore().userInfo; // 超级管理员 拥有所有权限 if (type === "button" && roles.includes("ROOT")) { diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index 4b027c12..77940aed 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -1,17 +1,21 @@ import type { RouteRecordRaw } from "vue-router"; import { constantRoutes } from "@/router"; import { store } from "@/store"; -import MenuAPI, { type RouteVO } from "@/api/menu"; +import MenuAPI, { type RouteVO } from "@/api/system/menu"; const modules = import.meta.glob("../../views/**/**.vue"); const Layout = () => import("@/layout/index.vue"); +import router from "@/router"; + export const usePermissionStore = defineStore("permission", () => { /** 所有路由,包括静态和动态路由 */ const routes = ref([]); /** 混合模式左侧菜单 */ const mixLeftMenus = ref([]); + const isRoutesLoaded = ref(false); + /** * 生成动态路由 */ @@ -21,6 +25,7 @@ export const usePermissionStore = defineStore("permission", () => { .then((data) => { const dynamicRoutes = transformRoutes(data); routes.value = constantRoutes.concat(dynamicRoutes); + isRoutesLoaded.value = true; resolve(dynamicRoutes); }) .catch((error) => { @@ -41,11 +46,29 @@ export const usePermissionStore = defineStore("permission", () => { } }; + /** + * 重置路由 + */ + const resetRouter = () => { + // 删除动态路由,保留静态路由 + routes.value.forEach((route) => { + if (route.name && !constantRoutes.find((r) => r.name === route.name)) { + router.removeRoute(route.name); // 从 router 实例中移除动态路由 + } + }); + + routes.value = []; + mixLeftMenus.value = []; + isRoutesLoaded.value = false; + }; + return { routes, generateRoutes, mixLeftMenus, setMixLeftMenus, + isRoutesLoaded, + resetRouter, }; }); diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index db62ab55..f5251aa1 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,14 +1,14 @@ -import AuthAPI, { type LoginData } from "@/api/auth"; -import UserAPI, { type UserInfo } from "@/api/user"; -import { resetRouter } from "@/router"; import { store } from "@/store"; -import { setToken, removeToken } from "@/utils/auth"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import { useDictStoreHook } from "@/store/modules/dict"; + +import AuthAPI, { type LoginData } from "@/api/auth"; +import UserAPI, { type UserInfo } from "@/api/system/user"; + +import { setToken, clearToken } from "@/utils/auth"; export const useUserStore = defineStore("user", () => { - const user = ref({ - roles: [], - perms: [], - }); + const userInfo = useStorage("userInfo", {} as UserInfo); /** * 登录 @@ -30,7 +30,11 @@ export const useUserStore = defineStore("user", () => { }); } - // 获取信息(用户昵称、头像、角色集合、权限集合) + /** + * 获取用户信息 + * + * @returns {UserInfo} 用户信息 + */ function getUserInfo() { return new Promise((resolve, reject) => { UserAPI.getInfo() @@ -39,11 +43,7 @@ export const useUserStore = defineStore("user", () => { reject("Verification failed, please Login again."); return; } - if (!data.roles || data.roles.length <= 0) { - reject("getUserInfo: roles must be a non-null array!"); - return; - } - Object.assign(user.value, { ...data }); + Object.assign(userInfo.value, { ...data }); resolve(data); }) .catch((error) => { @@ -52,12 +52,14 @@ export const useUserStore = defineStore("user", () => { }); } - // user logout + /** + * 登出 + */ function logout() { return new Promise((resolve, reject) => { AuthAPI.logout() .then(() => { - location.reload(); // 清空路由 + clearUserSession(); resolve(); }) .catch((error) => { @@ -66,21 +68,26 @@ export const useUserStore = defineStore("user", () => { }); } - // remove token - function resetToken() { + /** + * 清理用户会话 + * + * @returns + */ + function clearUserSession() { return new Promise((resolve) => { - removeToken(); - resetRouter(); + clearToken(); + usePermissionStoreHook().resetRouter(); + useDictStoreHook().clearDictionaryCache(); resolve(); }); } return { - user, - login, + userInfo, getUserInfo, + login, logout, - resetToken, + clearUserSession, }; });