/** * 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 formatCutCount(value) { var number = Number(value); if (!Number.isFinite(number)) return String(value); if (number > 999999) return String(Math.round(number / 10000)) + 'W+'; if (number > 9999) return String(Math.round(number / 1000) / 10) + 'W+'; return String(number); } 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.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : String(wallet); document.querySelectorAll('[data-aksrt-wallet-value]').forEach(function (element) { var text = element.dataset.aksrtCountFormat === 'cut-count' ? formatCutCount(wallet) : walletText; element.textContent = text; element.title = text; }); } 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) { var text = element.dataset.aksrtCountFormat === 'cut-count' ? formatCutCount(points) : pointsText; element.textContent = text; element.title = text; }); } } 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 ===== /* 推广链接由 PHP 直出,首屏即可见、可复制;这里只补异步才拿得到的 * 海报配置与佣金比例,取失败也不影响复制。 */ 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 url = input ? input.value : ''; if (copy) copy.disabled = !url; api('/revenue/me').then(function (r) { if (!r.ok) return; var j = r.json || {}; var ratio = root.querySelector('[data-affiliate-ratio]'); if (ratio) ratio.textContent = String(j.current_ratio || 0) + '%'; initAffiliatePoster(root, url || j.url || '', j.poster || {}, j.site_name || document.title); }).catch(function () { /* 海报与比例为增强项,静默失败即可。 */ }); if (copy) copy.addEventListener('click', function () { if (!input || !input.value) return; var done = function () { notyf('推广链接已复制', 'success', 3, 'aksrt-affiliate-copy-toast'); }; var fail = function () { input.focus(); input.select(); notyf('复制失败,请手动复制', 'danger', 3, 'aksrt-affiliate-copy-toast'); }; if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(input.value).then(done).catch(fail); else { input.focus(); input.select(); try { document.execCommand('copy'); done(); } catch (e) { fail(); } } }); } // ===== Referral poster (canvas preview modal: hero image + copy + QR + link) ===== function initAffiliatePoster(root, url, poster, siteName) { var button = root.querySelector('[data-affiliate-poster]'); var modal = document.querySelector('[data-aksrt-affiliate-poster-modal]'); var stage = document.querySelector('[data-affiliate-poster-stage]'); var download = document.querySelector('[data-affiliate-poster-download]'); if (!button || !modal) return; if (!url || !poster || poster.enabled !== true) return; button.hidden = false; [].forEach.call(modal.querySelectorAll('[data-affiliate-poster-close]'), function (closer) { closer.addEventListener('click', function () { closeModal(modal); }); }); var canvas = null; if (download) { download.addEventListener('click', function () { if (!canvas) return; try { var link = document.createElement('a'); link.download = 'referral-poster.png'; link.href = canvas.toDataURL('image/png'); document.body.appendChild(link); link.click(); link.remove(); } catch (err) { /* Canvas is same-origin generated; download can only fail if the browser blocks it. */ } }); } button.addEventListener('click', function () { if (typeof window.qrcode !== 'function') { if (stage) { stage.innerHTML = '

' + '二维码组件未加载。' + '

'; } openModal(modal); return; } if (stage) { stage.innerHTML = '

' + '正在生成海报…' + '

'; } if (download) download.hidden = true; openModal(modal); button.disabled = true; buildPosterCanvas(url, poster, siteName).then(function (built) { canvas = built; if (stage) { stage.innerHTML = ''; stage.appendChild(built); } if (download) download.hidden = false; }).catch(function () { if (stage) { stage.innerHTML = '

' + '海报生成失败,请重试。' + '

'; } }).finally(function () { button.disabled = false; }); }); } // 参考主题 poster-share.js 布局 1:1:768×1168,顶部主图占上半屏, // 左上角日期,标题竖蓝线 + 标题,正文,底部带边框盒(logo/站名 + 二维码 + 链接)。 function buildPosterCanvas(url, poster, siteName) { var width = 768, height = 1168; var canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; var ctx = canvas.getContext('2d'); ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, width, height); var loadImage = null; if (poster.image) { loadImage = new Promise(function (resolve) { var image = new Image(); image.crossOrigin = 'anonymous'; image.onload = function () { resolve(image); }; image.onerror = function () { resolve(null); }; image.src = poster.image; }); } else { loadImage = Promise.resolve(null); } return loadImage.then(function (image) { var imgHeight = height / 2; // 参考主题 rebate(非 product):顶部主图占上半屏。 // 顶部主图(cover 裁切)或纯色占位。 if (image && image.width && image.height) { var rect = coverRect(width, imgHeight, image.width, image.height); ctx.drawImage(image, rect.sx, rect.sy, rect.sWidth, rect.sHeight, 0, 0, width, imgHeight); } else { ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, width, imgHeight); } // 左上角日期(白字,覆盖在主图上)。 var now = new Date(); var week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; ctx.textBaseline = 'top'; ctx.textAlign = 'left'; ctx.fillStyle = 'rgba(255,255,255,0.95)'; ctx.font = 'bold 35px Arial, sans-serif'; ctx.fillText(week[now.getDay()], 40, 35); ctx.font = '28px Arial, sans-serif'; ctx.fillText((now.getMonth() + 1) + ' / ' + now.getDate(), 40, 88); // 标题竖蓝线。 ctx.strokeStyle = '#00a1ff'; ctx.lineWidth = 7; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(40, imgHeight + 38); ctx.lineTo(40, imgHeight + 74); ctx.stroke(); // 标题(粗体,最多 2 行)。 ctx.fillStyle = '#424242'; ctx.font = 'bold 35px Arial, sans-serif'; var titleLines = wrapText(ctx, String(poster.title || siteName || ''), width - 100).slice(0, 2); var cursorY = imgHeight + 40; for (var t = 0; t < titleLines.length; t++) { ctx.fillText(titleLines[t], 60, cursorY); cursorY += 52; } // 正文(简介,最多 3 行)。 var description = String(poster.description || ''); if (description) { ctx.fillStyle = '#585858'; ctx.font = '25px Arial, sans-serif'; var lines = wrapText(ctx, description, width - 80).slice(0, 3); var contentY = imgHeight + 160; for (var i = 0; i < lines.length; i++) { ctx.fillText(lines[i], 40, contentY); contentY += 38; } } // 底部带边框盒。 ctx.strokeStyle = 'rgba(122,122,122,0.2)'; ctx.lineWidth = 2; ctx.strokeRect(30, height - 230, width - 60, 200); // 站点名(logo 位,左侧)。 ctx.fillStyle = '#424242'; ctx.font = 'bold 30px Arial, sans-serif'; ctx.fillText(String(siteName || ''), 80, height - 175); ctx.fillStyle = '#94a3b8'; ctx.font = '20px Arial, sans-serif'; ctx.fillText('长按识别二维码访问', 80, height - 130); // 二维码(右下)。 var qr = window.qrcode(0, 'M'); qr.addData(url); qr.make(); var count = qr.getModuleCount(); var qrBox = 120; var cell = qrBox / count; var qrX = width - 200, qrY = height - 200; ctx.fillStyle = '#0f172a'; for (var r = 0; r < count; r++) { for (var c = 0; c < count; c++) { if (qr.isDark(r, c)) { ctx.fillRect(qrX + Math.floor(c * cell), qrY + Math.floor(r * cell), Math.ceil(cell), Math.ceil(cell)); } } } // 底部链接(居中)。 ctx.textAlign = 'center'; ctx.fillStyle = '#b4b4b4'; ctx.font = '22px Arial, sans-serif'; ctx.fillText(String(url).slice(0, 46), width / 2, height - 46); ctx.textAlign = 'left'; return canvas; }); } // cover 裁切:把源图按短边铺满目标框并居中裁切。 function coverRect(boxW, boxH, srcW, srcH) { var sx = 0, sy = 0, sWidth = srcW, sHeight = srcH; if (srcW / srcH > boxW / boxH) { sWidth = (boxW * srcH) / boxH; sx = (srcW - sWidth) / 2; } else { sHeight = (boxH * srcW) / boxW; sy = (srcH - sHeight) / 2; } return { sx: sx, sy: sy, sWidth: sWidth, sHeight: sHeight }; } function wrapText(ctx, text, maxWidth) { var lines = []; var current = ''; for (var i = 0; i < text.length; i++) { if (ctx.measureText(current + text[i]).width > maxWidth && current) { lines.push(current); current = text[i]; } else { current += text[i]; } } if (current) lines.push(current); return lines; } window.AKSRTAffiliateRevenueInit = initAffiliateRevenue; // ===== 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 redeemCardPass(type, card, password, keyOwner, toastId) { var body = { password: password, type: type }; if (card) body.card = card; return api('/pay/card-pass/redeem', { method: 'POST', headers: { 'Idempotency-Key': operationKey(keyOwner) }, body: JSON.stringify(body) }).then(function (r) { if (!r.ok || (r.json && r.json.code && !r.json.success)) { return { ok: false, message: (r.json && r.json.message) || '兑换失败' }; } var data = (r.json && r.json.data) ? r.json.data : r.json; resetOperationKey(keyOwner); if (type === 'vip' && window.AksrtModalRuntime && typeof window.AksrtModalRuntime.invalidate === 'function') { window.AksrtModalRuntime.invalidate(['vip', 'orders']); } notyf((data && data.message) || '兑换成功,正在刷新…', 'success', 5, toastId); window.setTimeout(function () { window.location.reload(); }, 800); return { ok: true }; }).catch(function () { return { ok: false, message: '网络错误,请重试' }; }); } // ===== 余额充值 / 转账 / 余额兑积分 ===== 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; var chargeBackdrop = null; // 开关自包含:不复依赖 jQuery/Bootstrap modal 运行时,行为与视觉 // 复刻 Bootstrap 3(.in 显隐 + .modal-backdrop + body.modal-open + ESC)。 function openChargeModal() { if (modal.classList.contains('in')) return; // 兼容旧缓存标记(uc-modal 带 hidden 属性) modal.removeAttribute('hidden'); // 打开态用 flex 而非 block:壳的 .flex.jc 负责双轴居中, // .modal.flex .modal-dialog{margin:0} 在 block 下会把对话框顶到左上角。 modal.style.display = 'flex'; void modal.offsetWidth; // 强制 reflow,让 .fade 过渡从初始态开始 modal.classList.add('in'); if (!chargeBackdrop) { chargeBackdrop = document.createElement('div'); chargeBackdrop.className = 'modal-backdrop fade in'; chargeBackdrop.setAttribute('data-aksrt-charge-backdrop', '1'); document.body.appendChild(chargeBackdrop); } document.body.classList.add('modal-open'); } function closeChargeModal() { if (!modal.classList.contains('in')) return; if (activePoll && typeof activePoll.abort === 'function') { activePoll.abort(); notyf('已停止查询支付状态', 'warning', 3, 'aksrt-balance-charge-payment-toast'); } activePoll = null; modal.classList.remove('in'); document.body.classList.remove('modal-open'); if (chargeBackdrop && chargeBackdrop.parentNode) { chargeBackdrop.parentNode.removeChild(chargeBackdrop); } chargeBackdrop = null; // 等过渡结束再撤 display,复刻 Bootstrap 的 fade-out 收尾 window.setTimeout(function () { if (!modal.classList.contains('in')) { modal.style.display = ''; } }, 300); } document.querySelectorAll('[data-aksrt-charge-open]').forEach(function (btn) { btn.addEventListener('click', openChargeModal); }); modal.addEventListener('click', function (e) { // 点遮罩层(.modal 自身)或关闭按钮(data-dismiss="modal") if (e.target === modal || (e.target.closest && e.target.closest('[data-dismiss="modal"]'))) { closeChargeModal(); } }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && modal.classList.contains('in')) { closeChargeModal(); } }); // Zibll data-for/data-value 选中模型:余额档位(.vip-product.product-box) // 选中变化不产生 change 事件(隐藏 input 由程序赋值),需显式重置幂等键。 var customInput = modal.querySelector('input[name="custom_price"]'); function selectProduct(value) { modal.querySelectorAll('[data-for="balance_product"]').forEach(function (el) { el.classList.toggle('active', el.getAttribute('data-value') === value); }); var hidden = modal.querySelector('input[name="balance_product"]'); if (hidden) hidden.value = value; // 选中预设档位即代表放弃自定义金额:清空输入框,否则框里残留的数字会在 // 提交时按「合法自定义金额」把 package 顶回 custom,静默覆盖刚点的档位。 if (value !== 'custom' && customInput) { customInput.value = ''; } if (form) resetOperationKey(form); } modal.querySelectorAll('[data-for="balance_product"]').forEach(function (el) { el.addEventListener('click', function () { selectProduct(el.getAttribute('data-value')); }); }); if (customInput) { customInput.addEventListener('input', function () { if (String(customInput.value || '').trim() !== '') { selectProduct('custom'); } }); } // 支付方式(.payment-method-radio);卡密渠道选中时隐藏金额选择、 // 显示卡密输入盒(data-controller="payment_method" 契约与参考主题一致)。 function cardPassBox() { return modal.querySelector('[data-controller="payment_method"][data-value="card_pass"]'); } function applyMethodVisibility(value) { var cardBox = cardPassBox(); if (cardBox) cardBox.style.display = value === 'card_pass' ? '' : 'none'; var chargeBoxes = modal.querySelectorAll('.charge-box'); chargeBoxes.forEach(function (el) { el.style.display = value === 'card_pass' ? 'none' : ''; }); } function selectMethod(value) { modal.querySelectorAll('[data-for="payment_method"]').forEach(function (el) { el.classList.toggle('active', el.getAttribute('data-value') === value); }); var hidden = modal.querySelector('input[name="payment_method"]'); if (hidden) hidden.value = value; applyMethodVisibility(value); if (form) resetOperationKey(form); } modal.querySelectorAll('[data-for="payment_method"]').forEach(function (el) { el.addEventListener('click', function () { selectMethod(el.getAttribute('data-value')); }); }); applyMethodVisibility((modal.querySelector('input[name="payment_method"]') || {}).value || ''); if (!form) return; resetOperationKeyOnChange(form); form.addEventListener('submit', function (e) { e.preventDefault(); if (busy) return; var methodEl = form.querySelector('input[name="payment_method"]'); var method = methodEl ? methodEl.value : ''; if (!method) { notyf('暂无可用支付方式', 'danger'); return; } if (method === 'card_pass') { var cardEl = form.querySelector('input[name="card_pass[card]"]'); var pwEl = form.querySelector('input[name="card_pass[password]"]'); var password = pwEl ? String(pwEl.value || '').trim() : ''; if (!password) { notyf('请输入卡密', 'danger'); if (pwEl) pwEl.focus(); return; } busy = true; notyf('正在兑换…', 'load', '', 'aksrt-balance-charge-toast'); redeemCardPass('balance', cardEl ? String(cardEl.value || '').trim() : '', password, form, 'aksrt-balance-charge-toast') .then(function (result) { busy = false; if (!result.ok) notyf(result.message, 'danger', 5, 'aksrt-balance-charge-toast'); }); return; } var pkgInput = form.querySelector('input[name="balance_product"]'); 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'; selectProduct('custom'); } if ((!pkg || pkg === 'custom') && !validCustom) { notyf('请选择或输入充值金额', 'danger'); return; } busy = true; notyf('正在创建充值订单…', 'load', '', 'aksrt-balance-charge-toast'); api('/pay/balance/charge', { method: 'POST', headers: { 'Idempotency-Key': operationKey(form) }, body: JSON.stringify({ package: pkg, // 预设档位下该字段为空串:服务端仅在 package=custom 时消费它, // 空串表示「未使用自定义金额」,不是非法值。 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 = '
未找到相关用户
'; return; } users.forEach(function (u) { var item = document.createElement('button'); item.type = 'button'; item.className = 'uc-transfer-user'; var avatar = document.createElement('img'); avatar.className = 'uc-transfer-user__avatar'; avatar.alt = ''; avatar.src = String(u.avatar || ''); item.appendChild(avatar); var displayName = document.createElement('span'); displayName.textContent = String(u.display_name || u.user_login || ''); item.appendChild(displayName); var login = document.createElement('span'); login.className = 'muted-2-color em09'; login.textContent = '@' + String(u.user_login || ''); item.appendChild(login); 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'); }); }); } // ===== 购买积分(Zibll points-pay modal 1:1:商品/自定义 + 余额/卡密支付) ===== function initPointsPay() { var modal = document.querySelector('[data-aksrt-points-pay-modal]'); if (!modal || modal.dataset.aksrtPointsPayInitialized === '1') return; modal.dataset.aksrtPointsPayInitialized = '1'; var form = modal.querySelector('[data-aksrt-points-pay-form]'); var busy = false; var backdrop = null; function openPointsModal() { if (modal.classList.contains('in')) return; modal.style.display = 'flex'; void modal.offsetWidth; modal.classList.add('in'); if (!backdrop) { backdrop = document.createElement('div'); backdrop.className = 'modal-backdrop fade in'; backdrop.setAttribute('data-aksrt-points-backdrop', '1'); document.body.appendChild(backdrop); } document.body.classList.add('modal-open'); } function closePointsModal() { if (!modal.classList.contains('in')) return; modal.classList.remove('in'); document.body.classList.remove('modal-open'); if (backdrop && backdrop.parentNode) backdrop.parentNode.removeChild(backdrop); backdrop = null; window.setTimeout(function () { if (!modal.classList.contains('in')) modal.style.display = ''; }, 300); } document.querySelectorAll('[data-aksrt-points-pay-open]').forEach(function (btn) { btn.addEventListener('click', openPointsModal); }); modal.addEventListener('click', function (e) { if (e.target === modal || (e.target.closest && e.target.closest('[data-dismiss="modal"]'))) { closePointsModal(); } }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && modal.classList.contains('in')) closePointsModal(); }); // Zibll data-for/data-value 选中模型:积分商品档位。 function selectProduct(value) { modal.querySelectorAll('[data-for="points_product"]').forEach(function (el) { el.classList.toggle('active', el.getAttribute('data-value') === value); }); var hidden = modal.querySelector('input[name="points_product"]'); if (hidden) hidden.value = value; if (form) resetOperationKey(form); } modal.querySelectorAll('[data-for="points_product"]').forEach(function (el) { el.addEventListener('click', function () { selectProduct(el.getAttribute('data-value')); }); }); var customInput = modal.querySelector('input[name="points_custom"]'); if (customInput) { customInput.addEventListener('input', function () { if (String(customInput.value || '').trim() !== '') selectProduct('custom'); }); } // 支付方式(余额/卡密);选中卡密时隐藏商品选择、显示卡密输入盒。 function cardPassBox() { return modal.querySelector('[data-controller="payment_method"][data-value="card_pass"]'); } function applyMethodVisibility(value) { var cardBox = cardPassBox(); if (cardBox) cardBox.style.display = value === 'card_pass' ? '' : 'none'; modal.querySelectorAll('.charge-box').forEach(function (el) { el.style.display = value === 'card_pass' ? 'none' : ''; }); } function selectMethod(value) { modal.querySelectorAll('[data-for="payment_method"]').forEach(function (el) { el.classList.toggle('active', el.getAttribute('data-value') === value); }); var hidden = modal.querySelector('input[name="payment_method"]'); if (hidden) hidden.value = value; applyMethodVisibility(value); if (form) resetOperationKey(form); } modal.querySelectorAll('[data-for="payment_method"]').forEach(function (el) { el.addEventListener('click', function () { selectMethod(el.getAttribute('data-value')); }); }); applyMethodVisibility((modal.querySelector('input[name="payment_method"]') || {}).value || ''); if (!form) return; resetOperationKeyOnChange(form); form.addEventListener('submit', function (e) { e.preventDefault(); if (busy) return; var methodEl = form.querySelector('input[name="payment_method"]'); var method = methodEl ? methodEl.value : ''; if (!method) { notyf('暂无可用支付方式', 'danger'); return; } if (method === 'card_pass') { var cardEl = form.querySelector('input[name="card_pass[card]"]'); var pwEl = form.querySelector('input[name="card_pass[password]"]'); var password = pwEl ? String(pwEl.value || '').trim() : ''; if (!password) { notyf('请输入卡密', 'danger'); if (pwEl) pwEl.focus(); return; } busy = true; notyf('正在兑换…', 'load', '', 'aksrt-balance-points-toast'); redeemCardPass('credits', cardEl ? String(cardEl.value || '').trim() : '', password, form, 'aksrt-balance-points-toast') .then(function (result) { busy = false; if (!result.ok) notyf(result.message, 'danger', 5, 'aksrt-balance-points-toast'); }); return; } var pkgInput = form.querySelector('input[name="points_product"]'); var pkg = pkgInput ? pkgInput.value : 'custom'; var customEl = form.querySelector('input[name="points_custom"]'); var custom = customEl ? String(customEl.value || '').trim() : ''; var validCustom = /^[1-9]\d{0,8}$/.test(custom); if (validCustom) { pkg = 'custom'; selectProduct('custom'); } if ((!pkg || pkg === 'custom') && !validCustom) { 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({ product: pkg, custom: validCustom ? custom : '0' }) }).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; // 提现来源随打开按钮传入:commission 走佣金池,其余走余额钱包。 // 每个来源的每日次数/额度不同,按钮上带了各自的 min/remaining, // 打开时覆盖到金额输入框,提交时把 source 一并回传。 document.querySelectorAll('[data-aksrt-withdraw-open]').forEach(function (btn) { btn.addEventListener('click', function () { var src = btn.getAttribute('data-aksrt-withdraw-source') || 'balance'; modal.dataset.aksrtWithdrawSource = src === 'commission' ? 'commission' : 'balance'; var amountEl = form ? form.querySelector('[data-aksrt-withdraw-amount]') : null; if (amountEl) { var min = btn.getAttribute('data-withdraw-min'); var remAmt = btn.getAttribute('data-withdraw-remaining-amount'); var remCnt = btn.getAttribute('data-withdraw-remaining-count'); if (min !== null) amountEl.setAttribute('data-withdraw-min', min); if (remAmt !== null) amountEl.setAttribute('data-withdraw-remaining-amount', remAmt); if (remCnt !== null) amountEl.setAttribute('data-withdraw-remaining-count', remCnt); } 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'); var source = modal.dataset.aksrtWithdrawSource === 'commission' ? 'commission' : 'balance'; api('/earnings/withdrawals', { method: 'POST', headers: { 'Idempotency-Key': operationKey(form) }, body: JSON.stringify({ amount: amount, method: method, account: account, source: source }) }).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 panelName = source === 'commission' ? 'revenue' : 'credits'; var panel = document.getElementById('panel-' + panelName) || (modal.closest ? modal.closest('.dashboard-panel') : null); var rest = (window.aksrtData && (window.aksrtData.restUrl || window.aksrtData.apiUrl)) || (window.aksrtUserCenter && window.aksrtUserCenter.restUrl) || ''; if (panel && rest) { fetch(rest.replace(/\/$/, '') + '/user-center/panel/' + panelName, { 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() { if (document.documentElement.dataset.aksrtAssetTabsBound === 'true') return; document.documentElement.dataset.aksrtAssetTabsBound = 'true'; function select(key) { document.querySelectorAll('.uc-asset-tabs__nav [data-aksrt-asset-tab]').forEach(function (link) { var li = link.closest('li'); if (!li) return; var linkKey = link.getAttribute('data-aksrt-asset-tab'); li.classList.toggle('active', linkKey === key || (key === 'points_date' && linkKey === 'points_free')); }); document.querySelectorAll('[data-aksrt-asset-pane]').forEach(function (pane) { var active = pane.getAttribute('data-aksrt-asset-pane') === key; pane.classList.toggle('is-active', active); pane.hidden = !active; }); } function loadPage(key, page) { var panel = document.querySelector('#panel-credits'); var rest = (window.aksrtData && (window.aksrtData.restUrl || window.aksrtData.apiUrl)) || ''; if (!panel || !rest) return; panel.classList.add('is-loading'); var url = rest.replace(/\/$/, '') + '/user-center/panel/credits?asset=' + encodeURIComponent(key) + '&page=' + encodeURIComponent(page); fetch(url, { 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 (!response.ok || !payload || !payload.success || !payload.data || typeof payload.data.html !== 'string') throw new Error('asset-page-load-failed'); panel.innerHTML = payload.data.html; if (window.jQuery) jQuery(document).trigger('post_ajax.ed', [panel]); if (typeof window.auto_fun === 'function') window.auto_fun(); select(key); }); }).catch(function () { notyf('记录加载失败,请重试', 'danger'); }).finally(function () { panel.classList.remove('is-loading'); }); } document.addEventListener('click', function (e) { var pageButton = e.target.closest('[data-aksrt-asset-page]'); if (pageButton) { e.preventDefault(); loadPage(pageButton.getAttribute('data-aksrt-asset-key') || 'points', parseInt(pageButton.getAttribute('data-aksrt-asset-page') || '1', 10) || 1); return; } var link = e.target.closest('[data-aksrt-asset-tab]'); if (!link) return; e.preventDefault(); select(link.getAttribute('data-aksrt-asset-tab')); }); } function initWithdrawHistory() { var modal = document.querySelector('[data-aksrt-withdraw-history-modal]'); if (!modal || modal.dataset.aksrtWithdrawHistoryInitialized === '1') return; modal.dataset.aksrtWithdrawHistoryInitialized = '1'; var list = modal.querySelector('[data-aksrt-withdraw-history-list]'); var pagination = modal.querySelector('[data-aksrt-withdraw-history-pagination]'); var statusLabels = { pending: '待处理', processing: '处理中', completed: '已完成', rejected: '已拒绝' }; var currentPage = 1; var loading = false; function text(value) { return value === null || value === undefined ? '' : String(value); } function appendText(parent, value, className) { var node = document.createElement('span'); if (className) node.className = className; node.textContent = text(value); parent.appendChild(node); return node; } function formatGrossAmount(value) { return text(value).replace(/\.00$/, ''); } function formatNetAmount(value) { return text(value); } function renderItems(items) { if (!list) return; list.textContent = ''; if (!Array.isArray(items) || !items.length) { var empty = document.createElement('div'); empty.className = 'uc-transactions__empty'; var emptyText = document.createElement('p'); emptyText.textContent = '暂无提现记录'; empty.appendChild(emptyText); list.appendChild(empty); return; } items.forEach(function (item) { var status = text(item && item.status).toLowerCase(); var row = document.createElement('div'); row.className = 'uc-withdraw-history__item'; var badge = appendText(row, statusLabels[status] || status, 'badg badg-sm uc-withdraw-history__status'); badge.classList.add(status === 'rejected' ? 'c-red' : (status === 'completed' ? 'c-green' : 'c-blue')); var gross = text(item && (item.gross_amount || item.amount)); var net = text(item && item.amount); var amount = document.createElement('span'); amount.className = 'uc-withdraw-history__amount em12'; amount.appendChild(document.createTextNode(formatGrossAmount(gross))); if (net !== '') { var netText = document.createElement('span'); netText.className = 'uc-withdraw-history__net'; netText.textContent = '(实际到账:' + formatNetAmount(net) + '元)'; amount.appendChild(netText); } row.appendChild(amount); var number = document.createElement('span'); number.className = 'uc-withdraw-history__number muted-2-color em09'; var numberLabel = document.createElement('span'); numberLabel.textContent = '订单号:'; number.appendChild(numberLabel); var code = document.createElement('code'); code.textContent = text(item && item.withdrawal_number); number.appendChild(code); row.appendChild(number); appendText(row, text(item && item.created_at), 'uc-withdraw-history__meta muted-2-color em09'); list.appendChild(row); }); } function renderPagination(page, maxPages) { if (!pagination) return; pagination.textContent = ''; if (maxPages <= 1) return; function addButton(label, target, disabled, current) { var button = document.createElement('button'); button.type = 'button'; button.className = 'uc-withdraw-history__page' + (current ? ' is-current' : ''); button.textContent = label; button.disabled = !!disabled; if (current) button.setAttribute('aria-current', 'page'); button.dataset.aksrtWithdrawHistoryPage = String(target); pagination.appendChild(button); } addButton('上一页', page - 1, page <= 1, false); for (var index = 1; index <= maxPages; index += 1) addButton(String(index), index, false, index === page); addButton('下一页', page + 1, page >= maxPages, false); } function loadPage(page) { if (loading || !list) return; loading = true; list.textContent = '加载中…'; var rest = (window.aksrtData && (window.aksrtData.restUrl || window.aksrtData.apiUrl)) || ''; if (!rest) { list.textContent = '记录加载失败,请重试'; loading = false; return; } var url = rest.replace(/\/$/, '') + '/earnings/withdrawals?page=' + encodeURIComponent(Math.max(1, page)) + '&per_page=10'; fetch(url, { 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 (!response.ok || !payload || !Array.isArray(payload.items)) throw new Error('withdraw-history-load-failed'); currentPage = Math.max(1, parseInt(payload.page, 10) || 1); var maxPages = Math.max(1, parseInt(payload.max_pages, 10) || 1); renderItems(payload.items); renderPagination(currentPage, maxPages); }); }).catch(function () { list.textContent = '记录加载失败,请重试'; if (pagination) pagination.textContent = ''; }).finally(function () { loading = false; }); } function open() { modal.hidden = false; document.body.classList.add('uc-modal-open'); loadPage(1); } 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(); }); }); if (pagination) { pagination.addEventListener('click', function (e) { var button = e.target.closest('[data-aksrt-withdraw-history-page]'); if (!button || button.disabled) return; e.preventDefault(); loadPage(parseInt(button.dataset.aksrtWithdrawHistoryPage || '1', 10) || 1); }); } } window.AKSRTWithdrawInit = initWithdraw; window.AKSRTAssetBalances = { apply: applyAssetBalances, refresh: refreshAssetBalances }; function bootAssets() { refreshAssetBalances(); initSigninGoto(); initAffiliateRevenue(); initVipShop(); initBalanceCharge(); initTransfer(); initPointsPay(); initWithdraw(); initWithdrawHistory(); initAssetTabs(); } jQuery(document).off('auto_fun.aksrt-credits').on('auto_fun.aksrt-credits', function () { bootAssets(); }); })();