fix(vip): 会员弹窗支付方式渠道对齐 Zibll initiate_pay_input 组件

支付方式 UI 不再自实现(uc-vip-shop__method 文本 radio),改为与其他
两个弹窗(充值/积分)完全同源的 Zibll zibpay_get_initiate_pay_input
组件结构:

- 支付方式行:.payment-method-radio.hollow-radio + logo 图 +
  data-for/data-value 选中模型(多渠道时展示「请选择支付方式」)
- 我的余额盒:data-controller == balance 条件显隐,展示货币符号与余额
  (视图模型透传 wallet_balance / currency_mark)
- 卡密盒:Zibll password_box 同构(mb10 padding-h10 padding-w6 +
  desc muted-box + form-control 卡号/卡密输入)
- hidden payment_method + initiate-pay 按钮类(mt6 but jb-red
  btn-block radius)
- 服务端 payment_method_logo_url() 统一映射 pay-*-logo.svg
- 显隐统一走 data-controller(==/!=)通用匹配,卡密选中隐藏 .charge-box
- 清理 uc-vip-shop__method* 死样式与旧 change 监听;契约测试同步锁定
  (.gitignore 白名单补 card-pass-modal-redeem.test.cjs)
This commit is contained in:
2026-09-18 12:44:38 +08:00
parent e72d0710e6
commit 721fa29b8d
5 changed files with 298 additions and 62 deletions
+78 -41
View File
@@ -102,43 +102,64 @@
append(parent, wrap);
}
function renderMethods(parent, methods, cardPass) {
function renderMethods(parent, methods, cardPass, wallet) {
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);
} else {
var wrap = node("div", "uc-vip-shop__methods mb10");
wrap.setAttribute("data-aksrt-vip-methods", "");
append(wrap, node("span", "uc-vip-shop__methods-label", "支付方式"));
wallet = wallet || {};
var defaultMethod = text(methods[0].id || "balance");
// 支付方式选择行(Zibll zibpay_get_initiate_pay_input 同构:
// .payment-method-radio.hollow-radio + logo 图 + data-for 选中模型;
// 与余额充值/购买积分弹窗完全一致的组件)。
if (methods.length > 1) {
append(parent, node("div", "muted-2-color em09 mb6", "请选择支付方式"));
var row = node("div", "flex mb10");
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);
var id = text(method.id || "balance");
var item = node("div", "flex jc hh payment-method-radio hollow-radio flex-auto pointer" + (index === 0 ? " active" : ""));
item.setAttribute("data-for", "payment_method");
item.setAttribute("data-value", id);
if (method.logo) {
var img = node("img");
img.src = text(method.logo);
img.alt = id + "-logo";
img.decoding = "async";
append(item, img);
}
append(item, node("div", "", method.name || id || ""));
append(row, item);
});
append(parent, wrap);
append(parent, row);
}
// 卡密渠道输入盒(契约与参考主题一致:data-controller="payment_method")。
// 我的余额盒(Zibll user_balance_box 同构:选中余额渠道时显示)。
if (methods.some(function (m) { return text(m.id) === "balance"; })) {
var balanceBox = node("div", "mb10 muted-box padding-h10");
balanceBox.setAttribute("data-controller", "payment_method");
balanceBox.setAttribute("data-condition", "==");
balanceBox.setAttribute("data-value", "balance");
if (defaultMethod !== "balance") balanceBox.style.display = "none";
var balanceRow = node("div", "flex jsb ac");
append(balanceRow, node("span", "muted-2-color", "我的余额"));
var balanceValue = node("div", "c-blue-2");
append(balanceValue, node("span", "px12 mr3", wallet.mark || "¥"));
append(balanceValue, node("span", "em14", text(wallet.balance || "0.00")));
append(balanceRow, balanceValue);
append(balanceBox, balanceRow);
append(parent, balanceBox);
}
// 卡密盒(Zibll password_box 同构:mb10 padding-h10 padding-w6 +
// data-controller="payment_method" 契约 + form-control 输入)。
if (cardPass) {
var box = node("div", "uc-vip-shop__card-pass mb10");
var box = node("div", "mb10 padding-h10 padding-w6");
box.setAttribute("data-controller", "payment_method");
box.setAttribute("data-condition", "==");
box.setAttribute("data-value", "card_pass");
box.style.display = "none";
if (defaultMethod !== "card_pass") box.style.display = "none";
if (cardPass.desc) append(box, node("div", "muted-box muted-2-color padding-10 mb10 em09", cardPass.desc));
append(box, node("div", "muted-2-color em09 mb6", cardPass.only_password ? "请输入卡密" : "请输入卡号和密码"));
if (!cardPass.only_password) {
@@ -157,15 +178,26 @@
append(box, pwInput);
append(parent, box);
}
var hidden = node("input");
hidden.type = "hidden";
hidden.name = "payment_method";
hidden.value = defaultMethod;
append(parent, hidden);
}
// 卡密渠道显隐:选中 card_pass 时隐藏套餐(.charge-box)、显示卡密输入盒。
// 渠道显隐:通用 data-controller 契约(==/!= 匹配当前 payment_method);
// 选中 card_pass 时隐藏套餐(.charge-box),与参考主题 pay.js 行为一致。
function applyVipMethodVisibility(root) {
var pane = root.closest ? root.closest(".aksrt-vip-pane") : null;
pane = pane || root;
var value = selectedMethod(pane);
var cardBox = pane.querySelector('[data-controller="payment_method"][data-value="card_pass"]');
if (cardBox) cardBox.style.display = value === "card_pass" ? "" : "none";
pane.querySelectorAll('[data-controller="payment_method"]').forEach(function (el) {
var condition = el.getAttribute("data-condition") || "==";
var target = el.getAttribute("data-value") || "";
var match = condition === "!=" ? value !== target : value === target;
el.style.display = match ? "" : "none";
});
pane.querySelectorAll(".charge-box").forEach(function (el) {
el.style.display = value === "card_pass" ? "none" : "";
});
@@ -286,6 +318,7 @@
var groups = Array.isArray(catalog.level_packages) ? catalog.level_packages : [];
var methods = Array.isArray(view.payment_methods) ? view.payment_methods : [];
var cardPass = view.card_pass && view.card_pass.enabled ? view.card_pass : null;
var wallet = { balance: text(catalog.wallet_balance || "0.00"), mark: text(view.currency_mark || "¥") };
var allowed = view.allowed_actions || {};
var reasons = view.action_reasons || {};
var modal = node("div", "box-body payvip-modal");
@@ -365,12 +398,12 @@
var products = node("div", "pay-vip-products");
renderProducts(products, group.items);
renderMethods(products, methods);
renderMethods(products, methods, cardPass, wallet);
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 || "暂无可用支付方式"));
var submit = node("button", "mt6 but jb-red initiate-pay btn-block radius aksrt-vip-submit", canPurchase ? (group.items[0].cta_label || actionLabel(action)) : (reason || "暂无可用支付方式"));
submit.type = "button";
submit.disabled = !canPurchase;
submit.setAttribute("data-vip-submit", "");
@@ -401,12 +434,10 @@
}
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";
var hidden = root.querySelector('input[name="payment_method"]');
if (hidden && hidden.value) return hidden.value;
var first = root.querySelector('[data-for="payment_method"]');
return first ? first.getAttribute("data-value") : "balance";
}
function selectedPackage(root) {
@@ -538,12 +569,18 @@
function bindModalUi(root) {
if (!root || root.dataset.aksrtVipBound === "1") return;
root.dataset.aksrtVipBound = "1";
root.addEventListener("change", function (event) {
var input = event.target.closest ? event.target.closest('input[name="aksrt_vip_pay_method"]') : null;
if (!input) return;
applyVipMethodVisibility(input);
});
root.addEventListener("click", function (event) {
var methodItem = event.target.closest ? event.target.closest('[data-for="payment_method"]') : null;
if (methodItem) {
var pane = methodItem.closest(".aksrt-vip-pane") || root;
pane.querySelectorAll('[data-for="payment_method"]').forEach(function (el) {
el.classList.toggle("active", el === methodItem);
});
var hidden = pane.querySelector('input[name="payment_method"]');
if (hidden) hidden.value = methodItem.getAttribute("data-value") || "";
applyVipMethodVisibility(pane);
return;
}
var tab = event.target.closest("[data-vip-tab]");
if (tab) {
event.preventDefault();