/**
* 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 = `
`;
// 添加样式
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工具已加载");