creditdaddy 1.5.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.json +3 -3
- package/package.json +1 -1
- package/src/assets/donate-alipay.svg +1 -0
- package/src/assets/donate-ifdian.svg +1 -0
- package/src/assets/donate-wechat.svg +1 -0
- package/src/checkin.js +11 -10
- package/src/constants.js +3 -1
- package/src/cookieSites.js +30 -11
- package/src/daemon.js +54 -10
- package/src/doubaoClient.js +168 -0
- package/src/externalQuota.js +113 -9
- package/src/i18n/en.json +1708 -1755
- package/src/i18n/ja.json +1708 -1755
- package/src/i18n/ko.json +1708 -1755
- package/src/i18n/zh-TW.json +1708 -1755
- package/src/minimaxClient.js +29 -0
- package/src/mirasimClient.js +3 -0
- package/src/panel.html +186 -84
- package/src/providers.js +39 -3
- package/src/traeClient.js +23 -15
- package/src/traeLocal.js +14 -4
- package/src/usageSync.js +10 -2
- package/src/workbuddyClient.js +0 -45
package/src/minimaxClient.js
CHANGED
|
@@ -286,6 +286,35 @@ export function normalizeMiniMaxQuota(data) {
|
|
|
286
286
|
};
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
+
/**
|
|
290
|
+
* 只查签到状态,不打 claim(10R 只读推送用,issue #33)。
|
|
291
|
+
* 刷新失败等凭据问题照常抛错;查询失败返回 null(推送侧降级为不带签到字段)。
|
|
292
|
+
* @returns {Promise<{checkedToday: boolean, streakDays: number, points: number, bonusPoints: number}|null>}
|
|
293
|
+
*/
|
|
294
|
+
export async function fetchMiniMaxCheckinStatus(account, ctx = {}) {
|
|
295
|
+
try {
|
|
296
|
+
return await withMiniMaxAuth(account, async (token) => {
|
|
297
|
+
const statusRes = await fetchJsonRace(SIGNIN_STATUS_URL, {
|
|
298
|
+
headers: authHeaders(token),
|
|
299
|
+
timeoutMs: FETCH_TIMEOUT_MS,
|
|
300
|
+
});
|
|
301
|
+
if (!statusRes.ok) return null;
|
|
302
|
+
const statusData = await statusRes.json().catch(() => null);
|
|
303
|
+
if (!statusData || statusData.base_resp?.status_code !== 0) return null;
|
|
304
|
+
const today = (statusData.data?.days || []).find((d) => d.is_today);
|
|
305
|
+
if (!today) return null;
|
|
306
|
+
return {
|
|
307
|
+
checkedToday: today.status === 3,
|
|
308
|
+
streakDays: today.day_no || 0,
|
|
309
|
+
points: today.points || 0,
|
|
310
|
+
bonusPoints: today.bonus_points || 0,
|
|
311
|
+
};
|
|
312
|
+
}, ctx);
|
|
313
|
+
} catch {
|
|
314
|
+
return null; // 推送是旁路:凭据失效 / 网络抖动都不该炸整轮推送
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
289
318
|
/**
|
|
290
319
|
* 每日自动签到 (checkin)
|
|
291
320
|
*/
|
package/src/mirasimClient.js
CHANGED
|
@@ -154,6 +154,9 @@ export function normalizeMirasimLimits(limits, profile = null) {
|
|
|
154
154
|
plan: profile?.plan ? String(profile.plan).toUpperCase() : (limits?.paid ? 'PRO' : 'FREE'),
|
|
155
155
|
planExpiresAt: epochToIso(profile?.plan_exp),
|
|
156
156
|
bottleneckLabel: isExhausted ? (bottleneck?.name || '额度') + '已用尽' : null,
|
|
157
|
+
// 结构化瓶颈(面板按词典分别 T() 窗口名与「已用尽」,替代拼串 bottleneckLabel——
|
|
158
|
+
// 上游新增窗口名(如 '30d')无词典映射时拼串会出「30d已用尽」混语)
|
|
159
|
+
bottleneck: isExhausted && bottleneck ? { name: bottleneck.name } : null,
|
|
157
160
|
parts,
|
|
158
161
|
empty: parts.length === 0,
|
|
159
162
|
exceeded: limits?.suspended === true || isExhausted,
|
package/src/panel.html
CHANGED
|
@@ -472,11 +472,6 @@
|
|
|
472
472
|
</div>
|
|
473
473
|
<div class="hint" data-i18n="作用于全部产品的定时签到轮(ZCode 活动领取在自身页签单独配置);修改立即生效,下一轮按新间隔执行。">作用于全部产品的定时签到轮(ZCode 活动领取在自身页签单独配置);修改立即生效,下一轮按新间隔执行。</div>
|
|
474
474
|
</div>
|
|
475
|
-
<div class="field">
|
|
476
|
-
<label data-i18n="WorkBuddy 国际版 活跃请求">WorkBuddy 国际版 活跃请求</label>
|
|
477
|
-
<label class="check"><input type="checkbox" id="cfg-wb-activity"> <span data-i18n="定期发送活跃请求(保持资格,不保证奖励)">定期发送活跃请求(保持资格,不保证奖励)</span></label>
|
|
478
|
-
<div class="hint" data-i18n="关闭后本机不再对国际版账号自动/手动发活跃请求;卡片与仪表盘的「活跃」入口一同隐藏。">关闭后本机不再对国际版账号自动/手动发活跃请求;卡片与仪表盘的「活跃」入口一同隐藏。</div>
|
|
479
|
-
</div>
|
|
480
475
|
<div class="field">
|
|
481
476
|
<label data-i18n="面板访问密码">面板访问密码</label>
|
|
482
477
|
<div id="sec-block"></div>
|
|
@@ -769,6 +764,35 @@
|
|
|
769
764
|
</div>
|
|
770
765
|
</div>
|
|
771
766
|
|
|
767
|
+
<!-- 捐赠支持(面向国内用户:爱发电 / 支付宝 / 微信;渠道与 10Router 一致,UI 照 CD 设计语言) -->
|
|
768
|
+
<div class="mask" id="m-donate">
|
|
769
|
+
<div class="modal">
|
|
770
|
+
<div class="modal-title"><span data-i18n="捐赠支持">捐赠支持</span><button class="close" data-close>✕</button></div>
|
|
771
|
+
<div class="hint" data-i18n="如果 CreditDaddy 对你有帮助,欢迎支持一下开发——免费渠道的每一行代码都是咖啡驱动的。">如果 CreditDaddy 对你有帮助,欢迎支持一下开发——免费渠道的每一行代码都是咖啡驱动的。</div>
|
|
772
|
+
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:14px">
|
|
773
|
+
<div style="display:flex;flex-direction:column;align-items:center;gap:8px;padding:14px 10px;border:1px solid var(--border-subtle);border-radius:10px">
|
|
774
|
+
<span style="font-size:26px">⚡</span>
|
|
775
|
+
<div style="font-weight:700">AiFaDian</div>
|
|
776
|
+
<div class="hint" data-i18n="爱发电 · Power me ⚡">爱发电 · Power me ⚡</div>
|
|
777
|
+
<img src="/assets/donate-ifdian.svg?v=3" alt="AiFaDian" style="width:140px;height:140px;margin-top:auto;border-radius:8px;padding:6px;flex:none">
|
|
778
|
+
</div>
|
|
779
|
+
<div style="display:flex;flex-direction:column;align-items:center;gap:8px;padding:14px 10px;border:1px solid var(--border-subtle);border-radius:10px">
|
|
780
|
+
<span style="font-size:26px">🅰️</span>
|
|
781
|
+
<div style="font-weight:700">Alipay</div>
|
|
782
|
+
<div class="hint" data-i18n="支付宝扫码打赏">支付宝扫码打赏</div>
|
|
783
|
+
<img src="/assets/donate-alipay.svg?v=3" alt="Alipay" style="width:140px;height:140px;margin-top:auto;border-radius:8px;padding:6px;flex:none">
|
|
784
|
+
</div>
|
|
785
|
+
<div style="display:flex;flex-direction:column;align-items:center;gap:8px;padding:14px 10px;border:1px solid var(--border-subtle);border-radius:10px">
|
|
786
|
+
<span style="font-size:26px">💚</span>
|
|
787
|
+
<div style="font-weight:700">WeChat Pay</div>
|
|
788
|
+
<div class="hint" data-i18n="微信扫码打赏">微信扫码打赏</div>
|
|
789
|
+
<img src="/assets/donate-wechat.svg?v=3" alt="WeChat Pay" style="width:140px;height:140px;margin-top:auto;border-radius:8px;padding:6px;flex:none">
|
|
790
|
+
</div>
|
|
791
|
+
</div>
|
|
792
|
+
<div class="modal-actions"><button class="btn primary" data-close data-i18n="关闭">关闭</button></div>
|
|
793
|
+
</div>
|
|
794
|
+
</div>
|
|
795
|
+
|
|
772
796
|
<!-- 10Router 设置 -->
|
|
773
797
|
<div class="mask" id="m-10r">
|
|
774
798
|
<div class="modal">
|
|
@@ -807,9 +831,9 @@
|
|
|
807
831
|
<!-- 免费额度池:推送设置 -->
|
|
808
832
|
<div class="mask" id="m-free-settings">
|
|
809
833
|
<div class="modal sm">
|
|
810
|
-
<div class="modal-title"><span data-i18n="
|
|
834
|
+
<div class="modal-title"><span data-i18n="额度卡片推送设置">额度卡片推送设置</span><button class="close" data-close>✕</button></div>
|
|
811
835
|
<div class="field">
|
|
812
|
-
<label class="check"><input type="checkbox" id="free-push-auto"> <span data-i18n="
|
|
836
|
+
<label class="check"><input type="checkbox" id="free-push-auto"> <span data-i18n="自动推送额度卡片到 10Router(Token Harbor / MiniMax / LongCat 等)">自动推送额度卡片到 10Router(Token Harbor / MiniMax / LongCat 等)</span></label>
|
|
813
837
|
</div>
|
|
814
838
|
<div class="field">
|
|
815
839
|
<label data-i18n="推送频率">推送频率</label>
|
|
@@ -821,7 +845,7 @@
|
|
|
821
845
|
<option value="240" data-i18n="每 4 小时">每 4 小时</option>
|
|
822
846
|
</select>
|
|
823
847
|
</div>
|
|
824
|
-
<div class="hint" data-i18n="把 CreditDaddy
|
|
848
|
+
<div class="hint" data-i18n="把 CreditDaddy 解析的额度数字(不含凭据)推到 10Router 配额页出卡;卡片在 10Router 具 7 天有效期。点「立即同步一次」或 10Router 页「刷新额度」也会立即推送。">把 CreditDaddy 解析的额度数字(不含凭据)推到 10Router 配额页出卡;卡片在 10Router 具 7 天有效期。点「立即同步一次」或 10Router 页「刷新额度」也会立即推送。</div>
|
|
825
849
|
<div class="hint" id="free-settings-status" style="margin-top:8px"></div>
|
|
826
850
|
<div class="modal-actions">
|
|
827
851
|
<button class="btn" style="margin-right:auto" id="free-settings-push-now" data-i18n="立即推送一次">立即推送一次</button>
|
|
@@ -969,6 +993,8 @@ const I = {
|
|
|
969
993
|
play: svg('<polygon points="6 4 20 12 6 20 6 4"/>'),
|
|
970
994
|
refresh: svg('<path d="M21 12a9 9 0 1 1-2.64-6.36L21 8"/><path d="M21 3v5h-5"/>'),
|
|
971
995
|
trash: svg('<path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/>'),
|
|
996
|
+
eye: svg('<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>'),
|
|
997
|
+
eyeOff: svg('<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>'),
|
|
972
998
|
plus: svg('<path d="M12 5v14M5 12h14"/>'),
|
|
973
999
|
upload: svg('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8l-5-5-5 5"/><path d="M12 3v12"/>'),
|
|
974
1000
|
download: svg('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/>'),
|
|
@@ -1023,6 +1049,9 @@ const COMPONENTS = [
|
|
|
1023
1049
|
{ id: 'free', label: '网页会话' },
|
|
1024
1050
|
{ id: 'tenrouter', label: '10Router' },
|
|
1025
1051
|
];
|
|
1052
|
+
// 捐赠二维码随日夜主题切换(顶层定义:applyTheme 的调用早于原块级定义,块内 function 不可达)
|
|
1053
|
+
// 捐赠二维码统一低饱和金黄(透明底),日夜主题通用,无需随主题切换
|
|
1054
|
+
function applyDonateQrTheme() { /* 统一金码:无主题切换 */ }
|
|
1026
1055
|
const HIDDEN_COMP_KEY = 'qd_hidden_components';
|
|
1027
1056
|
const DEFAULT_HIDDEN_COMP = ['catpaw']; // 妙手默认收起,右上角设置里可打开
|
|
1028
1057
|
state.hidden = (() => {
|
|
@@ -1250,7 +1279,6 @@ async function loadSettings() {
|
|
|
1250
1279
|
try {
|
|
1251
1280
|
const d = await api('/api/settings');
|
|
1252
1281
|
state.sec = { enabled: Boolean(d.panelKeyEnabled), loaded: true };
|
|
1253
|
-
state.wbActivity = d.workbuddyActivity !== false; // WB 国际版活跃请求总开关(默认开)
|
|
1254
1282
|
if (!d.panelKeyEnabled) setKey(''); // 关闭后清掉本地缓存的旧密钥
|
|
1255
1283
|
if (d.locale) renderLocale(d.locale);
|
|
1256
1284
|
} catch (e) { /* 401(密码开启但未输入)等状态由 promptKey 流程处理 */ }
|
|
@@ -1283,15 +1311,6 @@ async function applyDictFromServer() {
|
|
|
1283
1311
|
document.getElementById('set-locale')?.addEventListener('change', (ev) => setLocale(ev.target.value));
|
|
1284
1312
|
|
|
1285
1313
|
// ── 通用设置:全局自动签到(开关 + 频率,落盘立刻重调度)、日志默认显示方式(本机偏好)──
|
|
1286
|
-
const wbActOn = () => state.wbActivity !== false;
|
|
1287
|
-
$('cfg-wb-activity').addEventListener('change', async (e) => {
|
|
1288
|
-
try {
|
|
1289
|
-
await api('/api/settings', { method: 'PUT', json: { workbuddyActivity: e.target.checked } });
|
|
1290
|
-
await loadSettings();
|
|
1291
|
-
render(); renderStatus();
|
|
1292
|
-
toast(T('已保存'), true);
|
|
1293
|
-
} catch (err) { toast(err.message, false); }
|
|
1294
|
-
});
|
|
1295
1314
|
function fillAutoCheckin() {
|
|
1296
1315
|
const sc = state.status && state.status.scheduler;
|
|
1297
1316
|
if (!sc) return;
|
|
@@ -1329,6 +1348,7 @@ applyLogsDisplay(logsDisplayDefault());
|
|
|
1329
1348
|
// 由 renderThemeMode() 反映到菜单里的分段控件(主题只有那一个入口)。
|
|
1330
1349
|
function applyTheme(t) {
|
|
1331
1350
|
document.documentElement.dataset.theme = t;
|
|
1351
|
+
if (typeof applyDonateQrTheme === 'function') { try { applyDonateQrTheme(t); } catch {} }
|
|
1332
1352
|
}
|
|
1333
1353
|
function initTheme() {
|
|
1334
1354
|
let t = null;
|
|
@@ -1425,6 +1445,7 @@ function initTheme() {
|
|
|
1425
1445
|
// 需要跟随系统走菜单里的三态分段控件。
|
|
1426
1446
|
const themeBtn = $('btn-theme');
|
|
1427
1447
|
function resolvedTheme() { return document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light'; }
|
|
1448
|
+
|
|
1428
1449
|
function renderThemeButton() {
|
|
1429
1450
|
if (!themeBtn) return;
|
|
1430
1451
|
const cur = resolvedTheme();
|
|
@@ -1455,20 +1476,16 @@ function initTheme() {
|
|
|
1455
1476
|
else window.open(url, '_blank');
|
|
1456
1477
|
};
|
|
1457
1478
|
|
|
1458
|
-
//
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
if (window.creditdaddy && typeof window.creditdaddy.shellOpen === 'function')
|
|
1462
|
-
window.creditdaddy.shellOpen('https://github.com/sponsors/techysy');
|
|
1463
|
-
else window.open('https://github.com/sponsors/techysy', '_blank');
|
|
1464
|
-
};
|
|
1479
|
+
// 捐赠:弹窗展示三渠道(爱发电 / 支付宝 / 微信——国内用户为主,与 10Router 一致);
|
|
1480
|
+
// Sponsors 按钮跳转(桌面版走 IPC 桥,网页直接开浏览器)
|
|
1481
|
+
$('donate-btn').onclick = () => { closeHmenu(); openModal('m-donate'); };
|
|
1465
1482
|
}
|
|
1466
1483
|
|
|
1467
1484
|
// ── 状态 / 渲染 ──
|
|
1468
|
-
//
|
|
1485
|
+
// 统一「领鸡蛋」语义:全部签到产品线 = 领取积分(workbuddy-intl 的「活跃」语义随活跃领取线删除)
|
|
1469
1486
|
function statusOf(a) {
|
|
1470
1487
|
if (!CHECKIN_PRODUCTS.has(a.product)) return { cls: '', text: '', msg: '' }; // ZCode 无每日领取,不显示徽标
|
|
1471
|
-
|
|
1488
|
+
if (a.provider === 'workbuddy-intl') return { cls: '', text: '', msg: '' }; // 国际版无签到动作(活跃领取线已删),不显示徽标
|
|
1472
1489
|
const byProd = (state.status && state.status.todayByProduct) || {};
|
|
1473
1490
|
const today = byProd[a.product] || (state.status && state.status.today);
|
|
1474
1491
|
const done = state.status && state.status.todayDone && state.status.todayDone[a.id] === today;
|
|
@@ -1476,15 +1493,13 @@ function statusOf(a) {
|
|
|
1476
1493
|
const fresh = r && r.at && state.status && (Date.now() - new Date(r.at).getTime() < 26 * 3600e3);
|
|
1477
1494
|
if (r && fresh && r.status === 'limited' && done) return { cls: 'limited', text: T('本机已领'), msg: r.message };
|
|
1478
1495
|
if (done) {
|
|
1479
|
-
if (intl) return { cls: 'ok', text: T('今日活跃'), msg: r && r.message ? r.message : '' };
|
|
1480
1496
|
const amt = r && r.status === 'checked-in' && fresh && r.amount ? ' +' + fmtNum(r.amount) : '';
|
|
1481
|
-
const streak = r &&
|
|
1497
|
+
const streak = r && r.streakDays ? T(' · 连续 ') + r.streakDays + T(' 天') : '';
|
|
1482
1498
|
return { cls: 'ok', text: T('今日已领') + amt + streak, msg: r && r.message && !['checked-in', 'already'].includes(r.status) ? r.message : '' };
|
|
1483
1499
|
}
|
|
1484
|
-
|
|
1485
|
-
if (r && fresh && r.status === '
|
|
1486
|
-
|
|
1487
|
-
return { cls: 'pending', text: intl ? T('未活跃') : T('未领取'), msg: '' };
|
|
1500
|
+
if (r && fresh && r.status === 'failed') return { cls: 'fail', text: T('领取失败'), msg: r.message, err: true };
|
|
1501
|
+
if (r && fresh && r.status === 'no-activity') return { cls: 'pending', text: T('待领取'), msg: r.message };
|
|
1502
|
+
return { cls: 'pending', text: T('未领取'), msg: '' };
|
|
1488
1503
|
}
|
|
1489
1504
|
|
|
1490
1505
|
function expiryCell(a) {
|
|
@@ -1567,8 +1582,11 @@ function creditHtml(a) {
|
|
|
1567
1582
|
const planBadge = q.plan ? '<span class="badge">' + esc(T(q.plan)) + T(' 套餐</span>') : '';
|
|
1568
1583
|
const expLabel = q.planExpiresAt ? '<span class="dim">' + fmtTime(q.planExpiresAt).slice(0, 10) + T(' 到期</span>') : '';
|
|
1569
1584
|
// 状态采用温和的徽章,避免整行大红字制造恐慌
|
|
1585
|
+
// pill 不再用 mirasimClient 拼好的 bottleneckLabel(上游窗口名原文 + '已用尽' 拼串,
|
|
1586
|
+
// 英文界面会出「30d已用尽」这类混语)——改面板侧按词典分别 T():窗口名走词条
|
|
1587
|
+
// ('5小时窗口'→'5h window' 等,上游新名如 '30d' 拉丁原样),「已用尽」单独走词条。
|
|
1570
1588
|
const topStatus = isExhausted
|
|
1571
|
-
? '<span class="pill pending">' + esc(T(q.
|
|
1589
|
+
? '<span class="pill pending">' + esc(q.bottleneck ? T(q.bottleneck.name) + T('已用尽') : T('额度已用尽')) + '</span>'
|
|
1572
1590
|
: T('<span class="lbl">可用额度</span><b>') + fmtNum(q.remaining) + '%</b>';
|
|
1573
1591
|
|
|
1574
1592
|
const fmtUnits = (n) => (n >= 10000 ? (n / 10000).toFixed(2) + T('万') : fmtNum(Math.round(n)));
|
|
@@ -1640,7 +1658,7 @@ function cardHtml(a) {
|
|
|
1640
1658
|
+ (st.text ? '<span class="pill ' + st.cls + '" title="' + esc(a.lastResult ? fmtTime(a.lastResult.at) + ' ' + (a.lastResult.message || a.lastResult.status) : '') + '">' + esc(st.text) + '</span>' : '')
|
|
1641
1659
|
+ '</div><div class="ops">'
|
|
1642
1660
|
+ (a.product === 'zcode' ? T('<button class="icon-btn" data-act="claim" title="活动领取(billing/preview → claim,可能需过一次验证码)">') + I.gift + '</button>' : '')
|
|
1643
|
-
+ (canCheckin &&
|
|
1661
|
+
+ (canCheckin && a.provider !== 'workbuddy-intl' ? '<button class="icon-btn' + (state.busy[a.id] ? ' busy' : '') + '" data-act="checkin" title="' + T('立即领取') + '">' + (state.busy[a.id] ? I.refresh : I.play) + '</button>' : '')
|
|
1644
1662
|
+ (a.qoderWebDead ? '<button class="icon-btn" data-act="webrenew" title="' + T('网页会话已失效——打开登录窗口重新授权,关闭窗口时自动补 cookie(API token 不受影响)') + '">' + I.swap + '</button>' : '')
|
|
1645
1663
|
+ (a.canSwitch && !isCurrent && st.cls !== 'fail' ? T('<button class="icon-btn" data-act="switch" title="切换 ') + (CLIENT_LABEL[a.product] ? T(CLIENT_LABEL[a.product]) : prodLabel(a.product)) + T(' 客户端到此账号">') + I.swap + '</button>' : '')
|
|
1646
1664
|
+ T('<button class="icon-btn" data-act="quota" title="刷新积分">') + I.refresh + '</button>'
|
|
@@ -1752,11 +1770,9 @@ function renderProd() {
|
|
|
1752
1770
|
$('s-count').textContent = acc.length;
|
|
1753
1771
|
$('s-done-wrap').style.display = canCheckin ? 'contents' : 'none';
|
|
1754
1772
|
if (prod === 'workbuddy') {
|
|
1755
|
-
// 国内版 =
|
|
1773
|
+
// 国内版 = 每日签到送积分;国际版无签到动作(活跃领取线已删),只统计国内
|
|
1756
1774
|
const cnAcc = acc.filter((a) => a.provider === 'workbuddy');
|
|
1757
|
-
|
|
1758
|
-
$('s-done-wrap').innerHTML = (cnAcc.length ? T('<div class="stat"><span title="国内版每日签到送积分">领取(国内)</span><strong>') + cnAcc.filter(isDone).length + ' / ' + cnAcc.length + '</strong></div><div class="divider"></div>' : '')
|
|
1759
|
-
+ (intlAcc.length ? T('<div class="stat"><span title="国际版定期发送活跃请求保持资格;活跃不等于必有奖励">活跃(国际)</span><strong>') + intlAcc.filter(isDone).length + ' / ' + intlAcc.length + '</strong></div><div class="divider"></div>' : '');
|
|
1775
|
+
$('s-done-wrap').innerHTML = (cnAcc.length ? T('<div class="stat"><span title="国内版每日签到送积分">领取(国内)</span><strong>') + cnAcc.filter(isDone).length + ' / ' + cnAcc.length + '</strong></div><div class="divider"></div>' : '');
|
|
1760
1776
|
} else {
|
|
1761
1777
|
// 从 WorkBuddy 页切回来时 s-done 可能被 innerHTML 换没了,先重建结构再写值
|
|
1762
1778
|
if (!$('s-done')) $('s-done-wrap').innerHTML = T('<div class="stat"><span>今日已领</span><strong id="s-done"></strong></div><div class="divider"></div>');
|
|
@@ -1773,8 +1789,7 @@ function renderProd() {
|
|
|
1773
1789
|
document.querySelectorAll('#region button').forEach((x) => x.classList.toggle('active', x.dataset.r === state.region));
|
|
1774
1790
|
$('btn-checkin').style.display = canCheckin ? '' : 'none';
|
|
1775
1791
|
if (!$('btn-checkin').disabled) {
|
|
1776
|
-
|
|
1777
|
-
$('btn-checkin').innerHTML = I.play + (prod === 'workbuddy' && hasIntl ? T('领取 / 活跃全部') : T('领取全部 ') + prodLabel(prod));
|
|
1792
|
+
$('btn-checkin').innerHTML = I.play + T('领取全部 ') + prodLabel(prod);
|
|
1778
1793
|
}
|
|
1779
1794
|
// 顶栏产品专属入口:ZCode 设置组、Trae 打开客户端,带状态灯(运行中绿点呼吸)
|
|
1780
1795
|
const dot = (on, pulse) => '<span class="dot' + (on ? ' on' : '') + (on && pulse ? ' pulse' : '') + '"></span>';
|
|
@@ -1842,23 +1857,19 @@ function renderDash() {
|
|
|
1842
1857
|
const credit = creditSum(state.accounts.filter((a) => a.product !== 'zcode'));
|
|
1843
1858
|
const byProd = orderedVisibleComps().filter((id) => id !== 'tenrouter').map((id) => prodLabel(id) + ' ' + ofProduct(id).length).join(' · ');
|
|
1844
1859
|
const creditByProd = ['qoder', 'workbuddy', 'minimax'].filter(compVisible).map((id) => { const c = creditSum(ofProduct(id)); return prodLabel(id) + ' ' + (c.known ? fmtNum(c.sum) : '-'); }).join(' · ');
|
|
1845
|
-
//
|
|
1846
|
-
const intlAcc = signable.filter((a) => a.provider === 'workbuddy-intl' && wbActOn());
|
|
1847
|
-
const domAcc = signable.filter((a) => a.provider !== 'workbuddy-intl');
|
|
1848
|
-
const doneDom = domAcc.filter(isDone).length;
|
|
1849
|
-
const doneIntl = intlAcc.filter(isDone).length;
|
|
1860
|
+
// 今日进度:国际版 WorkBuddy 无签到动作(活跃领取线已删),signable 天然只剩可领取账号
|
|
1850
1861
|
$('kpis').innerHTML =
|
|
1851
1862
|
kpi(T('账号'), state.accounts.length, byProd)
|
|
1852
|
-
+ kpi(T('今日领取') +
|
|
1853
|
-
? doneDom + ' <small>/ ' + domAcc.length + '</small><small class="kpi-side">' + T(' · 活跃 {n} / {m}', { n: doneIntl, m: intlAcc.length }) + '</small>'
|
|
1854
|
-
: done + ' <small>/ ' + signable.length + '</small>',
|
|
1863
|
+
+ kpi(T('今日领取'), done + ' <small>/ ' + signable.length + '</small>',
|
|
1855
1864
|
!signable.length ? T('暂无可领取的账号')
|
|
1856
|
-
: (
|
|
1865
|
+
: (done === signable.length ? T('今天全部签完')
|
|
1857
1866
|
: T('待办 ') + (signable.length - done) + (failed ? T(' · 失败 ') + failed : '')),
|
|
1858
|
-
T('领取 =
|
|
1867
|
+
T('领取 = 每日签到'))
|
|
1859
1868
|
+ kpi(T('剩余积分'), credit.loading ? '…' : (credit.known ? fmtNum(credit.sum) : '-'), credit.loading ? T('正在读取各账号额度…') : creditByProd)
|
|
1860
1869
|
+ kpi(T('下次自动领取'), sch.ticking ? T('领取中…') : sch.nextTickAt ? fmtTime(sch.nextTickAt).slice(11) : '-',
|
|
1861
|
-
sch.lastTick
|
|
1870
|
+
sch.lastTick
|
|
1871
|
+
? T('上一轮 ') + fmtTime(sch.lastTick.at).slice(5) + ' · ' + esc(sch.lastTick.summaryKey ? T(sch.lastTick.summaryKey, sch.lastTick.summaryArgs) : (sch.lastTick.summary || ''))
|
|
1872
|
+
: T('每 ~2 小时一轮'));
|
|
1862
1873
|
|
|
1863
1874
|
// 仪表盘产品卡按组件设置里的顺序渲染(与标签栏同步),10Router 汇总卡按其顺序插入
|
|
1864
1875
|
const prodCardHtml = (p) => {
|
|
@@ -1870,16 +1881,10 @@ function renderDash() {
|
|
|
1870
1881
|
const d = list.filter(isDone).length;
|
|
1871
1882
|
const c = creditSum(list);
|
|
1872
1883
|
if (p.id === 'workbuddy') {
|
|
1873
|
-
// 国内 =
|
|
1884
|
+
// 国内 = 每日领取;国际无签到动作(活跃领取线已删),统计只覆盖国内账号
|
|
1874
1885
|
const cnList = list.filter((a) => a.provider === 'workbuddy');
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
if (cnList.length) parts.push(cnList.filter(isDone).length + ' / ' + cnList.length + T('(国内)'));
|
|
1878
|
-
if (intlList.length) parts.push(intlList.filter(isDone).length + ' / ' + intlList.length + T('(国际 · 不保证奖励)'));
|
|
1879
|
-
rows += T('<span class="lbl">领取 / 活跃</span><span class="val" title="') + esc(parts.join(T(',')) + (intlList.length ? T('(国际为活跃请求,不保证奖励)') : '')) + '">'
|
|
1880
|
-
+ (cnList.length ? cnList.filter(isDone).length + ' / ' + cnList.length + T(' 国内') : '')
|
|
1881
|
-
+ (cnList.length && intlList.length ? ' · ' : '')
|
|
1882
|
-
+ (intlList.length ? intlList.filter(isDone).length + ' / ' + intlList.length + T(' 国际') : '')
|
|
1886
|
+
rows += T('<span class="lbl">领取</span><span class="val" title="') + esc(cnList.length ? cnList.filter(isDone).length + ' / ' + cnList.length + T('(国内)') : '') + '">'
|
|
1887
|
+
+ (cnList.length ? cnList.filter(isDone).length + ' / ' + cnList.length + T(' 国内') : T('—'))
|
|
1883
1888
|
+ '</span>';
|
|
1884
1889
|
} else if (p.id === 'minimax') {
|
|
1885
1890
|
const planned = list.filter((a) => { const q = state.quotas[a.id]; return q && !q.error && !q.empty; }).length;
|
|
@@ -1944,7 +1949,7 @@ function renderDash() {
|
|
|
1944
1949
|
if (a.verified === false) att.push(Object.assign({ pill: 'fail', text: T('token 无效') }, base));
|
|
1945
1950
|
else if (ex.label === '已过期') att.push(Object.assign({ pill: 'fail', text: T('token 已过期') }, base));
|
|
1946
1951
|
else if (ex.warn) att.push(Object.assign({ pill: 'limited', text: ex.label.slice(5, 10) + T(' 过期') }, base));
|
|
1947
|
-
if (st.cls === 'fail') att.push(Object.assign({ pill: 'fail', text:
|
|
1952
|
+
if (st.cls === 'fail') att.push(Object.assign({ pill: 'fail', text: T('领取失败'), title: st.msg }, base));
|
|
1948
1953
|
}
|
|
1949
1954
|
for (const c of (tr.quotas && tr.quotas.connections) || []) {
|
|
1950
1955
|
if (!compVisible('tenrouter')) break;
|
|
@@ -1970,8 +1975,6 @@ function renderDash() {
|
|
|
1970
1975
|
? recent.map((a) => {
|
|
1971
1976
|
const r = a.lastResult;
|
|
1972
1977
|
let [cls, txt] = RES[r.status] || ['pending', r.status];
|
|
1973
|
-
// 国际版 WorkBuddy 是保持活跃(不保证奖励),不叫「领取」
|
|
1974
|
-
if (a.provider === 'workbuddy-intl' && r.status === 'checked-in') txt = T('活跃达成');
|
|
1975
1978
|
const label = r.status === 'checked-in' && r.amount ? txt + ' +' + fmtNum(r.amount) : txt;
|
|
1976
1979
|
return '<div class="item" data-view="' + a.product + '" title="' + esc(r.message || '') + '"><span class="item-main"><span class="item-name">' + esc(a.name || a.email || a.id) + '</span>' + provBadges(a.provider) + '</span>'
|
|
1977
1980
|
+ '<span class="item-side"><span class="pill ' + cls + '">' + esc(label) + '</span><span class="item-time">' + fmtTime(r.at).slice(5) + '</span></span></div>';
|
|
@@ -2001,7 +2004,7 @@ function renderStatus() {
|
|
|
2001
2004
|
} else {
|
|
2002
2005
|
chip.innerHTML = '';
|
|
2003
2006
|
}
|
|
2004
|
-
chip.title = sch.lastTick ? T('上一轮 ') + fmtTime(sch.lastTick.at) + T(':') + sch.lastTick.summary : '';
|
|
2007
|
+
chip.title = sch.lastTick ? T('上一轮 ') + fmtTime(sch.lastTick.at) + T(':') + (sch.lastTick.summaryKey ? T(sch.lastTick.summaryKey, sch.lastTick.summaryArgs) : sch.lastTick.summary || '') : '';
|
|
2005
2008
|
// 产品相关提示只在对应标签页出现
|
|
2006
2009
|
const hasIntl = state.view === 'qoder' && state.region !== 'cn' && state.accounts.some((a) => a.provider === 'qoder');
|
|
2007
2010
|
const n = $('notice');
|
|
@@ -2082,6 +2085,30 @@ async function installUmid() {
|
|
|
2082
2085
|
$('notice').addEventListener('click', (e) => { if (e.target.closest('#btn-umid')) installUmid(); });
|
|
2083
2086
|
// 覆盖 #notice(各产品横幅)与 #z-actions(ZCode 工具栏按钮组)的点击
|
|
2084
2087
|
document.addEventListener('click', async (e) => {
|
|
2088
|
+
// 免费额度页:站点卡隐藏 / 全部显示(拖拽排序在 renderFreePool 里经 bindCardDrag 绑定)
|
|
2089
|
+
const hideBtn = e.target.closest('[data-free-hide]');
|
|
2090
|
+
if (hideBtn) {
|
|
2091
|
+
state.hiddenFreeSites.add(hideBtn.dataset.freeHide);
|
|
2092
|
+
saveHiddenFreeSites();
|
|
2093
|
+
renderFreePool();
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
const doubaoBtn = e.target.closest('[data-open-doubao]');
|
|
2097
|
+
if (doubaoBtn) {
|
|
2098
|
+
if (window.creditdaddy && typeof window.creditdaddy.openDoubaoClient === 'function') {
|
|
2099
|
+
window.creditdaddy.openDoubaoClient().then((r) => {
|
|
2100
|
+
if (r && r.ok) toast(T('已启动豆包客户端'), true);
|
|
2101
|
+
else toast((r && r.error) || T('无法启动豆包客户端'), false);
|
|
2102
|
+
}).catch((err) => toast(String(err && err.message || err), false));
|
|
2103
|
+
} else toast(T('需要桌面版 CreditDaddy'), false);
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
if (e.target.closest('#free-show-all')) {
|
|
2107
|
+
state.hiddenFreeSites.clear();
|
|
2108
|
+
saveHiddenFreeSites();
|
|
2109
|
+
renderFreePool();
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2085
2112
|
if (e.target.closest('#zt-open')) {
|
|
2086
2113
|
try {
|
|
2087
2114
|
const r = await window.creditdaddy.openZcodeClient();
|
|
@@ -2488,30 +2515,78 @@ async function loadCookieSites(force) {
|
|
|
2488
2515
|
return state.cookieSites;
|
|
2489
2516
|
}
|
|
2490
2517
|
|
|
2518
|
+
// 免费额度页站点卡:顺序 / 显隐(本机持久化;拖拽复用 bindCardDrag,眼睛按钮切换显隐)
|
|
2519
|
+
const FREE_ORDER_KEY = 'qd_free_site_order';
|
|
2520
|
+
const FREE_HIDDEN_KEY = 'qd_hidden_free_sites';
|
|
2521
|
+
state.freeOrder = (() => {
|
|
2522
|
+
let arr = [];
|
|
2523
|
+
try { arr = JSON.parse(localStorage.getItem(FREE_ORDER_KEY) || '[]'); } catch {}
|
|
2524
|
+
return Array.isArray(arr) ? arr : [];
|
|
2525
|
+
})();
|
|
2526
|
+
function saveFreeOrder() { try { localStorage.setItem(FREE_ORDER_KEY, JSON.stringify(state.freeOrder)); } catch {} }
|
|
2527
|
+
state.hiddenFreeSites = (() => {
|
|
2528
|
+
let list = [];
|
|
2529
|
+
try { list = JSON.parse(localStorage.getItem(FREE_HIDDEN_KEY) || '[]'); } catch {}
|
|
2530
|
+
return new Set(Array.isArray(list) ? list : []);
|
|
2531
|
+
})();
|
|
2532
|
+
function saveHiddenFreeSites() { try { localStorage.setItem(FREE_HIDDEN_KEY, JSON.stringify([...state.hiddenFreeSites])); } catch {} }
|
|
2533
|
+
const freeVisible = (id) => !state.hiddenFreeSites.has(id);
|
|
2534
|
+
|
|
2535
|
+
function orderedFreeSites(sites) {
|
|
2536
|
+
const ids = sites.map((s) => s.id);
|
|
2537
|
+
const arr = state.freeOrder.filter((id) => ids.includes(id));
|
|
2538
|
+
for (const id of ids) if (!arr.includes(id)) arr.push(id);
|
|
2539
|
+
state.freeOrder = arr;
|
|
2540
|
+
return arr.map((id) => sites.find((s) => s.id === id)).filter(Boolean);
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2491
2543
|
function renderFreePool() {
|
|
2492
2544
|
const body = $('free-pool-body');
|
|
2493
2545
|
if (!body) return;
|
|
2494
2546
|
const sites = state.cookieSites;
|
|
2495
2547
|
const canCapture = Boolean(window.creditdaddy && typeof window.creditdaddy.openAuthWindow === 'function');
|
|
2496
2548
|
if (!sites) { body.innerHTML = T('<div class="dim">加载中…</div>'); loadCookieSites().then(() => renderFreePool()); return; }
|
|
2497
|
-
const
|
|
2549
|
+
const enabledSites = sites.filter((s) => s.disabled !== true);
|
|
2550
|
+
const totalAccounts = enabledSites.reduce((sum, s) => sum + (s.accounts?.length || 0), 0);
|
|
2498
2551
|
if ($('free-total-count')) $('free-total-count').textContent = totalAccounts;
|
|
2499
|
-
if ($('free-sites-count')) $('free-sites-count').textContent =
|
|
2552
|
+
if ($('free-sites-count')) $('free-sites-count').textContent = enabledSites.length;
|
|
2500
2553
|
if ($('cnt-free')) $('cnt-free').textContent = totalAccounts;
|
|
2501
2554
|
|
|
2502
|
-
if (!
|
|
2555
|
+
if (!enabledSites.length) {
|
|
2503
2556
|
body.innerHTML = T('<div class="muted-empty">暂无可捕获的供应商</div>');
|
|
2504
2557
|
return;
|
|
2505
2558
|
}
|
|
2506
2559
|
|
|
2507
|
-
|
|
2560
|
+
const hiddenCount = enabledSites.filter((s) => !freeVisible(s.id)).length;
|
|
2561
|
+
const showHiddenBar = hiddenCount > 0;
|
|
2562
|
+
const visibleSites = orderedFreeSites(sites).filter((s) => freeVisible(s.id) && s.disabled !== true);
|
|
2563
|
+
|
|
2564
|
+
body.innerHTML = (showHiddenBar
|
|
2565
|
+
? T('<div class="hint" style="grid-column:1/-1;display:flex;align-items:center;gap:8px">') + T('{n} 个站点已隐藏', { n: hiddenCount })
|
|
2566
|
+
+ ' <button class="btn" id="free-show-all" style="padding:2px 10px;font-size:12px">' + T('全部显示') + '</button></div>'
|
|
2567
|
+
: '')
|
|
2568
|
+
+ visibleSites.map((site) => {
|
|
2569
|
+
// entryOnly 站点(豆包):纯快捷入口卡——只出「打开」按钮与说明,无捕获/账号
|
|
2570
|
+
if (site.entryOnly === true) {
|
|
2571
|
+
const openBtn = canCapture
|
|
2572
|
+
? '<button class="btn primary" data-open-doubao="1">' + I.play + T('打开豆包') + '</button>'
|
|
2573
|
+
: T('<button class="btn" disabled title="需要桌面版 CreditDaddy">打开豆包</button>');
|
|
2574
|
+
return '<div class="card" style="display:flex;flex-direction:column;justify-content:flex-start;gap:8px;padding:14px 16px;background:var(--surface);border:1px solid var(--border-subtle);border-radius:14px;box-shadow:var(--shadow)">'
|
|
2575
|
+
+ '<div style="display:flex;align-items:center;justify-content:space-between;gap:10px">'
|
|
2576
|
+
+ '<span style="font-size:14px;font-weight:700">' + esc(site.label || site.name) + '</span>' + openBtn + '</div>'
|
|
2577
|
+
+ (site.hint ? '<div class="hint" style="margin:2px 0 0">' + esc(T(site.hint)) + '</div>' : '')
|
|
2578
|
+
+ '</div>';
|
|
2579
|
+
}
|
|
2508
2580
|
const rows = site.accounts || [];
|
|
2509
2581
|
const stateTxt = rows.length
|
|
2510
2582
|
? T('<span class="badge ok">已捕获 ') + rows.length + T(' 个会话</span>')
|
|
2511
2583
|
: T('<span class="badge limited">未捕获</span>');
|
|
2512
|
-
const
|
|
2513
|
-
|
|
2514
|
-
|
|
2584
|
+
const siteDisabled = site.disabled === true;
|
|
2585
|
+
const btn = siteDisabled
|
|
2586
|
+
? T('<button class="btn" disabled title="网页 cookie 无法参与该站活动(活动校验客户端环境)">网页版(暂不可用)</button>')
|
|
2587
|
+
: canCapture
|
|
2588
|
+
? '<button class="btn primary" data-capture-site="' + esc(site.id) + '">' + I.plus + T('网页版') + '</button>'
|
|
2589
|
+
: T('<button class="btn" disabled title="需要桌面版 CreditDaddy(无痕登录窗)">网页版</button>');
|
|
2515
2590
|
// 「粘贴捕获」:部分站点(小米账号 SSO)登录态挂设备指纹,CD 无痕窗也会被静默 SSO
|
|
2516
2591
|
// 拉回同一账号——多号并存走系统浏览器登录新号后手动粘 cookie(不依赖登录窗)。
|
|
2517
2592
|
const pasteBtn = ' <button class="btn" data-paste-capture="' + esc(site.id) + '" title="' + T('在其他浏览器登录该站点后,把会话 cookie 粘贴进来捕获(多账号并存的可靠路径)') + '">' + T('粘贴捕获') + '</button>';
|
|
@@ -2605,28 +2680,44 @@ function renderFreePool() {
|
|
|
2605
2680
|
+ '</div>'
|
|
2606
2681
|
+ '<div style="display:flex;align-items:center;gap:8px;flex:none">'
|
|
2607
2682
|
+ '<span class="dim" style="font-size:11.5px">' + (acc.capturedAt ? esc(fmtTime(acc.capturedAt)) : '–') + '</span>'
|
|
2683
|
+
+ (site.id === 'doubao' && canCapture ? '<button class="icon-btn" data-open-doubao="1" title="' + T('打开豆包客户端(签到请在客户端内完成)') + '">' + I.play + '</button>' : '')
|
|
2608
2684
|
+ '<button class="icon-btn" data-act="reprobe" data-site="' + esc(site.id) + '" data-id="' + esc(acc.id) + '" title="' + T('就地重探(免登录,用已存会话刷新身份与额度)') + '">' + I.refresh + '</button>'
|
|
2609
2685
|
+ '<button class="icon-btn del" data-act="del" data-id="' + esc(acc.id) + '" title="' + T('删除此账号') + '">' + I.trash + '</button>'
|
|
2610
2686
|
+ '</div></div>'
|
|
2611
2687
|
+ (metricHtml ? '<div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding-left:14px">' + metricHtml + '</div>' : '')
|
|
2612
2688
|
+ '</div>';
|
|
2613
2689
|
}).join('') + '</div>'
|
|
2614
|
-
: T('<div class="muted-empty" style="padding:16px 0 6px"
|
|
2690
|
+
: T('<div class="muted-empty" style="padding:16px 0 6px">还没有该站点的账号,点右上角「网页版」登录后自动捕获</div>');
|
|
2615
2691
|
|
|
2616
2692
|
// justify-content 不用 space-between:网格行高被最高卡撑齐后,单行账号会被推到卡底(沉底)
|
|
2617
|
-
|
|
2693
|
+
const eyeBtn = '<button class="icon-btn" data-free-hide="' + esc(site.id) + '" title="' + T('隐藏此站点卡片(「全部显示」可恢复)') + '">' + I.eyeOff + '</button>';
|
|
2694
|
+
return '<div class="card" draggable="true" data-id="' + esc(site.id) + '" style="display:flex;flex-direction:column;justify-content:flex-start;gap:8px;padding:14px 16px;background:var(--surface);border:1px solid var(--border-subtle);border-radius:14px;box-shadow:var(--shadow)">'
|
|
2618
2695
|
+ '<div><div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:6px">'
|
|
2619
2696
|
+ '<div style="display:flex;align-items:center;gap:8px">'
|
|
2620
2697
|
+ '<span style="font-size:14px;font-weight:700">' + esc(site.label || site.name) + '</span>'
|
|
2621
2698
|
+ stateTxt
|
|
2622
2699
|
+ '</div>'
|
|
2623
|
-
+ '<div style="display:flex;align-items:center;gap:6px">' + btn + pasteBtn + clearBtn + '</div>'
|
|
2700
|
+
+ '<div style="display:flex;align-items:center;gap:6px">' + btn + pasteBtn + clearBtn + eyeBtn + '</div>'
|
|
2624
2701
|
+ '</div>'
|
|
2625
2702
|
+ hint
|
|
2626
2703
|
+ '</div>'
|
|
2627
2704
|
+ accRows
|
|
2628
2705
|
+ '</div>';
|
|
2629
2706
|
}).join('');
|
|
2707
|
+
bindCardDrag(body, {
|
|
2708
|
+
kind: 'free-site',
|
|
2709
|
+
onReorder: (drag, targetId) => {
|
|
2710
|
+
if (!drag.id) return;
|
|
2711
|
+
const ids = state.freeOrder.slice();
|
|
2712
|
+
const from = ids.indexOf(drag.id);
|
|
2713
|
+
if (from >= 0) ids.splice(from, 1);
|
|
2714
|
+
const ti = ids.indexOf(targetId);
|
|
2715
|
+
ids.splice(ti < 0 ? ids.length : ti, 0, drag.id);
|
|
2716
|
+
state.freeOrder = ids;
|
|
2717
|
+
saveFreeOrder();
|
|
2718
|
+
renderFreePool();
|
|
2719
|
+
},
|
|
2720
|
+
});
|
|
2630
2721
|
}
|
|
2631
2722
|
|
|
2632
2723
|
function renderCookieSites() {
|
|
@@ -2642,8 +2733,8 @@ function renderCookieSites() {
|
|
|
2642
2733
|
? T('<span class="dim">已捕获 ') + rows.length + T(' 个会话</span>')
|
|
2643
2734
|
: T('<span class="dim">未捕获</span>');
|
|
2644
2735
|
const btn = canCapture
|
|
2645
|
-
? '<button class="btn" data-capture-site="' + esc(site.id) + '">' + T('
|
|
2646
|
-
: T('<button class="btn" disabled title="需要桌面版 CreditDaddy(无痕登录窗)"
|
|
2736
|
+
? '<button class="btn" data-capture-site="' + esc(site.id) + '">' + T('网页版') + '</button>'
|
|
2737
|
+
: T('<button class="btn" disabled title="需要桌面版 CreditDaddy(无痕登录窗)">网页版</button>');
|
|
2647
2738
|
const hint = site.hint ? T('<div class="hint">') + esc(site.hint) + '</div>' : '';
|
|
2648
2739
|
const accRows = rows.map((acc) =>
|
|
2649
2740
|
'<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px">'
|
|
@@ -2736,7 +2827,7 @@ $('free-settings-save')?.addEventListener('click', async () => {
|
|
|
2736
2827
|
},
|
|
2737
2828
|
});
|
|
2738
2829
|
closeModal('m-free-settings');
|
|
2739
|
-
toast(T('
|
|
2830
|
+
toast(T('额度卡片推送设置已保存'));
|
|
2740
2831
|
} catch (e) { toast(e.message, false); }
|
|
2741
2832
|
});
|
|
2742
2833
|
$('free-settings-push-now')?.addEventListener('click', async () => {
|
|
@@ -2780,7 +2871,10 @@ async function cookieSitePasteCapture(siteId) {
|
|
|
2780
2871
|
try {
|
|
2781
2872
|
const r = await api('/api/cookie-sites/' + encodeURIComponent(siteId) + '/capture', { json: { cookie: cookie.trim() } });
|
|
2782
2873
|
if (r && r.ok) {
|
|
2783
|
-
|
|
2874
|
+
// 豆包不推 10R(无外部配额卡),文案不带「同步 10Router」以免误导
|
|
2875
|
+
toast(site.no10rSync
|
|
2876
|
+
? T('{name} cookie 捕获成功,额度卡片已就绪', { name: site.name })
|
|
2877
|
+
: T('{name} cookie 捕获成功,同步到 10Router 后卡片点亮', { name: site.name }), true);
|
|
2784
2878
|
state.cookieSites = null;
|
|
2785
2879
|
loadCookieSites(true).then(() => { if (state.view === 'free') renderFreePool(); });
|
|
2786
2880
|
} else toast(T('捕获失败'), false);
|
|
@@ -2796,7 +2890,10 @@ if (window.creditdaddy && typeof window.creditdaddy.onCookieCaptured === 'functi
|
|
|
2796
2890
|
window.creditdaddy.onCookieCaptured((payload) => {
|
|
2797
2891
|
if (payload && payload.ok === false) { toast(payload.error || T('cookie 捕获失败'), false); return; }
|
|
2798
2892
|
const name = payload && payload.name;
|
|
2799
|
-
|
|
2893
|
+
const site2 = (state.cookieSites || []).find((s) => s.name === name) || null;
|
|
2894
|
+
toast(site2?.no10rSync
|
|
2895
|
+
? T('{name} cookie 捕获成功,额度卡片已就绪', { name: name || '' })
|
|
2896
|
+
: T('{name} cookie 捕获成功,同步到 10Router 后卡片点亮', { name: name || '' }), true);
|
|
2800
2897
|
state.cookieSites = null;
|
|
2801
2898
|
Promise.allSettled([loadCookieSites(true), refreshAccountList(), loadTrQuotas(true)])
|
|
2802
2899
|
.then(() => {
|
|
@@ -2804,6 +2901,11 @@ if (window.creditdaddy && typeof window.creditdaddy.onCookieCaptured === 'functi
|
|
|
2804
2901
|
if (state.view === 'free') renderFreePool();
|
|
2805
2902
|
renderCookieSites();
|
|
2806
2903
|
renderDash();
|
|
2904
|
+
// 收割时余额快照已随账号落库——账号卡上的余额读 state.quotas 缓存,
|
|
2905
|
+
// 不重拉就显示旧数字(实测:小米收割成功后卡面 ¥0.00 挂到手动刷新)。
|
|
2906
|
+
// 非 live 读快照零网络,成本可忽略;只刷 cookie-site 型账号。
|
|
2907
|
+
const ids = (state.accounts || []).filter((a) => a.meta?.cookieSiteId).map((a) => a.id);
|
|
2908
|
+
if (ids.length) loadQuotas(ids).then(renderDash);
|
|
2807
2909
|
});
|
|
2808
2910
|
});
|
|
2809
2911
|
}
|
|
@@ -3657,7 +3759,7 @@ function openChangelogModal() {
|
|
|
3657
3759
|
+ '<div style="font-weight:700;margin:0 0 4px">v' + esc(s.version)
|
|
3658
3760
|
+ (s.date ? ' <span class="dim" style="font-weight:400;font-size:11px">' + esc(s.date) + '</span>' : '') + '</div>'
|
|
3659
3761
|
+ (s.theme ? '<div class="hint">' + strip(s.theme) + '</div>' : '')
|
|
3660
|
-
+ (s.topics && s.topics.length ? '<div class="hint" style="margin-top:4px">' + s.topics.map(strip).join(' · ') + '</div>' : '')
|
|
3762
|
+
+ (s.topics && s.topics.length ? '<div class="hint" style="margin-top:4px">' + s.topics.map((t) => strip(T(t.trim()))).join(' · ') + '</div>' : '')
|
|
3661
3763
|
+ '</div>').join('')
|
|
3662
3764
|
: T('<div class="hint">暂无本地更新日志,请到 GitHub Releases 查看。</div>');
|
|
3663
3765
|
}).catch(openReleases);
|
|
@@ -3767,7 +3869,7 @@ $('znet-ok').addEventListener('click', async () => {
|
|
|
3767
3869
|
state.zProxyFirst = r.proxyFirst === true;
|
|
3768
3870
|
await loadZNet();
|
|
3769
3871
|
$('znet-url').value = '';
|
|
3770
|
-
$('znet-url').placeholder = state.zProxyUrl
|
|
3872
|
+
$('znet-url').placeholder = state.zProxyUrl ? T('当前代理:{url}(输入新值可更换,留空清除)', { url: state.zProxyUrl }) : (state.zHasEnvProxy ? T('跟随环境变量 HTTPS_PROXY') : 'http://192.168.31.101:7890');
|
|
3771
3873
|
$('znet-state').textContent = T('已保存:') + (state.zProxyFirst === true ? T('代理优先') : T('直连优先'))
|
|
3772
3874
|
+ (state.zProxyUrl ? T(' · 代理 ') + state.zProxyUrl : '');
|
|
3773
3875
|
toast(T('网络出口:') + (r.proxyFirst ? T('代理优先(直连兜底)') : T('直连优先(代理兜底)')) + (body.proxyUrl === '' ? T(',代理已清除') : T(',代理已保存')));
|
|
@@ -3844,10 +3946,11 @@ async function localScan() {
|
|
|
3844
3946
|
const sub = c.kind === 'app'
|
|
3845
3947
|
? esc(c.source) + (c.email ? ' · ' + esc(mask(c.email)) : c.phone ? ' · ' + esc(c.phone) : '') + (c.expiresAt ? T(' · 有效期至 ') + esc(fmtTime(c.expiresAt)) : '')
|
|
3846
3948
|
: esc(c.source) + ' · ' + esc(String(c.file || '').split(/[\\/]/).pop()) + T('(') + c.hits + T(' 处)');
|
|
3949
|
+
const intl = c.intlWarning ? '<div class="hint" style="color:var(--warn,#d4b83a);margin-top:4px">⚠ ' + esc(c.intlWarning) + '</div>' : '';
|
|
3847
3950
|
const btns = c.imported ? T('<span class="pill ok">已导入</span>') + (c.provider ? '<button class="btn" data-cid="' + esc(c.id) + T('" title="用本机凭据更新 token / 有效期 / 邮箱">同步信息</button>') : '')
|
|
3848
3951
|
: c.provider ? '<button class="btn primary" data-cid="' + esc(c.id) + T('">导入</button>')
|
|
3849
3952
|
: '<button class="btn" data-cid="' + esc(c.id) + T('" data-prov="qoder">导入·国际</button><button class="btn" data-cid="') + esc(c.id) + T('" data-prov="qoder-cn">导入·国内</button>');
|
|
3850
|
-
html += '<div class="cand"><div class="cand-main"><div class="cand-name">' + title + prov + '</div><div class="cand-sub">' + sub + '</div
|
|
3953
|
+
html += '<div class="cand"><div class="cand-main"><div class="cand-name">' + title + prov + '</div><div class="cand-sub">' + sub + '</div>' + intl + '</div><div class="row">' + btns + '</div></div>';
|
|
3851
3954
|
}
|
|
3852
3955
|
for (const e of r.errors || []) {
|
|
3853
3956
|
html += T('<div class="hint" style="color:var(--err)">读取失败:') + esc(e.file) + T(':') + esc(e.error) + '</div>';
|
|
@@ -4308,7 +4411,6 @@ $('btn-comp').addEventListener('click', async () => {
|
|
|
4308
4411
|
renderCompMenu();
|
|
4309
4412
|
fillAutoCheckin();
|
|
4310
4413
|
$('cfg-logs-display').value = logsDisplayDefault();
|
|
4311
|
-
$('cfg-wb-activity').checked = wbActOn();
|
|
4312
4414
|
// 网络出口(全局):预填当前顺序与脱敏代理地址
|
|
4313
4415
|
await loadZNet();
|
|
4314
4416
|
(state.zProxyFirst === true ? $('znet-proxy') : $('znet-direct')).checked = true;
|