user.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { defineStore } from 'pinia'
  2. import { computed, ref } from 'vue'
  3. import { TOKEN_KEY, REFRESH_TOKEN_KEY, USER_INFO_KEY } from '@/config/api'
  4. import { request, parseResponseJson } from '@/utils/request'
  5. import { buildMiniEncryptedLoginBody } from '@/utils/loginRsa'
  6. import { ensurePriceRealtimeConnected, stopPriceRealtime } from '@/utils/price-realtime'
  7. const PAGE_PATHS = {
  8. login: '/pages/login/login',
  9. client: '/pages/client/home/home',
  10. supplier: '/pages/supplier/home/home',
  11. deliverer: '/pages/deliverer/home/home'
  12. }
  13. export const useUserStore = defineStore('user', () => {
  14. const token = ref('')
  15. const refreshToken = ref('')
  16. const userInfo = ref(null)
  17. const isLoading = ref(false)
  18. function normalizeUserInfo(raw) {
  19. if (!raw || typeof raw !== 'object') return raw || null
  20. const avatarUrl =
  21. raw.avatarUrl != null && String(raw.avatarUrl).trim()
  22. ? String(raw.avatarUrl).trim()
  23. : raw.avatar_url != null && String(raw.avatar_url).trim()
  24. ? String(raw.avatar_url).trim()
  25. : ''
  26. return {
  27. ...raw,
  28. avatarUrl
  29. }
  30. }
  31. const isLoggedIn = computed(() => !!token.value && !!userInfo.value)
  32. const userRole = computed(() => userInfo.value?.role || 'client')
  33. const isClient = computed(() => userRole.value === 'client')
  34. const isSupplier = computed(() => userRole.value === 'supplier')
  35. const isDeliverer = computed(() => userRole.value === 'deliver')
  36. const homePath = computed(() => {
  37. if (userRole.value === 'supplier') return PAGE_PATHS.supplier
  38. if (userRole.value === 'deliver') return PAGE_PATHS.deliverer
  39. return PAGE_PATHS.client
  40. })
  41. function checkLoginStatus() {
  42. const savedToken = uni.getStorageSync(TOKEN_KEY)
  43. const savedUserInfo = uni.getStorageSync(USER_INFO_KEY)
  44. const savedRefreshToken = uni.getStorageSync(REFRESH_TOKEN_KEY)
  45. const normalizedToken =
  46. typeof savedToken === 'string' ? savedToken.trim() : savedToken ? String(savedToken).trim() : ''
  47. let normalizedUserInfo = null
  48. if (typeof savedUserInfo === 'string') {
  49. try {
  50. normalizedUserInfo = normalizeUserInfo(JSON.parse(savedUserInfo))
  51. } catch (error) {
  52. normalizedUserInfo = null
  53. }
  54. } else if (savedUserInfo && typeof savedUserInfo === 'object') {
  55. normalizedUserInfo = normalizeUserInfo(savedUserInfo)
  56. }
  57. if (normalizedToken && normalizedUserInfo) {
  58. token.value = normalizedToken
  59. refreshToken.value = typeof savedRefreshToken === 'string' ? savedRefreshToken : ''
  60. userInfo.value = normalizedUserInfo
  61. return
  62. }
  63. // 本地无有效登录态时,必须同步清空内存态,避免登录页 onShow 误判已登录后跳回首页
  64. token.value = ''
  65. refreshToken.value = ''
  66. userInfo.value = null
  67. }
  68. function setLoginInfo(data) {
  69. token.value = data.token || ''
  70. refreshToken.value = data.refreshToken || ''
  71. userInfo.value = normalizeUserInfo(data.userInfo || null)
  72. uni.setStorageSync(TOKEN_KEY, token.value)
  73. uni.setStorageSync(REFRESH_TOKEN_KEY, refreshToken.value)
  74. uni.setStorageSync(USER_INFO_KEY, userInfo.value)
  75. void ensurePriceRealtimeConnected()
  76. }
  77. async function login(params) {
  78. isLoading.value = true
  79. try {
  80. const encryptedBody = await buildMiniEncryptedLoginBody(params.username, params.password)
  81. const res = await request({
  82. url: '/mini/auth/login',
  83. method: 'POST',
  84. data: encryptedBody
  85. })
  86. const result = parseResponseJson(res)
  87. if (result && result.code === 200 && result.data) {
  88. setLoginInfo({
  89. token: result.data.token,
  90. refreshToken: result.data.refreshToken,
  91. userInfo: result.data.userInfo
  92. })
  93. return true
  94. }
  95. uni.showToast({ title: (result && result.message) || '登录失败', icon: 'none' })
  96. return false
  97. } catch (error) {
  98. uni.showToast({
  99. title: (error && error.message) || '网络请求失败',
  100. icon: 'none'
  101. })
  102. return false
  103. } finally {
  104. isLoading.value = false
  105. }
  106. }
  107. function clearLoginInfo() {
  108. token.value = ''
  109. refreshToken.value = ''
  110. userInfo.value = null
  111. uni.removeStorageSync(TOKEN_KEY)
  112. uni.removeStorageSync(REFRESH_TOKEN_KEY)
  113. uni.removeStorageSync(USER_INFO_KEY)
  114. stopPriceRealtime()
  115. }
  116. async function logout() {
  117. try {
  118. await request({
  119. url: '/mini/auth/logout',
  120. method: 'POST'
  121. })
  122. } catch (error) {
  123. // ignore
  124. } finally {
  125. clearLoginInfo()
  126. uni.reLaunch({ url: PAGE_PATHS.login })
  127. }
  128. }
  129. function navigateToHome() {
  130. uni.reLaunch({ url: homePath.value })
  131. }
  132. function updateUserInfo(info) {
  133. if (!userInfo.value || !info) return
  134. userInfo.value = normalizeUserInfo({ ...userInfo.value, ...info })
  135. uni.setStorageSync(USER_INFO_KEY, userInfo.value)
  136. }
  137. async function refreshUserInfo() {
  138. if (!token.value || !String(token.value).trim()) return
  139. try {
  140. const res = await request({
  141. url: '/mini/auth/current-user',
  142. method: 'GET'
  143. })
  144. const result = parseResponseJson(res)
  145. if (result.code !== 200 || !result.data) return
  146. userInfo.value = normalizeUserInfo(result.data)
  147. uni.setStorageSync(USER_INFO_KEY, userInfo.value)
  148. } catch {
  149. // ignore
  150. }
  151. }
  152. return {
  153. token,
  154. refreshToken,
  155. userInfo,
  156. isLoading,
  157. isLoggedIn,
  158. userRole,
  159. isClient,
  160. isSupplier,
  161. isDeliverer,
  162. homePath,
  163. checkLoginStatus,
  164. login,
  165. logout,
  166. clearLoginInfo,
  167. navigateToHome,
  168. updateUserInfo,
  169. refreshUserInfo
  170. }
  171. })