import Axios from 'axios' import { ResCode } from './constant' import type { AxiosResponse, AxiosRequestConfig } from 'axios' import { ui18n } from '@/lang' export type ResErrorHandler = >( response: AxiosResponse, data?: T ) => void export type ReqErrorHandler = ( err: Error, response: AxiosRequestConfig ) => void export type ResData = { code: ResCode message: string data: T msg: string } export type Hook = { before?: (config: AxiosRequestConfig) => void after?: (config: AxiosRequestConfig) => void } export const axiosFactory = () => { const axiosRaw = Axios.create() const axiosConfig = { token: localStorage.getItem('token'), unTokenSet: [] as string[], unReqErrorSet: [] as string[], unResErrorSet: [] as string[], resErrorHandler: [] as ResErrorHandler[], reqErrorHandler: [] as ReqErrorHandler[], unLoadingSet: [] as string[], hook: [] as Hook[] } type AxiosConfig = typeof axiosConfig type ExponseApi = { set: (val: AxiosConfig[K]) => void } & (AxiosConfig[K] extends Array ? { add: (...val: AxiosConfig[K]) => void del: (...val: AxiosConfig[K]) => void } : { del: () => void }) const getExponseApi = ( key: K ): ExponseApi => { let axiosObj = axiosConfig[key] as any[] const apis: any = { set(val: AxiosConfig[K]) { axiosObj = axiosConfig[key] = val as any } } if (Array.isArray(axiosObj)) { apis.add = (...val: any[]) => { axiosObj.push(...val) } apis.del = (...val: any[]) => { if (val) { apis.set(axiosObj.filter((item: any) => !val?.includes(item)) as any) } else { axiosObj.length = 0 } } } else { apis.del = () => { axiosConfig[key] = undefined as any } } return apis } const getToken = () => axiosConfig.token const setToken = (token: string) => { localStorage.setItem('token', token) axiosConfig.token = token } const delToken = () => { localStorage.removeItem('token') axiosConfig.token = null } const { set: setUnsetTokenURLS, add: addUnsetTokenURLS, del: delUnsetTokenURLS } = getExponseApi('unTokenSet') const { set: setResErrorHandler, add: addResErrorHandler, del: delResErrorHandler } = getExponseApi('resErrorHandler') const { set: setUnsetReqErrorURLS, add: addUnsetReqErrorURLS, del: delUnsetReqErrorURLS } = getExponseApi('unReqErrorSet') const { set: setReqErrorHandler, add: addReqErrorHandler, del: delReqErrorHandler } = getExponseApi('reqErrorHandler') const { set: setUnsetResErrorURLS, add: addUnsetResErrorURLS, del: delUnsetResErrorURLS } = getExponseApi('unResErrorSet') const { set: setHook, add: addHook, del: delHook } = getExponseApi('hook') const setDefaultURI = (url: string) => { axiosRaw.defaults.baseURL = url } const matchURL = (urls: string[], config: AxiosRequestConfig) => config && config.url && urls.includes(config.url) const callErrorHandler = (key: 'req' | 'res', ...args: any[]) => { Promise.resolve().then(() => { const api = `${key}ErrorHandler` ;(axiosConfig as any)[api].forEach((handler: any) => handler(...args)) }) } axiosRaw.interceptors.request.use(config => { for (const hook of axiosConfig.hook) { hook.before && hook.before(config) } if (!matchURL(axiosConfig.unTokenSet, config)) { if (!axiosConfig.token) { if (!matchURL(axiosConfig.unReqErrorSet, config)) { const error = new Error(ui18n.t('sys.NO_ACCESS')) callErrorHandler('req', error, config) throw error } } else { config.headers = { ...config.headers, token: axiosConfig.token } } } return config }) axiosRaw.interceptors.response.use( (response: AxiosResponse>) => { for (const hook of axiosConfig.hook) { hook.after && hook.after(response.config) } if (matchURL(axiosConfig.unResErrorSet, response.config)) { return response } if (response.status !== 200) { callErrorHandler('res', response) throw new Error(response.statusText) } else if (response.data.code !== ResCode.SUCCESS) { callErrorHandler('res', response, response.data) if (response.data.code === ResCode.TOKEN_INVALID) { delToken() } throw new Error(response?.data?.message) } else { return response.data.data } }, err => { for (const hook of axiosConfig.hook) { hook.after && hook.after(err.config) } if (!matchURL(axiosConfig.unResErrorSet, err.config)) { callErrorHandler('res', err.response) } throw new Error(err.response ? err.response.statusText : err) } ) type AxiosProcess = { getUri(config?: AxiosRequestConfig): string request(config: AxiosRequestConfig): Promise get( url: string, config?: AxiosRequestConfig ): Promise delete( url: string, config?: AxiosRequestConfig ): Promise head( url: string, config?: AxiosRequestConfig ): Promise options( url: string, config?: AxiosRequestConfig ): Promise post( url: string, data?: D, config?: AxiosRequestConfig ): Promise put( url: string, data?: D, config?: AxiosRequestConfig ): Promise patch( url: string, data?: D, config?: AxiosRequestConfig ): Promise postForm( url: string, data?: D, config?: AxiosRequestConfig ): Promise putForm( url: string, data?: D, config?: AxiosRequestConfig ): Promise patchForm( url: string, data?: D, config?: AxiosRequestConfig ): Promise } interface AxiosInstanceProcess extends AxiosProcess { (config: AxiosRequestConfig): Promise (url: string, config?: AxiosRequestConfig): Promise } const axios: AxiosInstanceProcess = axiosRaw as any return { axios, getToken, setToken, delToken, setUnsetTokenURLS, addUnsetTokenURLS, delUnsetTokenURLS, setResErrorHandler, addResErrorHandler, delResErrorHandler, setUnsetReqErrorURLS, addUnsetReqErrorURLS, delUnsetReqErrorURLS, setReqErrorHandler, addReqErrorHandler, delReqErrorHandler, setUnsetResErrorURLS, addUnsetResErrorURLS, delUnsetResErrorURLS, setDefaultURI, setHook, addHook, delHook } } export default axiosFactory