Files
wordpress-theme-aksrt/assets/js/credits.js
T
kate522 5fd7c212ed fix(runtime): 按参考主题硬切换为 loader/main/auto_fun 单一 DOM 生命周期
- 删除 AksrtFrontend registry/rehydrate 双路架构及 build/public.js 拼包入口,
  前台唯一初始路径为 PHP 本地栈(jQuery 1.9.1 → Bootstrap 3.4.1)
  → loader_js(_win/aksrtData 唯一注入)→ tbquire(['main']) → runtime/main.min.js
- window.auto_fun = debounce(z_auto_fun, 100) 为唯一重扫入口;所有模块改为
  执行一次 + off/on('auto_fun.aksrt-*') 命名空间重扫,data/class 标记幂等
- 局部更新协议统一:HTML 注入 → post_ajax.ed → auto_fun();
  远程 modal → loaded.bs.modal → auto_fun();JSON 成功 → zib_ajax.success
- 灯箱恢复 Miniimgbox/imgbox 唯一 owner(imgbox-container、a[data-imgbox]、
  imgbox_data),删除 AksrtLightbox/data-aksrt-lightbox 第二实现及 CSS/overlay,
  _win.imgbox* 重新接上 post-display 设置
- 死代码清理:runtime 下 11 组被自有实现替代的旧模块副本、无消费 vendored 库、
  顶层 grade.min.js、revenue.js、无调用方的 aksrt_get_win_runtime_config(),
  以及 loader 中 16 条死 mapping
- PHP 入队改为本地栈 + loader_js,routed/widget/submit 依赖统一换绑;
  用户卡片发布按钮恢复 nav_user_newposts_btn 设置门控
- 测试对齐:新增 frontend-lifecycle-contract,重写 navigation/lazyload/toast/
  auth-source/comment/page-display/post-visual 等断言为目标架构契约

验证:node --test widget-system+navigation 223 通过 0 失败;
构建脚本重建 main/imgbox min 与 CSS bundles;改动 PHP php -l、JS node --check
全部通过;git diff --check 干净;credits 重入 harness 通过。
2026-09-03 12:44:31 +08:00

808 lines
32 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* AKSRT Credits Frontend
*
* 功能:
* - 签到 panel:跳转至全局签到按钮
* - revenue panel:拉取 /revenue/me,复制推广链接
*
* 仅在 page-profile 页面 + 启用积分时加载。
*/
(function () {
'use strict';
var aksrt = window.aksrtData;
if (!aksrt) {
return;
}
var activePoll = null;
function operationKey(owner) {
if (!owner.dataset.aksrtOperationKey) {
owner.dataset.aksrtOperationKey = window.AksrtRequest.createIdempotencyKey();
}
return owner.dataset.aksrtOperationKey;
}
function resetOperationKey(owner) {
delete owner.dataset.aksrtOperationKey;
}
function resetOperationKeyOnChange(owner) {
owner.addEventListener('input', function () { resetOperationKey(owner); });
owner.addEventListener('change', function () { resetOperationKey(owner); });
}
function balanceMinor(value) {
var match = /^(0|[1-9]\d*)(?:\.(\d{1,2}))?$/.exec(String(value || '').trim());
if (!match) return null;
return (BigInt(match[1]) * 100n) + BigInt((match[2] || '').padEnd(2, '0') || '0');
}
function api(path, options) {
return window.AksrtRequest.request(path, options || {}).then(function (response) {
return {
ok: response.ok,
status: response.status,
json: response.json || {},
data: response.data,
};
}).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 applyAssetBalances(data) {
data = data || {};
var wallet = data.wallet_balance !== undefined ? data.wallet_balance : data.wallet;
var points = data.credit_balance !== undefined ? data.credit_balance : data.points_balance;
if (wallet !== undefined && wallet !== null && wallet !== '') {
var walletNumber = Number(wallet);
var walletText = Number.isFinite(walletNumber) ? walletNumber.toFixed(2) : String(wallet);
document.querySelectorAll('[data-aksrt-wallet-value]').forEach(function (element) {
element.textContent = walletText;
});
}
if (points !== undefined && points !== null && points !== '') {
var pointsNumber = Number(points);
var pointsText = Number.isFinite(pointsNumber) ? pointsNumber.toLocaleString() : String(points);
document.querySelectorAll('[data-aksrt-points-value]').forEach(function (element) {
element.textContent = pointsText;
});
}
}
function refreshAssetBalances(snapshot) {
if (snapshot && (snapshot.wallet_balance !== undefined || snapshot.wallet !== undefined)) {
applyAssetBalances(snapshot);
}
return api('/pay/assets').then(function (response) {
if (!response.ok) return null;
var data = response.data || (response.json && response.json.data) || response.json || {};
applyAssetBalances(data);
return data;
});
}
// Task-list "去签到" → scroll + click the real asset-card sign-in button.
function initSigninGoto() {
document.querySelectorAll('[data-aksrt-signin-goto]').forEach(function (el) {
if (el.dataset.aksrtSigninGotoInitialized === '1') return;
el.dataset.aksrtSigninGotoInitialized = '1';
el.addEventListener('click', function (e) {
e.preventDefault();
var root = document.querySelector('[data-aksrt-signin]');
var btn = root ? root.querySelector('[data-signin-btn]') : null;
if (!btn) return;
try {
if (root && typeof root.scrollIntoView === 'function') {
root.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
} catch (_) {}
if (!btn.disabled) {
btn.click();
} else {
btn.focus();
}
});
});
}
// ===== Forward-only affiliate revenue center =====
function initAffiliateRevenue() {
var root = document.querySelector('[data-aksrt-revenue-page]');
if (!root || root.dataset.affiliateBound) return;
root.dataset.affiliateBound = '1';
var input = root.querySelector('[data-affiliate-link]');
var copy = root.querySelector('[data-affiliate-copy]');
var feedback = root.querySelector('[data-affiliate-feedback]');
function setFeedback(text, error) { if (feedback) { feedback.textContent = text; feedback.classList.toggle('is-error', !!error); } }
api('/revenue/me').then(function (r) {
if (!r.ok) { setFeedback((r.json && r.json.message) || '推广数据加载失败。', true); return; }
var j = r.json || {}, stats = j.stats || {};
if (input) {
input.value = j.url || '';
/* Keep the complete ref URL readable on desktop; mobile CSS still caps it. */
var linkLength = String(j.url || '').length;
input.setAttribute('size', String(Math.max(28, Math.min(96, linkLength || 28))));
input.style.width = Math.max(28, Math.min(96, linkLength || 28)) + 'ch';
}
if (copy) copy.disabled = !j.url;
var ratio = root.querySelector('[data-affiliate-ratio]'); if (ratio) ratio.textContent = String(j.current_ratio || 0) + '%';
var promoters = root.querySelector('[data-affiliate-promoters]'); if (promoters) promoters.textContent = String(stats.promoters || 0);
var payers = root.querySelector('[data-affiliate-payers]'); if (payers) payers.textContent = String(stats.effective_payers || 0);
}).catch(function () { setFeedback('推广数据加载失败。', true); });
if (copy) copy.addEventListener('click', function () {
if (!input || !input.value) return;
var done = function () { setFeedback('推广链接已复制。'); };
if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(input.value).then(done).catch(function () { input.focus(); input.select(); setFeedback('复制失败,请手动复制。', true); });
else { input.focus(); input.select(); try { document.execCommand('copy'); done(); } catch (e) { setFeedback('复制失败,请手动复制。', true); } }
});
}
window.AKSRTAffiliateRevenueInit = initAffiliateRevenue;
// ===== VIP 积分兑换 =====
function initVipPointsExchange() {
var root = document.querySelector('[data-aksrt-vip-points]');
if (!root) return;
var tip = root.querySelector('[data-aksrt-vip-points-tip]');
var busy = false;
var coordinator = window.AksrtVipPurchaseCoordinator;
function setTip(text, isError) {
if (!tip) return;
tip.textContent = text || '';
tip.classList.toggle('is-error', !!isError);
}
root.addEventListener('click', function (e) {
var btn = e.target.closest('[data-aksrt-vip-points-buy]');
if (!btn || busy || btn.disabled) return;
e.preventDefault();
var packageId = parseInt(btn.getAttribute('data-package-id') || '0', 10);
if (!packageId) return;
busy = true;
btn.classList.add('is-loading');
setTip('正在兑换…');
coordinator.exchange({
packageId: packageId,
tags: ['vip', 'orders']
}).then(function (r) {
busy = false;
btn.classList.remove('is-loading');
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.classList.remove('is-loading');
setTip('网络错误,请重试', true);
});
});
}
// ===== VIP 开通 =====
function initVipShop() {
var root = document.querySelector('[data-aksrt-vip-shop]');
if (!root) return;
var tip = root.querySelector('[data-aksrt-vip-tip]');
var busy = false;
var coordinator = window.AksrtVipPurchaseCoordinator;
function setTip(text, isError) {
if (!tip) return;
tip.textContent = text || '';
tip.classList.toggle('is-error', !!isError);
}
function selectedMethod() {
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';
}
root.addEventListener('click', function (e) {
var btn = e.target.closest('[data-aksrt-vip-buy]');
if (!btn || busy) return;
e.preventDefault();
var packageId = parseInt(btn.getAttribute('data-package-id') || '0', 10);
if (!packageId) return;
busy = true;
btn.disabled = true;
btn.classList.add('is-loading');
setTip('正在创建订单…');
coordinator.start({
packageId: packageId,
paymentMethod: selectedMethod(),
tags: ['vip', 'orders'],
onPending: function (data) {
busy = false;
btn.disabled = false;
btn.classList.remove('is-loading');
if (data.payment_url) window.open(data.payment_url, '_blank');
setTip(data.message || '请完成支付,支付成功后将自动刷新。');
},
onSuccess: function (result) {
busy = false;
btn.disabled = false;
btn.classList.remove('is-loading');
setTip((result.data && result.data.message) || '开通成功,正在刷新…');
window.location.reload();
},
onFailure: function () {
busy = false;
btn.disabled = false;
btn.classList.remove('is-loading');
setTip('支付未完成,请重试。', true);
},
onTimeout: function () {
busy = false;
btn.disabled = false;
btn.classList.remove('is-loading');
setTip('支付状态暂未确认,请稍后在订单中心查看。', true);
},
onError: function (response) {
busy = false;
btn.disabled = false;
btn.classList.remove('is-loading');
setTip((response.json && response.json.message) || '开通失败', true);
}
});
});
}
// ===== 卡密兑换(余额 / 会员) =====
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;
resetOperationKeyOnChange(root);
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',
headers: { 'Idempotency-Key': operationKey(root) },
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;
resetOperationKey(root);
if (type === 'vip' && window.AksrtModalRuntime && typeof window.AksrtModalRuntime.invalidate === 'function') {
window.AksrtModalRuntime.invalidate(['vip', 'orders']);
}
setTip((data && data.message) || '兑换成功,正在刷新…');
window.location.reload();
}).catch(function () {
busy = false;
btn.disabled = false;
setTip('网络错误,请重试', true);
});
});
});
}
// ===== 余额充值 / 转账 / 余额兑积分 =====
function openModal(el) {
if (!el) return;
el.hidden = false;
el.classList.add('is-open');
document.body.classList.add('uc-modal-open');
}
function closeModal(el) {
if (!el) return;
if (activePoll && typeof activePoll.abort === 'function') {
activePoll.abort();
notyf('已停止查询支付状态', 'warning', 3, 'aksrt-balance-charge-payment-toast');
}
activePoll = null;
el.hidden = true;
el.classList.remove('is-open');
if (!document.querySelector('.uc-modal.is-open')) {
document.body.classList.remove('uc-modal-open');
}
}
function pollPaidOrder(orderNumber, tags) {
var coordinator = window.AksrtVipPurchaseCoordinator;
if (!orderNumber) return;
notyf('等待支付结果…', 'load', '', 'aksrt-balance-charge-payment-toast');
var handle = coordinator.poll(orderNumber, {
tags: tags || ['credits', 'orders'],
onTerminal: function (result) {
activePoll = null;
if (result.success) {
notyf('支付成功,正在刷新…', 'success', 5, 'aksrt-balance-charge-payment-toast');
refreshAssetBalances();
window.setTimeout(function () { window.location.reload(); }, 800);
return;
}
var message = result.data && result.data.message ? result.data.message : '支付未完成,请重试';
notyf(message, 'danger', 5, 'aksrt-balance-charge-payment-toast');
},
onTimeout: function () {
activePoll = null;
notyf('支付状态暂未确认,请稍后在订单中心查看', 'danger', 5, 'aksrt-balance-charge-payment-toast');
}
});
return handle;
}
function initBalanceCharge() {
var modal = document.querySelector('[data-aksrt-charge-modal]');
if (!modal || modal.dataset.aksrtChargeInitialized === '1') return;
modal.dataset.aksrtChargeInitialized = '1';
var form = modal.querySelector('[data-aksrt-charge-form]');
var busy = false;
document.querySelectorAll('[data-aksrt-charge-open]').forEach(function (btn) {
btn.addEventListener('click', function () { openModal(modal); });
});
modal.querySelectorAll('[data-aksrt-charge-close]').forEach(function (btn) {
btn.addEventListener('click', function () {
closeModal(modal);
});
});
modal.querySelectorAll('.uc-charge-package input').forEach(function (inp) {
inp.addEventListener('change', function () {
modal.querySelectorAll('.uc-charge-package').forEach(function (el) {
el.classList.toggle('is-active', el.contains(inp) && inp.checked);
});
});
});
if (!form) return;
resetOperationKeyOnChange(form);
form.addEventListener('submit', function (e) {
e.preventDefault();
if (busy) return;
var pkgInput = form.querySelector('input[name="balance_package"]:checked') || form.querySelector('input[name="balance_package"]');
var pkg = pkgInput ? pkgInput.value : 'custom';
var customEl = form.querySelector('input[name="custom_price"]');
var custom = customEl ? String(customEl.value || '').trim() : '';
var validCustom = /^(0|[1-9]\d*)(?:\.\d{1,2})?$/.test(custom) && custom !== '0' && custom !== '0.0' && custom !== '0.00';
if (validCustom) {
pkg = 'custom';
}
if ((!pkg || pkg === 'custom') && !validCustom && !pkgInput) {
notyf('请选择或输入充值金额', 'danger');
return;
}
if (pkg === 'custom' && !validCustom) {
notyf('请输入有效充值金额', 'danger');
return;
}
var methodEl = form.querySelector('input[name="payment_method"]:checked');
var method = methodEl ? methodEl.value : 'alipay';
busy = true;
notyf('正在创建充值订单…', 'load', '', 'aksrt-balance-charge-toast');
api('/pay/balance/charge', {
method: 'POST',
headers: { 'Idempotency-Key': operationKey(form) },
body: JSON.stringify({
package: pkg,
custom_price: custom,
payment_method: method
})
}).then(function (r) {
busy = false;
if (!r.ok || (r.json && r.json.code && !r.json.success)) {
notyf((r.json && r.json.message) || '充值失败', 'danger', 5, 'aksrt-balance-charge-toast');
return;
}
var data = (r.json && r.json.data) ? r.json.data : r.json;
resetOperationKey(form);
if (data && data.redirect && (data.payment_url || data.qr_content)) {
if (data.payment_url) window.open(data.payment_url, '_blank');
notyf(data.message || '请完成支付,支付成功后将自动刷新。', 'info', 5, 'aksrt-balance-charge-toast');
if (data.order_number) activePoll = pollPaidOrder(data.order_number, ['credits', 'orders']);
return;
}
notyf((data && data.message) || '充值成功,正在刷新…', 'success', 5, 'aksrt-balance-charge-toast');
refreshAssetBalances(data);
window.setTimeout(function () { window.location.reload(); }, 800);
}).catch(function () {
busy = false;
notyf('网络错误,请重试', 'danger', 5, 'aksrt-balance-charge-toast');
});
});
}
function initTransfer() {
var modal = document.querySelector('[data-aksrt-transfer-modal]');
if (!modal || modal.dataset.aksrtTransferInitialized === '1') return;
modal.dataset.aksrtTransferInitialized = '1';
var form = modal.querySelector('[data-aksrt-transfer-form]');
var results = modal.querySelector('[data-aksrt-transfer-results]');
var selected = modal.querySelector('[data-aksrt-transfer-selected]');
var recipientInput = modal.querySelector('[data-aksrt-transfer-recipient]');
var typeInput = modal.querySelector('[data-aksrt-transfer-type]');
var title = modal.querySelector('[data-aksrt-transfer-title]');
var amountLabel = modal.querySelector('[data-aksrt-transfer-amount-label]');
var balanceInfo = modal.querySelector('[data-aksrt-transfer-balance-info]');
var pointsInfo = modal.querySelector('[data-aksrt-transfer-points-info]');
var pointsTransferMin = 1;
var searchTimer = null;
var busy = false;
document.querySelectorAll('[data-aksrt-transfer-open]').forEach(function (btn) {
btn.addEventListener('click', function () {
var type = btn.getAttribute('data-aksrt-transfer-open') || 'balance';
pointsTransferMin = type === 'points'
? Math.max(1, parseInt(btn.getAttribute('data-aksrt-transfer-min') || '1', 10) || 1)
: 1;
if (typeInput) typeInput.value = type;
if (title) title.textContent = type === 'points' ? '积分转账' : '余额转账';
var amountEl = form ? form.querySelector('[data-aksrt-transfer-amount]') : null;
if (amountEl) {
amountEl.min = type === 'points' ? String(pointsTransferMin) : '0.01';
amountEl.step = type === 'points' ? '1' : '0.01';
amountEl.inputMode = type === 'points' ? 'numeric' : 'decimal';
amountEl.value = '';
}
if (amountLabel) amountLabel.textContent = type === 'points' ? '积分' : '金额';
if (balanceInfo) balanceInfo.hidden = type === 'points';
if (pointsInfo) pointsInfo.hidden = type !== 'points';
if (results) results.innerHTML = '';
if (selected) selected.textContent = '';
if (recipientInput) recipientInput.value = '';
openModal(modal);
});
});
modal.querySelectorAll('[data-aksrt-transfer-close]').forEach(function (btn) {
btn.addEventListener('click', function () { closeModal(modal); });
});
var searchEl = modal.querySelector('[data-aksrt-transfer-search]');
if (searchEl) {
searchEl.addEventListener('input', function () {
var q = String(searchEl.value || '').trim();
if (searchTimer) clearTimeout(searchTimer);
if (q.length < 1) {
if (results) results.innerHTML = '';
return;
}
searchTimer = setTimeout(function () {
api('/pay/transfer/search?s=' + encodeURIComponent(q)).then(function (r) {
if (!results) return;
results.innerHTML = '';
if (!r.ok) {
notyf((r.json && r.json.message) || '用户搜索失败', 'danger');
return;
}
var data = (r.json && r.json.data) ? r.json.data : r.json;
var users = (data && data.users) || [];
if (!users.length) {
results.innerHTML = '<div class="muted-2-color em09">未找到相关用户</div>';
return;
}
users.forEach(function (u) {
var item = document.createElement('button');
item.type = 'button';
item.className = 'uc-transfer-user';
item.innerHTML = '<img' + window.aksrtGetLazyImageAttr('lazy_avatar', u.avatar || '', 'uc-transfer-user__avatar', 'sm') + ' alt=""><span>' + (u.display_name || u.user_login) + '</span><span class="muted-2-color em09">@' + (u.user_login || '') + '</span>';
item.addEventListener('click', function () {
if (recipientInput) recipientInput.value = String(u.id);
if (selected) selected.textContent = '已选择:' + (u.display_name || u.user_login);
results.innerHTML = '';
});
results.appendChild(item);
});
});
}, 280);
});
}
if (!form) return;
resetOperationKeyOnChange(form);
form.addEventListener('submit', function (e) {
e.preventDefault();
if (busy) return;
var type = typeInput ? typeInput.value : 'balance';
var recipient = recipientInput ? parseInt(recipientInput.value || '0', 10) : 0;
var amountEl = form.querySelector('[data-aksrt-transfer-amount]');
var amount = amountEl ? amountEl.value : 0;
if (!recipient) {
notyf('请选择收款用户', 'danger');
return;
}
var pointsAmount = /^[1-9]\d*$/.test(String(amount)) ? BigInt(String(amount)) : 0n;
var cashAmount = balanceMinor(amount);
var validAmount = type === 'points'
? pointsAmount >= BigInt(pointsTransferMin) && pointsAmount <= BigInt(Number.MAX_SAFE_INTEGER)
: cashAmount !== null && cashAmount > 0n;
if (!validAmount) {
notyf('请输入有效金额', 'danger');
return;
}
busy = true;
notyf('正在转账…', 'load', '', 'aksrt-balance-transfer-toast');
api('/pay/transfer', {
method: 'POST',
headers: { 'Idempotency-Key': operationKey(form) },
body: JSON.stringify({
type: type,
recipient: recipient,
amount: type === 'points' ? Number(pointsAmount) : String(amount)
})
}).then(function (r) {
busy = false;
if (!r.ok || (r.json && r.json.code && !r.json.success)) {
notyf((r.json && r.json.message) || '转账失败', 'danger', 5, 'aksrt-balance-transfer-toast');
return;
}
var data = (r.json && r.json.data) ? r.json.data : r.json;
resetOperationKey(form);
notyf((data && data.message) || '转账成功,正在刷新…', 'success', 5, 'aksrt-balance-transfer-toast');
refreshAssetBalances();
window.setTimeout(function () { window.location.reload(); }, 800);
}).catch(function () {
busy = false;
notyf('网络错误,请重试', 'danger', 5, 'aksrt-balance-transfer-toast');
});
});
}
function initPointsExchange() {
var modal = document.querySelector('[data-aksrt-points-exchange-modal]');
if (!modal || modal.dataset.aksrtPointsExchangeInitialized === '1') return;
modal.dataset.aksrtPointsExchangeInitialized = '1';
var form = modal.querySelector('[data-aksrt-points-exchange-form]');
var amountEl = form ? form.querySelector('[data-aksrt-points-exchange-amount]') : null;
var preview = form ? form.querySelector('[data-aksrt-points-exchange-preview]') : null;
var busy = false;
document.querySelectorAll('[data-aksrt-points-exchange-open]').forEach(function (btn) {
btn.addEventListener('click', function () { openModal(modal); });
});
modal.querySelectorAll('[data-aksrt-points-exchange-close]').forEach(function (btn) {
btn.addEventListener('click', function () { closeModal(modal); });
});
if (!form) return;
resetOperationKeyOnChange(form);
function updatePreview() {
if (!preview || !amountEl) return;
var amount = balanceMinor(amountEl.value);
var rateRaw = amountEl.getAttribute('data-aksrt-points-exchange-rate') || '';
var rate = /^[1-9]\d*$/.test(rateRaw) ? BigInt(rateRaw) : 0n;
var scaled = amount !== null ? amount * rate : 0n;
preview.textContent = amount !== null && amount > 0n && rate > 0n && scaled % 100n === 0n
? '预计获得 ' + String(scaled / 100n) + ' 积分'
: '';
}
amountEl.addEventListener('input', updatePreview);
updatePreview();
form.addEventListener('submit', function (e) {
e.preventDefault();
if (busy) return;
var amount = amountEl ? String(amountEl.value || '').trim() : '';
if (!/^(0|[1-9]\d*)(?:\.\d{1,2})?$/.test(amount) || /^0(?:\.0{1,2})?$/.test(amount)) {
notyf('请输入最多两位小数的正数余额', 'danger');
return;
}
busy = true;
notyf('正在购买积分…', 'load', '', 'aksrt-balance-points-toast');
api('/pay/balance/points-exchange', {
method: 'POST',
headers: { 'Idempotency-Key': operationKey(form) },
body: JSON.stringify({ amount: amount })
}).then(function (r) {
busy = false;
if (!r.ok || (r.json && r.json.code && !r.json.success)) {
notyf((r.json && r.json.message) || '购买失败', 'danger', 5, 'aksrt-balance-points-toast');
return;
}
var data = (r.json && r.json.data) ? r.json.data : r.json;
resetOperationKey(form);
notyf((data && data.message) || '购买成功,正在刷新…', 'success', 5, 'aksrt-balance-points-toast');
refreshAssetBalances(data);
window.setTimeout(function () { window.location.reload(); }, 800);
}).catch(function () {
busy = false;
notyf('网络错误,请重试', 'danger', 5, 'aksrt-balance-points-toast');
});
});
}
function initWithdraw() {
var modal = document.querySelector('[data-aksrt-withdraw-modal]');
if (!modal || modal.dataset.aksrtWithdrawInitialized === '1') return;
modal.dataset.aksrtWithdrawInitialized = '1';
var form = modal.querySelector('[data-aksrt-withdraw-form]');
var busy = false;
document.querySelectorAll('[data-aksrt-withdraw-open]').forEach(function (btn) {
btn.addEventListener('click', function () { openModal(modal); });
});
modal.querySelectorAll('[data-aksrt-withdraw-close]').forEach(function (btn) {
btn.addEventListener('click', function () { closeModal(modal); });
});
if (!form) return;
resetOperationKeyOnChange(form);
form.addEventListener('submit', function (e) {
e.preventDefault();
if (busy) return;
var amountEl = form.querySelector('[data-aksrt-withdraw-amount]');
var methodEl = form.querySelector('[data-aksrt-withdraw-method]');
var accountEl = form.querySelector('[data-aksrt-withdraw-account]');
var rawAmount = amountEl ? String(amountEl.value || '').trim() : '';
var amount = rawAmount;
var amountMinor = balanceMinor(amount);
var minAmount = amountEl ? balanceMinor(amountEl.getAttribute('data-withdraw-min') || '0') : 0n;
var remainingAmount = amountEl ? balanceMinor(amountEl.getAttribute('data-withdraw-remaining-amount') || '0') : 0n;
var remainingCount = amountEl ? Number(amountEl.getAttribute('data-withdraw-remaining-count') || '0') : 0;
var method = methodEl ? methodEl.value : 'alipay';
var account = accountEl ? String(accountEl.value || '').trim() : '';
if (amountMinor === null || amountMinor <= 0n) {
notyf('提现金额必须为最多两位小数的正数', 'danger');
return;
}
if (minAmount === null || amountMinor < minAmount) {
notyf('提现金额低于最低提现门槛', 'danger');
return;
}
if (remainingCount <= 0) {
notyf('当日提现次数已用尽', 'danger');
return;
}
if (remainingAmount === null || amountMinor > remainingAmount) {
notyf('本次提现后将超出单日提现总额上限', 'danger');
return;
}
if (!account) {
notyf('请填写收款账号信息', 'danger');
return;
}
busy = true;
notyf('正在提交提现申请…', 'load', '', 'aksrt-balance-withdraw-toast');
api('/earnings/withdrawals', {
method: 'POST',
headers: { 'Idempotency-Key': operationKey(form) },
body: JSON.stringify({ amount: amount, method: method, account: account })
}).then(function (r) {
busy = false;
if (!r.ok || (r.json && r.json.code && !r.json.success)) {
notyf((r.json && r.json.message) || '提现失败', 'danger', 5, 'aksrt-balance-withdraw-toast');
return;
}
var data = (r.json && r.json.data) ? r.json.data : r.json;
resetOperationKey(form);
var successMessage = (data && data.message) || '申请已提交';
if (data && data.withdrawal_number) successMessage += '(' + data.withdrawal_number + ')';
notyf(successMessage, 'success', 5, 'aksrt-balance-withdraw-toast');
closeModal(modal);
var panel = modal.closest ? modal.closest('.dashboard-panel') : null;
panel = panel || document.getElementById('panel-credits');
var rest = (window.aksrtData && (window.aksrtData.restUrl || window.aksrtData.apiUrl)) || (window.aksrtUserCenter && window.aksrtUserCenter.restUrl) || '';
if (panel && rest) {
fetch(rest.replace(/\/$/, '') + '/user-center/panel/credits', { credentials: 'same-origin', headers: { 'X-WP-Nonce': (window.aksrtData && (window.aksrtData.restNonce || window.aksrtData.nonce)) || '' } })
.then(function (response) { return response.json(); })
.then(function (payload) {
if (!payload || !payload.success || !payload.data || typeof payload.data.html !== 'string') return;
panel.innerHTML = payload.data.html;
if (window.jQuery) jQuery(document).trigger('post_ajax.ed', [panel]);
if (typeof window.auto_fun === 'function') window.auto_fun();
});
}
}).catch(function () {
busy = false;
notyf('网络错误,请重试', 'danger', 5, 'aksrt-balance-withdraw-toast');
});
});
}
function initAssetTabs() {
var nav = document.querySelectorAll('[data-aksrt-asset-tab]');
if (!nav.length) return;
nav.forEach(function (link) {
if (link.dataset.aksrtAssetTabBound === 'true') return;
link.dataset.aksrtAssetTabBound = 'true';
link.addEventListener('click', function (e) {
e.preventDefault();
var key = link.getAttribute('data-aksrt-asset-tab');
document.querySelectorAll('.uc-asset-tabs__nav [data-aksrt-asset-tab]').forEach(function (a) {
var li = a.closest('li');
if (!li) return;
var aKey = a.getAttribute('data-aksrt-asset-tab');
var on = aKey === key || (key === 'points_date' && aKey === 'points_free');
li.classList.toggle('active', on);
});
var tabs = document.querySelector('.uc-asset-tabs');
if (tabs && typeof tabs.scrollIntoView === 'function') {
tabs.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
document.querySelectorAll('[data-aksrt-asset-pane]').forEach(function (pane) {
var on = pane.getAttribute('data-aksrt-asset-pane') === key;
pane.classList.toggle('is-active', on);
pane.hidden = !on;
});
});
});
}
function initWithdrawHistory() {
var modal = document.querySelector('[data-aksrt-withdraw-history-modal]');
if (!modal || modal.dataset.aksrtWithdrawHistoryInitialized === '1') return;
modal.dataset.aksrtWithdrawHistoryInitialized = '1';
function open() { modal.hidden = false; document.body.classList.add('uc-modal-open'); }
function close() { modal.hidden = true; document.body.classList.remove('uc-modal-open'); }
document.querySelectorAll('[data-aksrt-withdraw-history-open]').forEach(function (btn) {
btn.addEventListener('click', function (e) { e.preventDefault(); open(); });
});
modal.querySelectorAll('[data-aksrt-withdraw-history-close]').forEach(function (btn) {
btn.addEventListener('click', function (e) { e.preventDefault(); close(); });
});
}
window.AKSRTWithdrawInit = initWithdraw;
window.AKSRTAssetBalances = {
apply: applyAssetBalances,
refresh: refreshAssetBalances
};
function bootAssets() {
refreshAssetBalances();
initSigninGoto();
initAffiliateRevenue();
initVipShop();
initVipPointsExchange();
initCardPass();
initBalanceCharge();
initTransfer();
initPointsExchange();
initWithdraw();
initWithdrawHistory();
initAssetTabs();
}
jQuery(document).off('auto_fun.aksrt-credits').on('auto_fun.aksrt-credits', function () {
bootAssets();
});
})();