ethod, url, data) { try { return method + " " + url + " " + JSON.stringify(data || {}); } catch (_) { return method + " " + url; } } function _buildFormData(data) { const fd = new URLSearchParams(); if (data && typeof data === "object") { Object.keys(data).forEach((key) => { const v = data[key]; if (Array.isArray(v)) { v.forEach((val) => fd.append(key + "[]", val)); } else { fd.append(key, v); } }); } return fd; } function _normalize(obj) { const res = obj && typeof obj === "object" ? obj : { status: 0, info: "服务器响应格式错误,请联系管理员" }; // 统一 status if (typeof res.status === "undefined") { if (typeof res.code !== "undefined") { res.status = res.code === 0 || res.code === 200 || res.code === 1 ? 1 : 0; } else if (res.success === true) { res.status = 1; } else if (res.success === false) { res.status = 0; } else { res.status = 0; } } // 统一 info if (typeof res.info === "undefined") { if (typeof res.msg !== "undefined") { res.info = res.msg; } else if (typeof res.message !== "undefined") { res.info = res.message; } else { res.info = res.status ? "ok" : "请求失败"; } } return res; } function _checkLogin(res) { const tip = String((res && (res.info || res.message)) || ""); if ( res && (res.code === 401 || res.status === -1 || /登录|登錄|login/i.test(tip)) ) { _emit("modernapi:login-required", { res }); return true; } return false; } async function _request(method, url, data, options) { const opts = Object.assign( { timeout: DEFAULT_TIMEOUT, dedupe: true }, options || {}, ); const lockKey = _toLockKey(method, url, data); if (opts.dedupe && _locks.has(lockKey)) { return { status: 0, info: "请勿重复提交" }; } const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), opts.timeout); _locks.add(lockKey); _emit("modernapi:start", { method, url }); try { let fetchUrl = url; const fetchOpts = { method, headers: { "X-Requested-With": "XMLHttpRequest", }, signal: controller.signal, }; if (method === "POST") { fetchOpts.headers["Content-Type"] = "application/x-www-form-urlencoded"; fetchOpts.body = _buildFormData(data); } else { const qs = new URLSearchParams(); if (data && typeof data === "object") { Object.keys(data).forEach((k) => { const v = data[k]; if (Array.isArray(v)) v.forEach((val) => qs.append(k + "[]", val)); else qs.append(k, v); }); } fetchUrl += (fetchUrl.indexOf("?") >= 0 ? "&" : "?") + qs.toString(); } const response = await fetch(fetchUrl, fetchOpts); const text = await response.text(); if (!response.ok) { return { status: 0, info: "网络错误:" + response.status }; } let json; try { json = JSON.parse(text); } catch (e) { console.error("[ModernApi] 非 JSON 响应:", text); return { status: 0, info: "服务器响应格式错误,请联系管理员", }; } const res = _normalize(json); _checkLogin(res); return res; } catch (err) { if (err && err.name === "AbortError") { return { status: 0, info: "请求超时,请稍后重试" }; } console.error("[ModernApi] 请求异常:", err); return { status: 0, info: "请求失败,请检查网络" }; } finally { clearTimeout(timer); _locks.delete(lockKey); _emit("modernapi:end", { method, url }); } } window.ModernApi = { post(url, data = {}, options = {}) { return _request("POST", url, data, options); }, get(url, params = {}, options = {}) { return _request("GET", url, params, options); }, }; // --- BH 全局命名空间扩展 --- window.BH = window.BH || {}; /** * 互斥锁:防止重复操作 * @param {string} name 锁名称 * @param {number} ttl 自动解锁时间(ms),默认 3000 */ BH.lock = function (name, ttl = 3000) { const key = "_lock_" + name; if (window[key]) return false; window[key] = true; if (ttl > 0) setTimeout(() => BH.unlock(name), ttl); return true; }; BH.unlock = function (name) { window["_lock_" + name] = false; }; /** * 包装异步操作,自动显示/隐藏全局 Loading * @param {Promise} promise 异步任务 * @returns {Promise} */ BH.withLoading = async function (promise) { _emit("modernapi:start", { method: "WRAPPER" }); try { return await promise; } finally { _emit("modernapi:end", { method: "WRAPPER" }); } }; /** * 状态切换助手 (需依赖 jQuery) */ BH.showEmpty = function (elSelector, msg = "暂无数据") { const $el = window.jQuery ? window.jQuery(elSelector) : null; if (!$el || !$el.length) return; $el.html(`

${msg}

`); }; BH.showError = function ( elSelector, msg = "加载失败,请重试", retryFnName = "", ) { const $el = window.jQuery ? window.jQuery(elSelector) : null; if (!$el || !$el.length) return; const retryHtml = retryFnName ? `` : ""; $el.html(`

${msg}

${retryHtml}
`); }; // 自动处理 [data-busy] 按钮 (需依赖 jQuery) if (window.jQuery) { window.jQuery(document).on("click", "[data-busy]", function (e) { const $btn = window.jQuery(this); const name = $btn.data("busy") || "default"; const ttl = parseInt($btn.data("busy-ttl")) || 3000; if (!BH.lock(name, ttl)) { e.stopImmediatePropagation(); e.preventDefault(); return false; } }); } // Minimal loading overlay controlled by ModernApi start/end events (function () { if ( typeof window !== "undefined" && window.BH_DISABLE_LOADING_OVERLAY ) { return; } var ref = 0; var el = null; var timer = null; var delay = typeof window !== "undefined" && typeof window.BH_LOADING_DELAY_MS === "number" && window.BH_LOADING_DELAY_MS >= 0 ? window.BH_LOADING_DELAY_MS : 0; function ensureEl() { if (!el) { el = document.getElementById("modernapi-loading"); if (!el) { el = document.createElement("div"); el.id = "modernapi-loading"; el.innerHTML = '
'; if (document.body) { document.body.appendChild(el); } else { document.addEventListener( "DOMContentLoaded", function () { document.body && document.body.appendChild(el); }, ); } } } } function show() { ensureEl(); if (el && el.style.display !== "flex") { el.style.display = "flex"; } } function hide() { if (timer) { clearTimeout(timer); timer = null; } if (el) el.style.display = "none"; } document.addEventListener("modernapi:start", function () { ref++; if (ref === 1) { if (delay > 0) { if (timer) { clearTimeout(timer); timer = null; } timer = setTimeout(function () { if (ref > 0) show(); }, delay); } else { show(); } } }); document.addEventListener("modernapi:end", function () { ref = Math.max(0, ref - 1); if (ref === 0) { if (timer) { clearTimeout(timer); timer = null; } hide(); } }); })(); })();
图片加载不出来的时候请尝试切换图源
哎呀,书币不足啦
解锁本话:0书币
账户余额:0书币

做任务获币 充值福利