import { equalUrl, gendUrl, recursionCopy } from "@/utils"; import axios, { Method as BaseMethod, AxiosRequestConfig as BaseAxiosReqConfig, AxiosStatic as BaseAxiosStatic, AxiosResponse as BaseAxiosResponse, AxiosInterceptorManager as BaseAxiosInterceptorManager, } from "axios"; import { Loading } from "@kankan/components/index"; // 提取对象的值 export type ExtractValue = T extends { [key in K]: any } ? T[K] : never; // 排除基本类型 export type OmitBasic = keyof { [key in T as key extends K ? never : key]: any; }; // 去除对象中值为never的keyValue export type OmitNever = { [key in keyof T as T[key] extends never ? never : key]: T[key] extends never ? never : T[key]; }; export type defVoid = void | undefined | null; // 接口配置值 export type InterfaceConfig = BaseAxiosReqConfig & { url: string; paths?: BaseAxiosReqConfig["params"]; params?: BaseAxiosReqConfig["params"]; data?: BaseAxiosReqConfig["data"]; response?: any; }; // 配置值 export type InterfaceConfigArray = Array; // 接口配置 export type InterfacesConfig = { [key in BaseMethod]?: InterfaceConfigArray; }; type ExtractInterfacesMethodMap = { [key in keyof T as key extends BaseMethod ? key : never]: key; }; // 提取所有Methods export type ExtractInterfacesMethod = ExtractInterfacesMethodMap[keyof ExtractInterfacesMethodMap]; // 提取数组中的所有URL export type ExtractInterfaceArrayURL = T extends Array<{ url: infer U }> ? U : never; // 提取接口某个method的所有url export type ExtractInterfacesMethodURL = M extends ExtractInterfacesMethod ? M extends keyof T ? T[M] extends InterfaceConfigArray ? ExtractInterfaceArrayURL : T[M] : never : never; // 提取接口所有url export type ExtractInterfacesAllURL = { [key in keyof T]: T[key] extends InterfaceConfigArray ? ExtractInterfaceArrayURL : never; }[keyof T]; // 提取全部或者method的所有url export type ExtractInterfacesURL = M extends defVoid ? ExtractInterfacesAllURL : M extends ExtractInterfacesMethod ? ExtractInterfacesMethodURL : never; // 根据具体的method url 抽取有配置 export type ExtractInterfaceByMethodURL< T, M extends ExtractInterfacesMethod, U extends ExtractInterfacesURL > = M extends keyof T ? { [key in keyof T[M]]: T[M][key] extends InterfaceConfig ? T[M][key]["url"] extends U ? T[M][key] & { method: M } : never : never; }[keyof T[M]] : never; // 根据URL提取完整接口参数 export type ExtractInterface = M extends defVoid ? { [Method in keyof T]: Method extends ExtractInterfacesMethod ? U extends ExtractInterfacesURL ? ExtractInterfaceByMethodURL : never : never; }[keyof T] : M extends ExtractInterfacesMethod ? U extends ExtractInterfacesURL ? ExtractInterfaceByMethodURL : never : never; // 根据url method 获取axios需要的所有参数 export type InstanceConfig< T, U, M = defVoid, Config = ExtractInterface > = { config: Config; givenReqConfig: Omit; getUriConfig: Omit; reqConfig: Omit; resData: Promise>; reqData: ExtractValue; }; // 特定请求基础参数 type InstanceBaseArgs< T, Method, URL, instance = InstanceConfig > = {} extends ExtractValue ? [] : ExtractValue extends never ? [] : [ExtractValue]; // 特定请求返回返回值 type InstanceBaseReturn = ExtractValue< InstanceConfig, "resData" >; // 特定的GET相关接口函数声明 type InstanceGet = ( ...args: InstanceBaseArgs ) => InstanceBaseReturn; // 特定的POST相关接口函数声明 type InstancePost< T, Method, URL, Args extends InstanceBaseArgs = InstanceBaseArgs< T, Method, URL > > = ( ...args: Args extends [] ? [] : ExtractValue extends never ? [defVoid, ...Args] : {} extends Omit ? [ExtractValue] | [defVoid, ...Args] : | [ ExtractValue, ...[Omit, ...Omit] ] | [defVoid, ...Args] ) => InstanceBaseReturn; // 各个实例上的api定义 type GETURIM = "GET" | "DELETE" | "HEAD" | "OPTIONS"; export interface AxiosInstance { < URL extends ExtractInterfacesURL, Method extends ExtractInterfacesMethod | defVoid = defVoid >( config: ExtractValue< InstanceConfig, "reqConfig" > extends never ? { url: URL; method: Method } : ExtractValue, "reqConfig"> & { url: URL } ): ExtractValue, "resData">; < URL extends ExtractInterfacesURL, Instance extends InstanceConfig >( url: URL, config: Omit, "url"> ): ExtractValue; defaults: InterfaceConfig; interceptors: { request: BaseAxiosInterceptorManager; response: BaseAxiosInterceptorManager; }; getUri>( config: ExtractValue, "getUriConfig"> & { url: URL; } ): string; request< URL extends ExtractInterfacesURL, Method extends ExtractInterfacesMethod | defVoid = defVoid >( config: ExtractValue< InstanceConfig, "reqConfig" > extends never ? { url: URL; method: Method } : ExtractValue, "reqConfig"> & { url: URL } ): ExtractValue, "resData">; get>( url: URL, ...args: Parameters> ): ReturnType>; delete>( url: URL, ...args: Parameters> ): ReturnType>; head>( url: URL, ...args: Parameters> ): ReturnType>; options>( url: URL, ...args: Parameters> ): ReturnType>; post>( url: URL, ...args: Parameters> ): ReturnType>; put>( url: URL, ...args: Parameters> ): ReturnType>; patch>( url: URL, ...args: Parameters> ): ReturnType>; addIntercept: , RT, RS>( intercept: InterceptAtom ) => AxiosStatic< InterceptAfterInterfaces, RS> >; } // 拦截urls参数 export type InterceptURL> = | U | readonly [U, ExtractInterface["method"]]; export type InterceptURLS = readonly InterceptURL[]; export type InterceptsURLS = readonly InterceptURLS[]; // 抽取拦截参数的接口定义 export type ExtractInstanceConfig = M extends | ExtractInterfacesMethod | defVoid ? U extends ExtractInterfacesURL ? InstanceConfig : never : never; // 获取多个URL共有的config export type ExtractInterceptInstance< T, URLS, Attr extends string > = ExtractValue< OmitNever< { [Index in keyof URLS]: URLS[Index] extends InterceptURL ? URLS[Index] extends string ? ExtractInstanceConfig : ExtractInstanceConfig : never; }[keyof URLS] >, Attr >; // 拦截数组选项声明 export type InterceptAtom = { reqHandler?: ( config: Omit, "response"> ) => ReqReturn; errHandler?: (res?: BaseAxiosResponse) => void; resHandler?: ( res: ExtractInterceptInstance extends Promise ? P : any ) => ResReturn; urls: URLS; }; // 去除所有相同属性 type ExtractPublic = OmitNever< { [key in keyof T & keyof R]: T[key] extends object ? T[key] extends R[key] ? R[key] extends T[key] ? never : ExtractPublic : R[key] extends object ? ExtractPublic : never : never; } & { [key in OmitBasic]: T[key]; } >; // 传入请求配置更新接口 type UpdateInterfaceReq = OmitNever<{ [key in keyof T]: key extends keyof NV ? {} extends ExtractPublic ? never : ExtractPublic : T[key]; }>; // 传入请求响应配置更新接口 type UpdateInterface< T extends InterfaceConfig, NV > = "response" extends keyof NV ? Omit, "response"> & { response: NV["response"] } : UpdateInterfaceReq; // 传入函数配置,更新所有接口 type UpdaeInterfaces< T extends InterfacesConfig, US extends InterceptURLS, NV > = { [M in keyof T]: { [I in OmitBasic]: T[M][I] extends InterfaceConfig ? T[M][I]["url"] extends US[keyof US] ? UpdateInterface : readonly [T[M][I]["url"], M] extends US[OmitBasic] ? UpdateInterface : T[M][I] : T[M][I]; } & { [key in keyof T[M] & keyof []]: T[M][key]; }; }; // 通过拦截函数得resHandler和reqHandler更新所有接口 type InterceptAfterInterfaces< T extends InterfacesConfig, US extends InterceptURLS, RET, RES > = RET extends object | string | number | symbol ? RES extends object | string | number | symbol ? UpdaeInterfaces : UpdaeInterfaces : RES extends object | string | number | symbol ? UpdaeInterfaces : T; // 加工后得axios声明 export type AxiosStatic = Omit> & AxiosInstance; let spliceUrl = ""; export const setSpliceUrl = (splice = "") => (spliceUrl = splice); export const setupFactory = () => { type NeedAtom = InterceptAtom; type Needs = Array>>; const needs: Needs = []; const processAxios = { ...axios.create(), addIntercept(intercept: any) { needs.push(intercept); return processAxios as any; }, } as AxiosStatic; const getUriRaw = processAxios.getUri; processAxios.getUri = (config, ...args) => { return getUriRaw( { ...config, url: (processAxios.defaults.baseURL + config.url) as any, }, ...args ); }; // 拦截处理函数 const tapIntercept = ( url: string, method: BaseMethod | undefined, handler: (need: NeedAtom) => void ) => { if (needs) { let checkUrl = url; if (spliceUrl) { const index = url.indexOf(spliceUrl); if (~index) { checkUrl = url.substring(0, index); } } for (let need of needs) { const wise = need.urls.find((temp) => typeof temp === "string" ? equalUrl(temp, checkUrl) : equalUrl(temp[0], checkUrl) && method?.toUpperCase() === temp[1] ); wise && handler(need); } } }; const stopRequest = () => { const source = processAxios.CancelToken.source(); source.cancel("Illegal request"); }; const errorHandler = (res: BaseAxiosResponse, ret?: any) => { if (!res && ret && ret.isAxiosError) { res = { config: ret.config, status: -1, } as unknown as BaseAxiosResponse; } if (res?.config && res.config.url) { tapIntercept( res.config.url, res.config.method as any, ({ errHandler }) => { errHandler && errHandler(res); } ); } else { setTimeout(() => Loading.hide()); } return Promise.reject(res); }; processAxios.interceptors.request.use((config) => { let ret; if (config.url) { ret = { ...config } as any; try { tapIntercept(ret.url, ret.method, ({ reqHandler }) => { let attach = reqHandler && reqHandler(ret); if (attach) { ret = recursionCopy(ret, attach); } }); } catch (e) { console.error(e); stopRequest(); } if (ret.paths) { ret.url = gendUrl(ret.url, ret.paths); } ret; } else { ret = config; } return ret; }); processAxios.interceptors.response.use( (res) => { let ret = res.data; if (res.status < 200 || res.status >= 300) { return errorHandler(res); } else if (res.config.url) { tapIntercept( res.config.url, res.config.method as any, ({ resHandler }) => { if (resHandler) { ret = resHandler(ret); } } ); } return ret; }, (res) => errorHandler(res.response, res) ); return processAxios; }; export default setupFactory;