Files
pay/web/pay.html
T
wangjia 6da6964451 初始提交:岩美 pay 收款服务(支付宝当面付 + 多商户多渠道架构)
- Go/Gin/GORM + 纯 Go SQLite(无 cgo)
- Channel 多渠道接口:支付宝当面付(precreate)/电脑网站支付(page.pay) 已实现,微信占位
- 多商户 merchants 表,回调验签+金额核对+幂等+查单兜底
- 收款页/结果页/二维码端点;docs/ 设计文档与部署 Runbook
- 密钥走环境变量/Bitwarden,不入库

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 07:21:48 +08:00

92 lines
4.2 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>
:root{--bg:#0d1117;--card:#161b22;--card-2:#1c2330;--border:#283041;--fg:#e6edf3;--fg-soft:#aeb9c7;--muted:#7d8896;--accent:#58a6ff;--green:#3fb950;--radius:14px}
*{box-sizing:border-box}
body{margin:0;min-height:100vh;background:radial-gradient(1000px 500px at 80% -10%,rgba(88,166,255,.08),transparent 60%),var(--bg);color:var(--fg);font:15px/1.6 -apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;display:flex;align-items:center;justify-content:center;padding:24px}
.box{width:100%;max-width:420px}
h1{font-size:22px;margin:0 0 4px;text-align:center}
.sub{color:var(--muted);font-size:13px;text-align:center;margin-bottom:22px}
.item{display:flex;justify-content:space-between;align-items:center;gap:12px;background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:16px 18px;margin:12px 0;cursor:pointer;transition:.15s}
.item:hover{border-color:var(--accent);background:var(--card-2)}
.item.sel{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset}
.item .name{font-weight:600}
.item .desc{color:var(--fg-soft);font-size:13px;margin-top:2px}
.item .price{color:var(--green);font-size:20px;font-weight:700;white-space:nowrap}
.item .price small{font-size:12px;color:var(--muted);font-weight:400}
button{width:100%;margin-top:18px;padding:14px;border:0;border-radius:12px;background:var(--accent);color:#04122b;font-size:16px;font-weight:700;cursor:pointer;transition:.15s}
button:disabled{opacity:.5;cursor:not-allowed}
.msg{margin-top:14px;text-align:center;font-size:13px;color:var(--muted);min-height:18px}
.msg.err{color:#f85149}
.hint{margin-top:16px;font-size:12.5px;color:var(--muted);text-align:center;line-height:1.7}
.hint code{background:var(--card-2);border:1px solid var(--border);border-radius:4px;padding:1px 5px;color:var(--fg-soft)}
</style>
</head>
<body>
<div class="box">
<h1>选择套餐</h1>
<div class="sub">支付宝支付 · 沙箱联调</div>
<div id="list"></div>
<button id="pay" disabled>请选择套餐</button>
<div class="msg" id="msg"></div>
<div class="hint">
跳转到支付宝收银台后,用<strong>右边「登录支付宝账户付款」</strong><br>
买家账号 <code>vtlvff1163@sandbox.com</code> · 支付密码 <code>111111</code>
</div>
</div>
<script>
let selected = null;
const listEl = document.getElementById('list');
const payBtn = document.getElementById('pay');
const msgEl = document.getElementById('msg');
function setMsg(t, err){ msgEl.textContent = t || ''; msgEl.classList.toggle('err', !!err); }
async function load(){
try{
const r = await fetch('/api/v1/products');
const j = await r.json();
const items = j.data || [];
if(!items.length){ listEl.innerHTML = '<div class="sub">暂无可购套餐</div>'; return; }
listEl.innerHTML = '';
items.forEach(p => {
const el = document.createElement('div');
el.className = 'item';
el.innerHTML = `<div><div class="name">${p.name}</div><div class="desc">${p.description||''}</div></div>
<div class="price">¥${p.price}<small> 元</small></div>`;
el.onclick = () => {
document.querySelectorAll('.item').forEach(x=>x.classList.remove('sel'));
el.classList.add('sel');
selected = p;
payBtn.disabled = false;
payBtn.textContent = `支付 ¥${p.price}`;
};
listEl.appendChild(el);
});
}catch(e){ setMsg('加载套餐失败:'+e, true); }
}
payBtn.onclick = async () => {
if(!selected) return;
payBtn.disabled = true; setMsg('正在创建订单…');
try{
const r = await fetch('/api/v1/orders', {
method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({product_id: selected.id})
});
const j = await r.json();
if(!r.ok){ setMsg(j.message || '下单失败', true); payBtn.disabled=false; return; }
setMsg('正在跳转支付宝收银台…');
window.location.href = j.data.pay_url;
}catch(e){ setMsg('下单异常:'+e, true); payBtn.disabled=false; }
};
load();
</script>
</body>
</html>