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:
jinghui committed 2026-10-20 18:55:05 +08:00
1 parent 6a697a2663
commit ec8bfda853
8 files changed
+460 -3

No files matched your search

+118
View File
@@ -552,6 +552,111 @@ async function handleGetDownloadInfo(p, sendResponse) {
}
}
// ============ 购买:当前商品(套餐)→ 订单 → 支付 → 自动激活本机 ============
// 只调用授权系统的公开接口读取在售商品、创建订单,不改动服务端任何配置。
// 当前在售商品:由授权系统实时下发(页面显示的就是当前在售的)
async function getCardTypes() {
try {
const r = await authFetch("/public/projects/" + PROJECT_ID + "/card-types", {}, 8000);
if (r && r.code === 200 && Array.isArray(r.data)) return { ok: true, data: r.data };
return { ok: false, data: [], message: (r && r.message) || "商品加载失败" };
} catch (e) {
return { ok: false, data: [], message: String(e && e.message || e) };
}
}
// 创建订单:contact_info 带机器码 → 支付成功后服务端自动发卡并绑定本机
async function authCreateOrder(payType, cardTypeId) {
const pay = payType === "wxpay" ? "wxpay" : "alipay";
const types = await getCardTypes();
if (!types.ok || !types.data.length) return { ok: false, message: types.message || "当前暂无在售商品" };
const cardType = types.data.find(t => String(t.id) === String(cardTypeId))
|| types.data.find(t => Number(t.price) > 0)
|| types.data[0];
if (!cardType) return { ok: false, message: "商品不存在,请重新选择" };
const machine = await getMachineId();
const price = Number(cardType.price);
const r = await authFetch("/public/orders", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Api-Key": CARD_API_KEY },
body: JSON.stringify({
project_id: PROJECT_ID,
card_type_id: cardType.id,
amount: price,
pay_type: pay,
contact_info: "MACHINE:" + machine
})
}, 15000);
if (!r || r.code !== 200 || !r.data) return { ok: false, message: (r && r.message) || "创建订单失败" };
// 记住进行中的订单,供后台轮询恢复
const pendingOrder = {
orderNo: r.data.order_no,
payType: pay,
amount: r.data.pay_amount != null ? Number(r.data.pay_amount) : price,
originalPrice: price,
packageName: cardType.name || "",
createdAt: Date.now()
};
await chrome.storage.local.set({ pendingOrder });
scheduleOrderPolling();
return { ok: true, order: pendingOrder, payUrl: r.data.pay_url || "", cardTypeName: cardType.name };
}
// 查询订单:服务端发卡后返回 card_key,拿到即自动激活本机
async function authQueryOrder(orderNo) {
const r = await authFetch("/public/orders/query?order_no=" + encodeURIComponent(orderNo), {}, 8000);
if (!r || r.code !== 200 || !r.data) return { ok: false, message: (r && r.message) || "订单查询失败" };
const d = r.data;
const out = {
ok: true,
paid: d.status === "paid" || !!d.card_key,
status: d.status || "",
cardKey: d.card_key || "",
expireTime: d.expire_time || ""
};
if (out.cardKey) {
const act = await activateCard(out.cardKey);
out.activated = !!(act && act.ok);
out.message = (act && act.message) || "";
if (out.activated) {
await chrome.storage.local.remove(["pendingOrder"]);
await clearOrderAlarm();
}
}
return out;
}
// 后台轮询:购买页被关掉也能走完「支付 → 发卡 → 激活」
async function scheduleOrderPolling() {
try { if (chrome.alarms) await chrome.alarms.create("orderPoll", { periodInMinutes: 1 }); } catch (e) {}
}
async function clearOrderAlarm() {
try { if (chrome.alarms) await chrome.alarms.clear("orderPoll"); } catch (e) {}
}
if (chrome.alarms && chrome.alarms.onAlarm) {
chrome.alarms.onAlarm.addListener(async (alarm) => {
if (!alarm || alarm.name !== "orderPoll") return;
try {
const st = await chrome.storage.local.get("pendingOrder");
const po = st.pendingOrder;
if (!po || !po.orderNo) { await clearOrderAlarm(); return; }
// 超过 12 小时未完成就不再追问,避免永久轮询
if (Date.now() - (Number(po.createdAt) || 0) > 12 * 3600 * 1000) {
await chrome.storage.local.remove(["pendingOrder"]);
await clearOrderAlarm();
return;
}
const res = await authQueryOrder(po.orderNo);
if (res && res.activated) await clearOrderAlarm();
} catch (e) { /* 单次轮询失败不影响下次 */ }
});
}
// ============ 消息路由 ============
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
@@ -593,6 +698,19 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
})();
return true;
}
// 当前商品选择页(buy.html)用
if (msg.action === "getCardTypes") {
getCardTypes().then(sendResponse).catch(e => sendResponse({ ok: false, data: [], message: String(e && e.message || e) }));
return true;
}
if (msg.action === "authCreateOrder") {
authCreateOrder(msg.payType, msg.cardTypeId).then(sendResponse).catch(e => sendResponse({ ok: false, message: String(e && e.message || e) }));
return true;
}
if (msg.action === "authQueryOrder") {
authQueryOrder(msg.orderNo).then(sendResponse).catch(e => sendResponse({ ok: false, message: String(e && e.message || e) }));
return true;
}
if (msg.action === "setTask") {
ACTIVE_TASK = msg.task || null;
sendResponse({ ok: true });