/** * H5版本的请求工具 * 基于axios,兼容小程序的request接口 * 依赖:common.js (提供公共工具函数) */ // 环境配置 const env = { baseUrl: "https://m.hfdcschool.com", // baseUrl: 'https://yx.newfeifan.cn' }; // Loading 管理器 (H5版本) const loadingManager = { loadingCount: 0, loadingTimer: null, loadingElement: null, // 显示 loading show(options = {}) { const config = { title: "加载中...", mask: true, delay: 300, ...options, }; // 如果已经有 loading 在显示,只增加计数 if (this.loadingCount > 0) { this.loadingCount++; return; } // 延迟显示,避免快速请求造成闪烁 this.loadingTimer = setTimeout(() => { if (this.loadingCount > 0) { this.createLoadingElement(config.title); } }, config.delay); this.loadingCount++; }, // 创建Loading元素 createLoadingElement(title) { if (this.loadingElement) return; this.loadingElement = document.createElement("div"); this.loadingElement.className = "h5-loading-mask"; this.loadingElement.innerHTML = `
${title}
`; // 添加样式 const style = document.createElement("style"); style.textContent = ` .h5-loading-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 10000; } .h5-loading-content { background: white; padding: 20px; border-radius: 8px; text-align: center; min-width: 120px; } .h5-loading-spinner { width: 30px; height: 30px; border: 3px solid #f3f3f3; border-top: 3px solid #40ac6d; border-radius: 50%; animation: h5-spin 1s linear infinite; margin: 0 auto 10px; } @keyframes h5-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .h5-loading-text { color: #333; font-size: 14px; } `; document.head.appendChild(style); document.body.appendChild(this.loadingElement); }, // 隐藏 loading hide() { this.loadingCount = Math.max(0, this.loadingCount - 1); if (this.loadingCount === 0) { // 清除延迟显示的定时器 if (this.loadingTimer) { clearTimeout(this.loadingTimer); this.loadingTimer = null; } // 移除 loading 元素 if (this.loadingElement) { document.body.removeChild(this.loadingElement); this.loadingElement = null; } } }, // 强制隐藏所有 loading forceHide() { this.loadingCount = 0; if (this.loadingTimer) { clearTimeout(this.loadingTimer); this.loadingTimer = null; } if (this.loadingElement) { document.body.removeChild(this.loadingElement); this.loadingElement = null; } }, }; // 注意:getUrlParams, getDeviceInfo, getJSessionId, saveJSessionId // 这些函数已在 common.js 中定义,这里直接使用全局函数 const request = { async get(url, params = {}, options = {}) { return this.request(url, "GET", params, options); }, async post(url, data = {}, options = {}) { return this.request(url, "POST", data, options); }, async put(url, data = {}, options = {}) { return this.request(url, "PUT", data, options); }, async delete(url, data = {}, options = {}) { return this.request(url, "DELETE", data, options); }, async request(url, method, data, options = {}) { // 解析 loading 配置 let loadingConfig; if (options.loading === false) { loadingConfig = false; } else { loadingConfig = { show: true, title: "加载中...", mask: true, delay: 300, timeout: 10000, ...(typeof options.loading === "object" ? options.loading : {}), }; } // 解析请求配置 const requestConfig = { timeout: 15000, ...options.request, }; const shouldShowLoading = loadingConfig !== false && loadingConfig.show !== false; // 显示 loading if (shouldShowLoading) { loadingManager.show(loadingConfig); } // 获取设备信息 const deviceInfo = getDeviceInfo(); const devId = deviceInfo.deviceId || ""; const sbmc = deviceInfo.model || ""; // 处理URL,添加设备参数 const separator = url.includes("?") ? "&" : "?"; const finalUrl = `${url}${separator}devId=${devId}&sbmc=${sbmc}`; // 超时处理 let timeoutTimer = null; if (shouldShowLoading && loadingConfig.timeout) { timeoutTimer = setTimeout(() => { loadingManager.hide(); if (typeof showToastEffect !== "undefined") { showToastEffect("请求超时", 3000, "error"); } else { // alert('请求超时') } }, loadingConfig.timeout); } try { // 配置axios请求 const axiosConfig = { url: `${env.baseUrl}${finalUrl}`, method: method.toLowerCase(), timeout: requestConfig.timeout, headers: {}, }; // 处理请求数据 if (method.toUpperCase() === "GET") { axiosConfig.params = data; } else { if (options.formData) { axiosConfig.headers["Content-Type"] = "application/x-www-form-urlencoded"; // 转换为表单格式 const formData = new URLSearchParams(); Object.keys(data).forEach((key) => { const value = data[key]; // 如果是数组,为每个元素单独添加参数(同名参数重复) if (Array.isArray(value)) { value.forEach((item) => { formData.append(key, item); }); } else { formData.append(key, value); } }); axiosConfig.data = formData; } else { axiosConfig.headers["Content-Type"] = "application/json"; axiosConfig.data = data; } } // 发送请求 const response = await axios(axiosConfig); // 清除超时定时器 if (timeoutTimer) { clearTimeout(timeoutTimer); } // 检查服务器处理错误 if ( response.data && response.data.msg && response.data.msg.includes("页面执行时错误") ) { throw new Error("服务器处理错误"); } // 检查没有服务授权 - 直接回到小程序 if ( response.data && response.data.msg && response.data.msg.includes("没有服务授权") ) { handleH5NoServiceAuth(response.data.msg); throw new Error(response.data.msg); } // 检查登录过期 - 根据实际响应体格式 if ( response && (response.data.errorcode === 1 || response.data.msg === "登录已失效,请重新登录" || response.data.message === "登录过期" || response.data.error === "UNAUTHORIZED") ) { console.log("H5检测到登录过期,触发自动登录", response); handleH5LoginExpired(); throw new Error(response.msg || "登录过期"); } // 返回与小程序兼容的格式 return { data: response.data, }; } catch (error) { // 清除超时定时器 if (timeoutTimer) { clearTimeout(timeoutTimer); } // 处理错误 let errorMessage = "请求失败"; if (error.response) { errorMessage = `请求失败: ${error.response.status}`; } else if (error.request) { errorMessage = "网络连接失败"; } else { errorMessage = error.message || "未知错误"; } if (typeof showToastEffect !== "undefined") { showToastEffect(errorMessage, 3000, "error"); } else { // alert(errorMessage) } throw error; } finally { // 隐藏 loading if (shouldShowLoading) { loadingManager.hide(); } } }, }; // H5登录过期处理 const handleH5LoginExpired = () => { console.log("🔒 H5处理登录过期"); // 获取yhsbToken,有token就自动登录,没有就跳转登录页 const userInfo = localStorage.getItem("userInfo"); let yhsbToken = ""; if (userInfo) { try { const userData = JSON.parse(userInfo); yhsbToken = userData.yhsbToken; } catch (e) { console.error("解析用户信息失败:", e); } } if (yhsbToken) { // 直接调用自动登录接口(和自动登录页面一样的逻辑) request .post( `/service?ssServ=ssLogin&wdConfirmationCaptchaService=0&mdToken=${yhsbToken}`, { mdToken: yhsbToken }, { loading: false } ) .then((response) => { if (response && response.data) { console.log("✅ H5自动登录成功"); // 构建用户数据(和自动登录页面一样) const userData = { devId: response.data.devId, sbmc: response.data.sbmc, sessId: response.data.sessId, userId: response.data.userId, xm: response.data.xm, yhsbToken: response.data.yhsbToken, onlineToken: response.data.onlineToken, }; // 保存用户信息到H5本地存储 if (window.h5UserApi) { window.h5UserApi.saveUserInfo(userData); } // 通知小程序更新token if (typeof callNative === "function") { callNative("loginSuccess", "H5自动登录成功", { success: true, userInfo: userData, isAutoLogin: true, }); } // 刷新当前页面 setTimeout(() => window.location.reload(), 1000); } }) .catch((error) => { console.error("❌ H5自动登录失败:", error); window.location.href = "/page/login.html?from=expired"; }); } else { console.log("⚠️ 未找到yhsbToken,跳转登录页面"); window.location.href = "/page/login.html?from=expired"; } }; // H5没有服务授权处理 const handleH5NoServiceAuth = (errorMsg) => { // 显示错误提示 if (typeof showToastEffect !== "undefined") { // showToastEffect('没有服务授权,即将返回', 2000, 'error'); } else { } // 延迟一下让用户看到提示,然后返回小程序 setTimeout(() => { // 通知小程序返回 if (typeof callNative === "function") { callNative("noServiceAuth", "没有服务授权", { error: true, message: errorMsg, action: "goBack", }); } else { // 降级处理:直接关闭页面 if (window.history.length > 1) { window.history.back(); } else { window.close(); } } }, 1500); }; // 导出到全局 window.request = request; window.handleH5LoginExpired = handleH5LoginExpired; window.handleH5NoServiceAuth = handleH5NoServiceAuth; console.log("✅ H5 Request工具已加载");