Files
u-claw/portable/充值.html
2026-04-06 16:52:39 +08:00

681 lines
25 KiB
HTML
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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虾盘云 — 充值</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
--bg:#f5f5f7;
--surface:#ffffff;
--border:#e5e5e5;
--border-hover:#d0d0d0;
--text:#1a1a1a;
--text-muted:#6b7280;
--text-dim:#9ca3af;
--blue:#2563eb;
--blue-light:#eff6ff;
--blue-border:#bfdbfe;
--green:#16a34a;
--green-light:#f0fdf4;
--green-border:#bbf7d0;
--orange:#ea580c;
--orange-light:#fff7ed;
--orange-border:#fed7aa;
--red:#dc2626;
--yellow:#d97706;
--radius:14px;
--shadow:0 1px 3px rgba(0,0,0,0.08),0 1px 2px rgba(0,0,0,0.04);
--shadow-hover:0 4px 12px rgba(0,0,0,0.1),0 2px 4px rgba(0,0,0,0.06);
}
body{font-family:-apple-system,"Microsoft YaHei","PingFang SC",sans-serif;background:var(--bg);color:var(--text);min-height:100vh}
/* Header */
.header{
background:var(--surface);
border-bottom:1px solid var(--border);
padding:0 28px;height:56px;
display:flex;align-items:center;justify-content:space-between;
position:sticky;top:0;z-index:10;
}
.header-left{display:flex;align-items:center;gap:10px}
.logo{width:28px;height:28px;border-radius:7px;border:1px solid var(--border)}
.header-title{font-size:.95em;font-weight:700;color:var(--text)}
.header-badge{
font-size:.68em;padding:2px 8px;border-radius:20px;font-weight:600;
background:var(--orange-light);color:var(--orange);border:1px solid var(--orange-border);
}
/* Layout */
.container{max-width:520px;margin:0 auto;padding:28px 20px 80px}
/* Section toggle */
.section{display:none}
.section.active{display:block}
/* Key 手动输入 */
.key-input-card{
background:var(--surface);border:1.5px solid var(--border);
border-radius:var(--radius);padding:20px;margin-bottom:16px;
box-shadow:var(--shadow);
}
.key-input-title{font-size:.88em;font-weight:600;color:var(--text-muted);margin-bottom:10px}
.key-input-wrap{display:flex;gap:8px}
.key-input-wrap input{
flex:1;padding:9px 12px;
background:var(--bg);border:1.5px solid var(--border);
border-radius:9px;color:var(--text);font-size:.86em;
outline:none;transition:border-color .15s;font-family:inherit;
}
.key-input-wrap input:focus{border-color:var(--orange)}
.key-confirm-btn{
padding:9px 16px;border:none;border-radius:9px;
background:var(--blue);color:#fff;font-size:.84em;font-weight:600;
cursor:pointer;white-space:nowrap;font-family:inherit;transition:background .15s;
}
.key-confirm-btn:hover{background:#1d4ed8}
/* 账户面板 */
.xp-panel{
background:var(--surface);
border:1.5px solid var(--orange-border);
border-radius:var(--radius);
overflow:hidden;
box-shadow:var(--shadow);
margin-bottom:16px;
}
.xp-panel-head{
background:var(--orange-light);
padding:14px 18px;
border-bottom:1px solid var(--orange-border);
display:flex;align-items:center;justify-content:space-between;gap:8px;
}
.xp-panel-head-left{display:flex;align-items:center;gap:8px}
.xp-panel-title{font-size:.9em;font-weight:700;color:var(--orange)}
.xp-panel-body{padding:16px 18px;display:flex;flex-direction:column;gap:10px}
/* Key 行 */
.xp-key-box{
background:var(--bg);border:1px solid var(--border);
border-radius:9px;padding:10px 12px;
}
.xp-key-label{font-size:.68em;color:var(--text-dim);margin-bottom:4px;font-weight:600;letter-spacing:.04em}
.xp-key-inner{display:flex;align-items:center;gap:6px}
.xp-key-val{
flex:1;font-size:.72em;color:var(--text-muted);
font-family:"Consolas","Courier New",monospace;
word-break:break-all;line-height:1.4;
}
.xp-copy-btn{
background:var(--surface);border:1px solid var(--border);
color:var(--text-muted);border-radius:6px;
padding:4px 10px;font-size:.7em;font-weight:600;
cursor:pointer;white-space:nowrap;font-family:inherit;
transition:all .15s;flex-shrink:0;
}
.xp-copy-btn:hover{border-color:var(--blue);color:var(--blue)}
/* 余额行 */
.xp-bal-box{
background:var(--bg);border:1px solid var(--border);
border-radius:9px;padding:10px 12px;
display:flex;align-items:center;gap:8px;
}
.xp-bal-label{font-size:.72em;color:var(--text-dim);flex-shrink:0}
.xp-bal-val{flex:1;font-size:.95em;font-weight:700;color:var(--green)}
.xp-bal-val.warn{color:var(--yellow)}
.xp-bal-val.low{color:var(--red)}
.xp-bal-val.dim{color:var(--text-dim);font-weight:400;font-size:.82em}
.xp-refresh-btn{
background:none;border:1px solid var(--border);
color:var(--text-dim);border-radius:6px;
padding:3px 9px;font-size:.68em;cursor:pointer;
font-family:inherit;transition:all .15s;white-space:nowrap;flex-shrink:0;
}
.xp-refresh-btn:hover{border-color:var(--border-hover);color:var(--text)}
.xp-refresh-btn:disabled{opacity:.45;cursor:default}
/* 充值表单卡片 */
.form-card{
background:var(--surface);border:1.5px solid var(--border);
border-radius:var(--radius);padding:20px;margin-bottom:16px;
box-shadow:var(--shadow);
}
.form-card-title{
font-size:.9em;font-weight:700;color:var(--text);
margin-bottom:16px;display:flex;align-items:center;gap:8px;
}
/* 金额网格 */
.amt-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin-bottom:12px}
.amt-btn{
background:var(--bg);border:1.5px solid var(--border);
border-radius:10px;padding:12px 6px;text-align:center;
cursor:pointer;transition:all .15s;
}
.amt-btn:hover{border-color:var(--border-hover);box-shadow:var(--shadow-hover)}
.amt-btn.sel{border-color:var(--orange);background:var(--orange-light);box-shadow:0 0 0 1px var(--orange)}
.amt-cny{font-size:1em;font-weight:700;color:var(--text)}
.amt-quota{font-size:.62em;color:var(--text-dim);margin-top:2px}
.amt-btn.sel .amt-cny{color:var(--orange)}
.amt-btn.sel .amt-quota{color:rgba(234,88,12,.6)}
.custom-wrap{display:none;margin-bottom:8px}
.custom-inner{display:flex;align-items:center;gap:6px}
.custom-prefix{font-size:.9em;color:var(--text-muted)}
input[type="number"],input[type="text"]{
flex:1;padding:9px 12px;
background:var(--bg);border:1.5px solid var(--border);
border-radius:9px;color:var(--text);font-size:.86em;
outline:none;transition:border-color .15s;font-family:inherit;
-moz-appearance:textfield;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button{-webkit-appearance:none}
input:focus{border-color:var(--orange)}
.input-hint{font-size:.74em;color:var(--text-dim);margin-top:5px}
/* 分割线 */
.divider{height:1px;background:var(--border);margin:16px 0}
/* QR */
.qr-tabs{display:flex;gap:5px;margin-bottom:10px}
.qr-tab{
flex:1;padding:7px;border-radius:8px;
font-size:.78em;font-weight:600;
cursor:pointer;border:1.5px solid var(--border);
background:transparent;color:var(--text-muted);
font-family:inherit;transition:all .15s;text-align:center;
}
.qr-tab.active{background:var(--green-light);border-color:var(--green-border);color:var(--green)}
.qr-box{display:none;text-align:center}
.qr-box.active{display:block}
.qr-img{
width:168px;height:168px;object-fit:contain;
border-radius:10px;border:1px solid var(--border);
background:var(--bg);margin:0 auto 8px;display:block;
}
.qr-placeholder{
width:168px;height:168px;border-radius:10px;
border:1.5px dashed var(--border);background:var(--bg);
margin:0 auto 8px;display:flex;align-items:center;justify-content:center;
flex-direction:column;gap:6px;color:var(--text-dim);font-size:.78em;
}
.qr-name{font-size:.82em;color:var(--text-muted);font-weight:600}
.qr-sub{font-size:.7em;color:var(--text-dim);margin-top:2px;line-height:1.5}
/* 截图上传 */
.upload-area{
border:1.5px dashed var(--border);border-radius:10px;
padding:22px 16px;text-align:center;cursor:pointer;
transition:all .15s;position:relative;overflow:hidden;
background:var(--bg);
}
.upload-area:hover{border-color:var(--border-hover);background:var(--surface)}
.upload-area.has{border-color:var(--green);border-style:solid;background:var(--green-light)}
.upload-area input{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
.upload-icon{font-size:1.8em;margin-bottom:6px;color:var(--text-dim)}
.upload-text{font-size:.82em;color:var(--text-muted)}
.upload-sub{font-size:.72em;color:var(--text-dim);margin-top:3px}
.upload-preview{max-width:100%;max-height:160px;border-radius:8px;object-fit:contain;display:none;margin:0 auto}
label{display:block;font-size:.8em;color:var(--text-muted);font-weight:600;margin-bottom:8px}
/* 提交按钮 */
.submit-btn{
width:100%;padding:13px;border:none;border-radius:10px;
font-size:.94em;font-weight:700;cursor:pointer;
font-family:inherit;transition:all .15s;
background:var(--orange);color:#fff;
box-shadow:0 2px 8px rgba(234,88,12,0.25);
}
.submit-btn:hover{background:#c2410c;box-shadow:0 4px 14px rgba(234,88,12,0.3);transform:translateY(-1px)}
.submit-btn:active{transform:none}
.submit-btn:disabled{background:var(--text-dim);cursor:not-allowed;box-shadow:none;transform:none}
/* 成功页 */
.success-view{
background:var(--surface);border:1.5px solid var(--green-border);
border-radius:var(--radius);padding:40px 24px;
text-align:center;box-shadow:var(--shadow);
}
.success-icon{font-size:3em;margin-bottom:16px}
.success-title{font-size:1.2em;font-weight:700;color:var(--green);margin-bottom:8px}
.success-desc{color:var(--text-muted);font-size:.86em;line-height:1.8;margin-bottom:20px}
.success-tip{
background:var(--green-light);border:1px solid var(--green-border);
border-radius:10px;padding:14px 16px;
font-size:.8em;color:var(--text-muted);line-height:1.8;text-align:left;
}
.back-btn{
display:inline-flex;align-items:center;gap:5px;
margin-top:20px;padding:9px 20px;
background:var(--bg);border:1.5px solid var(--border);
border-radius:8px;color:var(--text-muted);font-size:.84em;
cursor:pointer;font-family:inherit;transition:all .15s;
}
.back-btn:hover{border-color:var(--border-hover);color:var(--text)}
/* Toast */
.toast{
position:fixed;top:20px;right:20px;
background:var(--green);color:#fff;
padding:10px 18px;border-radius:8px;
font-size:.82em;font-weight:500;
opacity:0;transform:translateY(-8px);
transition:all .25s;z-index:999;pointer-events:none;
box-shadow:0 4px 12px rgba(0,0,0,0.15);
}
.toast.show{opacity:1;transform:translateY(0)}
.toast.error{background:var(--red)}
.toast.info{background:var(--blue)}
@media(max-width:480px){
.amt-grid{grid-template-columns:repeat(2,1fr)}
.header{padding:0 16px}
.container{padding:20px 14px 80px}
}
</style>
</head>
<body>
<div class="header">
<div class="header-left">
<img class="logo" src="assets/logo.png" alt="" onerror="this.style.display='none'">
<span class="header-title">虾盘云 — 充值</span>
</div>
<span class="header-badge">虾盘出品</span>
</div>
<div class="container">
<!-- Key 手动输入(未检测到时显示) -->
<div class="key-input-card" id="keyInputCard" style="display:none">
<div class="key-input-title">未检测到 API Key请手动粘贴</div>
<div class="key-input-wrap">
<input type="text" id="manualKeyInput" placeholder="sk-xp-... 或 sk-...">
<button class="key-confirm-btn" onclick="confirmManualKey()">确认</button>
</div>
</div>
<!-- 主表单 -->
<div class="section active" id="mainSection">
<!-- 账户面板 -->
<div class="xp-panel">
<div class="xp-panel-head">
<div class="xp-panel-head-left">
<span style="font-size:1.1em">🦐</span>
<span class="xp-panel-title">虾盘云 · 账户</span>
</div>
<button class="xp-refresh-btn" id="refreshBtn" onclick="loadBalance()">刷新</button>
</div>
<div class="xp-panel-body">
<div class="xp-key-box">
<div class="xp-key-label">我的专属 KEY</div>
<div class="xp-key-inner">
<div class="xp-key-val" id="keyDisplay">检测中...</div>
<button class="xp-copy-btn" onclick="copyKey()">复制</button>
</div>
</div>
<div class="xp-bal-box">
<span class="xp-bal-label">当前余额</span>
<span class="xp-bal-val dim" id="balanceVal">查询中...</span>
</div>
</div>
</div>
<!-- 充值表单 -->
<div class="form-card">
<div class="form-card-title">选择充值金额</div>
<div class="amt-grid">
<div class="amt-btn" onclick="selectAmt(20)" data-amt="20">
<div class="amt-cny">¥20</div>
<div class="amt-quota">+1000万</div>
</div>
<div class="amt-btn" onclick="selectAmt(50)" data-amt="50">
<div class="amt-cny">¥50</div>
<div class="amt-quota">+2500万</div>
</div>
<div class="amt-btn" onclick="selectAmt(100)" data-amt="100">
<div class="amt-cny">¥100</div>
<div class="amt-quota">+5000万</div>
</div>
<div class="amt-btn" onclick="selectAmt(0)" data-amt="0">
<div class="amt-cny">自定</div>
<div class="amt-quota">输入金额</div>
</div>
</div>
<div class="custom-wrap" id="customWrap">
<div class="custom-inner">
<span class="custom-prefix">¥</span>
<input type="number" id="customAmt" placeholder="最低 ¥10" min="10" max="9999" oninput="onCustomInput()">
</div>
<div class="input-hint">¥1 = 50万 quota¥10 起充</div>
</div>
<div class="divider"></div>
<label>扫码付款</label>
<div class="qr-tabs">
<button class="qr-tab active" onclick="switchQr('alipay',this)">支付宝</button>
<button class="qr-tab" onclick="switchQr('wechat',this)">微信支付</button>
</div>
<div class="qr-box active" id="qr-alipay">
<div class="qr-placeholder" id="qr-alipay-ph">
<div style="font-size:1.8em">📱</div>
<div>支付宝收款码</div>
<div style="font-size:.68em;margin-top:2px;opacity:.6">(管理员配置后显示)</div>
</div>
<img class="qr-img" id="qr-alipay-img" src="" alt="支付宝" style="display:none"
onerror="this.style.display='none';document.getElementById('qr-alipay-ph').style.display='flex'">
<div class="qr-name">支付宝</div>
<div class="qr-sub">扫码付款 · 备注填写您的 Key 后8位</div>
</div>
<div class="qr-box" id="qr-wechat">
<div class="qr-placeholder" id="qr-wechat-ph">
<div style="font-size:1.8em">💚</div>
<div>微信收款码</div>
<div style="font-size:.68em;margin-top:2px;opacity:.6">(管理员配置后显示)</div>
</div>
<img class="qr-img" id="qr-wechat-img" src="" alt="微信" style="display:none"
onerror="this.style.display='none';document.getElementById('qr-wechat-ph').style.display='flex'">
<div class="qr-name">微信支付</div>
<div class="qr-sub">扫码付款 · 备注填写您的 Key 后8位</div>
</div>
<div class="divider"></div>
<label>上传付款截图 <span style="color:var(--text-dim);font-weight:400">(可选,有图更快审核)</span></label>
<div class="upload-area" id="uploadArea" onclick="document.getElementById('screenshotInput').click()">
<input type="file" id="screenshotInput" accept="image/*" style="display:none" onchange="onFileSelect(event)">
<div id="uploadPh">
<div class="upload-icon">📸</div>
<div class="upload-text">点击上传付款截图</div>
<div class="upload-sub">支持 JPG / PNG不超过 5MB</div>
</div>
<img id="uploadPreview" class="upload-preview">
</div>
<div class="divider"></div>
<label style="margin-top:4px">备注 <span style="color:var(--text-dim);font-weight:400">(可选)</span></label>
<input type="text" id="noteInput" placeholder="如有问题可备注,管理员会看到">
</div>
<button class="submit-btn" id="submitBtn" onclick="submitRecharge()">提交充值申请 →</button>
</div><!-- /mainSection -->
<!-- 成功页 -->
<div class="section" id="successSection">
<div class="success-view">
<div class="success-icon"></div>
<div class="success-title">申请已提交!</div>
<div class="success-desc">
您的充值申请已成功提交。<br>
管理员会在微信收到通知,一般 <strong style="color:var(--orange)">10分钟内</strong> 完成审核。
</div>
<div class="success-tip">
<strong style="color:var(--text)">审核完成后:</strong><br>
· 余额自动到账,无需任何操作<br>
· 点"刷新"即可看到最新余额<br>
· 如超过1小时未到账请联系管理员
</div>
<button class="back-btn" onclick="goBack()">← 返回</button>
</div>
</div>
</div><!-- /container -->
<div class="toast" id="toast"></div>
<script>
const API_BASE = 'https://api.u-claw.org';
const RECHARGE_API = API_BASE + '/recharge';
let currentKey = '';
let selectedAmt = -1;
let screenshotB64 = '';
let screenshotMime = 'image/jpeg';
window.addEventListener('DOMContentLoaded', () => {
initKey();
loadQrCodes();
});
// ── Key 检测 ─────────────────────────────────────────────
function initKey() {
const params = new URLSearchParams(window.location.search);
let key = params.get('key') || params.get('api_key') || '';
if (!key) key = localStorage.getItem('xiapan_key') || '';
if (key) { setKey(key); return; }
fetchKeyFromConfigServer().then(k => {
if (k) setKey(k);
else showKeyInput();
});
}
async function fetchKeyFromConfigServer() {
const ports = [18799, 18798, 18797, 18796, 18789];
for (const port of ports) {
try {
const r = await fetch(`http://localhost:${port}/config`, {signal: AbortSignal.timeout(800)});
if (r.ok) {
const cfg = await r.json();
const k = cfg?.providers?.xiapanyun?.api_key || '';
if (k) return k;
}
} catch(e) {}
}
return '';
}
function setKey(key) {
currentKey = key;
localStorage.setItem('xiapan_key', key);
const masked = key.length > 14 ? key.slice(0, 10) + '...' + key.slice(-6) : key;
document.getElementById('keyDisplay').textContent = masked;
document.getElementById('keyInputCard').style.display = 'none';
loadBalance();
}
function showKeyInput() {
document.getElementById('keyInputCard').style.display = 'block';
document.getElementById('keyDisplay').textContent = '未检测到';
document.getElementById('balanceVal').textContent = '—';
document.getElementById('balanceVal').className = 'xp-bal-val dim';
}
function confirmManualKey() {
const val = document.getElementById('manualKeyInput').value.trim();
if (val.length < 8) { showToast('Key 格式不对,请重新确认', 'error'); return; }
setKey(val);
}
// ── 余额查询 ─────────────────────────────────────────────
async function loadBalance() {
if (!currentKey) return;
const btn = document.getElementById('refreshBtn');
const valEl = document.getElementById('balanceVal');
btn.disabled = true;
valEl.textContent = '查询中...';
valEl.className = 'xp-bal-val dim';
try {
const d = new Date();
const monthStart = d.getFullYear() + '-' + String(d.getMonth()+1).padStart(2,'0') + '-01';
const hdrs = {'Authorization': 'Bearer ' + currentKey};
const [subRes, usageRes] = await Promise.all([
fetch(API_BASE + '/v1/dashboard/billing/subscription', {headers: hdrs}),
fetch(API_BASE + '/v1/dashboard/billing/usage?start_date=' + monthStart, {headers: hdrs})
]);
if (!subRes.ok) throw new Error('Key 无效');
const sub = await subRes.json();
const usage = usageRes.ok ? await usageRes.json() : {total_usage: 0};
const total = sub.hard_limit_usd || 0;
const used = (usage.total_usage || 0) / 100;
const remaining = Math.max(0, total - used);
const remCny = remaining * 7.2;
let cls = '';
if (remCny < 5) cls = 'low';
else if (remCny < 20) cls = 'warn';
valEl.textContent = '¥' + remCny.toFixed(2);
valEl.className = 'xp-bal-val' + (cls ? ' ' + cls : '');
} catch(e) {
valEl.textContent = '查询失败';
valEl.className = 'xp-bal-val dim';
} finally {
btn.disabled = false;
}
}
// ── 二维码 ─────────────────────────────────────────────
async function loadQrCodes() {
try {
const r = await fetch(RECHARGE_API + '/config', {signal: AbortSignal.timeout(3000)});
if (r.ok) {
const cfg = await r.json();
if (cfg.qr_alipay) showQrImg('alipay', cfg.qr_alipay);
if (cfg.qr_wechat) showQrImg('wechat', cfg.qr_wechat);
}
} catch(e) {}
}
function showQrImg(type, src) {
const img = document.getElementById('qr-' + type + '-img');
const ph = document.getElementById('qr-' + type + '-ph');
img.src = src;
img.style.display = 'block';
ph.style.display = 'none';
}
function switchQr(type, btn) {
document.querySelectorAll('.qr-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.qr-box').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
document.getElementById('qr-' + type).classList.add('active');
}
// ── 金额选择 ─────────────────────────────────────────────
function selectAmt(amt) {
document.querySelectorAll('.amt-btn').forEach(b => b.classList.remove('sel'));
document.querySelector(`.amt-btn[data-amt="${amt}"]`).classList.add('sel');
selectedAmt = amt;
document.getElementById('customWrap').style.display = amt === 0 ? 'block' : 'none';
if (amt !== 0) document.getElementById('customAmt').value = '';
}
function onCustomInput() {
selectedAmt = parseFloat(document.getElementById('customAmt').value) || 0;
}
function getEffectiveAmt() {
if (selectedAmt === 0) return parseFloat(document.getElementById('customAmt').value) || 0;
return selectedAmt;
}
// ── 截图上传 ─────────────────────────────────────────────
function onFileSelect(e) {
const file = e.target.files[0];
if (!file) return;
if (file.size > 5 * 1024 * 1024) { showToast('图片不超过5MB', 'error'); return; }
screenshotMime = file.type || 'image/jpeg';
const reader = new FileReader();
reader.onload = ev => {
const dataUrl = ev.target.result;
screenshotB64 = dataUrl.split(',')[1];
const preview = document.getElementById('uploadPreview');
preview.src = dataUrl;
preview.style.display = 'block';
document.getElementById('uploadPh').style.display = 'none';
document.getElementById('uploadArea').classList.add('has');
};
reader.readAsDataURL(file);
}
// ── 提交 ─────────────────────────────────────────────
async function submitRecharge() {
if (!currentKey) { showToast('请先输入您的 API Key', 'error'); return; }
const amount = getEffectiveAmt();
if (amount < 10) { showToast('充值金额最低 ¥10', 'error'); return; }
const btn = document.getElementById('submitBtn');
btn.disabled = true;
btn.textContent = '提交中...';
try {
const res = await fetch(RECHARGE_API + '/submit', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
api_key: currentKey,
amount_cny: amount,
screenshot_b64: screenshotB64,
screenshot_mime: screenshotMime,
note: document.getElementById('noteInput').value.trim()
})
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || '服务器错误');
document.getElementById('mainSection').classList.remove('active');
document.getElementById('successSection').classList.add('active');
} catch(e) {
showToast('提交失败:' + e.message, 'error');
btn.disabled = false;
btn.textContent = '提交充值申请 →';
}
}
function goBack() {
document.getElementById('successSection').classList.remove('active');
document.getElementById('mainSection').classList.add('active');
screenshotB64 = '';
document.getElementById('uploadPreview').style.display = 'none';
document.getElementById('uploadPh').style.display = 'block';
document.getElementById('uploadArea').classList.remove('has');
document.getElementById('screenshotInput').value = '';
document.getElementById('noteInput').value = '';
document.querySelectorAll('.amt-btn').forEach(b => b.classList.remove('sel'));
document.getElementById('customWrap').style.display = 'none';
document.getElementById('submitBtn').disabled = false;
document.getElementById('submitBtn').textContent = '提交充值申请 →';
selectedAmt = -1;
loadBalance();
}
// ── 工具 ─────────────────────────────────────────────
function copyKey() {
if (!currentKey) return;
navigator.clipboard.writeText(currentKey)
.then(() => showToast('Key 已复制'))
.catch(() => {
const el = document.createElement('textarea');
el.value = currentKey;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
showToast('Key 已复制');
});
}
let toastTimer;
function showToast(msg, type='') {
const t = document.getElementById('toast');
t.textContent = msg;
t.className = 'toast show' + (type ? ' ' + type : '');
clearTimeout(toastTimer);
toastTimer = setTimeout(() => t.classList.remove('show'), 3000);
}
</script>
</body>
</html>