perf(modal): unify cancellable frontend modal flows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
25ce1d8f43
commit
5375ad6429
36 files changed
+2623
-1806
No files matched your search
+348
-186
@@ -1,72 +1,246 @@
|
||||
/**
|
||||
* AKSRT VIP pay modal — zibll .pay-vip parity.
|
||||
* Loads modal HTML from GET /aksrt/v1/pay/vip/modal then purchases via POST /pay/vip.
|
||||
* AKSRT VIP pay modal — JSON view model + canonical purchase coordinator.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function api(path, options) {
|
||||
return window.AksrtRequest.request(path, Object.assign({}, options || {})).then(function (response) {
|
||||
return {
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
json: response.json || {},
|
||||
};
|
||||
}).catch(function (error) {
|
||||
var response = error && error.response ? error.response : {};
|
||||
return {
|
||||
ok: false,
|
||||
status: error && error.status ? error.status : (response.status || 0),
|
||||
json: error && error.json ? error.json : (response.json || { message: error && error.message }),
|
||||
};
|
||||
function text(value) {
|
||||
return String(value == null ? "" : value);
|
||||
}
|
||||
|
||||
function node(tag, className, value) {
|
||||
var el = document.createElement(tag);
|
||||
if (className) el.className = className;
|
||||
if (value !== undefined && value !== null) el.textContent = text(value);
|
||||
return el;
|
||||
}
|
||||
|
||||
function append(parent, child) {
|
||||
if (child) parent.appendChild(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
function levelMap(levels) {
|
||||
var map = Object.create(null);
|
||||
(Array.isArray(levels) ? levels : []).forEach(function (level) {
|
||||
if (level && level.level) map[String(level.level)] = level;
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
var activeVipShell = null;
|
||||
|
||||
function openModal() {
|
||||
activeVipShell = window.AksrtModalRuntime.open({
|
||||
className: "aksrt-vip-modal-shell",
|
||||
mobileBottom: false,
|
||||
skeleton: '<div class="aksrt-vip-modal-panel"><div class="aksrt-vip-modal-content" data-aksrt-vip-modal-body><div class="text-center padding-20 muted-2-color">加载中…</div></div></div>',
|
||||
telemetry: false,
|
||||
kind: "vip",
|
||||
});
|
||||
return activeVipShell;
|
||||
function actionLabel(action) {
|
||||
if (action === "renew") return "续费";
|
||||
if (action === "upgrade") return "升级";
|
||||
return "开通";
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
window.AksrtModalRuntime.close("vip");
|
||||
activeVipShell = null;
|
||||
function actionKey(action) {
|
||||
return action === "pay" ? "purchase" : action;
|
||||
}
|
||||
|
||||
function bindModalUi(root) {
|
||||
if (!root || root.dataset.aksrtVipBound === "1") return;
|
||||
root.dataset.aksrtVipBound = "1";
|
||||
function actionReason(reason) {
|
||||
if (reason === "no_payment_method") return "暂无可用支付方式";
|
||||
if (reason === "no_package") return "暂无可用套餐";
|
||||
if (reason === "not_available") return "当前不可用";
|
||||
return "";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
function renderEquity(parent, value) {
|
||||
if (!value) return;
|
||||
var equity = node("div");
|
||||
// The server sanitizes and wraps this admin-authored fragment before JSON.
|
||||
equity.innerHTML = text(value);
|
||||
while (equity.firstChild) parent.appendChild(equity.firstChild);
|
||||
}
|
||||
|
||||
var submit = e.target.closest("[data-vip-submit]");
|
||||
if (submit) {
|
||||
e.preventDefault();
|
||||
purchaseFromPane(submit.closest(".aksrt-vip-pane") || root, submit);
|
||||
function renderProducts(parent, items) {
|
||||
if (!Array.isArray(items) || !items.length) {
|
||||
append(parent, node("div", "muted-2-color text-center padding-10", "暂无可用套餐"));
|
||||
return;
|
||||
}
|
||||
var wrap = node("div", "mb10 label-box charge-box aksrt-vip-products");
|
||||
items.forEach(function (item, index) {
|
||||
if (!item || !item.package_id) return;
|
||||
var label = node("label", "aksrt-vip-product-label");
|
||||
var input = node("input");
|
||||
input.className = "hide vip-product-input";
|
||||
input.type = "radio";
|
||||
input.name = "vip_product_id_" + String(item.level || "group");
|
||||
input.setAttribute("data-aksrt-vip-package", "");
|
||||
input.value = String(item.package_id);
|
||||
input.checked = index === 0;
|
||||
label.appendChild(input);
|
||||
|
||||
var product = node("div", "zib-widget vip-product relative text-center product-box");
|
||||
if (item.discount_tag) append(product, node("div", "abs-right vip-tag badg jb-yellow", item.discount_tag));
|
||||
if (item.title) append(product, node("div", "em09 mb3", item.title));
|
||||
var priceRow = node("div", "flex abl gap6 jc");
|
||||
append(priceRow, node("div", "product-price c-red", item.price_label || ""));
|
||||
if (item.show_price_label) {
|
||||
var original = node("div", "original-price relative muted-2-color");
|
||||
var strike = node("s", "", item.show_price_label);
|
||||
append(original, strike);
|
||||
append(priceRow, original);
|
||||
}
|
||||
append(product, priceRow);
|
||||
if (item.days_label) append(product, node("div", "muted-2-color c-blue em09 p2-10 badg radius", item.days_label));
|
||||
append(label, product);
|
||||
append(wrap, label);
|
||||
});
|
||||
append(parent, wrap);
|
||||
}
|
||||
|
||||
function renderMethods(parent, methods) {
|
||||
methods = Array.isArray(methods) ? methods : [];
|
||||
if (!methods.length) {
|
||||
append(parent, node("div", "muted-2-color text-center padding-10", "暂无可用支付方式"));
|
||||
return;
|
||||
}
|
||||
if (methods.length === 1) {
|
||||
var one = node("input");
|
||||
one.type = "hidden";
|
||||
one.name = "aksrt_vip_pay_method";
|
||||
one.value = text(methods[0].id || "balance");
|
||||
one.setAttribute("data-aksrt-vip-method-fixed", "");
|
||||
append(parent, one);
|
||||
return;
|
||||
}
|
||||
var wrap = node("div", "uc-vip-shop__methods mb10");
|
||||
wrap.setAttribute("data-aksrt-vip-methods", "");
|
||||
append(wrap, node("span", "uc-vip-shop__methods-label", "支付方式"));
|
||||
methods.forEach(function (method, index) {
|
||||
var label = node("label", "uc-vip-shop__method");
|
||||
var input = node("input");
|
||||
input.type = "radio";
|
||||
input.name = "aksrt_vip_pay_method";
|
||||
input.value = text(method.id || "balance");
|
||||
input.checked = index === 0;
|
||||
append(label, input);
|
||||
append(label, node("span", "", method.name || method.id || ""));
|
||||
append(wrap, label);
|
||||
});
|
||||
append(parent, wrap);
|
||||
}
|
||||
|
||||
function renderModalView(body, view) {
|
||||
view = view || {};
|
||||
if (body.replaceChildren) body.replaceChildren();
|
||||
else body.innerHTML = "";
|
||||
|
||||
if (!view.enabled) {
|
||||
append(body, node("div", "box-body payvip-modal text-center padding-20", "会员功能未启用。"));
|
||||
return;
|
||||
}
|
||||
|
||||
var catalog = view.catalog || {};
|
||||
var member = view.member || {};
|
||||
var levels = levelMap(view.levels);
|
||||
var groups = Array.isArray(catalog.level_packages) ? catalog.level_packages : [];
|
||||
var methods = Array.isArray(view.payment_methods) ? view.payment_methods : [];
|
||||
var allowed = view.allowed_actions || {};
|
||||
var reasons = view.action_reasons || {};
|
||||
var modal = node("div", "box-body payvip-modal");
|
||||
modal.setAttribute("data-aksrt-vip-modal", "");
|
||||
if (view.version && view.version.catalog) modal.setAttribute("data-aksrt-vip-version", view.version.catalog);
|
||||
|
||||
var close = node("button", "aksrt-modal-close", "×");
|
||||
close.type = "button";
|
||||
close.setAttribute("data-aksrt-modal-close", "");
|
||||
close.setAttribute("aria-label", "关闭");
|
||||
append(modal, close);
|
||||
|
||||
var userBox = node("ul", "list-inline user-box flex ac mb10");
|
||||
var avatarItem = node("li", "avatar-img");
|
||||
if (member.avatar_url) {
|
||||
var avatar = node("img");
|
||||
avatar.src = text(member.avatar_url);
|
||||
avatar.alt = "";
|
||||
avatar.width = 42;
|
||||
avatar.height = 42;
|
||||
append(avatarItem, avatar);
|
||||
}
|
||||
append(userBox, avatarItem);
|
||||
var userInfo = node("li");
|
||||
append(userInfo, node("b", "em12", member.name || ""));
|
||||
if (member.level > 0) {
|
||||
var expiry = node("div", "muted-2-color em09");
|
||||
var badge = node("span", "badg c-yellow vip-expdate-tag", member.expires_label || "");
|
||||
append(expiry, badge);
|
||||
append(userInfo, expiry);
|
||||
} else if (member.state === "expired") {
|
||||
append(userInfo, node("div", "muted-2-color em09", "已过期"));
|
||||
} else if (catalog.desc) {
|
||||
append(userInfo, node("div", "muted-2-color em09", catalog.desc));
|
||||
}
|
||||
append(userBox, userInfo);
|
||||
append(modal, userBox);
|
||||
|
||||
var tabs = node("ul", "flex jsb mt10 mb20 vip-cardminis gutters-5 nav");
|
||||
var content = node("div", "tab-content mt10");
|
||||
var activeIndex = -1;
|
||||
groups.forEach(function (group, index) {
|
||||
if (activeIndex >= 0 || !group) return;
|
||||
if (Number(group.level) === Number(view.prefer_level)) activeIndex = index;
|
||||
});
|
||||
if (activeIndex < 0 && groups.length) activeIndex = 0;
|
||||
|
||||
groups.forEach(function (group, index) {
|
||||
if (!group || !Array.isArray(group.items) || !group.items.length) return;
|
||||
var level = Number(group.level || 0);
|
||||
var action = text(group.action || "pay");
|
||||
var tabId = "tab-payvip-" + level + "-" + action;
|
||||
var active = index === activeIndex;
|
||||
var tabItem = node("li", "relative" + (active ? " active" : ""));
|
||||
var tab = node("a", "aksrt-vip-tab", actionLabel(action) + (group.name || "VIP" + level));
|
||||
tab.href = "javascript:;";
|
||||
tab.setAttribute("data-vip-tab", tabId);
|
||||
append(tabItem, tab);
|
||||
append(tabs, tabItem);
|
||||
|
||||
var pane = node("div", "tab-pane aksrt-vip-pane" + (active ? " active" : ""));
|
||||
pane.id = tabId;
|
||||
pane.hidden = !active;
|
||||
var row = node("div", "pay-vip-form-row");
|
||||
var info = node("div", "pay-vip-info level-" + level);
|
||||
var levelInfo = levels[String(level)] || {};
|
||||
append(info, node("div", "v-name font-bold", group.name || levelInfo.name || "VIP" + level));
|
||||
if (levelInfo.desc) append(info, node("div", "muted-2-color em09 mb6", levelInfo.desc));
|
||||
renderEquity(info, levelInfo.equity);
|
||||
append(row, info);
|
||||
|
||||
var products = node("div", "pay-vip-products");
|
||||
renderProducts(products, group.items);
|
||||
renderMethods(products, methods);
|
||||
var actionName = actionKey(action);
|
||||
var actionAllowed = allowed[actionName] === true;
|
||||
var reason = actionReason(reasons[actionName]);
|
||||
var canPurchase = actionAllowed && methods.length > 0;
|
||||
var submit = node("button", "but jb-red btn-block padding-lg radius aksrt-vip-submit", canPurchase ? (group.items[0].cta_label || actionLabel(action)) : (reason || "暂无可用支付方式"));
|
||||
submit.type = "button";
|
||||
submit.disabled = !canPurchase;
|
||||
submit.setAttribute("data-vip-submit", "");
|
||||
append(products, submit);
|
||||
append(products, node("p", "aksrt-vip-modal-tip muted-2-color em09 mt10"));
|
||||
append(row, products);
|
||||
append(pane, row);
|
||||
append(content, pane);
|
||||
});
|
||||
append(modal, tabs);
|
||||
append(modal, content);
|
||||
|
||||
if (catalog.help_text) append(modal, node("div", "muted-2-color em09 mb6", catalog.help_text));
|
||||
if (catalog.more) append(modal, node("div", "muted-2-color mb10 em09 muted-box padding-10 mini-radius", catalog.more));
|
||||
var points = catalog.points_exchange || {};
|
||||
if (allowed.points_exchange !== false && points.enabled && Array.isArray(points.packages) && points.packages.length && catalog.vip_url) {
|
||||
var pointsWrap = node("div", "mt10");
|
||||
var pointsLink = node("a", "but c-green btn-block", "积分兑换会员");
|
||||
pointsLink.href = text(catalog.vip_url);
|
||||
append(pointsWrap, pointsLink);
|
||||
append(modal, pointsWrap);
|
||||
}
|
||||
append(body, modal);
|
||||
}
|
||||
|
||||
function selectedMethod(root) {
|
||||
@@ -79,165 +253,155 @@
|
||||
}
|
||||
|
||||
function selectedPackage(root) {
|
||||
var checked = root.querySelector('input[name="vip_product_id"]:checked');
|
||||
var checked = root.querySelector('[data-aksrt-vip-package]:checked');
|
||||
return checked ? parseInt(checked.value, 10) : 0;
|
||||
}
|
||||
|
||||
function setTip(root, text, isError) {
|
||||
var tip = root.querySelector("[data-aksrt-vip-tip]");
|
||||
function setTip(root, message, isError) {
|
||||
var tip = root.querySelector("[data-aksrt-vip-tip]") || root.querySelector(".aksrt-vip-modal-tip");
|
||||
if (!tip) return;
|
||||
tip.textContent = text || "";
|
||||
tip.textContent = message || "";
|
||||
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);
|
||||
var activePurchase = null;
|
||||
|
||||
function restoreButton(button) {
|
||||
if (!button) return;
|
||||
button.disabled = false;
|
||||
button.classList.remove("is-loading");
|
||||
}
|
||||
|
||||
function purchaseFromPane(pane, btn) {
|
||||
function purchaseFromPane(pane, button) {
|
||||
var packageId = selectedPackage(pane);
|
||||
if (!packageId) {
|
||||
setTip(pane, "请选择套餐", true);
|
||||
return;
|
||||
}
|
||||
if (btn.disabled) return;
|
||||
btn.disabled = true;
|
||||
btn.classList.add("is-loading");
|
||||
if (!button || button.disabled) return;
|
||||
var coordinator = window.AksrtVipPurchaseCoordinator;
|
||||
|
||||
button.disabled = true;
|
||||
button.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)) {
|
||||
window.AksrtModalRuntime.invalidate(["vip", "orders"]);
|
||||
if (data.payment_url) window.open(data.payment_url, "_blank");
|
||||
setTip(pane, data.message || "请完成支付,支付成功后将自动刷新。");
|
||||
if (data.order_number) pollOrder(data.order_number);
|
||||
return;
|
||||
}
|
||||
window.AksrtModalRuntime.invalidate(["vip", "orders"]);
|
||||
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 telemetry = window.AksrtModalTelemetry;
|
||||
var telemetryId = telemetry && typeof telemetry.start === "function" ? telemetry.start("vip") : "";
|
||||
function telemetryMark(event) {
|
||||
if (telemetry && telemetryId && typeof telemetry.mark === "function") telemetry.mark(telemetryId, event);
|
||||
}
|
||||
var shell = openModal();
|
||||
var body = shell.querySelector("[data-aksrt-vip-modal-body]");
|
||||
telemetryMark("shell");
|
||||
|
||||
api("/pay/vip/modal", { query: { vip_level: level } })
|
||||
.then(function (r) {
|
||||
loading = false;
|
||||
if (r.status === 401) {
|
||||
telemetryMark("unauthorized");
|
||||
closeModal();
|
||||
activePurchase = coordinator.start({
|
||||
packageId: packageId,
|
||||
paymentMethod: selectedMethod(pane),
|
||||
tags: ["vip", "orders"],
|
||||
onPending: function (data) {
|
||||
restoreButton(button);
|
||||
if (data.payment_url) window.open(data.payment_url, "_blank");
|
||||
setTip(pane, data.message || "请完成支付,支付成功后将自动刷新。");
|
||||
},
|
||||
onSuccess: function (result) {
|
||||
activePurchase = null;
|
||||
restoreButton(button);
|
||||
setTip(pane, (result.data && result.data.message) || "开通成功,正在刷新…");
|
||||
window.setTimeout(function () { window.location.reload(); }, 400);
|
||||
},
|
||||
onFailure: function (result) {
|
||||
activePurchase = null;
|
||||
restoreButton(button);
|
||||
setTip(pane, result.data && result.data.message ? result.data.message : "支付未完成,请重试。", true);
|
||||
},
|
||||
onTimeout: function () {
|
||||
activePurchase = null;
|
||||
restoreButton(button);
|
||||
setTip(pane, "支付状态暂未确认,请稍后在订单中心查看。", true);
|
||||
},
|
||||
onError: function (response) {
|
||||
activePurchase = null;
|
||||
restoreButton(button);
|
||||
var message = response && response.json && response.json.message ? response.json.message : "开通失败";
|
||||
if (response && response.status === 401) {
|
||||
message = "请先登录";
|
||||
var login = document.querySelector(".signin-loader");
|
||||
if (login) login.click();
|
||||
return;
|
||||
}
|
||||
if (!r.ok || !r.json || !r.json.html) {
|
||||
telemetryMark("error");
|
||||
if (body) {
|
||||
body.innerHTML =
|
||||
'<div class="text-center padding-20 c-red">' +
|
||||
((r.json && r.json.message) || "加载失败") +
|
||||
"</div>";
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (body) {
|
||||
body.innerHTML = r.json.html;
|
||||
telemetryMark("first-content");
|
||||
window.AksrtFrontend.rehydrate(body, "modal");
|
||||
bindModalUi(body);
|
||||
telemetryMark("ready");
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
loading = false;
|
||||
telemetryMark("error");
|
||||
if (body) {
|
||||
body.innerHTML = '<div class="text-center padding-20 c-red">网络错误</div>';
|
||||
}
|
||||
});
|
||||
setTip(pane, message, true);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
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")) {
|
||||
function bindModalUi(root) {
|
||||
if (!root || root.dataset.aksrtVipBound === "1") return;
|
||||
root.dataset.aksrtVipBound = "1";
|
||||
root.addEventListener("click", function (event) {
|
||||
var tab = event.target.closest("[data-vip-tab]");
|
||||
if (tab) {
|
||||
event.preventDefault();
|
||||
var id = tab.getAttribute("data-vip-tab");
|
||||
root.querySelectorAll(".aksrt-vip-tab").forEach(function (item) {
|
||||
if (item.parentElement) item.parentElement.classList.toggle("active", item === tab);
|
||||
});
|
||||
root.querySelectorAll(".aksrt-vip-pane").forEach(function (pane) {
|
||||
var active = pane.id === id;
|
||||
pane.hidden = !active;
|
||||
pane.classList.toggle("active", active);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var submit = event.target.closest("[data-vip-submit]");
|
||||
if (submit) {
|
||||
event.preventDefault();
|
||||
purchaseFromPane(submit.closest(".aksrt-vip-pane") || root, submit);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function vipPay(trigger) {
|
||||
if (!window.AksrtModalRuntime.isRolloutEnabled("vip")) return;
|
||||
var level = trigger
|
||||
? parseInt(trigger.getAttribute("vip-level") || trigger.getAttribute("data-vip-level") || "1", 10) || 1
|
||||
: 1;
|
||||
window.AksrtModalRuntime.openRemote({
|
||||
url: "/pay/vip/modal",
|
||||
query: { vip_level: level },
|
||||
className: "aksrt-vip-modal-shell",
|
||||
mobileBottom: false,
|
||||
skeleton: '<div class="aksrt-vip-modal-panel"><div class="aksrt-vip-modal-content" data-aksrt-vip-modal-body><div class="text-center padding-20 muted-2-color">加载中…</div></div></div>',
|
||||
telemetry: "vip",
|
||||
kind: "vip",
|
||||
responseType: "json",
|
||||
cacheTtl: 15000,
|
||||
cacheTags: ["vip"],
|
||||
renderData: function (data, session) {
|
||||
renderModalView(session.content, data);
|
||||
bindModalUi(session.content);
|
||||
},
|
||||
onError: function (error) {
|
||||
if (!error || error.code !== "unauthorized") return;
|
||||
window.AksrtModalRuntime.close("unauthorized");
|
||||
var login = document.querySelector(".signin-loader");
|
||||
if (login) login.click();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function onDocClick(event) {
|
||||
var trigger = event.target.closest(".pay-vip, a.pay-vip, .float-btn.pay-vip, [data-aksrt-pay-vip]");
|
||||
if (!trigger) return;
|
||||
var href = (trigger.getAttribute("href") || "").trim();
|
||||
if (href && href !== "#" && href.indexOf("javascript:") !== 0 && !trigger.classList.contains("pay-vip") && !trigger.hasAttribute("data-aksrt-pay-vip") && !trigger.hasAttribute("vip-level") && !trigger.hasAttribute("data-vip-level")) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
vipPay(t);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
vipPay(trigger);
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Capture phase so float/header anchors with href never navigate first.
|
||||
document.addEventListener("click", onDocClick, true);
|
||||
}
|
||||
document.addEventListener("aksrt:modal:close", function (event) {
|
||||
var detail = event && event.detail ? event.detail : {};
|
||||
var options = detail.session && detail.session.options ? detail.session.options : {};
|
||||
if (options.kind !== "vip" || !activePurchase) return;
|
||||
if (typeof activePurchase.abort === "function") activePurchase.abort();
|
||||
activePurchase = null;
|
||||
});
|
||||
|
||||
// This handler is delegated from document, so registry rehydration is not
|
||||
// needed. Bind exactly once and keep dynamically injected triggers working.
|
||||
function bindOnce() {
|
||||
if (window.__aksrtPayVipBound) return;
|
||||
window.__aksrtPayVipBound = true;
|
||||
init();
|
||||
document.addEventListener("click", onDocClick, true);
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
@@ -245,6 +409,4 @@
|
||||
} else {
|
||||
bindOnce();
|
||||
}
|
||||
|
||||
window.aksrtVipPay = vipPay;
|
||||
})();
|
||||
Reference in new issue
Block a user