import type { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios' import type { CreateAxiosOptions, RequestResult } from './model' import { ref } from 'vue' import axios from 'axios' import { TOKEN_KEY, USER_INFO_KEY, REFRESH_TOKEN_KEY, RBAC_REFRESH_TOKEN_KEY, RBAC_ACCESS_TOKEN_KEY, USER_APPLICATION_ID, USER_APPLICATION_TYPE, } from '@/global/cacheKey' import { notification } from 'ant-design-vue' import { userStore } from '@/store/modules/user' import Storage from 'web-storage-cache' const localStorage = new Storage() import router from '@/router' const env = import.meta.env import { validatenull, calcDate } from '@/utils/tool/translateValue' // 获取刷新token let refreshLock = false const refreshToken = async () => { const rbacStorageToken = window.localStorage.getItem(RBAC_REFRESH_TOKEN_KEY) // 获取存储的refreshToken、accessToken const userInfo = localStorage.get(USER_INFO_KEY) || {} const refresh_token = localStorage.get(REFRESH_TOKEN_KEY) || rbacStorageToken if (validatenull(userInfo)) return // 获取 秒数 const date = calcDate(userInfo.datetime, new Date().getTime()) // Math.round((new Date().getTime() - token.datetime) / 1000) if (validatenull(date)) return // 判断 调用接口 if (date.seconds >= userInfo.expiresIn && !refreshLock) { refreshLock = true const useUserStore = userStore() await useUserStore .getRefreshToken({ refreshToken: refresh_token }) .finally(() => { refreshLock = false }) .catch(() => { refreshLock = false }) } } export class JAxios { private axiosInstance: AxiosInstance private readonly options: CreateAxiosOptions constructor(options: CreateAxiosOptions) { this.options = options this.axiosInstance = axios.create(options) this.setInterceptors() } private setInterceptors() { this.axiosInstance.interceptors.request.use( (config: AxiosRequestConfig) => { // const userInfo = localStorage.get(USER_INFO_KEY) const rbacStorageToken = window.localStorage.getItem( RBAC_ACCESS_TOKEN_KEY ) const token = localStorage.get(TOKEN_KEY) || rbacStorageToken config.headers['api-version'] = '1.0' // 让每个请求携带自定义 token 请根据实际情况自行修改 if (token && !config.headers.Authorization) { config.headers['Authorization'] = `Bearer ${token}` } // if ( // !validatenull(userInfo) && // !config.headers['application-id'] // ) { // config.headers['application-id'] = userInfo.applicationId // } const _processAppId = ref( window.localStorage.getItem(USER_APPLICATION_ID) || localStorage.get('processAppId') ) if (_processAppId.value) { config.headers['processAppId'] = _processAppId.value } // 非4A const _processAppType = ref( window.localStorage.getItem(USER_APPLICATION_TYPE) || '' ) if (_processAppType.value) { config.headers['Authorizationapptype'] = _processAppType.value } // get请求增加时间戳,防止IE缓存 if (this.options.isGetTimeStamp) { if (config.method == 'get') { config.params = { _t: Date.parse(new Date().toString()) / 1000, ...config.params, } } } return config } ) this.axiosInstance.interceptors.response.use( (response: AxiosResponse) => { // 每次请求都更新返回的token,防止token过期 if (response.headers.token) { localStorage.set( this.options.tokenName, response.headers.token ) } const publicPath = env.VITE_PUBLIC_PATH as string const pathIdx = window.location.href.indexOf(publicPath) const toPath = window.location.href.slice( pathIdx > -1 ? pathIdx + publicPath.length : 0 ) // 许可验证 if (response.data.code == '40399') { localStorage.set('continueVisitUrl', toPath) return Promise.reject().finally(() => { router.push({ name: 'License40399' }) }) } if (response.data.code == '40398') { localStorage.set('continueVisitUrl', toPath) return Promise.reject().finally(() => { router.push({ name: 'VerifyLicense40398' }) }) } // 需要重新登陆,清除缓存中的token if ( new String(response.config.url).indexOf('/login') === -1 && (response.data.code === 401 || response.data.code === 401001) ) { // 刷新token // const refreshTokenData = localStorage.get(REFRESH_TOKEN_KEY) // refreshTokenData && refreshToken() // return null notification['warning']({ message: '提示', description: '登录信息过期请重新登录', }) const useUserStore = userStore() localStorage.delete(this.options.tokenName) useUserStore.logout() } if (response.request.responseType === 'blob') { return response } // 是否需要code校验 if (this.options.withoutCode) { return response.data } // 响应500 且有list属性(EXCEL导入文件报错时取回显值传弹窗) if (response.data.code === 500) { // 提示信息 notification['warning']({ message: '提示', description: ((response.data.message || {}).data || {}).msg || response.data.message || response.data.msg || '请求出现错误,请联系管理员', }) return response.data } // 操作成功返回data值,不成功提示相应错误信息 // 表单从别的接口拿、那个接口定义的成功code是0 if (response.data.code === 200 || response.data.code === 0) { return response.data } // 4a用户首次登录serve端,重置密码的接口 返回204 且data为空时,重置密码成功 if (response.status == 204 && !response.data) { return response } // 登陆成功 response.data 里面没有code!!!!!!!! 202305118 if ( response.status == 200 && !response.data.code && !validatenull(response.data) ) { return response } // 4a接口返回 // && response.statusText == 'OK' response.status == 200 || if (response.status > 200 && response.status < 500) { const rbacStorageToken = window.localStorage.getItem( RBAC_REFRESH_TOKEN_KEY ) // 刷新token const refreshTokenData = localStorage.get(REFRESH_TOKEN_KEY) || rbacStorageToken refreshTokenData && refreshToken() return response } // /licenses/html-backend/upload-license if ( response.status == 200 && response.config.url && response.config.url?.indexOf('licenses') > -1 ) { return response } // 响应非200提示信息 notification['warning']({ message: '提示', description: ((response.data.message || {}).data || {}).msg || response.data.message || response.data.msg || '请求出现错误,请联系管理员', }) throw response.data } ) } get(config: AxiosRequestConfig): Promise> { return this.request({ ...config, method: 'GET' }) } post(config: AxiosRequestConfig): Promise> { return this.request({ ...config, method: 'POST' }) } put(config: AxiosRequestConfig): Promise> { return this.request({ ...config, method: 'PUT' }) } delete(config: AxiosRequestConfig): Promise> { return this.request({ ...config, method: 'DELETE' }) } patch(config: AxiosRequestConfig): Promise> { return this.request({ ...config, method: 'PATCH' }) } private request( config: AxiosRequestConfig ): Promise> { return new Promise((resolve, reject) => { const timer = ref() const useUserStore = userStore() this.axiosInstance .request>>(config) .then((res: AxiosResponse>) => { resolve(res as unknown as Promise>) }) .catch((e: any) => { if ( e && e.response && e.response.data && (e.response.data.code === 401 || e.response.data.code === 401001 || e.response.data.code === 403006 || e.response.data.code === 400125) ) { timer.value = setTimeout(() => { localStorage.delete(this.options.tokenName) useUserStore.logout() clearTimeout(timer.value) timer.value = '' }, 500) notification['warning']({ message: '提示', description: ((e.response.data.message || {}).data || {}) .msg || ((e.response.data.message || {}).data || {}) .message || e.response.data.message || e.response.data.msg || '请求出现错误,请联系管理员', }) reject(e) } reject(e) }) }) } download(config: AxiosRequestConfig) { return new Promise((resolve, reject) => { this.axiosInstance .request>({ ...config, method: 'GET', responseType: 'blob', }) .then((res: AxiosResponse) => { const filedata = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8', }) const fileName = window.decodeURI( res.headers['content-disposition'].split('=')[1] ) const a = document.createElement('a') const url = window.URL.createObjectURL(filedata) a.href = url a.download = fileName a.click() a.remove() window.URL.revokeObjectURL(url) resolve(res as unknown as Promise) }) .catch((e: Error) => { reject(e) }) }) } }