user.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. import type { UserInfo, LoginInfo } from '/#/store';
  2. import type { ErrorMessageMode } from '/#/axios';
  3. import { defineStore } from 'pinia';
  4. import { store } from '/@/store';
  5. import { RoleEnum } from '/@/enums/roleEnum';
  6. import { PageEnum } from '/@/enums/pageEnum';
  7. import {
  8. ROLES_KEY,
  9. TOKEN_KEY,
  10. USER_INFO_KEY,
  11. LOGIN_INFO_KEY,
  12. DB_DICT_DATA_KEY,
  13. TENANT_ID,
  14. OAUTH2_THIRD_LOGIN_TENANT_ID,
  15. PWD_KEY,
  16. } from '/@/enums/cacheEnum';
  17. import { getAuthCache, setAuthCache, removeAuthCache } from '/@/utils/auth';
  18. import { GetUserInfoModel, LoginParams, ThirdLoginParams } from '/@/api/sys/model/userModel';
  19. import { doLogout, getUserInfo, loginApi, phoneLoginApi, thirdLogin } from '/@/api/sys/user';
  20. import { useI18n } from '/@/hooks/web/useI18n';
  21. import { useMessage } from '/@/hooks/web/useMessage';
  22. import { router } from '/@/router';
  23. import { usePermissionStore } from '/@/store/modules/permission';
  24. import { RouteRecordRaw } from 'vue-router';
  25. import { PAGE_NOT_FOUND_ROUTE, QIANKUN_ROUTE } from '/@/router/routes/basic';
  26. import { isArray } from '/@/utils/is';
  27. import { useGlobSetting } from '/@/hooks/setting';
  28. import { JDragConfigEnum } from '/@/enums/jeecgEnum';
  29. import { useSso } from '/@/hooks/web/useSso';
  30. import { getActions } from '/@/qiankun/state';
  31. import { useGlobSetting } from '/@/hooks/setting';
  32. import AES from 'crypto-js/aes';
  33. interface UserState {
  34. userInfo: Nullable<UserInfo>;
  35. token?: string;
  36. roleList: RoleEnum[];
  37. dictItems?: [];
  38. sessionTimeout?: boolean;
  39. lastUpdateTime: number;
  40. tenantid?: string | number;
  41. shareTenantId?: Nullable<string | number>;
  42. loginInfo?: Nullable<LoginInfo>;
  43. }
  44. export const useUserStore = defineStore({
  45. id: 'app-user',
  46. state: (): UserState => ({
  47. // 用户信息
  48. userInfo: null,
  49. // token
  50. token: undefined,
  51. // 角色列表
  52. roleList: [],
  53. // 字典
  54. dictItems: [],
  55. // session过期时间
  56. sessionTimeout: false,
  57. // Last fetch time
  58. lastUpdateTime: 0,
  59. //租户id
  60. tenantid: '',
  61. // 分享租户ID
  62. // 用于分享页面所属租户与当前用户登录租户不一致的情况
  63. shareTenantId: null,
  64. //登录返回信息
  65. loginInfo: null,
  66. }),
  67. getters: {
  68. getUserInfo(): UserInfo {
  69. return this.userInfo || getAuthCache<UserInfo>(USER_INFO_KEY) || {};
  70. },
  71. getLoginInfo(): LoginInfo {
  72. return this.loginInfo || getAuthCache<LoginInfo>(LOGIN_INFO_KEY) || {};
  73. },
  74. getToken(): string {
  75. return this.token || getAuthCache<string>(TOKEN_KEY);
  76. },
  77. getAllDictItems(): [] {
  78. return this.dictItems || getAuthCache(DB_DICT_DATA_KEY);
  79. },
  80. getRoleList(): RoleEnum[] {
  81. return this.roleList.length > 0 ? this.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY);
  82. },
  83. getSessionTimeout(): boolean {
  84. return !!this.sessionTimeout;
  85. },
  86. getLastUpdateTime(): number {
  87. return this.lastUpdateTime;
  88. },
  89. getTenant(): string | number {
  90. return this.tenantid || getAuthCache<string | number>(TENANT_ID);
  91. },
  92. // 是否有分享租户id
  93. hasShareTenantId(): boolean {
  94. return this.shareTenantId != null && this.shareTenantId !== '';
  95. },
  96. /** 获取用户加密过的密码 */
  97. getPassword() {
  98. return getAuthCache<string>(PWD_KEY);
  99. },
  100. },
  101. actions: {
  102. /** 设置用户密码并加密,理论上加密、解密的工作应仅在此模块进行 */
  103. setPassword(password: string) {
  104. // setAuthCache(PWD_KEY, AES.encrypt(password, PWD_KEY));
  105. setAuthCache(PWD_KEY, btoa(password));
  106. },
  107. setToken(info: string | undefined) {
  108. this.token = info ? info : ''; // for null or undefined value
  109. setAuthCache(TOKEN_KEY, info);
  110. },
  111. setRoleList(roleList: RoleEnum[]) {
  112. this.roleList = roleList;
  113. setAuthCache(ROLES_KEY, roleList);
  114. },
  115. setUserInfo(info: UserInfo | null) {
  116. this.userInfo = info;
  117. this.lastUpdateTime = new Date().getTime();
  118. setAuthCache(USER_INFO_KEY, info);
  119. },
  120. setLoginInfo(info: LoginInfo | null) {
  121. this.loginInfo = info;
  122. setAuthCache(LOGIN_INFO_KEY, info);
  123. },
  124. setAllDictItems(dictItems) {
  125. this.dictItems = dictItems;
  126. setAuthCache(DB_DICT_DATA_KEY, dictItems);
  127. },
  128. setTenant(id) {
  129. this.tenantid = id;
  130. setAuthCache(TENANT_ID, id);
  131. },
  132. setShareTenantId(id: NonNullable<typeof this.shareTenantId>) {
  133. this.shareTenantId = id;
  134. },
  135. setSessionTimeout(flag: boolean) {
  136. this.sessionTimeout = flag;
  137. },
  138. resetState() {
  139. this.userInfo = null;
  140. this.dictItems = [];
  141. this.token = '';
  142. this.roleList = [];
  143. this.sessionTimeout = false;
  144. },
  145. /**
  146. * 登录事件
  147. */
  148. async login(
  149. params: LoginParams & {
  150. goHome?: boolean;
  151. mode?: ErrorMessageMode;
  152. }
  153. ): Promise<GetUserInfoModel | null> {
  154. try {
  155. const { goHome = true, mode, ...loginParams } = params;
  156. const data = await loginApi(loginParams, mode);
  157. const { token, userInfo } = data;
  158. // save token
  159. this.setToken(token);
  160. this.setTenant(userInfo.loginTenantId);
  161. this.setPassword(params.password);
  162. // 将用户的用户名与密码存于数据库之中,这是为了
  163. return this.afterLoginAction(goHome, data);
  164. } catch (error) {
  165. return Promise.reject(error);
  166. }
  167. },
  168. /**
  169. * 扫码登录事件
  170. */
  171. async qrCodeLogin(token): Promise<GetUserInfoModel | null> {
  172. try {
  173. // save token
  174. this.setToken(token);
  175. return this.afterLoginAction(true, {});
  176. } catch (error) {
  177. return Promise.reject(error);
  178. }
  179. },
  180. /**
  181. * 登录完成处理
  182. * @param goHome
  183. */
  184. async afterLoginAction(goHome?: boolean, data?: any): Promise<any | null> {
  185. const glob = useGlobSetting();
  186. if (!this.getToken) return null;
  187. //获取用户信息
  188. const userInfo = await this.getUserInfoAction();
  189. const sessionTimeout = this.sessionTimeout;
  190. if (sessionTimeout) {
  191. this.setSessionTimeout(false);
  192. } else {
  193. const permissionStore = usePermissionStore();
  194. if (!permissionStore.isDynamicAddedRoute) {
  195. const routes = await permissionStore.buildRoutesAction();
  196. routes.forEach((route) => {
  197. router.addRoute(route as unknown as RouteRecordRaw);
  198. });
  199. router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
  200. router.addRoute(QIANKUN_ROUTE as unknown as RouteRecordRaw);
  201. permissionStore.setDynamicAddedRoute(true);
  202. }
  203. await this.setLoginInfo({ ...data, isLogin: true });
  204. //update-begin-author:liusq date:2022-5-5 for:登录成功后缓存拖拽模块的接口前缀
  205. localStorage.setItem(JDragConfigEnum.DRAG_BASE_URL, useGlobSetting().domainUrl);
  206. //update-end-author:liusq date:2022-5-5 for: 登录成功后缓存拖拽模块的接口前缀
  207. goHome && (await router.replace((userInfo && userInfo.homePath) || glob.homePath || PageEnum.BASE_HOME));
  208. // update-begin-author:sunjianlei date:20230306 for: 修复登录成功后,没有正确重定向的问题
  209. const redirect = router.currentRoute.value?.query?.redirect as string;
  210. // 判断是否有 redirect 重定向地址
  211. //update-begin---author:wangshuai ---date:20230424 for:【QQYUN-5195】登录之后直接刷新页面导致没有进入创建组织页面------------
  212. if (redirect && goHome) {
  213. //update-end---author:wangshuai ---date:20230424 for:【QQYUN-5195】登录之后直接刷新页面导致没有进入创建组织页面------------
  214. // 当前页面打开
  215. window.open(redirect, '_self');
  216. return data;
  217. }
  218. // update-end-author:sunjianlei date:20230306 for: 修复登录成功后,没有正确重定向的问题
  219. goHome && (await router.replace((userInfo && userInfo.homePath) || glob.homePath || PageEnum.BASE_HOME));
  220. }
  221. if (useGlobSetting().openQianKun) {
  222. const actions = getActions();
  223. actions.setGlobalState({ token: this.getToken, userInfo: userInfo, isMounted: false });
  224. }
  225. return data;
  226. },
  227. /**
  228. * 手机号登录
  229. * @param params
  230. */
  231. async phoneLogin(
  232. params: LoginParams & {
  233. goHome?: boolean;
  234. mode?: ErrorMessageMode;
  235. }
  236. ): Promise<GetUserInfoModel | null> {
  237. try {
  238. const { goHome = true, mode, ...loginParams } = params;
  239. const data = await phoneLoginApi(loginParams, mode);
  240. const { token } = data;
  241. // save token
  242. this.setToken(token);
  243. return this.afterLoginAction(goHome, data);
  244. } catch (error) {
  245. return Promise.reject(error);
  246. }
  247. },
  248. /**
  249. * 获取用户信息
  250. */
  251. async getUserInfoAction(): Promise<UserInfo | null> {
  252. if (!this.getToken) {
  253. return null;
  254. }
  255. const { userInfo, sysAllDictItems } = await getUserInfo();
  256. if (userInfo) {
  257. const { roles = [] } = userInfo;
  258. if (isArray(roles)) {
  259. const roleList = roles.map((item) => item.value) as RoleEnum[];
  260. this.setRoleList(roleList);
  261. } else {
  262. userInfo.roles = [];
  263. this.setRoleList([]);
  264. }
  265. this.setUserInfo(userInfo);
  266. }
  267. /**
  268. * 添加字典信息到缓存
  269. * @updateBy:lsq
  270. * @updateDate:2021-09-08
  271. */
  272. if (sysAllDictItems) {
  273. this.setAllDictItems(sysAllDictItems);
  274. }
  275. return userInfo;
  276. },
  277. /**
  278. * 退出登录
  279. */
  280. async logout(goLogin = false) {
  281. if (this.getToken) {
  282. try {
  283. await doLogout();
  284. } catch {
  285. console.log('注销Token失败');
  286. }
  287. }
  288. // //update-begin-author:taoyan date:2022-5-5 for: src/layouts/default/header/index.vue showLoginSelect方法 获取tenantId 退出登录后再次登录依然能获取到值,没有清空
  289. // let username:any = this.userInfo && this.userInfo.username;
  290. // if(username){
  291. // removeAuthCache(username)
  292. // }
  293. // //update-end-author:taoyan date:2022-5-5 for: src/layouts/default/header/index.vue showLoginSelect方法 获取tenantId 退出登录后再次登录依然能获取到值,没有清空
  294. this.setToken('');
  295. setAuthCache(TOKEN_KEY, null);
  296. this.setSessionTimeout(false);
  297. this.setUserInfo(null);
  298. this.setLoginInfo(null);
  299. this.setTenant(null);
  300. //update-begin-author:liusq date:2022-5-5 for:退出登录后清除拖拽模块的接口前缀
  301. localStorage.removeItem(JDragConfigEnum.DRAG_BASE_URL);
  302. //update-end-author:liusq date:2022-5-5 for: 退出登录后清除拖拽模块的接口前缀
  303. //如果开启单点登录,则跳转到单点统一登录中心
  304. const openSso = useGlobSetting().openSso;
  305. if (openSso == 'true') {
  306. await useSso().ssoLoginOut();
  307. }
  308. //update-begin---author:wangshuai ---date:20230224 for:[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
  309. //退出登录的时候需要用的应用id
  310. // if(isOAuth2AppEnv()){
  311. // let tenantId = getAuthCache(OAUTH2_THIRD_LOGIN_TENANT_ID);
  312. // removeAuthCache(OAUTH2_THIRD_LOGIN_TENANT_ID);
  313. // goLogin && await router.push({ name:"Login",query:{ tenantId:tenantId }})
  314. // }else{
  315. // // update-begin-author:sunjianlei date:20230306 for: 修复登录成功后,没有正确重定向的问题
  316. // goLogin && (await router.push({
  317. // path: PageEnum.BASE_LOGIN,
  318. // query: {
  319. // // 传入当前的路由,登录成功后跳转到当前路由
  320. // redirect: router.currentRoute.value.fullPath,
  321. // }
  322. // }));
  323. // // update-end-author:sunjianlei date:20230306 for: 修复登录成功后,没有正确重定向的问题
  324. // }
  325. goLogin &&
  326. (await router.push({
  327. path: PageEnum.BASE_LOGIN,
  328. query: {
  329. // 传入当前的路由,登录成功后跳转到当前路由
  330. redirect: router.currentRoute.value.fullPath,
  331. },
  332. }));
  333. //update-end---author:wangshuai ---date:20230224 for:[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
  334. },
  335. /**
  336. * 登录事件
  337. */
  338. async ThirdLogin(
  339. params: ThirdLoginParams & {
  340. goHome?: boolean;
  341. mode?: ErrorMessageMode;
  342. }
  343. ): Promise<any | null> {
  344. try {
  345. const { goHome = true, mode, ...ThirdLoginParams } = params;
  346. const data = await thirdLogin(ThirdLoginParams, mode);
  347. const { token } = data;
  348. // save token
  349. this.setToken(token);
  350. return this.afterLoginAction(goHome, data);
  351. } catch (error) {
  352. return Promise.reject(error);
  353. }
  354. },
  355. /**
  356. * 退出询问
  357. */
  358. confirmLoginOut() {
  359. // debugger;
  360. const { createConfirm } = useMessage();
  361. const { t } = useI18n();
  362. createConfirm({
  363. iconType: 'warning',
  364. title: t('sys.app.logoutTip'),
  365. content: t('sys.app.logoutMessage'),
  366. onOk: async () => {
  367. await this.logout(true);
  368. },
  369. });
  370. },
  371. async autoLogin() {
  372. try {
  373. const loginParams = {
  374. username: 'autoAdmin',
  375. password: 'autoAdmin123',
  376. checkKey: new Date().getTime(),
  377. };
  378. this.login(loginParams);
  379. } catch (error) {
  380. return Promise.reject(error);
  381. }
  382. },
  383. /** 解密用户密码,理论上加密、解密的工作应仅在此模块进行 */
  384. decryptPassword(password: string) {
  385. // const test1 = AES.encrypt('123123', '321');
  386. // const test2 = AES.decrypt(test1, '321');
  387. // console.log('debug', AES.decrypt(password, PWD_KEY));
  388. return atob(password);
  389. // return AES.decrypt(password, PWD_KEY).toString();
  390. },
  391. },
  392. });
  393. // Need to be used outside the setup
  394. export function useUserStoreWithOut() {
  395. return useUserStore(store);
  396. }