v1.10.0: 新增「当前商品选择页」——侧边栏购买入口改为插件内置 buy.html
- buy.html/css/js:实时拉取授权系统当前在售商品 → 选商品 → 选支付方式 → 下单 - background.js:新增 getCardTypes / authCreateOrder / authQueryOrder 三个消息与实现 - 支付成功自动发卡并激活本机;新增 alarms 权限做后台订单轮询(关页仍完成),12 小时未完成自动停 - sidepanel.js:licBuy 从跳 https://auth.88531.cn 改为打开内置 buy.html(不改服务端) - manifest 1.9.0 → 1.10.0 + alarms 权限 - CHANGELOG/README 同步:新增条目、文件结构、内置购买页说明、Gitea 源
This commit is contained in:
1 parent
6a697a2663
commit
ec8bfda853
8 files changed
+460
-3
No files matched your search
@@ -0,0 +1,137 @@
|
||||
/* 当前商品选择页:选套餐 → 选支付方式 → 下单 → 支付 → 自动激活本机 */
|
||||
const $ = (id) => document.getElementById(id);
|
||||
let packages = [];
|
||||
let selected = null;
|
||||
let orderNo = null;
|
||||
let pollTimer = null;
|
||||
|
||||
function esc(s) {
|
||||
return String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({
|
||||
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
|
||||
}[c]));
|
||||
}
|
||||
|
||||
function durationText(days) {
|
||||
const n = Number(days);
|
||||
if (!n) return '限时体验';
|
||||
if (n >= 999999) return '永久有效';
|
||||
return n + ' 天';
|
||||
}
|
||||
|
||||
async function loadPackages() {
|
||||
$('package-list').innerHTML = '<div class="loading">正在加载当前商品…</div>';
|
||||
try {
|
||||
const res = await chrome.runtime.sendMessage({ action: 'getCardTypes' });
|
||||
if (!res || !res.ok) throw new Error((res && res.message) || '加载失败');
|
||||
packages = (res.data || []).filter((p) => Number(p.price) > 0);
|
||||
if (!packages.length) {
|
||||
$('package-list').innerHTML = '<div class="empty">当前暂无在售商品,请稍后再试</div>';
|
||||
return;
|
||||
}
|
||||
renderPackages();
|
||||
} catch (e) {
|
||||
$('package-list').innerHTML = '<div class="empty">商品加载失败:' + esc(e.message) + '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderPackages() {
|
||||
$('package-list').innerHTML = packages.map((p) => `
|
||||
<div class="package" data-id="${esc(p.id)}">
|
||||
<div class="pkg-name">${esc(p.name)}</div>
|
||||
<div class="pkg-price">¥${esc(p.price)}</div>
|
||||
<div class="pkg-dur">${esc(durationText(p.duration_days))}</div>
|
||||
<button class="pkg-btn" data-id="${esc(p.id)}">选择此商品</button>
|
||||
</div>`).join('');
|
||||
document.querySelectorAll('.pkg-btn').forEach((btn) => {
|
||||
btn.addEventListener('click', () => selectPackage(btn.dataset.id));
|
||||
});
|
||||
}
|
||||
|
||||
function selectPackage(id) {
|
||||
selected = packages.find((p) => String(p.id) === String(id));
|
||||
if (!selected) return;
|
||||
document.querySelectorAll('.package').forEach((el) => {
|
||||
el.classList.toggle('active', el.dataset.id === String(id));
|
||||
});
|
||||
$('chosen-package').innerHTML = `已选商品:<b>${esc(selected.name)}</b> 价格 <b>¥${esc(selected.price)}</b> ${esc(durationText(selected.duration_days))}`;
|
||||
$('step-pay').hidden = false;
|
||||
$('step-pay').scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
|
||||
async function createOrder(payType) {
|
||||
if (!selected) return;
|
||||
$('order-panel').hidden = false;
|
||||
$('order-panel').scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status pending';
|
||||
status.textContent = '⏳ 正在创建订单…';
|
||||
try {
|
||||
const res = await chrome.runtime.sendMessage({
|
||||
action: 'authCreateOrder',
|
||||
payType,
|
||||
cardTypeId: selected.id
|
||||
});
|
||||
if (!res || !res.ok) throw new Error((res && res.message) || '创建订单失败');
|
||||
|
||||
orderNo = res.order.orderNo;
|
||||
status.textContent = `订单 ${orderNo}(¥${res.order.amount})已创建,正在打开支付页面…`;
|
||||
if (res.payUrl) window.open(res.payUrl, '_blank');
|
||||
startPolling();
|
||||
} catch (e) {
|
||||
status.className = 'order-status error';
|
||||
status.textContent = '✗ ' + e.message;
|
||||
}
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
if (pollTimer) clearInterval(pollTimer);
|
||||
let attempts = 0;
|
||||
pollTimer = setInterval(async () => {
|
||||
attempts++;
|
||||
if (attempts > 240) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status error';
|
||||
status.textContent = `✗ 等待支付超时。订单号 ${orderNo},如已付款请把订单号发给官网客服处理。`;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await chrome.runtime.sendMessage({ action: 'authQueryOrder', orderNo });
|
||||
if (!res || !res.ok) return;
|
||||
if (res.activated) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
showActivated(res);
|
||||
} else if (res.cardKey && !res.activated) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status error';
|
||||
status.textContent = '✗ 已支付但激活失败:' + (res.message || '请联系客服,提供订单号补发');
|
||||
} else {
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status pending';
|
||||
status.textContent = `⏳ 等待支付中…(订单 ${orderNo},已等待 ${attempts * 5} 秒)`;
|
||||
}
|
||||
} catch (e) {
|
||||
/* 单次查询失败不中断轮询 */
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function showActivated(res) {
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status success';
|
||||
status.innerHTML = `
|
||||
<div class="ok-title">✓ 支付成功,已自动激活</div>
|
||||
<div class="ok-line">卡密:<b>${esc(res.cardKey || '')}</b></div>
|
||||
<div class="ok-line">到期时间:${esc(res.expireTime || '永久')}</div>
|
||||
<div class="ok-line muted">回到插件侧边栏即可使用全部功能(本机已授权)。</div>`;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.pay-btn').forEach((btn) => {
|
||||
btn.addEventListener('click', () => createOrder(btn.dataset.pay));
|
||||
});
|
||||
|
||||
loadPackages();
|
||||
Reference in new issue
Block a user