user.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import { defineStore } from 'pinia';
  2. import { ref } from 'vue';
  3. import { CACHE_KEY } from '@/constants/index';
  4. // @ts-ignore 因为 utils 可能还没做完整的 ts 设置
  5. import { Local, Session } from '@/utils/storage';
  6. import { useLoginApi } from '@/api/system/login';
  7. import { useSystemApi } from '@/api/system/index';
  8. import { useUserApi } from '@/api/user/index';
  9. import type { LoginParams, UserInfo } from '@/types/user';
  10. import { sm3 } from 'sm-crypto';
  11. import to from 'await-to-js';
  12. const loginApi = useLoginApi();
  13. const systemApi = useSystemApi();
  14. const userApi = useUserApi();
  15. export const useUserStore = defineStore('user', () => {
  16. // ==================== State ====================
  17. const token = ref<string>(Local.get(CACHE_KEY.TOKEN) || '');
  18. const userInfo = ref<UserInfo>(Local.get(CACHE_KEY.USER_INFO) || ({} as UserInfo));
  19. const perms = ref<string[]>([]);
  20. const roles = ref<string[]>([]);
  21. const configSetting = ref<any>({});
  22. // 页面请求加载状态
  23. const loadings = {
  24. loginLoading: ref<boolean>(false),
  25. isLogining: ref<boolean>(false),
  26. fetchUserInfoLoading: ref<boolean>(false),
  27. logoutLoading: ref<boolean>(false),
  28. } as const;
  29. // ==================== Actions ====================
  30. /**
  31. * 设置请求加载状态
  32. */
  33. function setRequestLoading(field: keyof typeof loadings, value: boolean) {
  34. loadings[field].value = value;
  35. }
  36. /**
  37. * 检查验证码配置
  38. */
  39. async function checkCaptcha() {
  40. const [err, res] = await to(systemApi.getEntityMapByKeys({ configKeys: ['isCaptcha'] }));
  41. if (err) return;
  42. if (res?.data) {
  43. configSetting.value = res.data;
  44. }
  45. }
  46. function saveSciTokenFromLoginResponse(res: { data?: { sciToken?: string } } | null | undefined) {
  47. const sciToken = res?.data?.sciToken
  48. if (sciToken) {
  49. Local.set(CACHE_KEY.SCITOKEN, sciToken)
  50. }
  51. }
  52. /**
  53. * 清理用户状态和本地缓存
  54. */
  55. function clearUserStatus() {
  56. token.value = '';
  57. roles.value = [];
  58. perms.value = [];
  59. userInfo.value = {} as UserInfo;
  60. Local.remove(CACHE_KEY.TOKEN);
  61. Local.remove(CACHE_KEY.USER_INFO);
  62. Local.remove(CACHE_KEY.SCITOKEN);
  63. Local.remove(CACHE_KEY.PERMS);
  64. Local.remove(CACHE_KEY.ROLES);
  65. Session.clear();
  66. }
  67. /**
  68. * 用户登录
  69. */
  70. async function login(loginParams: LoginParams) {
  71. setRequestLoading('loginLoading', true);
  72. // 使用 sm3 加密密码
  73. const encryptedPassword = loginParams.password ? sm3(loginParams.password) : '';
  74. const [err, res] = await to(
  75. loginApi.signIn({
  76. userName: loginParams.userName,
  77. password: encryptedPassword,
  78. idValueC: loginParams.idValueC,
  79. idKeyC: loginParams.idKeyC,
  80. saltValue: loginParams.saltValue,
  81. })
  82. );
  83. setRequestLoading('loginLoading', false);
  84. if (err) {
  85. return Promise.reject(err);
  86. }
  87. const resToken = res?.data?.token;
  88. if (resToken) {
  89. token.value = resToken;
  90. Local.set(CACHE_KEY.TOKEN, resToken);
  91. saveSciTokenFromLoginResponse(res);
  92. // 登录成功后主动获取用户信息
  93. await fetchUserInfo();
  94. }
  95. return res;
  96. }
  97. /**
  98. * 企业微信免登
  99. */
  100. async function oAuthLogin(code: string) {
  101. setRequestLoading('isLogining', true);
  102. const [err, res] = await to(loginApi.oAuthLogin({ code }));
  103. setRequestLoading('isLogining', false);
  104. if (err) {
  105. return Promise.reject(err);
  106. }
  107. const resToken = res?.data?.token;
  108. if (resToken) {
  109. token.value = resToken;
  110. Local.set(CACHE_KEY.TOKEN, resToken);
  111. saveSciTokenFromLoginResponse(res);
  112. // 登录成功后主动获取用户信息
  113. await fetchUserInfo();
  114. }
  115. return res;
  116. }
  117. /**
  118. * 获取用户信息
  119. */
  120. async function fetchUserInfo() {
  121. setRequestLoading('fetchUserInfoLoading', true);
  122. const [err, res] = await to(userApi.getUserByUserName());
  123. setRequestLoading('fetchUserInfoLoading', false);
  124. if (err) {
  125. return Promise.reject(err);
  126. }
  127. // 解决解构变量和 ref 变量重名问题
  128. const {
  129. userInfo: resUserInfo,
  130. perms: resPerms,
  131. roles: resRoles,
  132. } = res?.data || {};
  133. userInfo.value = resUserInfo || ({} as UserInfo);
  134. perms.value = resPerms || [];
  135. roles.value = resRoles || [];
  136. Local.set(CACHE_KEY.USER_INFO, userInfo.value);
  137. Local.set(CACHE_KEY.PERMS, perms.value);
  138. Local.set(CACHE_KEY.ROLES, roles.value);
  139. }
  140. /**
  141. * 用户登出
  142. */
  143. async function logout() {
  144. setRequestLoading('logoutLoading', true);
  145. const [err] = await to(loginApi.signOut());
  146. setRequestLoading('logoutLoading', false);
  147. // 即便接口报错也要清空本地缓存和状态
  148. clearUserStatus();
  149. if (err) {
  150. console.warn('退出登录异常', err);
  151. }
  152. }
  153. return {
  154. ...loadings,
  155. token,
  156. userInfo,
  157. perms,
  158. roles,
  159. configSetting,
  160. login,
  161. oAuthLogin,
  162. fetchUserInfo,
  163. logout,
  164. clearUserStatus,
  165. setRequestLoading,
  166. checkCaptcha,
  167. };
  168. });