request.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. "use strict";
  2. const common_vendor = require("../common/vendor.js");
  3. const config_env = require("../config/env.js");
  4. const loadingManager = {
  5. loadingCount: 0,
  6. loadingTimer: null,
  7. isShowing: false,
  8. // 添加状态标记
  9. // 安全的隐藏toast方法
  10. safeHideToast() {
  11. },
  12. // 显示 loading
  13. show(options = {}) {
  14. const config = {
  15. title: "加载中...",
  16. mask: true,
  17. delay: 300,
  18. ...options
  19. };
  20. if (this.loadingCount > 0) {
  21. this.loadingCount++;
  22. return;
  23. }
  24. this.loadingTimer = setTimeout(() => {
  25. if (this.loadingCount > 0 && !this.isShowing) {
  26. try {
  27. common_vendor.index.showLoading({
  28. title: config.title,
  29. mask: config.mask
  30. });
  31. this.isShowing = true;
  32. } catch (error) {
  33. common_vendor.index.__f__("warn", "at utils/request.js:45", "showLoading failed:", error);
  34. }
  35. }
  36. }, config.delay);
  37. this.loadingCount++;
  38. },
  39. // 隐藏 loading
  40. hide() {
  41. this.loadingCount = Math.max(0, this.loadingCount - 1);
  42. if (this.loadingCount === 0) {
  43. if (this.loadingTimer) {
  44. clearTimeout(this.loadingTimer);
  45. this.loadingTimer = null;
  46. }
  47. if (this.isShowing) {
  48. try {
  49. common_vendor.index.hideLoading();
  50. } catch (error) {
  51. common_vendor.index.__f__("warn", "at utils/request.js:69", "hideLoading failed:", error);
  52. } finally {
  53. this.isShowing = false;
  54. }
  55. }
  56. }
  57. },
  58. // 强制隐藏所有 loading
  59. forceHide() {
  60. this.loadingCount = 0;
  61. if (this.loadingTimer) {
  62. clearTimeout(this.loadingTimer);
  63. this.loadingTimer = null;
  64. }
  65. if (this.isShowing) {
  66. try {
  67. common_vendor.index.hideLoading();
  68. } catch (error) {
  69. common_vendor.index.__f__("warn", "at utils/request.js:89", "forceHide failed:", error);
  70. } finally {
  71. this.isShowing = false;
  72. }
  73. }
  74. },
  75. // 安全显示toast(确保loading已隐藏)
  76. safeShowToast(options) {
  77. if (this.isShowing) {
  78. this.forceHide();
  79. setTimeout(() => {
  80. common_vendor.index.showToast(options);
  81. }, 100);
  82. } else {
  83. common_vendor.index.showToast(options);
  84. }
  85. }
  86. };
  87. const request = {
  88. async get(url, params = {}, options = {}) {
  89. return this.request(url, "GET", params, options);
  90. },
  91. async post(url, data = {}, options = {}) {
  92. return this.request(url, "POST", data, options);
  93. },
  94. async put(url, data = {}, options = {}) {
  95. return this.request(url, "PUT", data, options);
  96. },
  97. async delete(url, data = {}, options = {}) {
  98. return this.request(url, "DELETE", data, options);
  99. },
  100. async request(url, method, data, options = {}) {
  101. let loadingConfig;
  102. if (options.loading === false) {
  103. loadingConfig = false;
  104. } else {
  105. loadingConfig = {
  106. show: true,
  107. title: "加载中...",
  108. mask: true,
  109. delay: 300,
  110. timeout: 1e4,
  111. ...typeof options.loading === "object" ? options.loading : {}
  112. };
  113. }
  114. const requestConfig = {
  115. timeout: 15e3,
  116. // 默认网络超时 15 秒
  117. ...options.request
  118. };
  119. const shouldShowLoading = loadingConfig !== false && loadingConfig.show !== false;
  120. if (shouldShowLoading) {
  121. loadingManager.show(loadingConfig);
  122. }
  123. const deviceInfo = common_vendor.index.getStorageSync("deviceInfo") || {};
  124. const devId = deviceInfo.deviceId || "";
  125. const sbmc = deviceInfo.model || "";
  126. const separator = url.includes("?") ? "&" : "?";
  127. const finalUrl = `${url}${separator}devId=${devId}&sbmc=${sbmc}`;
  128. let timeoutTimer = null;
  129. if (shouldShowLoading && loadingConfig.timeout) {
  130. timeoutTimer = setTimeout(() => {
  131. loadingManager.hide();
  132. loadingManager.safeShowToast({
  133. title: "请求超时",
  134. icon: "none"
  135. });
  136. }, loadingConfig.timeout);
  137. }
  138. let requestData = data;
  139. if (options.formData && data && typeof data === "object") {
  140. requestData = Object.keys(data).map((key) => {
  141. const value = data[key];
  142. if (Array.isArray(value)) {
  143. return value.map((item) => `${encodeURIComponent(key)}=${encodeURIComponent(item)}`).join("&");
  144. } else {
  145. return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
  146. }
  147. }).join("&");
  148. }
  149. return new Promise((resolve, reject) => {
  150. common_vendor.index.request({
  151. url: `${config_env.env.baseUrl}${finalUrl}`,
  152. method,
  153. data: requestData,
  154. timeout: requestConfig.timeout,
  155. // 设置网络超时
  156. header: (() => {
  157. const headers = {};
  158. if (options.formData) {
  159. headers["content-type"] = "application/x-www-form-urlencoded";
  160. } else {
  161. headers["content-type"] = "application/json";
  162. }
  163. const jsessionId = common_vendor.index.getStorageSync("JSESSIONID");
  164. if (jsessionId) {
  165. headers["Cookie"] = `JSESSIONID=${jsessionId}`;
  166. }
  167. return headers;
  168. })(),
  169. success: (res) => {
  170. if (timeoutTimer) {
  171. clearTimeout(timeoutTimer);
  172. }
  173. const headers = res.header;
  174. const setCookie = headers["set-cookie"] || headers["Set-Cookie"];
  175. if (setCookie) {
  176. const match = setCookie.match(/JSESSIONID=([^;]+)/);
  177. if (match && match[1]) {
  178. common_vendor.index.setStorageSync("JSESSIONID", match[1]);
  179. }
  180. }
  181. if (res.statusCode === 200) {
  182. if (res && typeof res.data === "string" && res.data.includes("页面执行时错误")) {
  183. reject({
  184. message: "服务器处理错误" + res.data
  185. });
  186. loadingManager.safeShowToast({
  187. title: "服务器处理错误",
  188. icon: "none"
  189. });
  190. return;
  191. }
  192. if (res.data && (res.data.errorcode === 1 || res.data.msg === "登录已失效,请重新登录" || res.data.message === "登录过期" || res.data.error === "UNAUTHORIZED")) {
  193. common_vendor.index.__f__("log", "at utils/request.js:266", "🔒 检测到登录过期,跳转自动登录");
  194. common_vendor.index.__f__("log", "at utils/request.js:267", "过期响应数据:", res.data);
  195. handleLoginExpired();
  196. reject({ code: 401, message: res.data.msg || "登录过期" });
  197. return;
  198. }
  199. const responseData = {
  200. data: res.data
  201. };
  202. resolve(responseData);
  203. } else {
  204. reject(res);
  205. }
  206. },
  207. fail: (err) => {
  208. if (timeoutTimer) {
  209. clearTimeout(timeoutTimer);
  210. }
  211. loadingManager.safeShowToast({
  212. title: "网络请求失败",
  213. icon: "none"
  214. });
  215. reject(err);
  216. },
  217. complete: () => {
  218. if (shouldShowLoading) {
  219. loadingManager.hide();
  220. }
  221. }
  222. });
  223. });
  224. }
  225. };
  226. const handleLoginExpired = async () => {
  227. let userInfo = common_vendor.index.getStorageSync("userInfo") || {};
  228. if (typeof userInfo === "string") {
  229. userInfo = JSON.parse(userInfo);
  230. }
  231. let yhsbToken = userInfo.yhsbToken;
  232. common_vendor.index.__f__("log", "at utils/request.js:318", "🔒 处理登录过期 request.js:", userInfo);
  233. if (yhsbToken) {
  234. common_vendor.index.__f__("log", "at utils/request.js:321", "🔄 有token,跳转自动登录");
  235. common_vendor.index.navigateTo({
  236. url: `/pages/common/webview?dest=autoLogin&title=自动登录&from=expired&yhsbToken=${yhsbToken}`
  237. });
  238. } else {
  239. common_vendor.index.__f__("log", "at utils/request.js:327", "⚠️ 无token,获取微信授权码并跳转手动登录");
  240. try {
  241. const loginRes = await common_vendor.index.login({
  242. provider: "weixin"
  243. });
  244. common_vendor.index.__f__("log", "at utils/request.js:335", "获取到微信授权码:", loginRes.code);
  245. common_vendor.index.navigateTo({
  246. url: `/pages/common/webview?dest=login&title=登录&from=expired&wechatCode=${loginRes.code}`
  247. });
  248. } catch (error) {
  249. common_vendor.index.__f__("error", "at utils/request.js:342", "获取微信授权码失败:", error);
  250. common_vendor.index.navigateTo({
  251. url: "/pages/common/webview?dest=login&title=登录&from=expired"
  252. });
  253. }
  254. }
  255. };
  256. request.loadingManager = loadingManager;
  257. request.silent = {
  258. get: (url, params = {}) => request.get(url, params, { loading: false }),
  259. post: (url, data = {}) => request.post(url, data, { loading: false }),
  260. put: (url, data = {}) => request.put(url, data, { loading: false }),
  261. delete: (url, data = {}) => request.delete(url, data, { loading: false })
  262. };
  263. request.withLoading = (title) => ({
  264. get: (url, params = {}) => request.get(url, params, { loading: { title } }),
  265. post: (url, data = {}) => request.post(url, data, { loading: { title } }),
  266. put: (url, data = {}) => request.put(url, data, { loading: { title } }),
  267. delete: (url, data = {}) => request.delete(url, data, { loading: { title } })
  268. });
  269. exports.request = request;
  270. //# sourceMappingURL=../../.sourcemap/mp-weixin/utils/request.js.map