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> </div>' +
+ '<div>鍙傝�� https://doc.iocoder.cn/ 鏁欑▼</div>' +
+ '<div> </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