247 lines
8.4 KiB
JavaScript
247 lines
8.4 KiB
JavaScript
(function () {
|
|
var root = document.querySelector("[data-recharge-modal]");
|
|
if (!root) return;
|
|
|
|
var panel = root.querySelector(".recharge-modal__panel");
|
|
var openers = document.querySelectorAll("[data-recharge-open]");
|
|
var closers = root.querySelectorAll("[data-recharge-close]");
|
|
var packagesRoot = root.querySelector("[data-recharge-packages]");
|
|
var methodsRoot = root.querySelector("[data-recharge-methods]");
|
|
var amount = root.querySelector("[data-recharge-amount]");
|
|
var pay = root.querySelector("[data-recharge-pay]");
|
|
var status = root.querySelector("[data-recharge-status]");
|
|
var previousOverflow = "";
|
|
var returnFocus = null;
|
|
var paying = false;
|
|
|
|
function packages() {
|
|
return root.querySelectorAll("[data-recharge-package]");
|
|
}
|
|
|
|
function methods() {
|
|
return root.querySelectorAll("[data-recharge-method]");
|
|
}
|
|
|
|
function showStatus(message, ok) {
|
|
if (!status) return;
|
|
status.textContent = message || "";
|
|
status.hidden = !message;
|
|
status.classList.toggle("is-ok", !!ok);
|
|
}
|
|
|
|
function open(trigger) {
|
|
if (!root.hidden) return;
|
|
|
|
var oldDialog = document.querySelector("[data-play-coin].is-open");
|
|
if (oldDialog) {
|
|
var oldClose = oldDialog.querySelector("button[data-play-coin-close]");
|
|
if (oldClose) oldClose.click();
|
|
}
|
|
|
|
returnFocus = trigger && oldDialog ? document.querySelector("[data-play-coin-open]") : trigger;
|
|
previousOverflow = document.body.style.overflow;
|
|
showStatus("");
|
|
root.hidden = false;
|
|
document.body.style.overflow = "hidden";
|
|
if (panel) panel.focus();
|
|
}
|
|
|
|
function close() {
|
|
if (root.hidden) return;
|
|
root.hidden = true;
|
|
document.body.style.overflow = previousOverflow;
|
|
if (returnFocus && typeof returnFocus.focus === "function") returnFocus.focus();
|
|
}
|
|
|
|
function parsePayMethods(raw) {
|
|
try {
|
|
var list = JSON.parse(raw || "[]");
|
|
return Array.isArray(list) ? list : [];
|
|
} catch (e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function renderMethods(list) {
|
|
if (!methodsRoot) return;
|
|
methodsRoot.replaceChildren();
|
|
if (!list.length) {
|
|
var empty = document.createElement("p");
|
|
empty.className = "recharge-modal__empty";
|
|
empty.textContent = "该套餐暂无可用支付方式";
|
|
methodsRoot.appendChild(empty);
|
|
return;
|
|
}
|
|
list.forEach(function (item, index) {
|
|
var type = String((item && item.type) || "").trim();
|
|
var name = String((item && item.typeName) || type || "支付").trim();
|
|
if (!type) return;
|
|
var btn = document.createElement("button");
|
|
btn.className = "recharge-modal__method" + (index === 0 ? " is-selected" : "");
|
|
btn.type = "button";
|
|
btn.setAttribute("data-recharge-method", type);
|
|
btn.setAttribute("aria-pressed", index === 0 ? "true" : "false");
|
|
btn.innerHTML =
|
|
'<span class="recharge-modal__method-check" aria-hidden="true"><img src="/static/images/placeholder.png?v=2" data-src="/static/images/recharge/check.svg" alt="" loading="lazy" decoding="async"></span>' +
|
|
'<span class="recharge-modal__method-copy"><span></span><small>即时到账</small></span>';
|
|
btn.querySelector(".recharge-modal__method-copy span").textContent = name;
|
|
methodsRoot.appendChild(btn);
|
|
});
|
|
if (typeof window.initLazyImages === "function") {
|
|
window.initLazyImages(methodsRoot);
|
|
}
|
|
}
|
|
|
|
function selectPackage(button) {
|
|
Array.prototype.forEach.call(packages(), function (item) {
|
|
var selected = item === button;
|
|
item.classList.toggle("is-selected", selected);
|
|
item.setAttribute("aria-pressed", String(selected));
|
|
});
|
|
if (amount) amount.textContent = "¥" + (button.getAttribute("data-price") || "0");
|
|
renderMethods(parsePayMethods(button.getAttribute("data-pay-methods")));
|
|
showStatus("");
|
|
}
|
|
|
|
function bindMethodClicks() {
|
|
if (!methodsRoot) return;
|
|
methodsRoot.addEventListener("click", function (event) {
|
|
var button = event.target.closest("[data-recharge-method]");
|
|
if (!button || !methodsRoot.contains(button)) return;
|
|
Array.prototype.forEach.call(methods(), function (item) {
|
|
var selected = item === button;
|
|
item.classList.toggle("is-selected", selected);
|
|
item.setAttribute("aria-pressed", String(selected));
|
|
});
|
|
showStatus("");
|
|
});
|
|
}
|
|
|
|
Array.prototype.forEach.call(openers, function (button) {
|
|
button.addEventListener("click", function (event) {
|
|
event.preventDefault();
|
|
open(button);
|
|
});
|
|
});
|
|
|
|
Array.prototype.forEach.call(closers, function (element) {
|
|
element.addEventListener("click", close);
|
|
});
|
|
|
|
if (packagesRoot) {
|
|
packagesRoot.addEventListener("click", function (event) {
|
|
var button = event.target.closest("[data-recharge-package]");
|
|
if (!button || !packagesRoot.contains(button)) return;
|
|
selectPackage(button);
|
|
});
|
|
}
|
|
|
|
bindMethodClicks();
|
|
|
|
if (pay) {
|
|
pay.addEventListener("click", function () {
|
|
if (paying) return;
|
|
var selectedPackage = root.querySelector("[data-recharge-package].is-selected");
|
|
var selectedMethod = root.querySelector("[data-recharge-method].is-selected");
|
|
var packageId = selectedPackage ? Number(selectedPackage.getAttribute("data-package-id") || 0) : 0;
|
|
var payMode = selectedMethod ? selectedMethod.getAttribute("data-recharge-method") : "";
|
|
if (!packageId) {
|
|
showStatus("请选择充值套餐");
|
|
return;
|
|
}
|
|
if (!payMode) {
|
|
showStatus("请选择支付方式");
|
|
return;
|
|
}
|
|
paying = true;
|
|
pay.disabled = true;
|
|
showStatus("正在创建支付订单…");
|
|
var payload = { packageId: packageId, payMode: payMode };
|
|
var req =
|
|
window.HttpRequest && typeof window.HttpRequest.post === "function"
|
|
? window.HttpRequest.post("/api/coin/buy", payload)
|
|
: fetch("/api/coin/buy", {
|
|
method: "POST",
|
|
credentials: "same-origin",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(payload),
|
|
}).then(function (r) {
|
|
return r.json().then(function (body) {
|
|
return body;
|
|
});
|
|
});
|
|
req
|
|
.then(function (result) {
|
|
if (!result || Number(result.code) !== 200 || !result.data || !result.data.payUrl) {
|
|
throw new Error((result && (result.tip || result.msg)) || "创建支付订单失败");
|
|
}
|
|
showStatus("订单创建成功,正在前往支付…", true);
|
|
openPayInNewWindow(result.data.payUrl);
|
|
paying = false;
|
|
pay.disabled = false;
|
|
})
|
|
.catch(function (error) {
|
|
showStatus((error && error.message) || "创建支付订单失败,请稍后重试");
|
|
paying = false;
|
|
pay.disabled = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
function openPayInNewWindow(url) {
|
|
url = String(url || "").trim();
|
|
if (!url) return;
|
|
var opened = null;
|
|
try {
|
|
opened = window.open(url, "_blank", "noopener,noreferrer");
|
|
} catch (e) {
|
|
opened = null;
|
|
}
|
|
if (opened) {
|
|
try {
|
|
opened.opener = null;
|
|
} catch (e2) {}
|
|
showStatus("已在新窗口打开支付页面,请完成支付后返回本页", true);
|
|
return;
|
|
}
|
|
// 弹窗被拦截时用 <a target=_blank> 再试,仍不跳转当前页
|
|
var link = document.createElement("a");
|
|
link.href = url;
|
|
link.target = "_blank";
|
|
link.rel = "noopener noreferrer";
|
|
link.style.display = "none";
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
showStatus("若未打开支付页,请允许本站弹窗后重试", true);
|
|
}
|
|
|
|
document.addEventListener("keydown", function (event) {
|
|
if (root.hidden) return;
|
|
if (event.key === "Escape") {
|
|
event.preventDefault();
|
|
close();
|
|
return;
|
|
}
|
|
if (event.key !== "Tab") return;
|
|
|
|
var focusable = root.querySelectorAll("button:not([disabled]), a[href]");
|
|
if (!focusable.length) return;
|
|
var first = focusable[0];
|
|
var last = focusable[focusable.length - 1];
|
|
if (event.shiftKey && (document.activeElement === first || document.activeElement === panel)) {
|
|
event.preventDefault();
|
|
last.focus();
|
|
} else if (!event.shiftKey && document.activeElement === last) {
|
|
event.preventDefault();
|
|
first.focus();
|
|
}
|
|
});
|
|
|
|
window.openRechargeModal = function (trigger) {
|
|
open(trigger || null);
|
|
};
|
|
|
|
if (new URLSearchParams(window.location.search).get("recharge") === "1") open(null);
|
|
})();
|