feat: 购买流程重做(新页选套餐→选支付方式)+ 支付后后台自动激活 v1.8.0

- 修复「点击购买授权没反应」:支付方式选择行被 .pay-select-row 的 display:flex 压过 hidden 属性常驻显示;新增全局 [hidden]{display:none!important}
- 点「购买授权」改为打开新页面 buy.html:①展示本项目全部在售套餐 ②选套餐后才显示支付方式 ③下单支付
- 自动激活改为后台 chrome.alarms 每分钟轮询(关掉侧边栏/支付页也能激活),侧边栏轮询保留为快速通道
- authCreateOrder 支持传入所选套餐 cardTypeId;新增 getCardTypes 消息
This commit is contained in:
personal82555 committed 2026-10-20 18:57:04 +08:00
1 parent 540f506c78
commit 9348d52a98
10 files changed
+522 -92

No files matched your search

+56 -9
View File
@@ -16,7 +16,7 @@ const DEFAULT_AI = {
const AUTH_BASE = 'https://auth.88531.cn';
const AUTH_PROJECT_ID = 3;
const AUTH_API_KEY = 'ak_bbf83b76df8219388d7f60b9e67c7db2';
const CLIENT_VERSION = '1.7.9';
const CLIENT_VERSION = '1.8.0';
const TRIAL_MS = 72 * 60 * 60 * 1000; // 试用 72 小时(3 天)
const TRIAL_QUOTA = 100; // 试用期最多 100 条评论(时间/条数先到先停,防止白嫖薅量)
const GRACE_DAILY = 3; // 试用到期不硬锁:每天保留 3 条体验额度
@@ -210,6 +210,13 @@ async function authOnInstalled() {
} catch (error) {
console.error('启动时授权复验失败:', error);
}
// 有未完成订单则恢复后台轮询(支付后自动激活不依赖侧边栏是否开着)
try {
await scheduleOrderPolling();
} catch (error) {
console.error('恢复订单轮询失败:', error);
}
}
// 注册定时任务:心跳/复验/公告/更新检查
@@ -234,6 +241,8 @@ chrome.alarms?.onAlarm?.addListener(async (alarm) => {
await authGetAnnouncements();
} else if (alarm.name === 'authUpdateCheck') {
await authCheckUpdate();
} else if (alarm.name === 'orderPoll') {
await pollPendingOrder();
}
} catch (error) {
console.error('授权定时任务失败:', alarm.name, error);
@@ -459,16 +468,19 @@ async function usageTick() {
}
// 创建购买订单(contact_info 带机器码 → 支付成功后系统自动发卡绑定)
async function authCreateOrder(payType) {
async function authCreateOrder(payType, cardTypeId) {
const pay = payType === 'wxpay' ? 'wxpay' : 'alipay';
// 取项目第一个套餐
// 读取在售套餐:购买页选定 cardTypeId 时用选中的,否则取第一个(兼容旧调用)
const typesRes = await authFetch(`/api/public/projects/${AUTH_PROJECT_ID}/card-types`);
if (!typesRes.ok || !Array.isArray(typesRes.data) || typesRes.data.length === 0) {
return { ok: false, message: '暂无在售套餐,请稍后再试' };
}
const cardType = typesRes.data[0];
const cardType = (cardTypeId ? typesRes.data.find((t) => String(t.id) === String(cardTypeId)) : null)
|| typesRes.data.find((t) => Number(t.price) > 0)
|| typesRes.data[0];
if (!cardType) return { ok: false, message: '套餐不存在,请重新选择' };
const machineId = await getDeviceId();
const price = Number(cardType.price);
// 试用到期 24 小时内下单自动带限时优惠码(服务端按折扣重算实付金额)
@@ -510,8 +522,34 @@ async function authCreateOrder(payType) {
createdAt: Date.now()
};
await chrome.storage.local.set({ pendingOrder });
return { ok: true, order: pendingOrder, payUrl: res.data.pay_url };
await scheduleOrderPolling();
return { ok: true, order: pendingOrder, payUrl: res.data.pay_url, cardTypeName: cardType.name };
}
// 后台订单轮询:侧边栏/购买页关闭也能完成「支付 → 自动发卡 → 自动激活」
async function scheduleOrderPolling() {
if (!chrome.alarms) return;
const { pendingOrder } = await chrome.storage.local.get(['pendingOrder']);
if (!pendingOrder || !pendingOrder.orderNo) return;
await chrome.alarms.create('orderPoll', { periodInMinutes: 1 });
}
async function pollPendingOrder() {
const { pendingOrder } = await chrome.storage.local.get(['pendingOrder']);
if (!pendingOrder || !pendingOrder.orderNo) {
try { await chrome.alarms.clear('orderPoll'); } catch (e) { /* 无该 alarm */ }
return;
}
try {
const result = await authQueryOrder(pendingOrder.orderNo);
if (result && result.activated) {
await chrome.storage.local.remove(['pendingOrder']);
try { await chrome.alarms.clear('orderPoll'); } catch (e) { /* 无该 alarm */ }
}
} catch (error) {
console.error('后台订单轮询失败:', error);
}
}
// 查询订单(支付+自动发卡后返回 card_key;拿到卡密自动激活)
@@ -586,7 +624,16 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
}
if (request.action === 'authCreateOrder') {
authCreateOrder(request.payType).then((res) => sendResponse(res));
authCreateOrder(request.payType, request.cardTypeId).then((res) => sendResponse(res));
return true;
}
if (request.action === 'getCardTypes') {
authFetch(`/api/public/projects/${AUTH_PROJECT_ID}/card-types`).then((res) => {
sendResponse({ ok: !!res.ok, data: res.data || [], message: res.message });
}).catch((error) => {
sendResponse({ ok: false, message: error.message, data: [] });
});
return true;
}