index.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import axios, { AxiosResponse } from "axios";
  2. import qs from "qs";
  3. import { openLoading, closeLoading } from "./loading";
  4. import { openErrorMsg } from "./errorMsg";
  5. import {
  6. fromUrls,
  7. fileUrls,
  8. GetUrls,
  9. PostUrls,
  10. notLoginUrls,
  11. baseURL,
  12. unAuthCode,
  13. successCode,
  14. } from "./config";
  15. import { router } from "@/router";
  16. import { RouteName } from "@/router/config";
  17. import { isOfflineMode } from "@/util/offline";
  18. export * from "./urls";
  19. export * from "./config";
  20. export * from "./loading";
  21. export * from "./errorMsg";
  22. export type AuthHook = () => {
  23. token: string;
  24. userId: string;
  25. clear: () => void;
  26. };
  27. export const setAuthHook = (hook: AuthHook) => (getAuth = hook);
  28. let getAuth: AuthHook = () => ({ token: "", userId: "0", clear: () => { } });
  29. axios.defaults.baseURL = baseURL;
  30. axios.interceptors.request.use(async (config) => {
  31. if (config.method === "get" && config.params) {
  32. for (const key in config.params) {
  33. const val = config.params[key];
  34. if (typeof val === "string") {
  35. config.params[key] = val.replaceAll(/[\[\]]/g, "").trim();
  36. }
  37. }
  38. }
  39. if (!config.url) {
  40. return config;
  41. }
  42. const { token, userId } = getAuth();
  43. config.headers.token = token;
  44. config.headers.userid = userId;
  45. // 当链接存在 share=1 时,为所有请求头注入 caseId 与 sharePassword
  46. // 同时记录是否处于分享模式,以便后续跳过登录校验
  47. let isShareMode = false;
  48. try {
  49. const currentRoute = router.currentRoute?.value;
  50. const shareParam: any = currentRoute?.query?.share;
  51. console.log('currentRoute', currentRoute, shareParam)
  52. const isShare = Array.isArray(shareParam)
  53. ? shareParam.includes("1")
  54. : shareParam === "1";
  55. isShareMode = !!isShare;
  56. if (isShare) {
  57. const caseIdParam: any = currentRoute?.params?.caseId;
  58. const sharePwdParam: any = currentRoute?.query?.p;
  59. const caseIdHeader = Array.isArray(caseIdParam)
  60. ? caseIdParam[0]
  61. : caseIdParam;
  62. const sharePasswordHeader = Array.isArray(sharePwdParam)
  63. ? sharePwdParam[0]
  64. : sharePwdParam;
  65. if (caseIdHeader != null) {
  66. (config.headers as any).caseId = caseIdHeader;
  67. }
  68. if (sharePasswordHeader != null) {
  69. (config.headers as any).sharePassword = sharePasswordHeader;
  70. }
  71. }
  72. } catch (e) {
  73. // 忽略注入错误,保证请求不中断
  74. }
  75. const hasIgnore = config.params ? "ingoreRes" in config.params : false;
  76. // 分享模式下(share=1 且已注入 sharePassword/caseId),跳过登录校验
  77. const shareBypassLogin = (() => {
  78. try {
  79. const sharePwd = (config.headers as any)?.sharePassword;
  80. const caseIdHeader = (config.headers as any)?.caseId;
  81. return isShareMode && sharePwd != null && caseIdHeader != null;
  82. } catch {
  83. return false;
  84. }
  85. })();
  86. if (!hasIgnore) {
  87. const offline = isOfflineMode();
  88. if (!offline) {
  89. if (!token && !~notLoginUrls.indexOf(config.url) && !shareBypassLogin) {
  90. const redirect = encodeURIComponent(window.location.href);
  91. router.replace({ name: RouteName.login, query: { redirect } });
  92. throw "用户未登录";
  93. }
  94. }
  95. }
  96. if (~GetUrls.indexOf(config.url)) {
  97. config.method = "GET";
  98. } else if (~PostUrls.indexOf(config.url)) {
  99. config.method = "POST";
  100. if (!config.data && config.params) {
  101. config.data = config.params;
  102. }
  103. }
  104. // 处理需要用表单上传的请求
  105. if (~fromUrls.indexOf(config.url)) {
  106. config.data = qs.stringify(config.data);
  107. config.headers["Content-Type"] =
  108. "application/x-www-form-urlencoded; charset=utf-8;";
  109. } else if (~fileUrls.indexOf(config.url)) {
  110. const fromData = new FormData();
  111. Object.keys(config.data).forEach((key) => {
  112. if (key === 'files') {
  113. Array.from(config.data[key]).forEach(file => {
  114. fromData.append('files', file as any as File);
  115. })
  116. } else {
  117. fromData.append(key, config.data[key]);
  118. }
  119. });
  120. config.data = fromData;
  121. config.headers["Content-Type"] = "multipart/form-data";
  122. }
  123. openLoading(config.url);
  124. return config;
  125. });
  126. const responseInterceptor = (res: AxiosResponse<any, any>) => {
  127. closeLoading();
  128. const hasIgnore = res.config.params
  129. ? "ingoreRes" in res.config.params
  130. : false;
  131. if (!successCode.includes(res.data.code) && !hasIgnore) {
  132. let errMsg = res.data.msg || res.data.message;
  133. openErrorMsg(errMsg);
  134. const offline = isOfflineMode();
  135. if (!offline) {
  136. if (
  137. ~unAuthCode.indexOf(res.data.code) ||
  138. errMsg === "token已经失效,请重新登录"
  139. ) {
  140. getAuth().clear();
  141. const redirect = encodeURIComponent(window.location.href);
  142. router.replace({ name: RouteName.login, query: { redirect } });
  143. }
  144. }
  145. throw res.data.msg;
  146. }
  147. return res.data;
  148. };
  149. axios.interceptors.response.use(responseInterceptor, (error) => {
  150. closeLoading();
  151. if (error.response && error.response.data) {
  152. return responseInterceptor(error.response);
  153. } else {
  154. openErrorMsg(
  155. typeof error === "string" ? error : "请求失败,服务端发生了点小故障!"
  156. );
  157. return Promise.reject(error);
  158. }
  159. });
  160. export { axios };
  161. export type PaggingReq<T> = T & {
  162. pageNum: number;
  163. pageSize: number;
  164. };
  165. export type PaggingRes<T> = T & {
  166. total: number;
  167. list: T[];
  168. };