From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/config/axios/service.ts |  270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 270 insertions(+), 0 deletions(-)

diff --git a/src/config/axios/service.ts b/src/config/axios/service.ts
new file mode 100644
index 0000000..9214bf8
--- /dev/null
+++ b/src/config/axios/service.ts
@@ -0,0 +1,270 @@
+import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
+
+import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
+import qs from 'qs'
+import { config } from '@/config/axios/config'
+import {
+  getAccessToken,
+  getRefreshToken,
+  getTenantId,
+  getVisitTenantId,
+  removeToken,
+  setToken
+} from '@/utils/auth'
+import errorCode from './errorCode'
+
+import { resetRouter } from '@/router'
+import { deleteUserCache } from '@/hooks/web/useCache'
+import { ApiEncrypt } from '@/utils/encrypt'
+
+const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
+const { result_code, base_url, request_timeout } = config
+
+// 闇�瑕佸拷鐣ョ殑鎻愮ず銆傚拷鐣ュ悗锛岃嚜鍔� Promise.reject('error')
+const ignoreMsgs = [
+  '鏃犳晥鐨勫埛鏂颁护鐗�', // 鍒锋柊浠ょ墝琚垹闄ゆ椂锛屼笉鐢ㄦ彁绀�
+  '鍒锋柊浠ょ墝宸茶繃鏈�' // 浣跨敤鍒锋柊浠ょ墝锛屽埛鏂拌幏鍙栨柊鐨勮闂护鐗屾椂锛岀粨鏋滃洜涓鸿繃鏈熷け璐ワ紝姝ゆ椂闇�瑕佸拷鐣ャ�傚惁鍒欙紝浼氬鑷寸户缁� 401锛屾棤娉曡烦杞埌鐧诲嚭鐣岄潰
+]
+// 鏄惁鏄剧ず閲嶆柊鐧诲綍
+export const isRelogin = { show: false }
+// Axios 鏃犳劅鐭ュ埛鏂颁护鐗岋紝鍙傝�� https://www.dashingdog.cn/article/11 涓� https://segmentfault.com/a/1190000020210980 瀹炵幇
+// 璇锋眰闃熷垪
+let requestList: any[] = []
+// 鏄惁姝e湪鍒锋柊涓�
+let isRefreshToken = false
+// 璇锋眰鐧藉悕鍗曪紝鏃犻』 token 鐨勬帴鍙�
+const whiteList: string[] = ['/login', '/refresh-token']
+
+// 鍒涘缓axios瀹炰緥
+const service: AxiosInstance = axios.create({
+  baseURL: base_url, // api 鐨� base_url
+  timeout: request_timeout, // 璇锋眰瓒呮椂鏃堕棿
+  withCredentials: false, // 绂佺敤 Cookie 绛変俊鎭�
+  // 鑷畾涔夊弬鏁板簭鍒楀寲鍑芥暟
+  paramsSerializer: (params) => {
+    return qs.stringify(params, { allowDots: true })
+  }
+})
+
+// request鎷︽埅鍣�
+service.interceptors.request.use(
+  (config: InternalAxiosRequestConfig) => {
+    // 鏄惁闇�瑕佽缃� token
+    let isToken = (config!.headers || {}).isToken === false
+    whiteList.some((v) => {
+      if (config.url && config.url.indexOf(v) > -1) {
+        return (isToken = false)
+      }
+    })
+    if (getAccessToken() && !isToken) {
+      config.headers.Authorization = 'Bearer ' + getAccessToken() // 璁╂瘡涓姹傛惡甯﹁嚜瀹氫箟token
+    }
+    // 璁剧疆绉熸埛
+    if (tenantEnable && tenantEnable === 'true') {
+      const tenantId = getTenantId()
+      if (tenantId) config.headers['tenant-id'] = tenantId
+      // 鍙湁鐧诲綍鏃讹紝鎵嶈缃� visit-tenant-id 璁块棶绉熸埛
+      const visitTenantId = getVisitTenantId()
+      if (config.headers.Authorization && visitTenantId) {
+        config.headers['visit-tenant-id'] = visitTenantId
+      }
+    }
+    const method = config.method?.toUpperCase()
+    // 闃叉 GET 璇锋眰缂撳瓨
+    if (method === 'GET') {
+      config.headers['Cache-Control'] = 'no-cache'
+      config.headers['Pragma'] = 'no-cache'
+    }
+    // 鑷畾涔夊弬鏁板簭鍒楀寲鍑芥暟
+    else if (method === 'POST') {
+      const contentType = config.headers['Content-Type'] || config.headers['content-type']
+      if (contentType === 'application/x-www-form-urlencoded') {
+        if (config.data && typeof config.data !== 'string') {
+          config.data = qs.stringify(config.data)
+        }
+      }
+    }
+    // 鏄惁 API 鍔犲瘑
+    if ((config!.headers || {}).isEncrypt) {
+      try {
+        // 鍔犲瘑璇锋眰鏁版嵁
+        if (config.data) {
+          config.data = ApiEncrypt.encryptRequest(config.data)
+          // 璁剧疆鍔犲瘑鏍囪瘑澶�
+          config.headers[ApiEncrypt.getEncryptHeader()] = 'true'
+        }
+      } catch (error) {
+        console.error('璇锋眰鏁版嵁鍔犲瘑澶辫触:', error)
+        throw error
+      }
+    }
+    return config
+  },
+  (error: AxiosError) => {
+    // Do something with request error
+    console.log(error) // for debug
+    return Promise.reject(error)
+  }
+)
+
+// response 鎷︽埅鍣�
+service.interceptors.response.use(
+  async (response: AxiosResponse<any>) => {
+    let { data } = response
+    const config = response.config
+    if (!data) {
+      // 杩斿洖鈥淸HTTP]璇锋眰娌℃湁杩斿洖鍊尖��;
+      throw new Error()
+    }
+
+    // 妫�鏌ユ槸鍚﹂渶瑕佽В瀵嗗搷搴旀暟鎹�
+    const encryptHeader = ApiEncrypt.getEncryptHeader()
+    const isEncryptResponse =
+      response.headers[encryptHeader] === 'true' ||
+      response.headers[encryptHeader.toLowerCase()] === 'true'
+    if (isEncryptResponse && typeof data === 'string') {
+      try {
+        // 瑙e瘑鍝嶅簲鏁版嵁
+        data = ApiEncrypt.decryptResponse(data)
+      } catch (error) {
+        console.error('鍝嶅簲鏁版嵁瑙e瘑澶辫触:', error)
+        throw new Error('鍝嶅簲鏁版嵁瑙e瘑澶辫触: ' + (error as Error).message)
+      }
+    }
+
+    const { t } = useI18n()
+    // 鏈缃姸鎬佺爜鍒欓粯璁ゆ垚鍔熺姸鎬�
+    // 浜岃繘鍒舵暟鎹垯鐩存帴杩斿洖锛屼緥濡傝 Excel 瀵煎嚭
+    if (
+      response.request.responseType === 'blob' ||
+      response.request.responseType === 'arraybuffer'
+    ) {
+      // 娉ㄦ剰锛氬鏋滃鍑虹殑鍝嶅簲涓� json锛岃鏄庡彲鑳藉け璐ヤ簡锛屼笉鐩存帴杩斿洖杩涜涓嬭浇
+      if (response.data.type !== 'application/json') {
+        return response.data
+      }
+      data = await new Response(response.data).json()
+    }
+    const code = data.code || result_code
+    // 鑾峰彇閿欒淇℃伅
+    const msg = data.msg || errorCode[code] || errorCode['default']
+    if (ignoreMsgs.indexOf(msg) !== -1) {
+      // 濡傛灉鏄拷鐣ョ殑閿欒鐮侊紝鐩存帴杩斿洖 msg 寮傚父
+      return Promise.reject(msg)
+    } else if (code === 401) {
+      // 濡傛灉鏈璇侊紝骞朵笖鏈繘琛屽埛鏂颁护鐗岋紝璇存槑鍙兘鏄闂护鐗岃繃鏈熶簡
+      if (!isRefreshToken) {
+        isRefreshToken = true
+        // 1. 濡傛灉鑾峰彇涓嶅埌鍒锋柊浠ょ墝锛屽垯鍙兘鎵ц鐧诲嚭鎿嶄綔
+        if (!getRefreshToken()) {
+          return handleAuthorized()
+        }
+        // 2. 杩涜鍒锋柊璁块棶浠ょ墝
+        try {
+          const refreshTokenRes = await refreshToken()
+          // 2.1 鍒锋柊鎴愬姛锛屽垯鍥炴斁闃熷垪鐨勮姹� + 褰撳墠璇锋眰
+          setToken((await refreshTokenRes).data.data)
+          config.headers!.Authorization = 'Bearer ' + getAccessToken()
+          requestList.forEach((cb: any) => {
+            cb()
+          })
+          requestList = []
+          return service(config)
+        } catch (e) {
+          // 涓轰粈涔堥渶瑕� catch 寮傚父鍛紵鍒锋柊澶辫触鏃讹紝璇锋眰鍥犱负 Promise.reject 瑙﹀彂寮傚父銆�
+          // 2.2 鍒锋柊澶辫触锛屽彧鍥炴斁闃熷垪鐨勮姹�
+          requestList.forEach((cb: any) => {
+            cb()
+          })
+          // 鎻愮ず鏄惁瑕佺櫥鍑恒�傚嵆涓嶅洖鏀惧綋鍓嶈姹傦紒涓嶇劧浼氬舰鎴愰�掑綊
+          return handleAuthorized()
+        } finally {
+          requestList = []
+          isRefreshToken = false
+        }
+      } else {
+        // 娣诲姞鍒伴槦鍒楋紝绛夊緟鍒锋柊鑾峰彇鍒版柊鐨勪护鐗�
+        return new Promise((resolve) => {
+          requestList.push(() => {
+            config.headers!.Authorization = 'Bearer ' + getAccessToken() // 璁╂瘡涓姹傛惡甯﹁嚜瀹氫箟token 璇锋牴鎹疄闄呮儏鍐佃嚜琛屼慨鏀�
+            resolve(service(config))
+          })
+        })
+      }
+    } else if (code === 500) {
+      ElMessage.error(t('sys.api.errMsg500'))
+      return Promise.reject(new Error(msg))
+    } else if (code === 901) {
+      ElMessage.error({
+        offset: 300,
+        dangerouslyUseHTMLString: true,
+        message:
+          '<div>' +
+          t('sys.api.errMsg901') +
+          '</div>' +
+          '<div> &nbsp; </div>' +
+          '<div>鍙傝�� https://doc.iocoder.cn/ 鏁欑▼</div>' +
+          '<div> &nbsp; </div>' +
+          '<div>5 鍒嗛挓鎼缓鏈湴鐜</div>'
+      })
+      return Promise.reject(new Error(msg))
+    } else if (code !== 200) {
+      if (msg === '鏃犳晥鐨勫埛鏂颁护鐗�') {
+        // hard coding锛氬拷鐣ヨ繖涓彁绀猴紝鐩存帴鐧诲嚭
+        console.log(msg)
+        return handleAuthorized()
+      } else {
+        ElNotification.error({ title: msg })
+      }
+      return Promise.reject('error')
+    } else {
+      return data
+    }
+  },
+  (error: AxiosError) => {
+    console.log('err' + error) // for debug
+    let { message } = error
+    const { t } = useI18n()
+    if (message === 'Network Error') {
+      message = t('sys.api.errorMessage')
+    } else if (message.includes('timeout')) {
+      message = t('sys.api.apiTimeoutMessage')
+    } else if (message.includes('Request failed with status code')) {
+      message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
+    }
+    ElMessage.error(message)
+    return Promise.reject(error)
+  }
+)
+
+const refreshToken = async () => {
+  axios.defaults.headers.common['tenant-id'] = getTenantId()
+  return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
+}
+const handleAuthorized = () => {
+  const { t } = useI18n()
+  if (!isRelogin.show) {
+    // 濡傛灉宸茬粡鍒扮櫥褰曢〉闈㈠垯涓嶈繘琛屽脊绐楁彁绀�
+    if (window.location.href.includes('login')) {
+      return
+    }
+    isRelogin.show = true
+    ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), {
+      showCancelButton: false,
+      closeOnClickModal: false,
+      showClose: false,
+      closeOnPressEscape: false,
+      confirmButtonText: t('login.relogin'),
+      type: 'warning'
+    }).then(() => {
+      resetRouter() // 閲嶇疆闈欐�佽矾鐢辫〃
+      deleteUserCache() // 鍒犻櫎鐢ㄦ埛缂撳瓨
+      removeToken()
+      isRelogin.show = false
+      // 骞叉帀token鍚庡啀璧颁竴娆¤矾鐢辫瀹冭繃router.beforeEach鐨勬牎楠�
+      window.location.href = window.location.href
+    })
+  }
+  return Promise.reject(t('sys.api.timeoutMessage'))
+}
+export { service }

--
Gitblit v1.8.0