From cb075df41cbd41c9d294855d469cd12a89525021 Mon Sep 17 00:00:00 2001 From: gaoyunqi Date: Tue, 27 Feb 2024 15:19:54 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E5=AF=BC=E8=87=B4=E4=B8=A2=E5=A4=B1=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/router/guard/paramMenuGuard.ts | 134 ++++---- src/router/guard/permissionGuard.ts | 234 +++++++------- src/store/modules/user.ts | 459 ++++++++++++++-------------- 3 files changed, 413 insertions(+), 414 deletions(-) diff --git a/src/router/guard/paramMenuGuard.ts b/src/router/guard/paramMenuGuard.ts index 5fd75f2..417b1f4 100644 --- a/src/router/guard/paramMenuGuard.ts +++ b/src/router/guard/paramMenuGuard.ts @@ -1,68 +1,66 @@ -import type { Router } from 'vue-router'; -import { configureDynamicParamsMenu } from '../helper/menuHelper'; -import { Menu } from '../types'; -import { PermissionModeEnum } from '/@/enums/appEnum'; -import { useAppStoreWithOut } from '/@/store/modules/app'; - -import { usePermissionStoreWithOut } from '/@/store/modules/permission'; - -export function createParamMenuGuard(router: Router) { - const permissionStore = usePermissionStoreWithOut(); - router.beforeEach(async (to, _, next) => { - console.log('createParamMenuGuard', to); - - to.fullPath = (to.fullPath as string) + convertQuery(to); - - // filter no name route - if (!to.name) { - next(); - return; - } - - // menu has been built. - if (!permissionStore.getIsDynamicAddedRoute) { - next(); - return; - } - - let menus: Menu[] = []; - if (isBackMode()) { - menus = permissionStore.getBackMenuList; - } else if (isRouteMappingMode()) { - menus = permissionStore.getFrontMenuList; - } - menus.forEach((item) => configureDynamicParamsMenu(item, to.params)); - - next(); - }); -} - -const convertQuery = (to) => { - try { - if (to.meta.remark && to.meta.remark.indexOf('?') > -1 && to.fullPath.indexOf('?') <= -1) { - const str = to.meta.remark.substring(1); - const paramArray = str.split('&'); - for (const param of paramArray) { - const p = param.split('='); - to.query[p[0]] = p[1]; - } - return to.meta.remark; - } - return ''; - } catch { - return ''; - } -}; - -const getPermissionMode = () => { - const appStore = useAppStoreWithOut(); - return appStore.getProjectConfig.permissionMode; -}; - -const isBackMode = () => { - return getPermissionMode() === PermissionModeEnum.BACK; -}; - -const isRouteMappingMode = () => { - return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING; -}; +import type { Router } from 'vue-router'; +import { configureDynamicParamsMenu } from '../helper/menuHelper'; +import { Menu } from '../types'; +import { PermissionModeEnum } from '/@/enums/appEnum'; +import { useAppStoreWithOut } from '/@/store/modules/app'; + +import { usePermissionStoreWithOut } from '/@/store/modules/permission'; + +export function createParamMenuGuard(router: Router) { + const permissionStore = usePermissionStoreWithOut(); + router.beforeEach(async (to, _, next) => { + to.fullPath = (to.fullPath as string) + convertQuery(to); + + // filter no name route + if (!to.name) { + next(); + return; + } + + // menu has been built. + if (!permissionStore.getIsDynamicAddedRoute) { + next(); + return; + } + + let menus: Menu[] = []; + if (isBackMode()) { + menus = permissionStore.getBackMenuList; + } else if (isRouteMappingMode()) { + menus = permissionStore.getFrontMenuList; + } + menus.forEach((item) => configureDynamicParamsMenu(item, to.params)); + + next(); + }); +} + +const convertQuery = (to) => { + try { + if (to.meta.remark && to.meta.remark.indexOf('?') > -1 && to.fullPath.indexOf('?') <= -1) { + const str = to.meta.remark.substring(1); + const paramArray = str.split('&'); + for (const param of paramArray) { + const p = param.split('='); + to.query[p[0]] = p[1]; + } + return to.meta.remark; + } + return ''; + } catch { + return ''; + } +}; + +const getPermissionMode = () => { + const appStore = useAppStoreWithOut(); + return appStore.getProjectConfig.permissionMode; +}; + +const isBackMode = () => { + return getPermissionMode() === PermissionModeEnum.BACK; +}; + +const isRouteMappingMode = () => { + return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING; +}; diff --git a/src/router/guard/permissionGuard.ts b/src/router/guard/permissionGuard.ts index 8ef4dd3..8f1fe0c 100644 --- a/src/router/guard/permissionGuard.ts +++ b/src/router/guard/permissionGuard.ts @@ -1,117 +1,117 @@ -import type { Router, RouteRecordRaw } from 'vue-router'; - -import { usePermissionStoreWithOut } from '/@/store/modules/permission'; - -import { PageEnum } from '/@/enums/pageEnum'; -import { useUserStoreWithOut } from '/@/store/modules/user'; - -import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; - -import { RootRoute } from '/@/router/routes'; - -const LOGIN_PATH = PageEnum.BASE_LOGIN; - -const ROOT_PATH = RootRoute.path; - -const whitePathList: PageEnum[] = [LOGIN_PATH]; - -export function createPermissionGuard(router: Router) { - const userStore = useUserStoreWithOut(); - const permissionStore = usePermissionStoreWithOut(); - router.beforeEach(async (to, from, next) => { - if ( - from.path === ROOT_PATH && - to.path === PageEnum.BASE_HOME && - userStore.getUserInfo.homePath && - userStore.getUserInfo.homePath !== PageEnum.BASE_HOME - ) { - next(userStore.getUserInfo.homePath); - return; - } - - const token = userStore.getToken; - - // Whitelist can be directly entered - if (whitePathList.includes(to.path as PageEnum)) { - if (to.path === LOGIN_PATH && token) { - const isSessionTimeout = userStore.getSessionTimeout; - try { - await userStore.afterLoginAction(); - if (!isSessionTimeout) { - next((to.query?.redirect as string) || '/'); - return; - } - } catch {} - } - next(); - return; - } - - // token does not exist - if (!token) { - // You can access without permission. You need to set the routing meta.ignoreAuth to true - if (to.meta.ignoreAuth) { - next(); - return; - } - - // redirect login page - const redirectData: { path: string; replace: boolean; query?: Recordable } = { - path: LOGIN_PATH, - replace: true, - }; - if (to.path) { - redirectData.query = { - ...redirectData.query, - redirect: to.path, - }; - } - next(redirectData); - return; - } - - // Jump to the 404 page after processing the login - if ( - from.path === LOGIN_PATH && - to.name === PAGE_NOT_FOUND_ROUTE.name && - to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME) - ) { - next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME); - return; - } - - // get userinfo while last fetch time is empty - if (userStore.getLastUpdateTime === 0) { - try { - await userStore.getUserInfoAction(); - } catch (err) { - next(); - return; - } - } - - if (permissionStore.getIsDynamicAddedRoute) { - next(); - return; - } - const routes = await permissionStore.buildRoutesAction(false); - - routes.forEach((route) => { - router.addRoute(route as unknown as RouteRecordRaw); - }); - - router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); - - permissionStore.setDynamicAddedRoute(true); - - if (to.name === PAGE_NOT_FOUND_ROUTE.name) { - // 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容 - next({ path: to.fullPath, replace: true, query: to.query }); - } else { - const redirectPath = (from.query.redirect || to.path) as string; - const redirect = decodeURIComponent(redirectPath); - const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }; - next(nextData); - } - }); -} +import type { Router, RouteRecordRaw } from 'vue-router'; + +import { usePermissionStoreWithOut } from '/@/store/modules/permission'; + +import { PageEnum } from '/@/enums/pageEnum'; +import { useUserStoreWithOut } from '/@/store/modules/user'; + +import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; + +import { RootRoute } from '/@/router/routes'; + +const LOGIN_PATH = PageEnum.BASE_LOGIN; + +const ROOT_PATH = RootRoute.path; + +const whitePathList: PageEnum[] = [LOGIN_PATH]; + +export function createPermissionGuard(router: Router) { + const userStore = useUserStoreWithOut(); + const permissionStore = usePermissionStoreWithOut(); + router.beforeEach(async (to, from, next) => { + if ( + from.path === ROOT_PATH && + to.path === PageEnum.BASE_HOME && + userStore.getUserInfo.homePath && + userStore.getUserInfo.homePath !== PageEnum.BASE_HOME + ) { + next(userStore.getUserInfo.homePath); + return; + } + + const token = userStore.getToken; + + // Whitelist can be directly entered + if (whitePathList.includes(to.path as PageEnum)) { + if (to.path === LOGIN_PATH && token) { + const isSessionTimeout = userStore.getSessionTimeout; + try { + await userStore.afterLoginAction(); + if (!isSessionTimeout) { + next((to.query?.redirect as string) || '/'); + return; + } + } catch {} + } + next(); + return; + } + + // token does not exist + if (!token) { + // You can access without permission. You need to set the routing meta.ignoreAuth to true + if (to.meta.ignoreAuth) { + next(); + return; + } + + // redirect login page + const redirectData: { path: string; replace: boolean; query?: Recordable } = { + path: LOGIN_PATH, + replace: true, + }; + if (to.path) { + redirectData.query = { + ...redirectData.query, + redirect: to.path, + }; + } + next(redirectData); + return; + } + + // Jump to the 404 page after processing the login + if ( + from.path === LOGIN_PATH && + to.name === PAGE_NOT_FOUND_ROUTE.name && + to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME) + ) { + next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME); + return; + } + + // get userinfo while last fetch time is empty + if (userStore.getLastUpdateTime === 0) { + try { + await userStore.getUserInfoAction(); + } catch (err) { + next(); + return; + } + } + + if (permissionStore.getIsDynamicAddedRoute) { + next(); + return; + } + + const routes = await permissionStore.buildRoutesAction(); + + routes.forEach((route) => { + router.addRoute(route as unknown as RouteRecordRaw); + }); + + router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); + permissionStore.setDynamicAddedRoute(true); + + if (to.name === PAGE_NOT_FOUND_ROUTE.name) { + // 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容 + next({ path: to.fullPath, replace: true, query: to.query }); + } else { + const redirectPath = (from.query.redirect || to.path) as string; + const redirect = decodeURIComponent(redirectPath); + const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }; + next(nextData); + } + }); +} diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index f042c32..ca95780 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,229 +1,230 @@ -import type { UserInfo } from '/#/store'; -import type { ErrorMessageMode } from '/#/axios'; -import { defineStore } from 'pinia'; -import { store } from '/@/store'; -import { PageEnum } from '/@/enums/pageEnum'; -import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; -import { getAuthCache, setAuthCache } from '/@/utils/auth'; -import { GetUserInfoModel, LoginParams, RoleInfo } from '/@/api/system/login/model'; -import { doLogout, getUserInfo, loginApi } from '/@/api/system/login'; -import { useI18n } from '/@/hooks/web/useI18n'; -import { useMessage } from '/@/hooks/web/useMessage'; -import { router } from '/@/router'; -import { usePermissionStore } from '/@/store/modules/permission'; -import { RouteRecordRaw } from 'vue-router'; -import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; -import { h } from 'vue'; -import { getAppEnvConfig } from '/@/utils/env'; -interface UserState { - userInfo: Nullable; - token?: string; - roleList: RoleInfo[]; - sessionTimeout?: boolean; - lastUpdateTime: number; -} - -export const useUserStore = defineStore({ - id: 'app-user', - state: (): UserState => ({ - // user info - userInfo: null, - // token - token: undefined, - // roleList - roleList: [], - // Whether the login expired - sessionTimeout: false, - // Last fetch time - lastUpdateTime: 0, - }), - getters: { - getUserInfo(): UserInfo { - return this.userInfo || getAuthCache(USER_INFO_KEY) || {}; - }, - getToken(): string { - return this.token || getAuthCache(TOKEN_KEY); - }, - getRoleList(): RoleInfo[] { - return this.roleList && this.roleList.length > 0 - ? this.roleList - : getAuthCache(ROLES_KEY); - }, - getSessionTimeout(): boolean { - return !!this.sessionTimeout; - }, - getLastUpdateTime(): number { - return this.lastUpdateTime; - }, - }, - actions: { - setToken(info: string | undefined) { - this.token = info ? info : ''; // for null or undefined value - setAuthCache(TOKEN_KEY, info); - }, - setRoleList(roleList: RoleInfo[]) { - this.roleList = roleList; - setAuthCache(ROLES_KEY, roleList); - }, - setUserInfo(info: UserInfo | null) { - this.userInfo = info; - this.lastUpdateTime = new Date().getTime(); - setAuthCache(USER_INFO_KEY, info); - }, - setSessionTimeout(flag: boolean) { - this.sessionTimeout = flag; - }, - resetState() { - this.userInfo = null; - this.token = ''; - this.roleList = []; - this.sessionTimeout = false; - }, - /** - * @description: OAUTH Login - */ - async oauthLogin( - params: { - token: string; - } & { - goHome?: boolean; - mode?: ErrorMessageMode; - }, - ): Promise { - try { - const { goHome = true, token } = params; - - // save token - this.setToken(token); - - return this.afterLoginAction(goHome); - } catch (error) { - return Promise.reject(error); - } - }, - /** - * @description: login - */ - async login( - params: LoginParams & { - goHome?: boolean; - mode?: ErrorMessageMode; - }, - ): Promise { - try { - const { goHome = true, mode, ...loginParams } = params; - const data = await loginApi(loginParams, mode); - - const { token } = data; - // save token - this.setToken(token); - - return this.afterLoginAction(goHome); - } catch (error) { - return Promise.reject(error); - } - }, - async afterLoginAction(goHome?: boolean): Promise { - if (!this.getToken) return null; - - // get user info - const userInfo = await this.getUserInfoAction(); - - // setOtherToken(this.getToken); - - const sessionTimeout = this.sessionTimeout; - if (sessionTimeout) { - this.setSessionTimeout(false); - } else { - const permissionStore = usePermissionStore(); - - if (!permissionStore.isDynamicAddedRoute) { - const routes = await permissionStore.buildRoutesAction(); - routes.forEach((route) => { - router.addRoute(route as unknown as RouteRecordRaw); - }); - router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); - permissionStore.setDynamicAddedRoute(true); - } - goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME)); - } - - setOtherToken(this.getToken); - return Promise.resolve(userInfo); - }, - async getUserInfoAction(): Promise { - if (!this.getToken) return null; - const userInfoResult = await getUserInfo(); - - const { roles = [] } = userInfoResult; - - const userInfo = userInfoResult as unknown as UserInfo; - this.setUserInfo(userInfo); - this.setRoleList(roles); - return Promise.resolve(userInfoResult); - }, - /** - * @description: logout - */ - async logout(goLogin = false) { - if (this.getToken) { - try { - await doLogout(); - } catch { - console.log('注销Token失败'); - } - } - this.setToken(undefined); - this.setSessionTimeout(false); - this.setUserInfo(null); - goLogin && router.push(PageEnum.BASE_LOGIN); - }, - - /** - * @description: Confirm before logging out - */ - confirmLoginOut() { - const { createConfirm } = useMessage(); - const { t } = useI18n(); - createConfirm({ - iconType: 'warning', - title: () => h('span', t('温馨提醒')), - content: () => h('span', t('是否确认退出系统?')), - onOk: async () => { - await this.logout(true); - }, - okText: () => t('确认'), - cancelText: () => t('取消'), - }); - }, - }, -}); - -// Need to be used outside the setup -export function useUserStoreWithOut() { - return useUserStore(store); -} - -//设置其他url 项目 token -function setOtherToken(token: string) { - // console.log('other token', getAppEnvConfig()); // something like: "https://codegeex.cn" or "https://codegeex.cn" or - getAppEnvConfig() - .VITE_GLOB_OUT_LINK_URL?.split(',') - ?.forEach((item) => { - // 创建子域的iframe, 用于传送数据 - const iframe = document.createElement('iframe'); - iframe.src = `${item}`; - iframe.style.display = 'none'; - document.body.append(iframe); - - // 使用postMessage()发送数据到子系统 - setTimeout(function () { - iframe.contentWindow?.postMessage(token, item); - }, 2000); - - // 销毁iframe - setTimeout(function () { - iframe.remove(); - }, 4000); - }); -} +import type { UserInfo } from '/#/store'; +import type { ErrorMessageMode } from '/#/axios'; +import { defineStore } from 'pinia'; +import { store } from '/@/store'; +import { PageEnum } from '/@/enums/pageEnum'; +import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; +import { getAuthCache, setAuthCache } from '/@/utils/auth'; +import { GetUserInfoModel, LoginParams, RoleInfo } from '/@/api/system/login/model'; +import { doLogout, getUserInfo, loginApi } from '/@/api/system/login'; +import { useI18n } from '/@/hooks/web/useI18n'; +import { useMessage } from '/@/hooks/web/useMessage'; +import { router } from '/@/router'; +import { usePermissionStore } from '/@/store/modules/permission'; +import { RouteRecordRaw } from 'vue-router'; +import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; +import { h } from 'vue'; +import { getAppEnvConfig } from '/@/utils/env'; +interface UserState { + userInfo: Nullable; + token?: string; + roleList: RoleInfo[]; + sessionTimeout?: boolean; + lastUpdateTime: number; +} + +export const useUserStore = defineStore({ + id: 'app-user', + state: (): UserState => ({ + // user info + userInfo: null, + // token + token: undefined, + // roleList + roleList: [], + // Whether the login expired + sessionTimeout: false, + // Last fetch time + lastUpdateTime: 0, + }), + getters: { + getUserInfo(): UserInfo { + return this.userInfo || getAuthCache(USER_INFO_KEY) || {}; + }, + getToken(): string { + return this.token || getAuthCache(TOKEN_KEY); + }, + getRoleList(): RoleInfo[] { + return this.roleList && this.roleList.length > 0 + ? this.roleList + : getAuthCache(ROLES_KEY); + }, + getSessionTimeout(): boolean { + return !!this.sessionTimeout; + }, + getLastUpdateTime(): number { + return this.lastUpdateTime; + }, + }, + actions: { + setToken(info: string | undefined) { + this.token = info ? info : ''; // for null or undefined value + setAuthCache(TOKEN_KEY, info); + }, + setRoleList(roleList: RoleInfo[]) { + this.roleList = roleList; + setAuthCache(ROLES_KEY, roleList); + }, + setUserInfo(info: UserInfo | null) { + this.userInfo = info; + this.lastUpdateTime = new Date().getTime(); + setAuthCache(USER_INFO_KEY, info); + }, + setSessionTimeout(flag: boolean) { + this.sessionTimeout = flag; + }, + resetState() { + this.userInfo = null; + this.token = ''; + this.roleList = []; + this.sessionTimeout = false; + }, + /** + * @description: OAUTH Login + */ + async oauthLogin( + params: { + token: string; + } & { + goHome?: boolean; + mode?: ErrorMessageMode; + }, + ): Promise { + try { + const { goHome = true, token } = params; + + // save token + this.setToken(token); + + return this.afterLoginAction(goHome); + } catch (error) { + return Promise.reject(error); + } + }, + /** + * @description: login + */ + async login( + params: LoginParams & { + goHome?: boolean; + mode?: ErrorMessageMode; + }, + ): Promise { + try { + const { goHome = true, mode, ...loginParams } = params; + const data = await loginApi(loginParams, mode); + + const { token } = data; + // save token + this.setToken(token); + + return await this.afterLoginAction(goHome); + } catch (error) { + return Promise.reject(error); + } + }, + async afterLoginAction(goHome?: boolean): Promise { + if (!this.getToken) return null; + + // get user info + const userInfo = await this.getUserInfoAction(); + + // setOtherToken(this.getToken); + + const sessionTimeout = this.sessionTimeout; + if (sessionTimeout) { + this.setSessionTimeout(false); + } else { + const permissionStore = usePermissionStore(); + + if (!permissionStore.getIsDynamicAddedRoute) { + permissionStore.setDynamicAddedRoute(true); + + const routes = await permissionStore.buildRoutesAction(); + routes.forEach((route) => { + router.addRoute(route as unknown as RouteRecordRaw); + }); + router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); + } + goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME)); + } + + setOtherToken(this.getToken); + return Promise.resolve(userInfo); + }, + async getUserInfoAction(): Promise { + if (!this.getToken) return null; + const userInfoResult = await getUserInfo(); + + const { roles = [] } = userInfoResult; + + const userInfo = userInfoResult as unknown as UserInfo; + this.setUserInfo(userInfo); + this.setRoleList(roles); + return Promise.resolve(userInfoResult); + }, + /** + * @description: logout + */ + async logout(goLogin = false) { + if (this.getToken) { + try { + await doLogout(); + } catch { + console.log('注销Token失败'); + } + } + this.setToken(undefined); + this.setSessionTimeout(false); + this.setUserInfo(null); + goLogin && router.push(PageEnum.BASE_LOGIN); + }, + + /** + * @description: Confirm before logging out + */ + confirmLoginOut() { + const { createConfirm } = useMessage(); + const { t } = useI18n(); + createConfirm({ + iconType: 'warning', + title: () => h('span', t('温馨提醒')), + content: () => h('span', t('是否确认退出系统?')), + onOk: async () => { + await this.logout(true); + }, + okText: () => t('确认'), + cancelText: () => t('取消'), + }); + }, + }, +}); + +// Need to be used outside the setup +export function useUserStoreWithOut() { + return useUserStore(store); +} + +//设置其他url 项目 token +function setOtherToken(token: string) { + // console.log('other token', getAppEnvConfig()); // something like: "https://codegeex.cn" or "https://codegeex.cn" or + getAppEnvConfig() + .VITE_GLOB_OUT_LINK_URL?.split(',') + ?.forEach((item) => { + // 创建子域的iframe, 用于传送数据 + const iframe = document.createElement('iframe'); + iframe.src = `${item}`; + iframe.style.display = 'none'; + document.body.append(iframe); + + // 使用postMessage()发送数据到子系统 + setTimeout(function () { + iframe.contentWindow?.postMessage(token, item); + }, 2000); + + // 销毁iframe + setTimeout(function () { + iframe.remove(); + }, 4000); + }); +}