user.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { defineStore } from 'pinia'
  2. import { computed, ref } from 'vue'
  3. import { AUTH_API, TOKEN_KEY, REFRESH_TOKEN_KEY, USER_INFO_KEY, PAGE_PATHS } from '@/config/api'
  4. import { request, parseResponseJson } from '@/utils/request'
  5. import { buildMiniEncryptedLoginBody } from '@/utils/loginRsa'
  6. export const useUserStore = defineStore('user', () => {
  7. const token = ref('')
  8. const refreshToken = ref('')
  9. const userInfo = ref(null)
  10. const isLoading = ref(false)
  11. function normalizeUserInfo(raw) {
  12. if (!raw || typeof raw !== 'object') return raw || null
  13. const avatarUrl =
  14. raw.avatarUrl != null && String(raw.avatarUrl).trim()
  15. ? String(raw.avatarUrl).trim()
  16. : raw.avatar_url != null && String(raw.avatar_url).trim()
  17. ? String(raw.avatar_url).trim()
  18. : ''
  19. return {
  20. ...raw,
  21. avatarUrl
  22. }
  23. }
  24. const isLoggedIn = computed(() => !!token.value && !!userInfo.value)
  25. const userRole = computed(() => userInfo.value?.role || '')
  26. /** 登录成功默认进入工作台 Tab */
  27. const homePath = computed(() => PAGE_PATHS.workbench)
  28. function checkLoginStatus() {
  29. const savedToken = uni.getStorageSync(TOKEN_KEY)
  30. const savedUserInfo = uni.getStorageSync(USER_INFO_KEY)
  31. const savedRefreshToken = uni.getStorageSync(REFRESH_TOKEN_KEY)
  32. const normalizedToken =
  33. typeof savedToken === 'string' ? savedToken.trim() : savedToken ? String(savedToken).trim() : ''
  34. let normalizedUserInfo = null
  35. if (typeof savedUserInfo === 'string') {
  36. try {
  37. normalizedUserInfo = normalizeUserInfo(JSON.parse(savedUserInfo))
  38. } catch (error) {
  39. normalizedUserInfo = null
  40. }
  41. } else if (savedUserInfo && typeof savedUserInfo === 'object') {
  42. normalizedUserInfo = normalizeUserInfo(savedUserInfo)
  43. }
  44. if (normalizedToken && normalizedUserInfo) {
  45. token.value = normalizedToken
  46. refreshToken.value = typeof savedRefreshToken === 'string' ? savedRefreshToken : ''
  47. userInfo.value = normalizedUserInfo
  48. return
  49. }
  50. token.value = ''
  51. refreshToken.value = ''
  52. userInfo.value = null
  53. }
  54. function setLoginInfo(data) {
  55. token.value = data.token || ''
  56. refreshToken.value = data.refreshToken || ''
  57. userInfo.value = normalizeUserInfo(data.userInfo || null)
  58. uni.setStorageSync(TOKEN_KEY, token.value)
  59. uni.setStorageSync(REFRESH_TOKEN_KEY, refreshToken.value)
  60. uni.setStorageSync(USER_INFO_KEY, userInfo.value)
  61. }
  62. async function login(params) {
  63. isLoading.value = true
  64. try {
  65. const encryptedBody = await buildMiniEncryptedLoginBody(params.username, params.password)
  66. const res = await request({
  67. url: AUTH_API.LOGIN,
  68. method: 'POST',
  69. data: encryptedBody
  70. })
  71. const result = parseResponseJson(res)
  72. if (result && result.code === 200 && result.data) {
  73. setLoginInfo({
  74. token: result.data.token,
  75. refreshToken: result.data.refreshToken,
  76. userInfo: result.data.userInfo
  77. })
  78. return true
  79. }
  80. uni.showToast({ title: (result && result.message) || '登录失败', icon: 'none' })
  81. return false
  82. } catch (error) {
  83. uni.showToast({
  84. title: (error && error.message) || '网络请求失败',
  85. icon: 'none'
  86. })
  87. return false
  88. } finally {
  89. isLoading.value = false
  90. }
  91. }
  92. function clearLoginInfo() {
  93. token.value = ''
  94. refreshToken.value = ''
  95. userInfo.value = null
  96. uni.removeStorageSync(TOKEN_KEY)
  97. uni.removeStorageSync(REFRESH_TOKEN_KEY)
  98. uni.removeStorageSync(USER_INFO_KEY)
  99. }
  100. async function logout() {
  101. try {
  102. await request({
  103. url: AUTH_API.LOGOUT,
  104. method: 'POST'
  105. })
  106. } catch (error) {
  107. // ignore
  108. } finally {
  109. clearLoginInfo()
  110. uni.reLaunch({ url: PAGE_PATHS.login })
  111. }
  112. }
  113. function navigateToHome() {
  114. uni.switchTab({
  115. url: homePath.value,
  116. fail: () => {
  117. uni.reLaunch({ url: homePath.value })
  118. }
  119. })
  120. }
  121. function updateUserInfo(info) {
  122. if (!userInfo.value || !info) return
  123. userInfo.value = normalizeUserInfo({ ...userInfo.value, ...info })
  124. uni.setStorageSync(USER_INFO_KEY, userInfo.value)
  125. }
  126. async function refreshUserInfo() {
  127. if (!token.value || !String(token.value).trim()) return
  128. try {
  129. const res = await request({
  130. url: AUTH_API.CURRENT_USER,
  131. method: 'GET'
  132. })
  133. const result = parseResponseJson(res)
  134. if (result.code !== 200 || !result.data) return
  135. userInfo.value = normalizeUserInfo(result.data)
  136. uni.setStorageSync(USER_INFO_KEY, userInfo.value)
  137. } catch {
  138. // ignore
  139. }
  140. }
  141. return {
  142. token,
  143. refreshToken,
  144. userInfo,
  145. isLoading,
  146. isLoggedIn,
  147. userRole,
  148. homePath,
  149. checkLoginStatus,
  150. login,
  151. logout,
  152. clearLoginInfo,
  153. navigateToHome,
  154. updateUserInfo,
  155. refreshUserInfo
  156. }
  157. })