feat(pay): card-pass redeem for VIP and balance (zibll-style)

Rewrite charge-card into typed single-use card_pass inventory with public redeem REST, user-center UI for balance/VIP, admin type-aware create/batch, and CAS mark-used fulfillment via Credits/activate_vip.
This commit is contained in:
kate522 committed 2026-07-14 20:13:46 +08:00
1 parent 5d7b138c2c
commit d34c954b83
14 files changed
+936 -132

No files matched your search

+68 -1
View File
@@ -442,17 +442,84 @@
});
}
// ===== 卡密兑换(余额 / 会员) =====
function initCardPass() {
var roots = document.querySelectorAll('[data-aksrt-card-pass]');
if (!roots || !roots.length) return;
Array.prototype.forEach.call(roots, function (root) {
var tip = root.querySelector('[data-aksrt-card-tip]');
var busy = false;
function setTip(text, isError) {
if (!tip) return;
tip.textContent = text || '';
tip.classList.toggle('is-error', !!isError);
}
var btn = root.querySelector('[data-aksrt-card-redeem]');
if (!btn) return;
btn.addEventListener('click', function () {
if (busy || btn.disabled) return;
var type = btn.getAttribute('data-type') || root.getAttribute('data-aksrt-card-pass') || '';
var pwInput = root.querySelector('[data-aksrt-card-password]');
var cardInput = root.querySelector('[data-aksrt-card-no]');
var password = pwInput ? String(pwInput.value || '').trim() : '';
var card = cardInput ? String(cardInput.value || '').trim() : '';
if (!password) {
setTip('请输入卡密', true);
if (pwInput) pwInput.focus();
return;
}
if (cardInput && !card) {
setTip('请输入卡号', true);
cardInput.focus();
return;
}
busy = true;
btn.disabled = true;
setTip('正在兑换…');
var body = { password: password, type: type };
if (card) body.card = card;
api('/pay/card-pass/redeem', {
method: 'POST',
body: JSON.stringify(body)
}).then(function (r) {
busy = false;
btn.disabled = false;
if (!r.ok || (r.json && r.json.code && !r.json.success)) {
setTip((r.json && r.json.message) || '兑换失败', true);
return;
}
var data = (r.json && r.json.data) ? r.json.data : r.json;
setTip((data && data.message) || '兑换成功,正在刷新…');
window.location.reload();
}).catch(function () {
busy = false;
btn.disabled = false;
setTip('网络错误,请重试', true);
});
});
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
initSignin();
initInvite();
initVipShop();
initVipPointsExchange();
initVipPointsExchange();
initCardPass();
});
} else {
initSignin();
initInvite();
initVipShop();
initVipPointsExchange();
initCardPass();
}
})();