setup.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. import { equalUrl, gendUrl, recursionCopy } from "@/utils";
  2. import axios, {
  3. Method as BaseMethod,
  4. AxiosRequestConfig as BaseAxiosReqConfig,
  5. AxiosStatic as BaseAxiosStatic,
  6. AxiosResponse as BaseAxiosResponse,
  7. AxiosInterceptorManager as BaseAxiosInterceptorManager,
  8. } from "axios";
  9. import { Loading } from "@kankan/components/index";
  10. // 提取对象的值
  11. export type ExtractValue<T, K extends string> = T extends { [key in K]: any }
  12. ? T[K]
  13. : never;
  14. // 排除基本类型
  15. export type OmitBasic<T extends string | number | symbol, K> = keyof {
  16. [key in T as key extends K ? never : key]: any;
  17. };
  18. // 去除对象中值为never的keyValue
  19. export type OmitNever<T> = {
  20. [key in keyof T as T[key] extends never ? never : key]: T[key] extends never
  21. ? never
  22. : T[key];
  23. };
  24. export type defVoid = void | undefined | null;
  25. // 接口配置值
  26. export type InterfaceConfig = BaseAxiosReqConfig & {
  27. url: string;
  28. paths?: BaseAxiosReqConfig["params"];
  29. params?: BaseAxiosReqConfig["params"];
  30. data?: BaseAxiosReqConfig["data"];
  31. response?: any;
  32. };
  33. // 配置值
  34. export type InterfaceConfigArray = Array<InterfaceConfig>;
  35. // 接口配置
  36. export type InterfacesConfig = {
  37. [key in BaseMethod]?: InterfaceConfigArray;
  38. };
  39. type ExtractInterfacesMethodMap<T> = {
  40. [key in keyof T as key extends BaseMethod ? key : never]: key;
  41. };
  42. // 提取所有Methods
  43. export type ExtractInterfacesMethod<T> =
  44. ExtractInterfacesMethodMap<T>[keyof ExtractInterfacesMethodMap<T>];
  45. // 提取数组中的所有URL
  46. export type ExtractInterfaceArrayURL<T> = T extends Array<{ url: infer U }>
  47. ? U
  48. : never;
  49. // 提取接口某个method的所有url
  50. export type ExtractInterfacesMethodURL<T, M> =
  51. M extends ExtractInterfacesMethod<T>
  52. ? M extends keyof T
  53. ? T[M] extends InterfaceConfigArray
  54. ? ExtractInterfaceArrayURL<T[M]>
  55. : T[M]
  56. : never
  57. : never;
  58. // 提取接口所有url
  59. export type ExtractInterfacesAllURL<T> = {
  60. [key in keyof T]: T[key] extends InterfaceConfigArray
  61. ? ExtractInterfaceArrayURL<T[key]>
  62. : never;
  63. }[keyof T];
  64. // 提取全部或者method的所有url
  65. export type ExtractInterfacesURL<T, M = defVoid> = M extends defVoid
  66. ? ExtractInterfacesAllURL<T>
  67. : M extends ExtractInterfacesMethod<T>
  68. ? ExtractInterfacesMethodURL<T, M>
  69. : never;
  70. // 根据具体的method url 抽取有配置
  71. export type ExtractInterfaceByMethodURL<
  72. T,
  73. M extends ExtractInterfacesMethod<T>,
  74. U extends ExtractInterfacesURL<T, M>
  75. > = M extends keyof T
  76. ? {
  77. [key in keyof T[M]]: T[M][key] extends InterfaceConfig
  78. ? T[M][key]["url"] extends U
  79. ? T[M][key] & { method: M }
  80. : never
  81. : never;
  82. }[keyof T[M]]
  83. : never;
  84. // 根据URL提取完整接口参数
  85. export type ExtractInterface<T, U, M = defVoid> = M extends defVoid
  86. ? {
  87. [Method in keyof T]: Method extends ExtractInterfacesMethod<T>
  88. ? U extends ExtractInterfacesURL<T, Method>
  89. ? ExtractInterfaceByMethodURL<T, Method, U>
  90. : never
  91. : never;
  92. }[keyof T]
  93. : M extends ExtractInterfacesMethod<T>
  94. ? U extends ExtractInterfacesURL<T, M>
  95. ? ExtractInterfaceByMethodURL<T, M, U>
  96. : never
  97. : never;
  98. // 根据url method 获取axios需要的所有参数
  99. export type InstanceConfig<
  100. T,
  101. U,
  102. M = defVoid,
  103. Config = ExtractInterface<T, U, M>
  104. > = {
  105. config: Config;
  106. givenReqConfig: Omit<Config, "method" | "url" | "response">;
  107. getUriConfig: Omit<Config, "method" | "response">;
  108. reqConfig: Omit<Config, "response">;
  109. resData: Promise<ExtractValue<Config, "response">>;
  110. reqData: ExtractValue<Config, "data">;
  111. };
  112. // 特定请求基础参数
  113. type InstanceBaseArgs<
  114. T,
  115. Method,
  116. URL,
  117. instance = InstanceConfig<T, URL, Method>
  118. > = {} extends ExtractValue<instance, "givenReqConfig">
  119. ? []
  120. : ExtractValue<instance, "givenReqConfig"> extends never
  121. ? []
  122. : [ExtractValue<instance, "givenReqConfig">];
  123. // 特定请求返回返回值
  124. type InstanceBaseReturn<T, Method, URL> = ExtractValue<
  125. InstanceConfig<T, URL, Method>,
  126. "resData"
  127. >;
  128. // 特定的GET相关接口函数声明
  129. type InstanceGet<T, Method, URL> = (
  130. ...args: InstanceBaseArgs<T, Method, URL>
  131. ) => InstanceBaseReturn<T, Method, URL>;
  132. // 特定的POST相关接口函数声明
  133. type InstancePost<
  134. T,
  135. Method,
  136. URL,
  137. Args extends InstanceBaseArgs<T, Method, URL> = InstanceBaseArgs<
  138. T,
  139. Method,
  140. URL
  141. >
  142. > = (
  143. ...args: Args extends []
  144. ? []
  145. : ExtractValue<Args[0], "data"> extends never
  146. ? [defVoid, ...Args]
  147. : {} extends Omit<Args[0], "data">
  148. ? [ExtractValue<Args[0], "data">] | [defVoid, ...Args]
  149. :
  150. | [
  151. ExtractValue<Args[0], "data">,
  152. ...[Omit<Args[0], "data">, ...Omit<Args, 0>]
  153. ]
  154. | [defVoid, ...Args]
  155. ) => InstanceBaseReturn<T, Method, URL>;
  156. // 各个实例上的api定义
  157. type GETURIM = "GET" | "DELETE" | "HEAD" | "OPTIONS";
  158. export interface AxiosInstance<T> {
  159. <
  160. URL extends ExtractInterfacesURL<T, Method>,
  161. Method extends ExtractInterfacesMethod<T> | defVoid = defVoid
  162. >(
  163. config: ExtractValue<
  164. InstanceConfig<T, URL, Method>,
  165. "reqConfig"
  166. > extends never
  167. ? { url: URL; method: Method }
  168. : ExtractValue<InstanceConfig<T, URL, Method>, "reqConfig"> & { url: URL }
  169. ): ExtractValue<InstanceConfig<T, URL, Method>, "resData">;
  170. <
  171. URL extends ExtractInterfacesURL<T>,
  172. Instance extends InstanceConfig<T, URL>
  173. >(
  174. url: URL,
  175. config: Omit<ExtractValue<Instance, "reqConfig">, "url">
  176. ): ExtractValue<Instance, "resData">;
  177. defaults: InterfaceConfig;
  178. interceptors: {
  179. request: BaseAxiosInterceptorManager<InterfaceConfig>;
  180. response: BaseAxiosInterceptorManager<BaseAxiosResponse>;
  181. };
  182. getUri<URL extends ExtractInterfacesURL<T, GETURIM>>(
  183. config: ExtractValue<InstanceConfig<T, URL, GETURIM>, "getUriConfig"> & {
  184. url: URL;
  185. }
  186. ): string;
  187. request<
  188. URL extends ExtractInterfacesURL<T, Method>,
  189. Method extends ExtractInterfacesMethod<T> | defVoid = defVoid
  190. >(
  191. config: ExtractValue<
  192. InstanceConfig<T, URL, Method>,
  193. "reqConfig"
  194. > extends never
  195. ? { url: URL; method: Method }
  196. : ExtractValue<InstanceConfig<T, URL, Method>, "reqConfig"> & { url: URL }
  197. ): ExtractValue<InstanceConfig<T, URL, Method>, "resData">;
  198. get<URL extends ExtractInterfacesURL<T, "GET">>(
  199. url: URL,
  200. ...args: Parameters<InstanceGet<T, "GET", URL>>
  201. ): ReturnType<InstanceGet<T, "GET", URL>>;
  202. delete<URL extends ExtractInterfacesURL<T, "DELETE">>(
  203. url: URL,
  204. ...args: Parameters<InstanceGet<T, "DELETE", URL>>
  205. ): ReturnType<InstanceGet<T, "DELETE", URL>>;
  206. head<URL extends ExtractInterfacesURL<T, "HEAD">>(
  207. url: URL,
  208. ...args: Parameters<InstanceGet<T, "HEAD", URL>>
  209. ): ReturnType<InstanceGet<T, "HEAD", URL>>;
  210. options<URL extends ExtractInterfacesURL<T, "OPTIONS">>(
  211. url: URL,
  212. ...args: Parameters<InstanceGet<T, "OPTIONS", URL>>
  213. ): ReturnType<InstanceGet<T, "OPTIONS", URL>>;
  214. post<URL extends ExtractInterfacesURL<T, "POST">>(
  215. url: URL,
  216. ...args: Parameters<InstancePost<T, "POST", URL>>
  217. ): ReturnType<InstancePost<T, "POST", URL>>;
  218. put<URL extends ExtractInterfacesURL<T, "PUT">>(
  219. url: URL,
  220. ...args: Parameters<InstancePost<T, "PUT", URL>>
  221. ): ReturnType<InstancePost<T, "PUT", URL>>;
  222. patch<URL extends ExtractInterfacesURL<T, "PATCH">>(
  223. url: URL,
  224. ...args: Parameters<InstancePost<T, "PATCH", URL>>
  225. ): ReturnType<InstancePost<T, "PATCH", URL>>;
  226. addIntercept: <R extends InterceptURLS<T>, RT, RS>(
  227. intercept: InterceptAtom<T, R, RT, RS>
  228. ) => AxiosStatic<
  229. InterceptAfterInterfaces<T, R, Omit<RT, "method" | "url" | "response">, RS>
  230. >;
  231. }
  232. // 拦截urls参数
  233. export type InterceptURL<T, U = ExtractInterfacesAllURL<T>> =
  234. | U
  235. | readonly [U, ExtractInterface<T, U>["method"]];
  236. export type InterceptURLS<T> = readonly InterceptURL<T>[];
  237. export type InterceptsURLS<T> = readonly InterceptURLS<T>[];
  238. // 抽取拦截参数的接口定义
  239. export type ExtractInstanceConfig<T, U, M = defVoid> = M extends
  240. | ExtractInterfacesMethod<T>
  241. | defVoid
  242. ? U extends ExtractInterfacesURL<T, M>
  243. ? InstanceConfig<T, U, M>
  244. : never
  245. : never;
  246. // 获取多个URL共有的config
  247. export type ExtractInterceptInstance<
  248. T,
  249. URLS,
  250. Attr extends string
  251. > = ExtractValue<
  252. OmitNever<
  253. {
  254. [Index in keyof URLS]: URLS[Index] extends InterceptURL<T>
  255. ? URLS[Index] extends string
  256. ? ExtractInstanceConfig<T, URLS[Index]>
  257. : ExtractInstanceConfig<T, URLS[Index][0], URLS[Index][1]>
  258. : never;
  259. }[keyof URLS]
  260. >,
  261. Attr
  262. >;
  263. // 拦截数组选项声明
  264. export type InterceptAtom<T, URLS, ReqReturn = any, ResReturn = any> = {
  265. reqHandler?: (
  266. config: Omit<ExtractInterceptInstance<T, URLS, "config">, "response">
  267. ) => ReqReturn;
  268. errHandler?: (res?: BaseAxiosResponse) => void;
  269. resHandler?: (
  270. res: ExtractInterceptInstance<T, URLS, "resData"> extends Promise<infer P>
  271. ? P
  272. : any
  273. ) => ResReturn;
  274. urls: URLS;
  275. };
  276. // 去除所有相同属性
  277. type ExtractPublic<T, R> = OmitNever<
  278. {
  279. [key in keyof T & keyof R]: T[key] extends object
  280. ? T[key] extends R[key]
  281. ? R[key] extends T[key]
  282. ? never
  283. : ExtractPublic<T[key], R[key]>
  284. : R[key] extends object
  285. ? ExtractPublic<T[key], R[key]>
  286. : never
  287. : never;
  288. } & {
  289. [key in OmitBasic<keyof T, keyof R>]: T[key];
  290. }
  291. >;
  292. // 传入请求配置更新接口
  293. type UpdateInterfaceReq<T extends InterfaceConfig, NV> = OmitNever<{
  294. [key in keyof T]: key extends keyof NV
  295. ? {} extends ExtractPublic<T[key], NV[key]>
  296. ? never
  297. : ExtractPublic<T[key], NV[key]>
  298. : T[key];
  299. }>;
  300. // 传入请求响应配置更新接口
  301. type UpdateInterface<
  302. T extends InterfaceConfig,
  303. NV
  304. > = "response" extends keyof NV
  305. ? Omit<UpdateInterfaceReq<T, NV>, "response"> & { response: NV["response"] }
  306. : UpdateInterfaceReq<T, NV>;
  307. // 传入函数配置,更新所有接口
  308. type UpdaeInterfaces<
  309. T extends InterfacesConfig,
  310. US extends InterceptURLS<T>,
  311. NV
  312. > = {
  313. [M in keyof T]: {
  314. [I in OmitBasic<keyof T[M], keyof []>]: T[M][I] extends InterfaceConfig
  315. ? T[M][I]["url"] extends US[keyof US]
  316. ? UpdateInterface<T[M][I], NV>
  317. : readonly [T[M][I]["url"], M] extends US[OmitBasic<keyof US, keyof []>]
  318. ? UpdateInterface<T[M][I], NV>
  319. : T[M][I]
  320. : T[M][I];
  321. } & {
  322. [key in keyof T[M] & keyof []]: T[M][key];
  323. };
  324. };
  325. // 通过拦截函数得resHandler和reqHandler更新所有接口
  326. type InterceptAfterInterfaces<
  327. T extends InterfacesConfig,
  328. US extends InterceptURLS<T>,
  329. RET,
  330. RES
  331. > = RET extends object | string | number | symbol
  332. ? RES extends object | string | number | symbol
  333. ? UpdaeInterfaces<T, US, RET & { response: RES }>
  334. : UpdaeInterfaces<T, US, RET>
  335. : RES extends object | string | number | symbol
  336. ? UpdaeInterfaces<T, US, { response: RES }>
  337. : T;
  338. // 加工后得axios声明
  339. export type AxiosStatic<T> = Omit<BaseAxiosStatic, keyof AxiosInstance<T>> &
  340. AxiosInstance<T>;
  341. let spliceUrl = "";
  342. export const setSpliceUrl = (splice = "") => (spliceUrl = splice);
  343. export const setupFactory = <T extends InterfacesConfig>() => {
  344. type NeedAtom<R> = InterceptAtom<T, R>;
  345. type Needs = Array<NeedAtom<InterceptURLS<T>>>;
  346. const needs: Needs = [];
  347. const processAxios = {
  348. ...axios.create(),
  349. addIntercept(intercept: any) {
  350. needs.push(intercept);
  351. return processAxios as any;
  352. },
  353. } as AxiosStatic<T>;
  354. const getUriRaw = processAxios.getUri;
  355. processAxios.getUri = (config, ...args) => {
  356. return getUriRaw(
  357. {
  358. ...config,
  359. url: (processAxios.defaults.baseURL + config.url) as any,
  360. },
  361. ...args
  362. );
  363. };
  364. // 拦截处理函数
  365. const tapIntercept = (
  366. url: string,
  367. method: BaseMethod | undefined,
  368. handler: (need: NeedAtom<any>) => void
  369. ) => {
  370. if (needs) {
  371. let checkUrl = url;
  372. if (spliceUrl) {
  373. const index = url.indexOf(spliceUrl);
  374. if (~index) {
  375. checkUrl = url.substring(0, index);
  376. }
  377. }
  378. for (let need of needs) {
  379. const wise = need.urls.find((temp) =>
  380. typeof temp === "string"
  381. ? equalUrl(temp, checkUrl)
  382. : equalUrl(temp[0], checkUrl) && method?.toUpperCase() === temp[1]
  383. );
  384. wise && handler(need);
  385. }
  386. }
  387. };
  388. const stopRequest = () => {
  389. const source = processAxios.CancelToken.source();
  390. source.cancel("Illegal request");
  391. };
  392. const errorHandler = (res: BaseAxiosResponse, ret?: any) => {
  393. if (!res && ret && ret.isAxiosError) {
  394. res = {
  395. config: ret.config,
  396. status: -1,
  397. } as unknown as BaseAxiosResponse;
  398. }
  399. if (res?.config && res.config.url) {
  400. tapIntercept(
  401. res.config.url,
  402. res.config.method as any,
  403. ({ errHandler }) => {
  404. errHandler && errHandler(res);
  405. }
  406. );
  407. } else {
  408. setTimeout(() => Loading.hide());
  409. }
  410. return Promise.reject(res);
  411. };
  412. processAxios.interceptors.request.use((config) => {
  413. let ret;
  414. if (config.url) {
  415. ret = { ...config } as any;
  416. try {
  417. tapIntercept(ret.url, ret.method, ({ reqHandler }) => {
  418. let attach = reqHandler && reqHandler(ret);
  419. if (attach) {
  420. ret = recursionCopy(ret, attach);
  421. }
  422. });
  423. } catch (e) {
  424. console.error(e);
  425. stopRequest();
  426. }
  427. if (ret.paths) {
  428. ret.url = gendUrl(ret.url, ret.paths);
  429. }
  430. ret;
  431. } else {
  432. ret = config;
  433. }
  434. return ret;
  435. });
  436. processAxios.interceptors.response.use(
  437. (res) => {
  438. let ret = res.data;
  439. if (res.status < 200 || res.status >= 300) {
  440. return errorHandler(res);
  441. } else if (res.config.url) {
  442. tapIntercept(
  443. res.config.url,
  444. res.config.method as any,
  445. ({ resHandler }) => {
  446. if (resHandler) {
  447. ret = resHandler(ret);
  448. }
  449. }
  450. );
  451. }
  452. return ret;
  453. },
  454. (res) => errorHandler(res.response, res)
  455. );
  456. return processAxios;
  457. };
  458. export default setupFactory;