Bläddra i källkod

登录完成 解耦实现

yuanmingze 8 månader sedan
förälder
incheckning
eff47084ae

+ 10 - 0
src/main.ts

@@ -1,7 +1,17 @@
 import { createSSRApp } from 'vue'
 
+// ...existing code...
+import { setAuthHandlers } from '@/services/request'
+
 import { setupStore } from '@/stores'
+import { useUserStoreWithOut } from '@/stores/modules/user'
+
+setAuthHandlers({
+  getAccessToken: () => useUserStoreWithOut().access_token,
+  onUnauthorized: () => useUserStoreWithOut().logout(),
+})
 
+// ...existing code...
 import App from './App.vue'
 export function createApp() {
   const app = createSSRApp(App)

+ 14 - 75
src/services/request/index.ts

@@ -1,8 +1,16 @@
-import { useUserStoreWithOut } from '@/stores/modules/user'
-
 import { hideGlobalLoading, showGlobalLoading } from '@/utils/loading'
 
-import { BASE_API, MODE, NOT_OAUTH_BASIC_TOKEN, OAUTH_BASIC_TOKEN, TIMEOUT } from './config'
+import { TIMEOUT } from './config'
+import {
+  buildHeaders,
+  getErrorMessage,
+  handleUnauthorized,
+  isWhiteList,
+  normalizeHttpError,
+  resetUnauthorizedHandled,
+  resolveUrl,
+  setAuthHandlers,
+} from './utils'
 
 /* -------------------------------------------------------------------------- */
 /*                                   类型                                     */
@@ -50,27 +58,23 @@ export function request<T = any>(config: RequestConfig): Promise<ApiResponse<T>>
         const statusCode = res.statusCode ?? 0
         const body = res.data as ApiResponse<T>
 
-        // 白名单接口:完全放行
         if (isWhiteList(config.url)) {
           return resolve(body)
         }
 
-        // 仅校验 HTTP 状态码
         if (statusCode === 200) {
           return resolve(body)
         }
 
-        // 401:统一登出
         if (statusCode === 401) {
           handleUnauthorized()
           return reject(normalizeHttpError(res, config.url))
         }
 
-        // 其他 HTTP 错误
         if (!config.silent) {
           uni.showModal({
             title: '提示',
-            content: getErrorMessage(body, statusCode),
+            content: getErrorMessage(body),
             showCancel: false,
           })
         }
@@ -131,7 +135,7 @@ export function requestRaw<T = any>(config: RequestConfig): Promise<T> {
         if (!config.silent) {
           uni.showModal({
             title: '提示',
-            content: `请求失败(HTTP ${statusCode})`,
+            content: getErrorMessage(res.data as any),
             showCancel: false,
           })
         }
@@ -183,69 +187,4 @@ const http = {
 
 export default http
 
-/* -------------------------------------------------------------------------- */
-/*                                 工具函数                                   */
-/* -------------------------------------------------------------------------- */
-
-function resolveUrl(url: string) {
-  // #ifdef MP
-  return BASE_API + url
-  // #endif
-
-  // #ifdef H5
-  if (MODE === 'development') return url
-  return BASE_API + url
-  // #endif
-
-  return BASE_API + url
-}
-
-function isWhiteList(url: string) {
-  return ['/auth/oauth/token'].some((item) => url.includes(item))
-}
-
-function buildHeaders(url: string, extraHeader?: UniApp.RequestOptions['header']) {
-  const headers: Record<string, any> = {
-    ...(extraHeader || {}),
-  }
-
-  const userStore = useUserStoreWithOut()
-  const accessToken = userStore.access_token
-
-  if (url.includes('auth/mobile/token/sms')) {
-    headers.Authorization = NOT_OAUTH_BASIC_TOKEN
-  } else if (url.includes('auth/oauth/token')) {
-    headers.Authorization = OAUTH_BASIC_TOKEN
-    headers['TENANT-ID'] = '1'
-  } else if (accessToken) {
-    headers.Authorization = `Bearer ${accessToken}`
-  }
-
-  return headers
-}
-
-function handleUnauthorized() {
-  const userStore = useUserStoreWithOut()
-  userStore.logout()
-
-  uni.reLaunch({
-    url: '/pages/login/index',
-  })
-}
-
-function getErrorMessage(body: unknown, statusCode: number) {
-  if (body && typeof body === 'object') {
-    const msg = (body as any).msg
-    if (typeof msg === 'string' && msg.trim()) return msg
-  }
-  return `请求失败(HTTP ${statusCode})`
-}
-
-function normalizeHttpError(res: UniApp.RequestSuccessCallbackResult, url: string) {
-  return {
-    url,
-    statusCode: res.statusCode ?? 0,
-    data: res.data,
-    header: res.header,
-  }
-}
+export { resetUnauthorizedHandled, setAuthHandlers }

+ 88 - 0
src/services/request/utils.ts

@@ -0,0 +1,88 @@
+import { BASE_API, MODE, NOT_OAUTH_BASIC_TOKEN, OAUTH_BASIC_TOKEN } from './config'
+
+type AuthHandlers = {
+  getAccessToken?: () => string | undefined
+  onUnauthorized?: () => void
+}
+
+let authHandlers: AuthHandlers = {}
+let unauthorizedHandled = false
+
+export function setAuthHandlers(handlers: AuthHandlers) {
+  authHandlers = handlers
+}
+
+export function resetUnauthorizedHandled() {
+  unauthorizedHandled = false
+}
+
+export function handleUnauthorized() {
+  if (unauthorizedHandled) return
+  unauthorizedHandled = true
+
+  authHandlers.onUnauthorized?.()
+
+  uni.showModal({
+    title: '提示',
+    content: '当前登录失效,请重新登录',
+    showCancel: false,
+    success() {
+      uni.reLaunch({
+        url: '/pages/login/index',
+      })
+    },
+  })
+}
+
+export function resolveUrl(url: string) {
+  // #ifdef MP
+  return BASE_API + url
+  // #endif
+
+  // #ifdef H5
+  if (MODE === 'development') return url
+  return BASE_API + url
+  // #endif
+
+  return BASE_API + url
+}
+
+export function isWhiteList(url: string) {
+  return ['/auth/oauth/token'].some((item) => url.includes(item))
+}
+
+export function buildHeaders(url: string, extraHeader?: UniApp.RequestOptions['header']) {
+  const headers: Record<string, any> = {
+    ...(extraHeader || {}),
+  }
+
+  const accessToken = authHandlers.getAccessToken?.()
+
+  if (url.includes('auth/mobile/token/sms')) {
+    headers.Authorization = NOT_OAUTH_BASIC_TOKEN
+  } else if (url.includes('auth/oauth/token')) {
+    headers.Authorization = OAUTH_BASIC_TOKEN
+    headers['TENANT-ID'] = '1'
+  } else if (accessToken) {
+    headers.Authorization = `Bearer ${accessToken}`
+  }
+
+  return headers
+}
+
+export function getErrorMessage(body: unknown) {
+  if (body && typeof body === 'object') {
+    const msg = (body as any).msg
+    if (typeof msg === 'string' && msg.trim()) return msg
+  }
+  return '网络异常,请稍后再试'
+}
+
+export function normalizeHttpError(res: UniApp.RequestSuccessCallbackResult, url: string) {
+  return {
+    url,
+    statusCode: res.statusCode ?? 0,
+    data: res.data,
+    header: res.header,
+  }
+}

+ 2 - 0
src/stores/modules/user.ts

@@ -9,6 +9,7 @@ import type {
   LoginRequest,
 } from '@/services/modules/auth/type'
 import type { UserInfoItem } from '@/services/modules/auth/userInfo'
+import { resetUnauthorizedHandled } from '@/services/request'
 
 import { pinia } from '@/stores/index'
 
@@ -47,6 +48,7 @@ export const useUserStore = defineStore('user', {
       }
       // 登录成功
       this.access_token = res.access_token
+      resetUnauthorizedHandled()
       // 拉取用户信息
       await this.getUserInfoByCode()
       return {

+ 7 - 0
src/types/unplugin-auto-import.d.ts

@@ -0,0 +1,7 @@
+declare module 'unplugin-auto-import/vite' {
+  import type { Options } from 'unplugin-auto-import'
+  import type { Plugin } from 'vite'
+
+  const AutoImport: (options?: Options) => Plugin
+  export default AutoImport
+}

+ 1 - 1
tsconfig.json

@@ -15,5 +15,5 @@
       "miniprogram-api-typings"
     ]
   },
-  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
+  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "vite.config.ts"]
 }

+ 0 - 2
vite.config.ts

@@ -29,7 +29,5 @@ export default defineConfig(async () => {
         '@': path.resolve(__dirname, 'src'),
       },
     },
-
-    css: {},
   }
 })