/** * @program: kicc-ui * @description: 当前用户信息存储中心 * @author: wangxiang4 * @create: 2022/4/9 */ import { defineStore } from 'pinia'; import { store } from '/@/store'; import { PageEnum } from '/@/enums/pageEnum'; import { ACCESS_TOKEN_KEY, PERMISSIONS_KEY, REFRESH_TOKEN_KEY, ROLE_IDS_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; import { getAuthCache, setAuthCache } from '/@/utils/auth'; import { KiccUser } from '/@/api/common/base/entity'; import { LoginParams } from '/@/api/platform/core/entity/user'; import { logout, getUserInfo, login } from '/@/api/platform/core/controller/user'; 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 defaultAvatar from '/@/assets/images/defaultAvatar.svg'; import { urlToBase64 } from '/@/utils/file/base64Conver'; import { useGlobSetting } from '/@/hooks/setting'; import { isUrl, isEmpty } from '/@/utils/is'; import { h } from 'vue'; import { getAuthClient } from '/@/utils'; import { merge } from 'lodash-es'; import { RequestOptions } from '/#/axios'; interface UserState { userInfo: Nullable; sessionTimeout?: boolean; lastUpdateTime: number; roleIds: string[]; permissions: string[]; access_token?: string; refresh_token?: string; } export const useUserStore = defineStore({ id: 'app-user', state: (): UserState => ({ // 用户信息 userInfo: getAuthCache(USER_INFO_KEY), // 登录是否过期记录(确保下次登陆不刷新路由直接还原) sessionTimeout: false, // 最后一次性更新用户信息时间(用于页面刷新更新用户数据) lastUpdateTime: 0, // 角色ID用于权限校验 roleIds: getAuthCache(ROLE_IDS_KEY), // 按钮权限标识用于权限校验 permissions: getAuthCache(PERMISSIONS_KEY), // 访问令牌 access_token: getAuthCache(ACCESS_TOKEN_KEY), // 刷新令牌 refresh_token: getAuthCache(REFRESH_TOKEN_KEY), }), getters: { getUserInfo(): KiccUser { return this.userInfo || {}; }, getAccessToken(): string { return this.access_token; }, getRefreshToken(): string { return this.refresh_token; }, getRoleIds(): string[] { return this.roleIds; }, getPermissions(): string[] { return this.permissions; }, getSessionTimeout(): boolean { return !!this.sessionTimeout; }, getLastUpdateTime(): number { return this.lastUpdateTime; }, }, actions: { setRoleIds(roleIds: string[]) { this.roleIds = roleIds; setAuthCache(ROLE_IDS_KEY, roleIds); }, setPermissions(permissions: string[]) { this.permissions = permissions; setAuthCache(PERMISSIONS_KEY, permissions); }, setAccessToken(accessToken: string) { this.access_token = accessToken; setAuthCache(ACCESS_TOKEN_KEY, accessToken); }, setRefreshToken(refreshToken: string) { this.refresh_token = refreshToken; setAuthCache(REFRESH_TOKEN_KEY, refreshToken); }, setUserInfo(userInfo: Nullable) { this.userInfo = userInfo; this.lastUpdateTime = new Date().getTime(); setAuthCache(USER_INFO_KEY, userInfo); }, setSessionTimeout(flag: boolean) { this.sessionTimeout = flag; }, resetState(): void { this.setSessionTimeout(false); this.setUserInfo(null); this.setAccessToken(''); this.setRefreshToken(''); this.setRoleIds([]); this.setPermissions([]); }, /** 登录 */ async login(params: LoginParams): Promise { try { const { goHome = true, clientId = '', ...loginParams } = params; // 处理自定义授权客户端 if (clientId) { const client = getAuthClient(clientId); !isEmpty(client) && merge(loginParams, { options: { clientId: client[0], clientSecret: client[1] } as RequestOptions }); } const data = await login(loginParams); const { access_token, refresh_token } = data; this.setAccessToken(access_token); this.setRefreshToken(refresh_token); return this.afterLoginAction(goHome); } catch (error) { return Promise.reject(error); } }, /** 登录成功后动作 */ async afterLoginAction(goHome?: boolean): Promise { if (!this.getAccessToken) return null; // 获取用户信息 const userInfo = await this.getUserInfoAction(); const sessionTimeout = this.sessionTimeout; if (sessionTimeout) { this.setSessionTimeout(false); } else { // 处理路由与菜单的构建,并且进行缓存 const permissionStore = usePermissionStore(); // 使用isDynamicAddedRoute字段做菜单路由缓存功能 if (!permissionStore.isDynamicAddedRoute) { const routes = await permissionStore.buildRoutesAction(); routes.forEach((route) => { router.addRoute(route as unknown as RouteRecordRaw); }); permissionStore.setDynamicAddedRoute(true); } goHome && await router.replace(userInfo?.homePath || PageEnum.BASE_HOME); } return userInfo; }, /** 获取用户信息 */ async getUserInfoAction(): Promise { const { apiUrl } = useGlobSetting(); const { t } = useI18n(); try { const userInfo = await getUserInfo(); userInfo.avatar = userInfo.avatar ? isUrl(userInfo.avatar) ? userInfo.avatar : apiUrl + userInfo.avatar : await urlToBase64(defaultAvatar); // 存储用户扩展信息,便于鉴权 this.setUserInfo(userInfo); this.setRoleIds(userInfo.roleIds); this.setPermissions(userInfo.permissions); return userInfo; } catch (e) { // 防止 system-biz 微服务挂掉后导致token授权成功重新登陆覆盖授权客户端密钥 this.resetState(); throw Error(t('sys.api.errMsg503')); } }, /** 登出 */ async logout(goLogin = false) { try { await logout(); } catch { console.log('注销Token失败'); } this.resetState(); goLogin && await router.push(PageEnum.BASE_LOGIN); }, /** 退出前确认 */ confirmLoginOut() { const { createConfirm } = useMessage(); const { t } = useI18n(); createConfirm({ iconType: 'warning', title: () => h('span', t('sys.app.logoutTip')), content: () => h('span', t('sys.app.logoutMessage')), onOk: async () => { await this.logout(true); } }); } } }); // 需要在设置之外使用 export function useUserStoreWithOut() { return useUserStore(store); }