From 54def95458d26f9db0549e4b9a69f78582102841 Mon Sep 17 00:00:00 2001 From: yaoyn Date: Thu, 19 Sep 2024 15:47:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=84=E7=BB=87=E6=9C=BA=E6=9E=84=E5=8F=AF?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=8C=BA=E5=9F=9F=E3=80=81=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E3=80=81=E5=B1=82=E7=BA=A7=20=E6=94=AF=E6=8C=81cas=E7=99=BB?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/system/department/model/index.ts | 1 + src/api/system/login/index.ts | 18 +- src/router/index.ts | 5 +- src/router/routes/index.ts | 11 + src/store/modules/user.ts | 519 +++++++++--------- src/utils/http/axios/index.ts | 16 +- src/views/secondDev/TokenLogin.vue | 40 ++ .../department/components/DeptDrawer.vue | 27 +- 8 files changed, 377 insertions(+), 260 deletions(-) create mode 100644 src/views/secondDev/TokenLogin.vue diff --git a/src/api/system/department/model/index.ts b/src/api/system/department/model/index.ts index 8d08f3a..f6068b9 100644 --- a/src/api/system/department/model/index.ts +++ b/src/api/system/department/model/index.ts @@ -46,6 +46,7 @@ export interface DepartmentModel { enabledMark: number; //排序码 departmentLabel?: any; //部门标签 departmentType?: number; //组织类型 + areaId?: string;//区域 } /** diff --git a/src/api/system/login/index.ts b/src/api/system/login/index.ts index a343721..bfd953e 100644 --- a/src/api/system/login/index.ts +++ b/src/api/system/login/index.ts @@ -10,6 +10,7 @@ import { } from './model'; enum Api { + TokenByCas='/', Login = '/system/login', Logout = '/system/logout', GetUserInfo = '/organization/user/current/info', @@ -47,10 +48,10 @@ export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal') }, ); } -export function singleLoginApi(params, mode) { - return defHttp.post( +export function getTokenByCas(params, mode) { + return defHttp.get( { - url: Api.Login + '/' + params.ltpasToken, + url: Api.TokenByCas + '?ticket=' + params.ticket, params:{}, }, { @@ -58,6 +59,17 @@ export function singleLoginApi(params, mode) { }, ); } +export function singleLoginApi(params, mode) { + return defHttp.post( + { + url: Api.Login + '/' + params.ltpasToken, + params:{}, + }, + { + errorMessageMode: mode, + }, + ); +} /** * @description: getUserInfo diff --git a/src/router/index.ts b/src/router/index.ts index 3107c46..bb2296e 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,7 +1,7 @@ import type { RouteRecordRaw } from 'vue-router'; import type { App } from 'vue'; -import { createRouter, createWebHashHistory } from 'vue-router'; +import {createRouter, createWebHashHistory, createWebHistory} from 'vue-router'; import { basicRoutes } from './routes'; // 白名单应该包含基本静态路由 @@ -17,7 +17,8 @@ getRouteNames(basicRoutes); // 创建一个可以被 Vue 应用程序使用的路由实例 export const router = createRouter({ // 创建一个 hash 历史记录。 - history: createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH), + history: createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH), + //history: createWebHistory(import.meta.env.VITE_PUBLIC_PATH), // 应该添加到路由的初始路由列表。 routes: basicRoutes as unknown as RouteRecordRaw[], // 是否应该禁止尾部斜杠。默认为假 diff --git a/src/router/routes/index.ts b/src/router/routes/index.ts index c4af61d..cf5ac52 100644 --- a/src/router/routes/index.ts +++ b/src/router/routes/index.ts @@ -43,10 +43,21 @@ export const LoginRoute: AppRouteRecordRaw = { } }; +export const TokenLoginRoute: AppRouteRecordRaw = { + path: '/tokenLogin', + name: 'tokenLogin', + component: () => import('/@/views/secondDev/TokenLogin.vue'), + meta: { + title: t('Token登录'), + ignoreAuth: true//跳过登录检查 + } +}; + // Basic routing without permissions // 未经许可的基本路由 export const basicRoutes = [ LoginRoute, + TokenLoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 92195a2..6d34510 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,250 +1,269 @@ -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, singleLoginApi } 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); - } - }, - /** - * @description: singleLogin - */ - async singleLogin( - params: any - ): Promise { - try { - const data = await singleLoginApi(params, params.mode); - const userInfo = await this.getUserInfoAction(); - - const { token } = data; - // save token - this.setToken(token); - - return await this.afterLoginAction(false, params.targetURL || params.redirect); - } catch (error) { - return Promise.reject(error); - } - }, - async afterLoginAction(goHome?: boolean, redirect?): 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); - } - redirect && (await router.replace(decodeURIComponent(redirect))); - 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, getTokenByCas, getUserInfo, loginApi, singleLoginApi} 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 { token } = params; + params.goHome=true; + return await this.tokenLogin(token,params); + } 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; + params.goHome=true; + return await this.tokenLogin(token,params); + } catch (error) { + return Promise.reject(error); + } + }, + async casLogin( + params: any + ): Promise { + try { + const data = await getTokenByCas(params, params.mode); + const { token } = data; + return await this.tokenLogin(token,params); + } catch (error) { + return Promise.reject(error); + } + }, + /** + * 拿到token后的登录动作 + * @param params + */ + async tokenLogin( + token: string, + params: any + ): Promise { + try { + // save token + this.setToken(token); + + return await this.afterLoginAction(params.goHome, params.targetURL || params.redirect); + } catch (error) { + return Promise.reject(error); + } + }, + /** + * @description: singleLogin + */ + async singleLogin( + params: any + ): Promise { + try { + const data = await singleLoginApi(params, params.mode); + const { token } = data; + params.goHome=false; + return await this.tokenLogin(token,params); + } catch (error) { + return Promise.reject(error); + } + }, + + async afterLoginAction(goHome?: boolean, redirect?): 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); + } + redirect && (await router.replace(decodeURIComponent(redirect))); + 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); + }); +} diff --git a/src/utils/http/axios/index.ts b/src/utils/http/axios/index.ts index 21a76fe..d64d98f 100644 --- a/src/utils/http/axios/index.ts +++ b/src/utils/http/axios/index.ts @@ -82,11 +82,21 @@ const transform: AxiosTransform = { timeoutMsg = t('登录超时,请重新登录!'); const userStore = useUserStoreWithOut(); userStore.setToken(undefined); - if (!window.location.hash.includes('login')) { + if (!window.location.hash.includes('login')&&!window.location.pathname.includes('login') + &&!window.location.hash.includes('tokenLogin')&&!window.location.pathname.includes('tokenLogin')) { userStore.logout(true); } - const go = useGo(); - go('/login'); + if(data.urlToRedirectTo){ + //登录页面不跳转 + if(!window.location.hash.includes('login')&&!window.location.pathname.includes('login') + &&!window.location.hash.includes('tokenLogin')&&!window.location.pathname.includes('tokenLogin')){ + window.location.href=data.urlToRedirectTo; + } + options.errorMessageMode="none"; + }else{ + const go = useGo(); + go('/login'); + } break; default: if (msg) { diff --git a/src/views/secondDev/TokenLogin.vue b/src/views/secondDev/TokenLogin.vue new file mode 100644 index 0000000..a912fd6 --- /dev/null +++ b/src/views/secondDev/TokenLogin.vue @@ -0,0 +1,40 @@ + + + diff --git a/src/views/system/department/components/DeptDrawer.vue b/src/views/system/department/components/DeptDrawer.vue index e1c6ec3..740b372 100644 --- a/src/views/system/department/components/DeptDrawer.vue +++ b/src/views/system/department/components/DeptDrawer.vue @@ -4,7 +4,7 @@ @register="registerDrawer" showFooter :title="getTitle" - width="45%" + width="50%" @ok="handleSubmit" > @@ -112,16 +112,39 @@ defaultValue: 1, componentProps: { options: [ + { label: '总部', value: 3, disabled:true }, + { label: '板块', value: 2, disabled:true }, { label: '公司', value: 1 }, - { label: '部门', value: 0 }, + { label: '部门', value: 0 } ], onChange: deptTypeChange, }, required: true, }, + { + field: 'areaId', + label: '行政区域', + component: 'Area', + componentProps: { + placeholder: '请选择行政区域' + }, + }, ]; const companySchema: FormSchema[] = [ + { + field: 'companyLvl', + label: '公司层级', + component: 'RadioButtonGroup', + defaultValue: null, + componentProps: { + options: [ + { label: '三级业务单位', value: 3 }, + { label: '四级项目公司/场站', value: 4 } + ], + }, + required: false, + }, { field: 'departmentNature', label: '公司性质',