feat: v1.7.9 试用72h+100条额度+到期降级+24h优惠码;v1.7.8 移除图片回复模式
注:本提交由 Gitee v1.7.7 基线重建(原 GitHub 仓库账号暂停、源码包已丢),重建后经真机功能测试与 v1.7.9 行为一致。
This commit is contained in:
1 parent
fae84ff6c7
commit
540f506c78
8 files changed
+360
-436
No files matched your search
+151
-22
@@ -16,8 +16,33 @@ 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.7';
|
||||
const TRIAL_MS = 24 * 60 * 60 * 1000; // 未授权试用1天
|
||||
const CLIENT_VERSION = '1.7.9';
|
||||
const TRIAL_MS = 72 * 60 * 60 * 1000; // 试用 72 小时(3 天)
|
||||
const TRIAL_QUOTA = 100; // 试用期最多 100 条评论(时间/条数先到先停,防止白嫖薅量)
|
||||
const GRACE_DAILY = 3; // 试用到期不硬锁:每天保留 3 条体验额度
|
||||
const PROMO = { code: 'XHS24H', percent: 20, windowMs: 24 * 60 * 60 * 1000 }; // 到期后 24 小时限时优惠(8 折)
|
||||
|
||||
// ===== 试用用量统计(时间/条数额度 + 到期降级都读这里) =====
|
||||
function todayStr() {
|
||||
const d = new Date();
|
||||
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
|
||||
}
|
||||
|
||||
async function getUsage() {
|
||||
const { trialUsage } = await chrome.storage.local.get(['trialUsage']);
|
||||
const u = trialUsage && typeof trialUsage === 'object' ? trialUsage : {};
|
||||
return {
|
||||
total: Number(u.total) || 0,
|
||||
day: u.day || '',
|
||||
dayCount: Number(u.dayCount) || 0,
|
||||
quotaHitAt: Number(u.quotaHitAt) || 0,
|
||||
trialEndedAt: Number(u.trialEndedAt) || 0
|
||||
};
|
||||
}
|
||||
|
||||
async function saveUsage(u) {
|
||||
await chrome.storage.local.set({ trialUsage: u });
|
||||
}
|
||||
|
||||
// 把用户填写的地址规范化为完整的 chat/completions 端点
|
||||
function buildChatCompletionsUrl(baseUrl) {
|
||||
@@ -156,7 +181,7 @@ async function authOnInstalled() {
|
||||
const result = await chrome.storage.local.get(['trialStartedAt']);
|
||||
if (!result.trialStartedAt) {
|
||||
await chrome.storage.local.set({ trialStartedAt: Date.now() });
|
||||
console.log('试用期开始(1天)');
|
||||
console.log('试用期开始(3 天 · 上限 ' + TRIAL_QUOTA + ' 条)');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化试用期失败:', error);
|
||||
@@ -318,7 +343,7 @@ async function authGetAnnouncements() {
|
||||
return { ok: false, message: res.message || '拉取公告失败' };
|
||||
}
|
||||
|
||||
// 读取授权状态(valid授权 > 1天试用 > 锁定)
|
||||
// 读取授权状态(valid授权 > 72 小时试用 > 到期降级体验,不硬锁)
|
||||
async function authGetStatus() {
|
||||
const { licenseState, trialStartedAt } = await chrome.storage.local.get(['licenseState', 'trialStartedAt']);
|
||||
|
||||
@@ -338,16 +363,99 @@ async function authGetStatus() {
|
||||
if (!trialStartedAt) {
|
||||
await chrome.storage.local.set({ trialStartedAt: start });
|
||||
}
|
||||
const remainingMs = start + TRIAL_MS - Date.now();
|
||||
if (remainingMs > 0) {
|
||||
const usage = await getUsage();
|
||||
const trialEndAt = start + TRIAL_MS;
|
||||
const timeUp = Date.now() >= trialEndAt;
|
||||
const quotaReached = usage.quotaHitAt > 0;
|
||||
|
||||
// 试用期内:时间没到 且 评论额度没用完
|
||||
if (!timeUp && !quotaReached) {
|
||||
return {
|
||||
state: 'trial',
|
||||
remainingMs,
|
||||
remainingHours: Math.max(1, Math.ceil(remainingMs / 3600000)),
|
||||
trialEndAt: start + TRIAL_MS
|
||||
remainingMs: trialEndAt - Date.now(),
|
||||
remainingHours: Math.max(1, Math.ceil((trialEndAt - Date.now()) / 3600000)),
|
||||
trialEndAt,
|
||||
quotaTotal: TRIAL_QUOTA,
|
||||
quotaUsed: usage.total,
|
||||
quotaLeft: Math.max(0, TRIAL_QUOTA - usage.total)
|
||||
};
|
||||
}
|
||||
return { state: 'locked' };
|
||||
|
||||
// 到期(时间到 或 额度用完)→ 降级体验:不硬锁,保留数据 + 每天 3 条 + 24h 限时优惠
|
||||
if (!usage.trialEndedAt) {
|
||||
usage.trialEndedAt = quotaReached && usage.quotaHitAt ? usage.quotaHitAt : trialEndAt;
|
||||
await saveUsage(usage);
|
||||
}
|
||||
const today = todayStr();
|
||||
const dayCount = usage.day === today ? usage.dayCount : 0;
|
||||
const dayLeft = Math.max(0, GRACE_DAILY - dayCount);
|
||||
const promoLeftMs = Math.max(0, usage.trialEndedAt + PROMO.windowMs - Date.now());
|
||||
return {
|
||||
state: 'grace',
|
||||
trialEndedAt: usage.trialEndedAt,
|
||||
graceDaily: GRACE_DAILY,
|
||||
dayCount,
|
||||
dayLeft,
|
||||
quotaTotal: TRIAL_QUOTA,
|
||||
quotaUsed: usage.total,
|
||||
promo: {
|
||||
code: PROMO.code,
|
||||
percent: PROMO.percent,
|
||||
promoLeftMs,
|
||||
active: promoLeftMs > 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 每成功一条评论调用一次:试用期扣 100 条额度;到期后扣每日 3 条;授权用户不计
|
||||
// 返回 allowed=false 时调用方应立即停止本轮任务
|
||||
async function usageTick() {
|
||||
const { licenseState } = await chrome.storage.local.get(['licenseState']);
|
||||
if (licenseState && licenseState.valid) {
|
||||
return { allowed: true, state: 'authorized' };
|
||||
}
|
||||
|
||||
const { trialStartedAt } = await chrome.storage.local.get(['trialStartedAt']);
|
||||
const start = trialStartedAt || Date.now();
|
||||
const usage = await getUsage();
|
||||
const inTrial = Date.now() < start + TRIAL_MS && !usage.quotaHitAt;
|
||||
|
||||
if (inTrial) {
|
||||
usage.total += 1;
|
||||
if (usage.total >= TRIAL_QUOTA && !usage.quotaHitAt) {
|
||||
usage.quotaHitAt = Date.now();
|
||||
usage.trialEndedAt = usage.quotaHitAt;
|
||||
}
|
||||
await saveUsage(usage);
|
||||
const quotaLeft = Math.max(0, TRIAL_QUOTA - usage.total);
|
||||
return {
|
||||
allowed: quotaLeft > 0,
|
||||
state: quotaLeft > 0 ? 'trial' : 'grace',
|
||||
quotaLeft,
|
||||
message: quotaLeft > 0 ? '' :
|
||||
`试用额度 ${TRIAL_QUOTA} 条已用完,已自动停止;到期后每天仍可体验 ${GRACE_DAILY} 条`
|
||||
};
|
||||
}
|
||||
|
||||
// 降级期:每日额度
|
||||
const today = todayStr();
|
||||
if (usage.day !== today) {
|
||||
usage.day = today;
|
||||
usage.dayCount = 0;
|
||||
}
|
||||
usage.dayCount += 1;
|
||||
usage.total += 1;
|
||||
await saveUsage(usage);
|
||||
const dayLeft = Math.max(0, GRACE_DAILY - usage.dayCount);
|
||||
return {
|
||||
allowed: dayLeft > 0,
|
||||
state: 'grace',
|
||||
dayCount: usage.dayCount,
|
||||
graceDaily: GRACE_DAILY,
|
||||
dayLeft,
|
||||
message: dayLeft > 0 ? '' :
|
||||
`今日 ${GRACE_DAILY} 条体验额度已用完(明天恢复),购买授权解锁无限量`
|
||||
};
|
||||
}
|
||||
|
||||
// 创建购买订单(contact_info 带机器码 → 支付成功后系统自动发卡绑定)
|
||||
@@ -362,26 +470,42 @@ async function authCreateOrder(payType) {
|
||||
const cardType = typesRes.data[0];
|
||||
|
||||
const machineId = await getDeviceId();
|
||||
const res = await authFetch('/api/public/orders', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
project_id: AUTH_PROJECT_ID,
|
||||
card_type_id: cardType.id,
|
||||
amount: Number(cardType.price),
|
||||
pay_type: pay,
|
||||
contact_info: `MACHINE:${machineId}`
|
||||
}
|
||||
const price = Number(cardType.price);
|
||||
// 试用到期 24 小时内下单自动带限时优惠码(服务端按折扣重算实付金额)
|
||||
const status = await authGetStatus();
|
||||
const useCoupon = !!(status.state === 'grace' && status.promo && status.promo.active);
|
||||
const orderBody = () => ({
|
||||
project_id: AUTH_PROJECT_ID,
|
||||
card_type_id: cardType.id,
|
||||
amount: price,
|
||||
pay_type: pay,
|
||||
contact_info: `MACHINE:${machineId}`,
|
||||
...(useCoupon ? { coupon_code: PROMO.code } : {})
|
||||
});
|
||||
|
||||
let res = await authFetch('/api/public/orders', { method: 'POST', body: orderBody() });
|
||||
let couponApplied = useCoupon;
|
||||
if (!res.ok && useCoupon) {
|
||||
// 优惠码异常也不能挡住下单:去掉优惠码重试一次
|
||||
console.log('优惠码下单失败,改用原价重试:', res.message);
|
||||
const retryBody = orderBody();
|
||||
delete retryBody.coupon_code;
|
||||
res = await authFetch('/api/public/orders', { method: 'POST', body: retryBody });
|
||||
couponApplied = false;
|
||||
}
|
||||
|
||||
if (!res.ok || !res.data) {
|
||||
return { ok: false, message: res.message || '创建订单失败' };
|
||||
}
|
||||
|
||||
// 记录进行中的订单,便于侧边栏恢复轮询
|
||||
// 记录进行中的订单,便于侧边栏恢复轮询(金额优先用服务端实付金额)
|
||||
const serverPay = res.data.pay_amount != null ? Number(res.data.pay_amount) : null;
|
||||
const fallbackPay = couponApplied ? Math.max(0.01, Math.round(price * (1 - PROMO.percent / 100) * 100) / 100) : price;
|
||||
const pendingOrder = {
|
||||
orderNo: res.data.order_no,
|
||||
payType: pay,
|
||||
amount: Number(cardType.price),
|
||||
amount: serverPay != null ? serverPay : fallbackPay,
|
||||
originalPrice: price,
|
||||
couponCode: couponApplied ? PROMO.code : '',
|
||||
packageName: cardType.name || '',
|
||||
createdAt: Date.now()
|
||||
};
|
||||
@@ -451,6 +575,11 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'usageTick') {
|
||||
usageTick().then((data) => sendResponse({ ok: true, data }));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'authActivate') {
|
||||
authVerify(request.cardKey).then((res) => sendResponse(res));
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user