/** * AKSRT VIP pay modal — zibll .pay-vip parity. * Loads modal HTML from GET /aksrt/v1/pay/vip/modal then purchases via POST /pay/vip. */ (function () { "use strict"; function restBase() { var aksrt = window.aksrtData || window.aksrt || {}; var siteUrl = aksrt.siteUrl || aksrt.homeUrl || (window.location.origin + "/"); if (window.location.protocol === "https:" && siteUrl.substring(0, 5) === "http:") { siteUrl = "https:" + siteUrl.substring(5); } var raw = aksrt.apiUrl || aksrt.restUrl || aksrt.rest_url || ""; if (raw) { return String(raw).replace(/\/$/, ""); } return siteUrl.replace(/\/$/, "") + "/index.php?rest_route=/aksrt/v1"; } /** * Join REST root + path [+ query]. * Pretty: /wp-json/aksrt/v1/pay/vip/modal?vip_level=1 * Plain: index.php?rest_route=/aksrt/v1/pay/vip/modal&vip_level=1 * Never put a second "?" after rest_route= (that 404s). */ function restUrl(path, query) { path = String(path || ""); if (path.charAt(0) !== "/") path = "/" + path; var base = restBase(); var qstr = ""; if (query && typeof query === "object") { var parts = []; Object.keys(query).forEach(function (k) { if (query[k] === undefined || query[k] === null) return; parts.push(encodeURIComponent(k) + "=" + encodeURIComponent(String(query[k]))); }); qstr = parts.join("&"); } else if (typeof query === "string" && query) { qstr = query.replace(/^\?/, ""); } if (base.indexOf("rest_route=") !== -1) { var url = base + path; if (qstr) url += "&" + qstr; return url; } var pretty = base + path; if (qstr) pretty += (pretty.indexOf("?") >= 0 ? "&" : "?") + qstr; return pretty; } function nonceHeaders() { var aksrt = window.aksrtData || window.aksrt || {}; var n = aksrt.restNonce || aksrt.nonce || ""; return n ? { "X-WP-Nonce": n } : {}; } function api(path, options) { var opts = Object.assign({}, options || {}); var query = opts.query; if (Object.prototype.hasOwnProperty.call(opts, "query")) { delete opts.query; } var onlyPath = String(path || ""); var inlineQ = null; var qi = onlyPath.indexOf("?"); if (qi >= 0) { inlineQ = onlyPath.slice(qi + 1); onlyPath = onlyPath.slice(0, qi); } var url = restUrl(onlyPath, query || inlineQ); var merged = Object.assign( { credentials: "same-origin", headers: Object.assign({ "Content-Type": "application/json" }, nonceHeaders()), }, opts ); return fetch(url, merged).then(function (r) { return r .json() .catch(function () { return { message: "Invalid JSON (HTTP " + r.status + ")" }; }) .then(function (j) { return { ok: r.ok, status: r.status, json: j }; }); }); } function ensureModalShell() { var el = document.getElementById("modal_pay_uservip"); if (el) return el; el = document.createElement("div"); el.id = "modal_pay_uservip"; el.className = "aksrt-vip-modal-overlay"; el.setAttribute("aria-hidden", "true"); el.innerHTML = ''; document.body.appendChild(el); el.addEventListener("click", function (e) { if (e.target === el || e.target.closest(".aksrt-vip-modal-close")) { closeModal(); } }); document.addEventListener("keydown", function (e) { if (e.key === "Escape") closeModal(); }); return el; } function openModal() { var el = ensureModalShell(); el.classList.add("is-open"); el.setAttribute("aria-hidden", "false"); document.body.classList.add("aksrt-vip-modal-open"); } function closeModal() { var el = document.getElementById("modal_pay_uservip"); if (!el) return; el.classList.remove("is-open"); el.setAttribute("aria-hidden", "true"); document.body.classList.remove("aksrt-vip-modal-open"); } function bindModalUi(root) { if (!root || root.dataset.aksrtVipBound === "1") return; root.dataset.aksrtVipBound = "1"; root.addEventListener("click", function (e) { var tab = e.target.closest("[data-vip-tab]"); if (tab) { e.preventDefault(); var id = tab.getAttribute("data-vip-tab"); root.querySelectorAll(".aksrt-vip-tab").forEach(function (a) { a.parentElement && a.parentElement.classList.remove("active"); }); tab.parentElement && tab.parentElement.classList.add("active"); root.querySelectorAll(".aksrt-vip-pane").forEach(function (p) { var on = p.id === id; p.hidden = !on; p.classList.toggle("active", on); }); return; } var submit = e.target.closest("[data-vip-submit]"); if (submit) { e.preventDefault(); purchaseFromPane(submit.closest(".aksrt-vip-pane") || root, submit); } }); } function selectedMethod(root) { var fixed = root.querySelector("[data-aksrt-vip-method-fixed]"); if (fixed && fixed.value) return fixed.value; var checked = root.querySelector('input[name="aksrt_vip_pay_method"]:checked'); if (checked) return checked.value; var first = root.querySelector('input[name="aksrt_vip_pay_method"]'); return first ? first.value : "balance"; } function selectedPackage(root) { var checked = root.querySelector('input[name="vip_product_id"]:checked'); return checked ? parseInt(checked.value, 10) : 0; } function setTip(root, text, isError) { var tip = root.querySelector("[data-aksrt-vip-tip]"); if (!tip) return; tip.textContent = text || ""; tip.classList.toggle("is-error", !!isError); } function pollOrder(orderNumber) { if (!orderNumber) return; var tries = 0; var timer = setInterval(function () { tries += 1; api("/pay/content/order/" + encodeURIComponent(orderNumber)) .then(function (r) { if (r.ok && r.json && r.json.paid) { clearInterval(timer); window.location.reload(); } }) .catch(function () {}); if (tries >= 40) clearInterval(timer); }, 3000); } function purchaseFromPane(pane, btn) { var packageId = selectedPackage(pane); if (!packageId) { setTip(pane, "请选择套餐", true); return; } if (btn.disabled) return; btn.disabled = true; btn.classList.add("is-loading"); setTip(pane, "正在创建订单…"); api("/pay/vip", { method: "POST", body: JSON.stringify({ package_id: packageId, payment_method: selectedMethod(pane), }), }) .then(function (r) { btn.disabled = false; btn.classList.remove("is-loading"); if (!r.ok || (r.json && r.json.code && !r.json.success && r.json.success !== true)) { var msg = (r.json && r.json.message) || "开通失败"; if (r.status === 401) { msg = "请先登录"; document.querySelector(".signin-loader") && document.querySelector(".signin-loader").click(); } setTip(pane, msg, true); return; } var data = r.json && r.json.data ? r.json.data : r.json; if (data && data.redirect && (data.payment_url || data.qr_content)) { if (data.payment_url) window.open(data.payment_url, "_blank"); setTip(pane, data.message || "请完成支付,支付成功后将自动刷新。"); if (data.order_number) pollOrder(data.order_number); return; } setTip(pane, (data && data.message) || "开通成功,正在刷新…"); setTimeout(function () { window.location.reload(); }, 400); }) .catch(function () { btn.disabled = false; btn.classList.remove("is-loading"); setTip(pane, "网络错误,请重试", true); }); } var loading = false; function vipPay(trigger) { var level = 1; if (trigger) { level = parseInt(trigger.getAttribute("vip-level") || trigger.getAttribute("data-vip-level") || "1", 10) || 1; } if (loading) return; loading = true; var shell = ensureModalShell(); var body = shell.querySelector("[data-aksrt-vip-modal-body]"); if (body) body.innerHTML = '
加载中…
'; openModal(); api("/pay/vip/modal", { query: { vip_level: level } }) .then(function (r) { loading = false; if (r.status === 401) { closeModal(); var login = document.querySelector(".signin-loader"); if (login) login.click(); return; } if (!r.ok || !r.json || !r.json.html) { if (body) { body.innerHTML = '
' + ((r.json && r.json.message) || "加载失败") + "
"; } return; } if (body) { body.innerHTML = r.json.html; bindModalUi(body); } }) .catch(function () { loading = false; if (body) { body.innerHTML = '
网络错误
'; } }); } function onDocClick(e) { // Header CTA, float rail, UC buttons, VIP hover cards. var t = e.target.closest(".pay-vip, a.pay-vip, .float-btn.pay-vip, [data-aksrt-pay-vip]"); if (!t) return; // Real external href without modal intent: leave alone. var href = (t.getAttribute("href") || "").trim(); if (href && href !== "#" && href.indexOf("javascript:") !== 0 && !t.classList.contains("pay-vip") && !t.hasAttribute("data-aksrt-pay-vip") && !t.hasAttribute("vip-level") && !t.hasAttribute("data-vip-level")) { return; } e.preventDefault(); e.stopPropagation(); vipPay(t); } function init() { // Capture phase so float/header anchors with href never navigate first. document.addEventListener("click", onDocClick, true); } // Prefer module registry, but always bind once as hard fallback // (float rail must work even if AksrtFrontend.rehydrate is a no-op). if (window.__aksrtPayVipBound) { // already initialized } else if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") { window.AksrtFrontend.register("aksrt-pay-vip", function () { if (window.__aksrtPayVipBound) return; window.__aksrtPayVipBound = true; init(); }); // Also bind immediately — float button is in footer, available now. if (!window.__aksrtPayVipBound) { window.__aksrtPayVipBound = true; init(); } } else if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", function () { if (window.__aksrtPayVipBound) return; window.__aksrtPayVipBound = true; init(); }); } else { window.__aksrtPayVipBound = true; init(); } window.aksrtVipPay = vipPay; })();