deepseek-harness-wallet 0.2.0 → 0.2.1
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/CHANGELOG.md +5 -0
- package/index.js +79 -17
- package/integrations/dsh-session-delete/compatibility.json +1 -1
- package/lib/client.js +355 -148
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.2.1 - 2026-08-20
|
|
6
|
+
|
|
7
|
+
- 标签上「本场」恢复常显(¥0.00 也显示,新会话不再缺席);仅未定价模型仍隐藏。/ The chip shows the session cost again even at ¥0.00; only unpriced models stay hidden.
|
|
8
|
+
- 面板/浮动窗版本号移至底部右下角,不再与顶栏按钮挤压。 / Panel version tags moved to the footer, clear of the header buttons.
|
|
9
|
+
|
|
5
10
|
## 0.2.0 - 2026-08-18
|
|
6
11
|
|
|
7
12
|
- 新增多账户管理与热切换:面板内“账户管理”可添加多个账户(名称 + API Key),切换后无需重启,下一次 LLM 调用即按新账户计费;key 界面掩码显示,余额查询跟随当前账户(contributed in PR #4 by mxchen-xyz)。 / Added multi-account management with hot switching: manage accounts in the panel, and the very next LLM call is billed with the newly activated key — no restart needed; keys stay masked in the UI and balance follows the active account.
|
package/index.js
CHANGED
|
@@ -110,6 +110,41 @@ export function normalizeThreshold(value) {
|
|
|
110
110
|
return Math.min(100000, Math.max(0, Math.round(parsed * 100) / 100))
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// Low-balance thresholds are per-currency: a USD account warns against its
|
|
114
|
+
// own $ threshold, a CNY account against its own ¥ one; they never compare
|
|
115
|
+
// across currencies. The legacy single-value store migrates into CNY.
|
|
116
|
+
// Per-ACCOUNT thresholds: two accounts in the same currency may keep
|
|
117
|
+
// different warning lines ("one account is 1, another is 2"). Keyed by
|
|
118
|
+
// account id; the per-currency map stays as the fallback for the
|
|
119
|
+
// no-active-account (system key) case and as the migration source.
|
|
120
|
+
export function normalizeAccountThresholds(value) {
|
|
121
|
+
const source = value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {}
|
|
122
|
+
const out = {}
|
|
123
|
+
for (const [id, raw] of Object.entries(source)) {
|
|
124
|
+
if (typeof id !== 'string' || id === '' || id.length > 100) continue
|
|
125
|
+
if (id === '__proto__' || id === 'prototype' || id === 'constructor') continue
|
|
126
|
+
const parsed = Number.parseFloat(raw)
|
|
127
|
+
if (!Number.isFinite(parsed)) continue
|
|
128
|
+
out[id] = Math.min(100000, Math.max(0, Math.round(parsed * 100) / 100))
|
|
129
|
+
if (Object.keys(out).length >= 50) break
|
|
130
|
+
}
|
|
131
|
+
return out
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function normalizeThresholds(value) {
|
|
135
|
+
const source = value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {}
|
|
136
|
+
const out = {}
|
|
137
|
+
for (const [code, raw] of Object.entries(source)) {
|
|
138
|
+
if (!/^[A-Z]{3}$/.test(code)) continue
|
|
139
|
+
if (code === '__proto__' || code === 'prototype' || code === 'constructor') continue
|
|
140
|
+
const parsed = Number.parseFloat(raw)
|
|
141
|
+
if (!Number.isFinite(parsed)) continue
|
|
142
|
+
out[code] = Math.min(100000, Math.max(0, Math.round(parsed * 100) / 100))
|
|
143
|
+
if (Object.keys(out).length >= 20) break
|
|
144
|
+
}
|
|
145
|
+
return out
|
|
146
|
+
}
|
|
147
|
+
|
|
113
148
|
function finiteCounter(value) {
|
|
114
149
|
return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : 0
|
|
115
150
|
}
|
|
@@ -188,7 +223,8 @@ export function normalizeStoreData(value, atMs = Date.now()) {
|
|
|
188
223
|
}
|
|
189
224
|
const normalized = {
|
|
190
225
|
version: STORE_VERSION,
|
|
191
|
-
|
|
226
|
+
thresholds: normalizeThresholds(source.thresholds && Object.keys(source.thresholds).length > 0 ? source.thresholds : { CNY: normalizeThreshold(source.threshold) }),
|
|
227
|
+
accountThresholds: normalizeAccountThresholds(source.accountThresholds),
|
|
192
228
|
sessions,
|
|
193
229
|
officialProviders: normalizeProviderList(source.officialProviders),
|
|
194
230
|
knownProviders: normalizeProviderList(source.knownProviders),
|
|
@@ -201,7 +237,7 @@ function loadStore() {
|
|
|
201
237
|
return normalizeStoreData(JSON.parse(readFileSync(STORE_PATH, 'utf8')))
|
|
202
238
|
} catch {
|
|
203
239
|
return {
|
|
204
|
-
store: { version: STORE_VERSION,
|
|
240
|
+
store: { version: STORE_VERSION, thresholds: { CNY: DEFAULT_THRESHOLD }, accountThresholds: {}, sessions: {}, officialProviders: [], knownProviders: [] },
|
|
205
241
|
migrated: false,
|
|
206
242
|
}
|
|
207
243
|
}
|
|
@@ -346,6 +382,11 @@ export function removeAccount(id) {
|
|
|
346
382
|
const index = accounts.accounts.findIndex((account) => account.id === id)
|
|
347
383
|
if (index < 0) return { ok: false, error: 'account not found' }
|
|
348
384
|
accounts.accounts.splice(index, 1)
|
|
385
|
+
// Drop the account's own threshold line along with it.
|
|
386
|
+
if (store.accountThresholds && Object.hasOwn(store.accountThresholds, id)) {
|
|
387
|
+
delete store.accountThresholds[id]
|
|
388
|
+
scheduleAccountsSave(null)
|
|
389
|
+
}
|
|
349
390
|
// Deliberately NOT unsetting the credentials seam: the key currently in
|
|
350
391
|
// .credentials.yaml keeps working for LLM billing; the UI just reports
|
|
351
392
|
// "no active account" and balance falls back to the seam key.
|
|
@@ -551,13 +592,14 @@ function sessionView(sessionId) {
|
|
|
551
592
|
official: {
|
|
552
593
|
tokens: official,
|
|
553
594
|
cost: session.official.priced === true ? session.official.cost : null,
|
|
595
|
+
priced: session.official.priced === true,
|
|
554
596
|
models: session.official.models,
|
|
555
597
|
},
|
|
556
598
|
third: { tokens: third, models: session.third.models },
|
|
557
599
|
}
|
|
558
600
|
}
|
|
559
601
|
|
|
560
|
-
function snapshotView(sessionId
|
|
602
|
+
function snapshotView(sessionId) {
|
|
561
603
|
const currency = balanceCurrency(balance.balances)
|
|
562
604
|
const active = activeAccount()
|
|
563
605
|
return {
|
|
@@ -571,10 +613,19 @@ function snapshotView(sessionId, threshold) {
|
|
|
571
613
|
error: balance.available ? null : balance.error,
|
|
572
614
|
},
|
|
573
615
|
session: sessionView(sessionId),
|
|
574
|
-
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
|
|
616
|
+
// Thresholds are per-ACCOUNT first (each account keeps its own line even
|
|
617
|
+
// in the same currency); the per-currency map only serves the
|
|
618
|
+
// no-active-account case and inherits into accounts without one yet.
|
|
619
|
+
threshold: active !== null
|
|
620
|
+
? (store.accountThresholds[active.id] ?? store.thresholds[currency || 'CNY'] ?? 0)
|
|
621
|
+
: (store.thresholds[currency || 'CNY'] ?? 0),
|
|
622
|
+
lowBalance: balance.available && currency !== null
|
|
623
|
+
&& (function () {
|
|
624
|
+
const line = active !== null
|
|
625
|
+
? (store.accountThresholds[active.id] ?? store.thresholds[currency] ?? 0)
|
|
626
|
+
: (store.thresholds[currency] ?? 0)
|
|
627
|
+
return line > 0 && balanceTotal() < line
|
|
628
|
+
})(),
|
|
578
629
|
rechargeUrl: RECHARGE_URL,
|
|
579
630
|
accounts: {
|
|
580
631
|
activeId: accounts.activeId,
|
|
@@ -637,12 +688,10 @@ export function apply(ctx, config) {
|
|
|
637
688
|
storeNeedsSave = false
|
|
638
689
|
scheduleSave(ctx.logger)
|
|
639
690
|
}
|
|
640
|
-
//
|
|
641
|
-
// still override
|
|
642
|
-
let threshold = store.threshold
|
|
691
|
+
// Thresholds live ONLY in the persisted store; an explicit row config may
|
|
692
|
+
// still override the CNY line for power users, but the bundle patch sets none.
|
|
643
693
|
if (Number.isFinite(config.threshold)) {
|
|
644
|
-
|
|
645
|
-
store.threshold = threshold
|
|
694
|
+
store.thresholds = normalizeThresholds({ ...store.thresholds, CNY: normalizeThreshold(config.threshold) })
|
|
646
695
|
scheduleSave(ctx.logger)
|
|
647
696
|
}
|
|
648
697
|
|
|
@@ -694,7 +743,7 @@ export function apply(ctx, config) {
|
|
|
694
743
|
path: '/api/wallet/snapshot',
|
|
695
744
|
handler: (req, res) => {
|
|
696
745
|
if (req.method !== 'GET') return json(res, 405, { ok: false, error: 'method-not-allowed' })
|
|
697
|
-
return json(res, 200, snapshotView(sessionParam(req)
|
|
746
|
+
return json(res, 200, snapshotView(sessionParam(req)))
|
|
698
747
|
},
|
|
699
748
|
})
|
|
700
749
|
const disposeThreshold = ctx.webServer.register({
|
|
@@ -706,10 +755,19 @@ export function apply(ctx, config) {
|
|
|
706
755
|
if (body === null || typeof body.threshold !== 'number' || !Number.isFinite(body.threshold)) {
|
|
707
756
|
return json(res, 400, { ok: false, error: 'threshold must be a number' })
|
|
708
757
|
}
|
|
709
|
-
|
|
710
|
-
|
|
758
|
+
const currency = typeof body.currency === 'string' && /^[A-Z]{3}$/.test(body.currency) ? body.currency : (balanceCurrency(balance.balances) || 'CNY')
|
|
759
|
+
if (currency === '__proto__' || currency === 'prototype' || currency === 'constructor') return json(res, 400, { ok: false, error: 'bad currency' })
|
|
760
|
+
const clamped = Math.min(100000, Math.max(0, Math.round(body.threshold * 100) / 100))
|
|
761
|
+
// An active account keeps its own threshold line; only the system-key
|
|
762
|
+
// mode writes the shared per-currency map.
|
|
763
|
+
const active = activeAccount()
|
|
764
|
+
if (active !== null) {
|
|
765
|
+
store.accountThresholds = normalizeAccountThresholds({ ...store.accountThresholds, [active.id]: clamped })
|
|
766
|
+
} else {
|
|
767
|
+
store.thresholds = normalizeThresholds({ ...store.thresholds, [currency]: clamped })
|
|
768
|
+
}
|
|
711
769
|
scheduleSave(ctx.logger)
|
|
712
|
-
return json(res, 200, { ok: true, threshold:
|
|
770
|
+
return json(res, 200, { ok: true, threshold: clamped, currency, accountId: active !== null ? active.id : null })
|
|
713
771
|
},
|
|
714
772
|
})
|
|
715
773
|
const disposeRefresh = ctx.webServer.register({
|
|
@@ -797,7 +855,11 @@ export function apply(ctx, config) {
|
|
|
797
855
|
if (body === null || typeof body.id !== 'string') return json(res, 400, { ok: false, error: 'id is required' })
|
|
798
856
|
const result = await activateAccount(ctx, body.id)
|
|
799
857
|
if (!result.ok) return json(res, 400, { ok: false, error: result.error })
|
|
800
|
-
|
|
858
|
+
// Carry the account's own threshold so the input can jump instantly,
|
|
859
|
+
// before the balance refresh lands.
|
|
860
|
+
const currency = balanceCurrency(balance.balances) || 'CNY'
|
|
861
|
+
const threshold = store.accountThresholds[result.account.id] ?? store.thresholds[currency] ?? 0
|
|
862
|
+
return json(res, 200, { ok: true, account: result.account, threshold })
|
|
801
863
|
},
|
|
802
864
|
})
|
|
803
865
|
const disposeRemove = ctx.webServer.register({
|
package/lib/client.js
CHANGED
|
@@ -14,7 +14,7 @@ window.__ModuleLoader__.load({
|
|
|
14
14
|
|
|
15
15
|
var POLL_MS = 15000
|
|
16
16
|
// Keep in lockstep with package.json; a test enforces the sync.
|
|
17
|
-
var WALLET_VERSION = '0.2.
|
|
17
|
+
var WALLET_VERSION = '0.2.1'
|
|
18
18
|
var CONFIRM_KEY = 'dsh-wallet-recharge-confirmed'
|
|
19
19
|
var CHIP_LAYOUT_KEY = 'dshw-chip-layout-v4'
|
|
20
20
|
var PANEL_POS_KEY = 'dshw-panel-pos-v1'
|
|
@@ -23,6 +23,7 @@ window.__ModuleLoader__.load({
|
|
|
23
23
|
var NOTIFY_CONFIG_KEY = 'dshw-completion-notify-v1'
|
|
24
24
|
var NOTIFY_CONFIG_EVENT = 'dshw-completion-notify-change'
|
|
25
25
|
var SETTINGS_EVENT = 'dshw-settings-change'
|
|
26
|
+
var LOW_BLINK_KEY = 'dshw-low-blink-v1'
|
|
26
27
|
var NOTIFY_LEADER_KEY = 'dshw-completion-notify-leader-v1'
|
|
27
28
|
var PERMANENT_DELETE_KEY = 'dshw-permanent-delete-v1'
|
|
28
29
|
var PERMANENT_DELETE_EVENT = 'dshw-permanent-delete-change'
|
|
@@ -259,7 +260,8 @@ window.__ModuleLoader__.load({
|
|
|
259
260
|
'.dshw_anchorHome>.dshw_chip{box-sizing:border-box;max-width:100%;min-width:0;overflow:hidden}',
|
|
260
261
|
'.dshw_chip{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15));background:transparent;height:22px;color:var(--dsw-alias-label-primary,#1f2328);white-space:nowrap;border-radius:999px;align-items:stretch;font-size:12px;line-height:1;display:inline-flex;position:relative;touch-action:none;user-select:none;cursor:grab}',
|
|
261
262
|
'.dshw_chip:hover,.dshw_chip:focus-within{border-color:var(--dsw-alias-brand-primary,#4aa3ff)}',
|
|
262
|
-
'.dshw_chipLow{border-color:var(--dsw-alias-state-error-primary,#e5534b);color:var(--dsw-alias-state-error-primary,#e5534b);animation:
|
|
263
|
+
'.dshw_chipLow{border-color:var(--dsw-alias-state-error-primary,#e5534b);color:var(--dsw-alias-state-error-primary,#e5534b);animation:dshwChipPulseIn 1.8s ease-in-out infinite}',
|
|
264
|
+
'.dshw_chipLow:hover,.dshw_chipLow:focus-within{border-color:var(--dsw-alias-state-error-primary,#e5534b)}',
|
|
263
265
|
'.dshw_chipDocked{position:fixed;z-index:79;background:var(--dsw-alias-bg-overlay,#fff);box-shadow:0 2px 10px rgba(0,0,0,.16)}',
|
|
264
266
|
'.dshw_chipDragging{cursor:grabbing;box-shadow:0 6px 18px rgba(0,0,0,.22)}',
|
|
265
267
|
'.dshw_snapPreview{position:fixed;z-index:78;pointer-events:none;box-sizing:border-box;border:2px dashed var(--dsw-alias-brand-primary,#4aa3ff);background:rgba(74,163,255,.10);box-shadow:0 0 0 3px rgba(74,163,255,.10);border-radius:999px;transition:left .06s ease,top .06s ease,width .06s ease,height .06s ease}',
|
|
@@ -272,6 +274,7 @@ window.__ModuleLoader__.load({
|
|
|
272
274
|
'.dshw_chipVertical .dshw_sep{display:none}',
|
|
273
275
|
'.dshw_chipVertical .dshw_recharge{width:100%;box-sizing:border-box;border-left:0;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15));padding:3px 1px;justify-content:center;border-radius:0 0 7px 7px}',
|
|
274
276
|
'.dshw_bottomDockHost{box-sizing:border-box!important;padding-bottom:30px!important}',
|
|
277
|
+
'@keyframes dshwChipPulseIn{0%,100%{box-shadow:inset 0 0 0 0 rgba(229,83,75,0)}50%{box-shadow:inset 0 0 0 3px rgba(229,83,75,.32)}}',
|
|
275
278
|
'@keyframes dshwPulse{0%,100%{box-shadow:0 0 0 0 rgba(229,83,75,.45)}50%{box-shadow:0 0 0 5px rgba(229,83,75,0)}}',
|
|
276
279
|
'.dshw_sep{opacity:.45}',
|
|
277
280
|
'.dshw_chipMain,.dshw_recharge{border:0;background:transparent;color:inherit;font:inherit;cursor:pointer;align-items:center;display:inline-flex;gap:6px;margin:0}',
|
|
@@ -318,24 +321,95 @@ window.__ModuleLoader__.load({
|
|
|
318
321
|
'.dshw_chipToggle{display:inline-flex;align-items:center;gap:6px;height:24px;padding:0 9px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15));border-radius:999px;background:transparent;font-size:11.5px;color:var(--dsw-alias-label-secondary,rgba(31,35,40,.68));cursor:pointer;white-space:nowrap;transition:color .12s,border-color .12s,background-color .12s}',
|
|
319
322
|
'.dshw_chipToggle:hover{border-color:var(--dsw-alias-brand-primary,#4aa3ff)}',
|
|
320
323
|
'.dshw_chipToggle input{margin:0;accent-color:var(--dsw-alias-brand-primary,#4aa3ff)}',
|
|
321
|
-
'.dshw_acctScroll{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15));border-radius:8px;overflow-y:auto;max-height:
|
|
324
|
+
'.dshw_acctScroll{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15));border-radius:8px;overflow-y:auto;max-height:58px;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l3,rgba(0,0,0,.25)) transparent;margin:2px 0}',
|
|
322
325
|
'.dshw_acctScroll::-webkit-scrollbar{width:6px}',
|
|
323
326
|
'.dshw_acctScroll::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3,rgba(0,0,0,.25));border-radius:3px}',
|
|
324
|
-
'.dshw_acctScroll .dshw_row{padding:
|
|
327
|
+
'.dshw_acctScroll .dshw_row{padding:2px 6px}',
|
|
328
|
+
'.dshw_balanceCard.dshw_low{border-color:var(--dsw-alias-state-error-primary,#e5534b)}',
|
|
329
|
+
'.dshw_balanceCard.dshw_low .dshw_balNum{color:var(--dsw-alias-state-error-primary,#e5534b)}',
|
|
330
|
+
'.dshw_chipLow .dshw_chipMain>span:not(.dshw_homePrimary):not(.dshw_sep){color:var(--dsw-alias-label-primary,#1f2328)}',
|
|
331
|
+
'.dshw_chipLow .dshw_thirdText .dshw_homePrimaryValue{color:inherit}',
|
|
332
|
+
'.dshw_chipLow .dshw_balanceText .dshw_homePrimaryLabel{color:var(--dsw-alias-label-primary,#1f2328)!important}',
|
|
333
|
+
'.dshw_chipLow .dshw_balanceText .dshw_homePrimaryValue{color:var(--dsw-alias-state-error-primary,#e5534b)!important}',
|
|
334
|
+
'.dshw_chipLow.dshw_chipVertical .dshw_chipMain>.dshw_metric:not(:first-child) .dshw_metricLabel,.dshw_chipLow.dshw_chipVertical .dshw_chipMain>.dshw_metric:not(:first-child) .dshw_metricValue{color:var(--dsw-alias-label-primary,#1f2328)}',
|
|
335
|
+
'.dshw_chipLow.dshw_chipVertical .dshw_chipMain>.dshw_metric:first-child .dshw_metricValue{color:var(--dsw-alias-state-error-primary,#e5534b)}',
|
|
336
|
+
'.dshw_chipLow.dshw_chipVertical .dshw_chipMain>.dshw_metric:first-child .dshw_metricLabel{color:var(--dsw-alias-label-primary,#1f2328)}',
|
|
337
|
+
'.dshw_chipLow.dshw_noBlink{animation:none}',
|
|
325
338
|
'.dshw_acctMore{display:flex;justify-content:flex-end;font-size:10.5px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45));margin-top:3px}',
|
|
326
|
-
'.dshw_acctRow{display:flex;align-items:center;gap:
|
|
327
|
-
'.dshw_acctRow+.dshw_acctRow{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.
|
|
339
|
+
''.trim() || '.dshw_acctRow{display:flex;align-items:center;gap:5px;padding:2px 6px;min-height:26px}',
|
|
340
|
+
'.dshw_acctRow+.dshw_acctRow{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.06))}',
|
|
328
341
|
'.dshw_acctRow.current{background:var(--dsw-alias-brand-soft,rgba(74,163,255,.10))}',
|
|
329
|
-
'.dshw_acctAvatar{flex:none;width:
|
|
330
|
-
'.dshw_acctInfo{flex:1;min-width:0;display:flex;
|
|
331
|
-
'.dshw_acctName{font-size:
|
|
342
|
+
'.dshw_acctAvatar{flex:none;width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:650;user-select:none}',
|
|
343
|
+
'.dshw_acctInfo{flex:1;min-width:0;display:flex;align-items:center;gap:6px}',
|
|
344
|
+
'.dshw_acctName{font-size:11.5px;font-weight:550;color:var(--dsw-alias-label-primary,inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:0 1 auto}',
|
|
332
345
|
'.dshw_acctBadge{flex:none;font-size:9.5px;color:var(--dsw-alias-brand-primary,#4aa3ff);border:1px solid var(--dsw-alias-brand-primary,#4aa3ff);border-radius:4px;padding:0 4px;line-height:14px;opacity:.85}',
|
|
333
|
-
'.dshw_acctKey{font-family:ui-monospace,Consolas,monospace;font-size:10px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
|
|
346
|
+
'.dshw_acctKey{font-family:ui-monospace,Consolas,monospace;font-size:10px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}',
|
|
334
347
|
'.dshw_acctNow{flex:none;padding:1px 7px;border-radius:999px;background:var(--dsw-alias-brand-soft,rgba(74,163,255,.14));color:var(--dsw-alias-brand-primary,#4aa3ff);font-size:10.5px;font-weight:550;line-height:16px}',
|
|
335
348
|
'.dshw_settingsSection .dshw_setCard{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--dsw-alias-border-l1,rgba(0,0,0,.08))}',
|
|
336
349
|
'.dshw_settingsSection .dshw_setCell{background:var(--dsw-alias-bg-elevated,transparent);border-top:none!important;padding:8px 10px}',
|
|
337
350
|
'.dshw_settingsSection .dshw_setCell:hover{background:var(--dsw-alias-bg-l1,rgba(127,127,127,.06))}',
|
|
338
351
|
'.dshw_settingsSection .dshw_setCell.wide{grid-column:1/-1}',
|
|
352
|
+
'.dshw_settingsSection{--dshw-card-radius:11px;max-width:900px;gap:12px!important}',
|
|
353
|
+
'.dshw_settingsHeader{display:flex;align-items:flex-end;justify-content:space-between;gap:12px}',
|
|
354
|
+
'.dshw_settingsHeading{font-size:16px;font-weight:650;letter-spacing:-.01em}',
|
|
355
|
+
'.dshw_settingsLead{margin-top:2px;font-size:11.5px;color:var(--dsw-alias-label-tertiary,#6b7280)}',
|
|
356
|
+
'.dshw_versionBadge{flex:none;padding:2px 7px;border-radius:999px;background:var(--dsw-alias-bg-l1,rgba(127,127,127,.07));color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45));font-size:10px}',
|
|
357
|
+
'.dshw_settingsHero{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.13));border-radius:var(--dshw-card-radius);background:var(--dsw-alias-bg-elevated,#fff);padding:13px 15px}',
|
|
358
|
+
'.dshw_settingsHero.dshw_low{border-color:var(--dsw-alias-state-error-primary,#e5534b)}',
|
|
359
|
+
'.dshw_settingsHeroTop{display:flex;align-items:center;gap:8px}',
|
|
360
|
+
'.dshw_settingsHeroLabel{font-size:11.5px;color:var(--dsw-alias-label-tertiary,#6b7280)}',
|
|
361
|
+
'.dshw_accountPill{display:inline-flex;align-items:center;max-width:180px;padding:2px 7px;border-radius:999px;background:var(--dsw-alias-brand-soft,rgba(74,163,255,.10));color:var(--dsw-alias-label-secondary,rgba(31,35,40,.68));font-size:10.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
|
|
362
|
+
'.dshw_settingsHeroMain{display:flex;align-items:flex-end;gap:18px;margin-top:7px}',
|
|
363
|
+
'.dshw_settingsBalance{font-size:28px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums;letter-spacing:-.025em}',
|
|
364
|
+
'.dshw_settingsHero.dshw_low .dshw_settingsBalance{color:var(--dsw-alias-state-error-primary,#e5534b)}',
|
|
365
|
+
'.dshw_settingsSpend{display:flex;flex-direction:column;gap:2px;padding-bottom:1px}',
|
|
366
|
+
'.dshw_settingsSpend strong{font-size:14px;font-variant-numeric:tabular-nums}',
|
|
367
|
+
'.dshw_settingsHeroMeta{display:flex;align-items:center;gap:7px;margin-top:9px;color:var(--dsw-alias-label-tertiary,#6b7280);font-size:11px;white-space:nowrap}',
|
|
368
|
+
'.dshw_settingsGrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px}',
|
|
369
|
+
'.dshw_settingsSection .dshw_setCard{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:0;border:0;background:transparent;overflow:visible}',
|
|
370
|
+
'.dshw_settingsSection .dshw_setCard>.dshw_setCell{min-width:0;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.13))!important;border-radius:var(--dshw-card-radius);background:var(--dsw-alias-bg-elevated,#fff);padding:11px 12px}',
|
|
371
|
+
'.dshw_settingsSection .dshw_setCard>.dshw_setCell:hover{background:var(--dsw-alias-bg-elevated,#fff)}',
|
|
372
|
+
'.dshw_settingsSection .dshw_setCard>.dshw_setCell.wide{grid-column:1/-1}',
|
|
373
|
+
'.dshw_reminderCard{display:block!important;padding:0!important;overflow:hidden}',
|
|
374
|
+
'.dshw_settingsGroup{min-width:0;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.13));border-radius:var(--dshw-card-radius);background:var(--dsw-alias-bg-elevated,#fff);overflow:hidden}',
|
|
375
|
+
'.dshw_settingsGroupHeader{padding:10px 12px;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}',
|
|
376
|
+
'.dshw_settingsGroupTitle{font-size:12px;font-weight:650}',
|
|
377
|
+
'.dshw_settingsGroupHint{margin-top:2px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45));font-size:10.5px}',
|
|
378
|
+
'.dshw_settingsField{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;padding:8px 12px}',
|
|
379
|
+
'.dshw_settingsField+.dshw_settingsField{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.07))}',
|
|
380
|
+
'.dshw_settingsFieldLabel{display:flex;min-width:0;flex-direction:column;gap:2px}',
|
|
381
|
+
'.dshw_settingsFieldLabel>strong{font-size:11.5px;font-weight:550}',
|
|
382
|
+
'.dshw_settingsFieldLabel>span{font-size:10px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45))}',
|
|
383
|
+
'.dshw_settingsInline{display:flex;align-items:center;justify-content:flex-end;gap:6px;min-width:0}',
|
|
384
|
+
'.dshw_settingsInline .dshw_input{height:26px;box-sizing:border-box}',
|
|
385
|
+
'.dshw_settingsInline .dshw_select{height:26px}',
|
|
386
|
+
'.dshw_settingChoices{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding:9px 12px}',
|
|
387
|
+
'.dshw_settingChoice{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0;padding:7px 9px;border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.09));border-radius:8px;background:var(--dsw-alias-bg-l1,rgba(127,127,127,.04))}',
|
|
388
|
+
'.dshw_settingChoiceCopy{min-width:0;display:flex;flex-direction:column;gap:1px}',
|
|
389
|
+
'.dshw_settingChoiceCopy strong{font-size:11px;font-weight:550;white-space:nowrap}',
|
|
390
|
+
'.dshw_settingChoiceCopy span{font-size:9.5px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
|
|
391
|
+
'.dshw_switch{position:relative;flex:none;width:34px;height:20px;display:inline-flex;cursor:pointer}',
|
|
392
|
+
'.dshw_switch>input{position:absolute;inset:0;opacity:0;margin:0;cursor:pointer}',
|
|
393
|
+
'.dshw_track{position:absolute;inset:0;border-radius:999px;background:var(--dsw-alias-border-l3,rgba(0,0,0,.22));transition:background-color .15s}',
|
|
394
|
+
'.dshw_knob{position:absolute;left:2px;top:2px;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-bg-overlay,#fff);box-shadow:0 1px 3px rgba(0,0,0,.24);transition:transform .15s}',
|
|
395
|
+
'.dshw_switch>input:checked+.dshw_track{background:var(--dsw-alias-brand-primary,#4aa3ff)}',
|
|
396
|
+
'.dshw_switch>input:checked~.dshw_knob{transform:translateX(14px)}',
|
|
397
|
+
'.dshw_switch>input:focus-visible+.dshw_track{outline:2px solid var(--dsw-alias-brand-primary,#4aa3ff);outline-offset:2px}',
|
|
398
|
+
'.dshw_switch>input:disabled+.dshw_track{opacity:.38}.dshw_switch>input:disabled~.dshw_knob{opacity:.7}',
|
|
399
|
+
'.dshw_accountHeader{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:2px}',
|
|
400
|
+
'.dshw_accountCount{font-size:10.5px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45))}',
|
|
401
|
+
'.dshw_settingsSection .dshw_acctScroll{max-height:150px;margin:0;border-radius:var(--dshw-card-radius)}',
|
|
402
|
+
'.dshw_settingsSection .dshw_acctRow{min-height:38px;padding:6px 9px;gap:8px}',
|
|
403
|
+
'.dshw_settingsSection .dshw_acctAvatar{width:24px;height:24px;font-size:11px}',
|
|
404
|
+
'.dshw_settingsSection .dshw_acctInfo{align-items:flex-start;flex-direction:column;gap:1px}',
|
|
405
|
+
'.dshw_settingsSection .dshw_acctName{font-size:11.5px}',
|
|
406
|
+
'.dshw_settingsSection .dshw_acctKey{font-size:9.5px}',
|
|
407
|
+
'.dshw_accountAdd{display:grid;grid-template-columns:120px minmax(150px,1fr) auto;gap:6px;padding:9px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.13));border-radius:var(--dshw-card-radius);background:var(--dsw-alias-bg-l1,rgba(127,127,127,.035))}',
|
|
408
|
+
'.dshw_accountAdd .dshw_input{box-sizing:border-box;width:100%;height:28px}',
|
|
409
|
+
'.dshw_settingsFooter{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:2px}',
|
|
410
|
+
'.dshw_settingsFooterActions{display:flex;align-items:center;gap:7px}',
|
|
411
|
+
'.dshw_settingsFooter .dshw_btn{height:30px;padding:0 14px}',
|
|
412
|
+
'@media (max-width:760px){.dshw_settingsGrid,.dshw_settingsSection .dshw_setCard{grid-template-columns:1fr}.dshw_settingsSection .dshw_setCard>.dshw_setCell.wide{grid-column:1}.dshw_accountAdd{grid-template-columns:1fr}.dshw_settingsFooter{align-items:flex-start;flex-direction:column-reverse}.dshw_settingsFooterActions{width:100%}.dshw_settingsFooterActions .dshw_btn{flex:1}.dshw_settingsHeroMeta{white-space:normal;flex-wrap:wrap}}',
|
|
339
413
|
'.dshw_actionRow{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin:2px 0}',
|
|
340
414
|
'.dshw_textDanger{display:inline-flex;align-items:center;gap:5px;height:22px;padding:0 4px;border:none;background:transparent;font:inherit;font-size:11px;color:var(--dsw-alias-label-quaternary,rgba(31,35,40,.45));cursor:pointer;border-radius:4px;transition:color .12s,background-color .12s}',
|
|
341
415
|
'.dshw_textDanger:hover{color:var(--dsw-alias-state-error-primary,#e5534b);background:var(--dsw-alias-state-error-soft,rgba(229,83,75,.12))}',
|
|
@@ -865,6 +939,22 @@ function fmtCurrency(value, currency) {
|
|
|
865
939
|
var cfg = readNotifyConfig()
|
|
866
940
|
return cfg.autoCloseMs === null ? 'keep' : String(Math.round(cfg.autoCloseMs / 1000))
|
|
867
941
|
})
|
|
942
|
+
var [lowBlinkEnabled, setLowBlinkEnabled] = React.useState(function () {
|
|
943
|
+
try { return compatibility.storage.getItem(LOW_BLINK_KEY) !== 'false' } catch (e) { return true }
|
|
944
|
+
})
|
|
945
|
+
var [pdEnabled, setPdEnabled] = React.useState(function () {
|
|
946
|
+
try { return compatibility.storage.getItem(PERMANENT_DELETE_KEY) === 'true' } catch (e) { return false }
|
|
947
|
+
})
|
|
948
|
+
var [pdSupported, setPdSupported] = React.useState(function () {
|
|
949
|
+
return compatibility.hasCapability('permanentDelete')
|
|
950
|
+
})
|
|
951
|
+
React.useEffect(function () {
|
|
952
|
+
if (typeof window.addEventListener !== 'function') return
|
|
953
|
+
function refreshCap() { setPdSupported(compatibility.hasCapability('permanentDelete')) }
|
|
954
|
+
window.addEventListener(HOST_CAPABILITY_EVENT, refreshCap)
|
|
955
|
+
refreshCap()
|
|
956
|
+
return function () { window.removeEventListener(HOST_CAPABILITY_EVENT, refreshCap) }
|
|
957
|
+
}, [])
|
|
868
958
|
|
|
869
959
|
React.useEffect(function () {
|
|
870
960
|
var stopped = false
|
|
@@ -903,6 +993,12 @@ function fmtCurrency(value, currency) {
|
|
|
903
993
|
compatibility.dispatch(SETTINGS_EVENT)
|
|
904
994
|
}
|
|
905
995
|
|
|
996
|
+
var thresholdSaveTimerRef = React.useRef(null)
|
|
997
|
+
function queueThresholdSave(value) {
|
|
998
|
+
if (thresholdSaveTimerRef.current) clearTimeout(thresholdSaveTimerRef.current)
|
|
999
|
+
thresholdSaveTimerRef.current = setTimeout(function () { saveThreshold(value) }, 600)
|
|
1000
|
+
}
|
|
1001
|
+
|
|
906
1002
|
function persistNotify(enabled, timeout) {
|
|
907
1003
|
var autoCloseMs = timeout === 'keep' ? null : Number.parseInt(timeout, 10) * 1000
|
|
908
1004
|
if (!Number.isFinite(autoCloseMs) && timeout !== 'keep') autoCloseMs = 10000
|
|
@@ -914,14 +1010,21 @@ function fmtCurrency(value, currency) {
|
|
|
914
1010
|
compatibility.dispatch(NOTIFY_CONFIG_EVENT)
|
|
915
1011
|
}
|
|
916
1012
|
|
|
917
|
-
function
|
|
918
|
-
|
|
1013
|
+
function persistLowBlink(enabled) {
|
|
1014
|
+
enabled = enabled === true
|
|
1015
|
+
setLowBlinkEnabled(enabled)
|
|
1016
|
+
try { compatibility.storage.setItem(LOW_BLINK_KEY, String(enabled)) } catch (e) { /* ignore */ }
|
|
1017
|
+
compatibility.dispatch(SETTINGS_EVENT)
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
function saveThreshold(valueArg) {
|
|
1021
|
+
var value = Number.parseFloat(valueArg !== undefined ? valueArg : thresholdDraft)
|
|
919
1022
|
if (!Number.isFinite(value)) return
|
|
920
1023
|
value = Math.min(100000, Math.max(0, Math.round(value * 100) / 100))
|
|
921
1024
|
fetch('/api/wallet/threshold', {
|
|
922
1025
|
method: 'POST',
|
|
923
1026
|
headers: { 'content-type': 'application/json' },
|
|
924
|
-
body: JSON.stringify({ threshold: value })
|
|
1027
|
+
body: JSON.stringify({ threshold: value, currency: (snapshot && snapshot.balance && snapshot.balance.currency) || 'CNY' })
|
|
925
1028
|
}).then(function (resp) { return resp.json() }).then(function (json) {
|
|
926
1029
|
if (json && json.ok) {
|
|
927
1030
|
setThresholdDraft(json.threshold.toFixed(2))
|
|
@@ -936,7 +1039,11 @@ function fmtCurrency(value, currency) {
|
|
|
936
1039
|
if (json && json.ok) { setAccounts(json); setAccountsError(null) }
|
|
937
1040
|
}).catch(function () { /* ignore */ })
|
|
938
1041
|
fetch('/api/wallet/snapshot').then(function (resp) { return resp.json() }).then(function (json) {
|
|
939
|
-
if (json && json.ok)
|
|
1042
|
+
if (json && json.ok) {
|
|
1043
|
+
setSnapshot(json)
|
|
1044
|
+
// 切换账号后阈值输入框立即跳到该账号货币的阈值
|
|
1045
|
+
if (json.threshold !== undefined && json.threshold !== null) setThresholdDraft(json.threshold.toFixed(2))
|
|
1046
|
+
}
|
|
940
1047
|
}).catch(function () { /* ignore */ })
|
|
941
1048
|
}
|
|
942
1049
|
|
|
@@ -969,6 +1076,8 @@ function fmtCurrency(value, currency) {
|
|
|
969
1076
|
}).then(function (resp) { return resp.json() }).then(function (json) {
|
|
970
1077
|
setSwitchingId(null)
|
|
971
1078
|
setAccountNotice(json && json.ok ? '\u5df2\u5207\u6362\u5230\u300c' + name + '\u300d' : (json && json.error ? String(json.error) : '\u5207\u6362\u5931\u8d25'))
|
|
1079
|
+
// 阈值输入框零等待跳转: 激活响应自带该账号阈值
|
|
1080
|
+
if (json && json.ok && json.threshold !== undefined && json.threshold !== null) setThresholdDraft(json.threshold.toFixed(2))
|
|
972
1081
|
reloadAccounts()
|
|
973
1082
|
}).catch(function () { setSwitchingId(null); setAccountNotice('\u5207\u6362\u5931\u8d25') })
|
|
974
1083
|
}
|
|
@@ -994,22 +1103,38 @@ function fmtCurrency(value, currency) {
|
|
|
994
1103
|
// —— 余额卡 ——
|
|
995
1104
|
var lowBalance = snapshot && snapshot.lowBalance === true
|
|
996
1105
|
var sessionCost = snapshot && snapshot.session && snapshot.session.official && snapshot.session.official.cost !== null && snapshot.session.official.cost !== undefined ? sessionCostText(snapshot.session.official.cost, snapshot && snapshot.balance ? snapshot.balance.currency : null) : '--'
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1106
|
+
var currencyCode = bal && typeof bal.currency === 'string' ? bal.currency : 'CNY'
|
|
1107
|
+
var primaryBalance = bal && Array.isArray(bal.balances) && bal.balances.length > 0 ? bal.balances[0] : null
|
|
1108
|
+
var toppedText = primaryBalance ? fmtCurrency(primaryBalance.topped_up_balance, primaryBalance.currency) : '--'
|
|
1109
|
+
var grantedText = primaryBalance ? fmtCurrency(primaryBalance.granted_balance, primaryBalance.currency) : '--'
|
|
1110
|
+
rows.push(React.createElement('div', { key: 'head', className: 'dshw_settingsHeader' },
|
|
1111
|
+
React.createElement('div', null,
|
|
1112
|
+
React.createElement('div', { className: 'dshw_settingsHeading' }, 'DeepSeek 账户中心'),
|
|
1113
|
+
React.createElement('div', { className: 'dshw_settingsLead' }, '余额、展示、提醒与账户切换'))))
|
|
1114
|
+
rows.push(React.createElement('div', { key: 'balcard', className: lowBalance ? 'dshw_settingsHero dshw_low' : 'dshw_settingsHero' },
|
|
1115
|
+
React.createElement('div', { className: 'dshw_settingsHeroTop' },
|
|
1116
|
+
React.createElement('span', { className: 'dshw_settingsHeroLabel' }, 'DeepSeek 官方余额'),
|
|
1117
|
+
React.createElement('span', { className: 'dshw_accountPill', title: activeName || '跟随系统 Key' }, activeName ? '当前 · ' + activeName : '跟随系统 Key'),
|
|
1002
1118
|
React.createElement('span', { className: 'dshw_balFill' }),
|
|
1003
|
-
React.createElement('span', { className: '
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1119
|
+
lowBalance ? React.createElement('span', { className: 'dshw_balWarn' }, '余额偏低') : null),
|
|
1120
|
+
React.createElement('div', { className: 'dshw_settingsHeroMain' },
|
|
1121
|
+
React.createElement('strong', { className: 'dshw_settingsBalance' }, balanceText),
|
|
1122
|
+
React.createElement('span', { className: 'dshw_settingsSpend' },
|
|
1123
|
+
React.createElement('span', { className: 'dshw_muted' }, sessionCostLabel(currencyCode)),
|
|
1124
|
+
React.createElement('strong', null, sessionCost))),
|
|
1125
|
+
React.createElement('div', { className: 'dshw_settingsHeroMeta' },
|
|
1126
|
+
React.createElement('span', null, '充值 ' + toppedText),
|
|
1127
|
+
React.createElement('span', { className: 'dshw_balDot' }, '·'),
|
|
1128
|
+
React.createElement('span', null, '赠送 ' + grantedText),
|
|
1129
|
+
React.createElement('span', { className: 'dshw_balDot' }, '·'),
|
|
1130
|
+
React.createElement('span', null, currencyCode))))
|
|
1008
1131
|
|
|
1009
1132
|
// —— 设置卡 ——
|
|
1010
1133
|
var cells = []
|
|
1011
1134
|
cells.push(React.createElement('div', { key: 'vis', className: 'dshw_setCell' },
|
|
1012
|
-
React.createElement('span', { className: '
|
|
1135
|
+
React.createElement('span', { className: 'dshw_settingsFieldLabel' },
|
|
1136
|
+
React.createElement('strong', null, '显示内容'),
|
|
1137
|
+
React.createElement('span', null, '选择标签中的数据来源')),
|
|
1013
1138
|
React.createElement('span', { className: 'dshw_balFill' }),
|
|
1014
1139
|
React.createElement('label', { className: 'dshw_chipToggle' },
|
|
1015
1140
|
React.createElement('input', {
|
|
@@ -1024,7 +1149,9 @@ function fmtCurrency(value, currency) {
|
|
|
1024
1149
|
onChange: function (event) { persistVisibility({ official: visibility.official, third: event.target.checked }) }
|
|
1025
1150
|
}), '\u7b2c\u4e09\u65b9')))
|
|
1026
1151
|
cells.push(React.createElement('div', { key: 'sc', className: 'dshw_setCell' },
|
|
1027
|
-
React.createElement('span', { className: '
|
|
1152
|
+
React.createElement('span', { className: 'dshw_settingsFieldLabel' },
|
|
1153
|
+
React.createElement('strong', null, '标签比例'),
|
|
1154
|
+
React.createElement('span', null, '按当前停靠位置限制上限')),
|
|
1028
1155
|
React.createElement('span', { className: 'dshw_balFill' }),
|
|
1029
1156
|
React.createElement('span', { className: 'dshw_scaleControl' },
|
|
1030
1157
|
React.createElement('input', {
|
|
@@ -1035,44 +1162,78 @@ function fmtCurrency(value, currency) {
|
|
|
1035
1162
|
onChange: function (event) { persistScale(Number.parseFloat(event.target.value) / 100) }
|
|
1036
1163
|
}),
|
|
1037
1164
|
React.createElement('span', { className: 'dshw_scaleValue' }, Math.round(scale * 100) + '%'))))
|
|
1038
|
-
cells.push(React.createElement('div', { key: '
|
|
1039
|
-
React.createElement('
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
'
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1165
|
+
cells.push(React.createElement('div', { key: 'quad', className: 'dshw_setCell wide dshw_reminderCard' },
|
|
1166
|
+
React.createElement('div', { className: 'dshw_settingsGroupHeader' },
|
|
1167
|
+
React.createElement('div', { className: 'dshw_settingsGroupTitle' }, '提醒与会话'),
|
|
1168
|
+
React.createElement('div', { className: 'dshw_settingsGroupHint' }, '提醒方式、低余额状态与会话控制')),
|
|
1169
|
+
React.createElement('div', { className: 'dshw_settingChoices' },
|
|
1170
|
+
React.createElement('div', { className: 'dshw_settingChoice' },
|
|
1171
|
+
React.createElement('span', { className: 'dshw_settingChoiceCopy' },
|
|
1172
|
+
React.createElement('strong', null, '完成提醒'),
|
|
1173
|
+
React.createElement('span', null, '对话结束后通知')),
|
|
1174
|
+
React.createElement('select', {
|
|
1175
|
+
className: 'dshw_select',
|
|
1176
|
+
'aria-label': '完成提醒',
|
|
1177
|
+
value: notifyEnabled ? notifyTimeout : 'off',
|
|
1178
|
+
onChange: function (event) {
|
|
1179
|
+
var v = event.target.value
|
|
1180
|
+
if (v === 'off') { persistNotify(false, notifyTimeout); return }
|
|
1181
|
+
persistNotify(true, v)
|
|
1182
|
+
}
|
|
1183
|
+
},
|
|
1184
|
+
React.createElement('option', { value: 'off' }, '关闭'),
|
|
1185
|
+
React.createElement('option', { value: '5' }, '5 秒'),
|
|
1186
|
+
React.createElement('option', { value: '10' }, '10 秒'),
|
|
1187
|
+
React.createElement('option', { value: '30' }, '30 秒'),
|
|
1188
|
+
React.createElement('option', { value: '60' }, '60 秒'),
|
|
1189
|
+
React.createElement('option', { value: 'keep' }, '一直保留'))),
|
|
1190
|
+
React.createElement('div', { className: 'dshw_settingChoice' },
|
|
1191
|
+
React.createElement('span', { className: 'dshw_settingChoiceCopy' },
|
|
1192
|
+
React.createElement('strong', null, '低余额阈值'),
|
|
1193
|
+
React.createElement('span', null, thresholdNotice || (currencyCode + ' · 输入后自动保存'))),
|
|
1194
|
+
React.createElement('span', { className: 'dshw_settingsInline' },
|
|
1195
|
+
React.createElement('span', { style: { fontWeight: 700, color: 'var(--dsw-alias-label-primary,inherit)' } }, currencyCode === 'USD' ? '$' : '¥'),
|
|
1196
|
+
React.createElement('input', {
|
|
1197
|
+
className: 'dshw_input', type: 'number', min: '0', step: '0.01',
|
|
1198
|
+
style: { width: '64px' },
|
|
1199
|
+
value: thresholdDraft,
|
|
1200
|
+
title: '低于此余额时提醒;0 表示关闭',
|
|
1201
|
+
'aria-label': '低余额阈值 (' + currencyCode + ')',
|
|
1202
|
+
onInput: function (event) { setThresholdDraft(event.target.value); queueThresholdSave(event.target.value) },
|
|
1203
|
+
onChange: function (event) { setThresholdDraft(event.target.value); queueThresholdSave(event.target.value) }
|
|
1204
|
+
}),
|
|
1205
|
+
React.createElement('span', { className: 'dshw_muted' }, currencyCode))),
|
|
1206
|
+
React.createElement('div', { className: 'dshw_settingChoice' },
|
|
1207
|
+
React.createElement('span', { className: 'dshw_settingChoiceCopy' },
|
|
1208
|
+
React.createElement('strong', null, '低余额闪烁'),
|
|
1209
|
+
React.createElement('span', null, '红框向内轻微闪烁')),
|
|
1210
|
+
React.createElement('label', { className: 'dshw_switch' },
|
|
1211
|
+
React.createElement('input', {
|
|
1212
|
+
type: 'checkbox', checked: lowBlinkEnabled,
|
|
1213
|
+
'aria-label': '低余额时红色闪烁',
|
|
1214
|
+
onChange: function (event) { persistLowBlink(event.target.checked) }
|
|
1215
|
+
}),
|
|
1216
|
+
React.createElement('span', { className: 'dshw_track', 'aria-hidden': 'true' }),
|
|
1217
|
+
React.createElement('span', { className: 'dshw_knob', 'aria-hidden': 'true' }))),
|
|
1218
|
+
React.createElement('div', { className: 'dshw_settingChoice' },
|
|
1219
|
+
React.createElement('span', { className: 'dshw_settingChoiceCopy' },
|
|
1220
|
+
React.createElement('strong', null, '永久删除会话'),
|
|
1221
|
+
React.createElement('span', null, pdSupported ? '在会话菜单中提供入口' : '当前宿主不支持')),
|
|
1222
|
+
React.createElement('label', { className: 'dshw_switch', title: pdSupported ? '在会话菜单中显示永久删除' : '当前宿主未提供永久删除能力' },
|
|
1223
|
+
React.createElement('input', {
|
|
1224
|
+
type: 'checkbox', checked: pdSupported && pdEnabled, disabled: !pdSupported,
|
|
1225
|
+
'aria-label': '开启永久删除会话',
|
|
1226
|
+
onChange: function (event) {
|
|
1227
|
+
if (!pdSupported) return
|
|
1228
|
+
var enabled = event.target.checked
|
|
1229
|
+
setPdEnabled(enabled)
|
|
1230
|
+
try { compatibility.storage.setItem(PERMANENT_DELETE_KEY, String(enabled)) } catch (e) { /* ignore */ }
|
|
1231
|
+
compatibility.dispatch(PERMANENT_DELETE_EVENT)
|
|
1232
|
+
}
|
|
1233
|
+
}),
|
|
1234
|
+
React.createElement('span', { className: 'dshw_track', 'aria-hidden': 'true' }),
|
|
1235
|
+
React.createElement('span', { className: 'dshw_knob', 'aria-hidden': 'true' })))))
|
|
1236
|
+
)
|
|
1076
1237
|
rows.push(React.createElement('div', { key: 'setcard', className: 'dshw_setCard' }, cells))
|
|
1077
1238
|
|
|
1078
1239
|
// —— Provider 分桶(Issue #21:包装官方的路由勾选计入官方计费) ——
|
|
@@ -1113,7 +1274,9 @@ function fmtCurrency(value, currency) {
|
|
|
1113
1274
|
}
|
|
1114
1275
|
|
|
1115
1276
|
// —— 账户管理 ——
|
|
1116
|
-
rows.push(React.createElement('div', { key: 'acc-t', className: '
|
|
1277
|
+
rows.push(React.createElement('div', { key: 'acc-t', className: 'dshw_accountHeader' },
|
|
1278
|
+
React.createElement('span', { className: 'dshw_title' }, '账户管理'),
|
|
1279
|
+
React.createElement('span', { className: 'dshw_accountCount' }, list.length + ' 个账户')))
|
|
1117
1280
|
if (accountsError) {
|
|
1118
1281
|
rows.push(React.createElement('div', { key: 'acc-e', className: 'dshw_muted' }, accountsError))
|
|
1119
1282
|
} else if (list.length === 0) {
|
|
@@ -1142,52 +1305,50 @@ function fmtCurrency(value, currency) {
|
|
|
1142
1305
|
}, switchingId === acc.id ? '\u2026' : '\u5207\u6362'),
|
|
1143
1306
|
React.createElement('button', {
|
|
1144
1307
|
key: 'r', type: 'button', className: 'dshw_btn',
|
|
1145
|
-
style: { height: '
|
|
1308
|
+
style: { height: '24px', padding: '0 8px', fontSize: '10.5px' },
|
|
1146
1309
|
title: '\u5220\u9664\u8d26\u6237',
|
|
1310
|
+
'aria-label': '删除账户 ' + acc.name,
|
|
1147
1311
|
onClick: function () { removeAccount(acc.id, acc.name) }
|
|
1148
|
-
}, '
|
|
1312
|
+
}, '删除'))
|
|
1149
1313
|
})
|
|
1150
1314
|
rows.push(React.createElement('div', { key: 'acc-scroll', className: 'dshw_acctScroll' }, acctRows))
|
|
1151
|
-
if (list.length > 2) rows.push(React.createElement('div', { key: 'acc-more', className: 'dshw_acctMore' }, '\u5171 ' + list.length + ' \u4e2a\u8d26\u6237\uff0c\u6ed1\u52a8\u67e5\u770b\u66f4\u591a'))
|
|
1152
1315
|
}
|
|
1153
|
-
rows.push(React.createElement('div', { key: 'acc-add', className: '
|
|
1316
|
+
rows.push(React.createElement('div', { key: 'acc-add', className: 'dshw_accountAdd' },
|
|
1154
1317
|
React.createElement('input', {
|
|
1155
|
-
className: 'dshw_input',
|
|
1318
|
+
className: 'dshw_input',
|
|
1156
1319
|
placeholder: '\u540d\u79f0', 'aria-label': '\u540d\u79f0',
|
|
1157
1320
|
value: nameDraft,
|
|
1158
1321
|
onInput: function (event) { setNameDraft(event.target.value) },
|
|
1159
1322
|
onChange: function (event) { setNameDraft(event.target.value) }
|
|
1160
1323
|
}),
|
|
1161
1324
|
React.createElement('input', {
|
|
1162
|
-
className: 'dshw_input',
|
|
1325
|
+
className: 'dshw_input',
|
|
1163
1326
|
placeholder: 'sk-...', 'aria-label': 'API Key',
|
|
1164
1327
|
value: keyDraft,
|
|
1165
1328
|
onInput: function (event) { setKeyDraft(event.target.value) },
|
|
1166
1329
|
onChange: function (event) { setKeyDraft(event.target.value) }
|
|
1167
1330
|
}),
|
|
1168
1331
|
React.createElement('button', {
|
|
1169
|
-
type: 'button', className: 'dshw_btn dshw_btnPrimary',
|
|
1332
|
+
type: 'button', className: 'dshw_btn dshw_btnPrimary', style: { height: '28px', padding: '0 14px' },
|
|
1170
1333
|
onClick: addAccount
|
|
1171
1334
|
}, '添加')))
|
|
1172
1335
|
if (accountNotice) {
|
|
1173
1336
|
rows.push(React.createElement('div', { key: 'acc-n', className: 'dshw_muted' }, accountNotice))
|
|
1174
1337
|
}
|
|
1175
1338
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
React.createElement('
|
|
1179
|
-
type: 'button', className: 'dshw_btn dshw_btnPrimary',
|
|
1180
|
-
onClick: function () { if (close) close(); window.open('https://platform.deepseek.com/top_up', '_blank', 'noopener') }
|
|
1181
|
-
}, '\u2197 \u53bb\u5b98\u65b9\u5145\u503c'),
|
|
1339
|
+
rows.push(React.createElement('div', { key: 'footer', className: 'dshw_settingsFooter' },
|
|
1340
|
+
React.createElement('span', { className: 'dshw_versionBadge' }, 'DeepSeek Harness Control Center v' + WALLET_VERSION),
|
|
1341
|
+
React.createElement('span', { className: 'dshw_settingsFooterActions' },
|
|
1182
1342
|
React.createElement('button', {
|
|
1183
1343
|
type: 'button', className: 'dshw_btn',
|
|
1184
1344
|
onClick: function () {
|
|
1185
1345
|
fetch('/api/wallet/refresh', { method: 'POST' }).then(reloadAccounts).catch(function () { /* ignore */ })
|
|
1186
1346
|
}
|
|
1187
|
-
}, '
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1347
|
+
}, '刷新余额'),
|
|
1348
|
+
React.createElement('button', {
|
|
1349
|
+
type: 'button', className: 'dshw_btn dshw_btnPrimary',
|
|
1350
|
+
onClick: function () { if (close) close(); window.open('https://platform.deepseek.com/top_up', '_blank', 'noopener') }
|
|
1351
|
+
}, '↗ 去官方充值'))))
|
|
1191
1352
|
return React.createElement('div', { className: 'dshw_settingsSection', style: { display: 'flex', flexDirection: 'column', gap: '6px', fontSize: '12px', color: 'var(--dsw-alias-label-primary,#1f2328)' } }, rows)
|
|
1192
1353
|
}
|
|
1193
1354
|
|
|
@@ -1206,6 +1367,7 @@ function fmtCurrency(value, currency) {
|
|
|
1206
1367
|
var confirmButtonRef = React.useRef(null)
|
|
1207
1368
|
var restoreFocusRef = React.useRef(null)
|
|
1208
1369
|
var thresholdInitializedRef = React.useRef(false)
|
|
1370
|
+
var thresholdEditTimerRef = React.useRef(null)
|
|
1209
1371
|
var [data, setData] = React.useState(null)
|
|
1210
1372
|
var [open, setOpen] = React.useState(false)
|
|
1211
1373
|
var [panelStyle, setPanelStyle] = React.useState({ visibility: 'hidden' })
|
|
@@ -1350,9 +1512,14 @@ function fmtCurrency(value, currency) {
|
|
|
1350
1512
|
if (!alive) return
|
|
1351
1513
|
dataRef.current = json
|
|
1352
1514
|
setData(json)
|
|
1353
|
-
if (
|
|
1354
|
-
|
|
1355
|
-
|
|
1515
|
+
if (json.threshold !== undefined && json.threshold !== null) {
|
|
1516
|
+
// Follow the active currency's own threshold line: switching
|
|
1517
|
+
// accounts (and thus currency) refreshes the draft unless the
|
|
1518
|
+
// user is mid-edit (the 600ms auto-save owns that window).
|
|
1519
|
+
setThresholdDraft(function (prev) {
|
|
1520
|
+
if (thresholdInitializedRef.current === 'editing') return prev
|
|
1521
|
+
return json.threshold.toFixed(2)
|
|
1522
|
+
})
|
|
1356
1523
|
}
|
|
1357
1524
|
if (showOfficial && json.lowBalance) {
|
|
1358
1525
|
if (!notifiedRef.current) {
|
|
@@ -1853,14 +2020,14 @@ function fmtCurrency(value, currency) {
|
|
|
1853
2020
|
}).catch(function () { /* page reminders remain available */ })
|
|
1854
2021
|
}
|
|
1855
2022
|
|
|
1856
|
-
function saveThreshold() {
|
|
1857
|
-
var value = Number.parseFloat(thresholdDraft)
|
|
2023
|
+
function saveThreshold(valueArg) {
|
|
2024
|
+
var value = Number.parseFloat(valueArg !== undefined ? valueArg : thresholdDraft)
|
|
1858
2025
|
if (!Number.isFinite(value)) return
|
|
1859
2026
|
value = Math.min(100000, Math.max(0, Math.round(value * 100) / 100))
|
|
1860
2027
|
fetch('/api/wallet/threshold', {
|
|
1861
2028
|
method: 'POST',
|
|
1862
2029
|
headers: { 'content-type': 'application/json' },
|
|
1863
|
-
body: JSON.stringify({ threshold: value })
|
|
2030
|
+
body: JSON.stringify({ threshold: value, currency: (dataRef.current && dataRef.current.balance && dataRef.current.balance.currency) || 'CNY' })
|
|
1864
2031
|
}).then(function (resp) { return resp.json() }).then(function (json) {
|
|
1865
2032
|
if (json && json.ok) {
|
|
1866
2033
|
setThresholdDraft(json.threshold.toFixed(2))
|
|
@@ -1869,6 +2036,12 @@ function fmtCurrency(value, currency) {
|
|
|
1869
2036
|
}).catch(function () { /* ignore */ })
|
|
1870
2037
|
}
|
|
1871
2038
|
|
|
2039
|
+
var thresholdSaveTimerRef = React.useRef(null)
|
|
2040
|
+
function queueThresholdSave(value) {
|
|
2041
|
+
if (thresholdSaveTimerRef.current) clearTimeout(thresholdSaveTimerRef.current)
|
|
2042
|
+
thresholdSaveTimerRef.current = setTimeout(function () { saveThreshold(value) }, 600)
|
|
2043
|
+
}
|
|
2044
|
+
|
|
1872
2045
|
function clearSession() {
|
|
1873
2046
|
if (!sessionId) return
|
|
1874
2047
|
fetch('/api/wallet/clear-session', {
|
|
@@ -1961,6 +2134,9 @@ function fmtCurrency(value, currency) {
|
|
|
1961
2134
|
setAccountNotice('\u5df2\u5207\u6362\u5230\u300c' + json.account.name + '\u300d')
|
|
1962
2135
|
loadAccounts()
|
|
1963
2136
|
refreshBalance()
|
|
2137
|
+
// 切换账号: 解锁 + 激活响应自带阈值, 输入框零等待跳转
|
|
2138
|
+
thresholdInitializedRef.current = false
|
|
2139
|
+
if (json.threshold !== undefined && json.threshold !== null) setThresholdDraft(json.threshold.toFixed(2))
|
|
1964
2140
|
} else {
|
|
1965
2141
|
setAccountNotice((json && json.error) || '\u5207\u6362\u5931\u8d25')
|
|
1966
2142
|
}
|
|
@@ -2102,7 +2278,10 @@ function fmtCurrency(value, currency) {
|
|
|
2102
2278
|
// cap the slider there; floating and side docks keep the full range.
|
|
2103
2279
|
var scaleMaxPercent = chipDock === 'home' ? 105 : 125
|
|
2104
2280
|
var chipVertical = chipDock === 'left' || chipDock === 'right' || chipDock === 'content-left'
|
|
2105
|
-
var
|
|
2281
|
+
var lowBlinkOff = false
|
|
2282
|
+
try { lowBlinkOff = compatibility.storage.getItem(LOW_BLINK_KEY) === 'false' } catch (e) { /* ignore */ }
|
|
2283
|
+
var lowBlinkOn = !lowBlinkOff
|
|
2284
|
+
var chipClass = low ? (lowBlinkOff ? 'dshw_chip dshw_chipLow dshw_noBlink' : 'dshw_chip dshw_chipLow') : 'dshw_chip'
|
|
2106
2285
|
var cssZoom = compatibility.supportsCssZoom()
|
|
2107
2286
|
var chipStyle = cssZoom
|
|
2108
2287
|
? { zoom: chipScale }
|
|
@@ -2122,15 +2301,16 @@ function fmtCurrency(value, currency) {
|
|
|
2122
2301
|
React.createElement('span', { className: 'dshw_metricLabel' }, label),
|
|
2123
2302
|
React.createElement('span', { className: 'dshw_metricValue' }, value))
|
|
2124
2303
|
}
|
|
2125
|
-
//
|
|
2126
|
-
//
|
|
2127
|
-
//
|
|
2128
|
-
|
|
2129
|
-
|
|
2304
|
+
// The session cost stays on the chip even at ¥0.00. Three states:
|
|
2305
|
+
// no session record yet → show ¥0.00 (a fresh chat must not lose the
|
|
2306
|
+
// segment), priced → show the value, unpriced (priced === false) →
|
|
2307
|
+
// hide, because no honest number exists.
|
|
2308
|
+
var chipCostHidden = official.priced === false
|
|
2309
|
+
var chipCostValue = (official.cost === null || official.cost === undefined) ? 0 : official.cost
|
|
2130
2310
|
if (chipVertical) {
|
|
2131
2311
|
if (showOfficial) {
|
|
2132
2312
|
chipTextParts.push(verticalMetric('bal', '余额', balanceText))
|
|
2133
|
-
if (
|
|
2313
|
+
if (!chipCostHidden) chipTextParts.push(verticalMetric('cost', sessionCostLabel(bal.currency), sessionCostText(chipCostValue, bal.currency)))
|
|
2134
2314
|
chipTextParts.push(verticalMetric('off', '\u5b98', fmtTokens(officialTokens)))
|
|
2135
2315
|
}
|
|
2136
2316
|
if (showThird) chipTextParts.push(verticalMetric('third', '\u4e09\u65b9', fmtTokens(thirdTokens)))
|
|
@@ -2139,7 +2319,7 @@ function fmtCurrency(value, currency) {
|
|
|
2139
2319
|
chipTextParts.push(React.createElement('span', { key: 'bal', className: 'dshw_balanceText dshw_homePrimary' },
|
|
2140
2320
|
React.createElement('span', { className: 'dshw_homePrimaryLabel' }, '余额 '),
|
|
2141
2321
|
React.createElement('span', { className: 'dshw_homePrimaryValue' }, balanceText)))
|
|
2142
|
-
if (
|
|
2322
|
+
if (!chipCostHidden) chipTextParts.push(React.createElement('span', { key: 'cost' }, sessionCostLabel(bal.currency) + ' ' + sessionCostText(chipCostValue, bal.currency)))
|
|
2143
2323
|
chipTextParts.push(React.createElement('span', { key: 'off' }, '\u5b98 ' + fmtTokens(officialTokens)))
|
|
2144
2324
|
}
|
|
2145
2325
|
if (showOfficial && showThird) chipTextParts.push(React.createElement('span', { key: 'sep', className: 'dshw_sep' }, '|'))
|
|
@@ -2248,7 +2428,9 @@ function fmtCurrency(value, currency) {
|
|
|
2248
2428
|
'aria-label': '\u4f59\u989d\u63d0\u9192\u9608\u503c\uff08CNY\uff09',
|
|
2249
2429
|
value: thresholdDraft === null ? '' : thresholdDraft,
|
|
2250
2430
|
onChange: function (event) {
|
|
2251
|
-
thresholdInitializedRef.current =
|
|
2431
|
+
thresholdInitializedRef.current = 'editing'
|
|
2432
|
+
if (thresholdEditTimerRef.current) clearTimeout(thresholdEditTimerRef.current)
|
|
2433
|
+
thresholdEditTimerRef.current = setTimeout(function () { thresholdInitializedRef.current = false }, 15000)
|
|
2252
2434
|
setThresholdDraft(event.target.value)
|
|
2253
2435
|
}
|
|
2254
2436
|
})
|
|
@@ -2345,7 +2527,6 @@ function fmtCurrency(value, currency) {
|
|
|
2345
2527
|
title: '拖动控制面板',
|
|
2346
2528
|
onPointerDown: onPanelDown
|
|
2347
2529
|
},
|
|
2348
|
-
React.createElement('span', { className: 'dshw_muted', style: { flex: '1', textAlign: 'center', fontSize: '10px', letterSpacing: '.02em' } }, 'v' + WALLET_VERSION),
|
|
2349
2530
|
React.createElement('button', {
|
|
2350
2531
|
type: 'button',
|
|
2351
2532
|
className: 'dshw_btn',
|
|
@@ -2392,7 +2573,7 @@ function fmtCurrency(value, currency) {
|
|
|
2392
2573
|
subParts.push(React.createElement('span', { key: 'd' + i, className: 'dshw_balDot' }, '\u00b7'))
|
|
2393
2574
|
subParts.push(React.createElement('span', { key: 'x' + i }, info.currency + ' ' + fmtCurrency(info.total_balance, info.currency)))
|
|
2394
2575
|
})
|
|
2395
|
-
return React.createElement('div', { className: 'dshw_balanceCard' },
|
|
2576
|
+
return React.createElement('div', { className: low ? 'dshw_balanceCard dshw_low' : 'dshw_balanceCard' },
|
|
2396
2577
|
React.createElement('div', { className: 'dshw_balLine' },
|
|
2397
2578
|
React.createElement('span', { className: 'dshw_muted' }, '\u4f59\u989d'),
|
|
2398
2579
|
React.createElement('span', { className: 'dshw_balNum' }, fmtCurrency(first.total_balance, first.currency)),
|
|
@@ -2429,49 +2610,72 @@ function fmtCurrency(value, currency) {
|
|
|
2429
2610
|
}),
|
|
2430
2611
|
React.createElement('span', null, '\u7b2c\u4e09\u65b9'))))
|
|
2431
2612
|
cells.push(React.createElement('div', { key: 'sc', className: 'dshw_setCell' }, scaleControl))
|
|
2432
|
-
|
|
2433
|
-
|
|
2613
|
+
// 完成提醒 + 低额阈值 同行(无保存按钮后 276px 放得下)
|
|
2614
|
+
cells.push(React.createElement('div', { key: 'nfth', className: 'dshw_setCell', style: { gap: '5px' } },
|
|
2615
|
+
React.createElement('span', { className: 'dshw_muted', style: { flex: 'none' } }, '\u63d0\u9192'),
|
|
2616
|
+
React.createElement('select', {
|
|
2617
|
+
className: 'dshw_select',
|
|
2618
|
+
style: { flex: '0 0 auto' },
|
|
2619
|
+
value: notifyConfig.enabled ? (notifyConfig.timeout === 0 ? 'keep' : String(notifyConfig.timeout)) : 'off',
|
|
2620
|
+
'aria-label': '\u5b8c\u6210\u63d0\u9192',
|
|
2621
|
+
onChange: function (event) {
|
|
2622
|
+
var v = event.target.value
|
|
2623
|
+
if (v === 'off') { saveNotifyConfig({ enabled: false, timeout: notifyConfig.timeout }); return }
|
|
2624
|
+
saveNotifyConfig({ enabled: true, timeout: v === 'keep' ? 0 : Number.parseInt(v, 10) })
|
|
2625
|
+
requestNotify()
|
|
2626
|
+
}
|
|
2627
|
+
},
|
|
2628
|
+
React.createElement('option', { value: 'off' }, '\u5173\u95ed'),
|
|
2629
|
+
React.createElement('option', { value: '5' }, '5 \u79d2'),
|
|
2630
|
+
React.createElement('option', { value: '10' }, '10 \u79d2'),
|
|
2631
|
+
React.createElement('option', { value: '30' }, '30 \u79d2'),
|
|
2632
|
+
React.createElement('option', { value: '60' }, '60 \u79d2'),
|
|
2633
|
+
React.createElement('option', { value: 'keep' }, '\u4e00\u76f4\u4fdd\u7559')),
|
|
2434
2634
|
React.createElement('span', { className: 'dshw_balFill' }),
|
|
2435
|
-
React.createElement('span', { className: '
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
'aria-label': '
|
|
2635
|
+
React.createElement('span', { className: 'dshw_muted', style: { flex: 'none' } }, '\u9608\u503c'),
|
|
2636
|
+
React.createElement('input', {
|
|
2637
|
+
className: 'dshw_input', type: 'number', min: '0', step: '0.01',
|
|
2638
|
+
style: { width: '64px', flex: 'none' },
|
|
2639
|
+
value: thresholdDraft,
|
|
2640
|
+
title: '\u4f4e\u4e8e\u6b64\u4f59\u989d\u65f6\u63d0\u9192\uff080 \u5173\u95ed\uff09\uff1b\u8f93\u5165\u540e\u81ea\u52a8\u4fdd\u5b58',
|
|
2641
|
+
'aria-label': '\u4f4e\u989d\u9608\u503c (' + (bal.currency === 'USD' ? 'USD' : 'CNY') + ')',
|
|
2642
|
+
onInput: function (event) { setThresholdDraft(event.target.value); queueThresholdSave(event.target.value) },
|
|
2643
|
+
onChange: function (event) { setThresholdDraft(event.target.value); queueThresholdSave(event.target.value) }
|
|
2644
|
+
})))
|
|
2645
|
+
// 低额闪烁 + 永久删除 同行
|
|
2646
|
+
cells.push(React.createElement('div', { key: 'blinkpd', className: 'dshw_setCell', style: { gap: '5px' } },
|
|
2647
|
+
React.createElement('span', { className: 'dshw_muted', style: { flex: 'none' } }, '\u4f4e\u989d\u95ea\u70c1'),
|
|
2648
|
+
React.createElement('label', { className: 'dshw_switch' },
|
|
2649
|
+
React.createElement('input', {
|
|
2650
|
+
type: 'checkbox',
|
|
2651
|
+
checked: lowBlinkOn,
|
|
2652
|
+
'aria-label': '\u4f4e\u989d\u65f6\u7ea2\u8272\u95ea\u70c1',
|
|
2453
2653
|
onChange: function (event) {
|
|
2454
|
-
|
|
2654
|
+
try { compatibility.storage.setItem(LOW_BLINK_KEY, String(event.target.checked)) } catch (e) { /* ignore */ }
|
|
2655
|
+
compatibility.dispatch(SETTINGS_EVENT)
|
|
2455
2656
|
}
|
|
2456
|
-
},
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2657
|
+
}),
|
|
2658
|
+
React.createElement('span', { className: 'dshw_track', 'aria-hidden': 'true' }),
|
|
2659
|
+
React.createElement('span', { className: 'dshw_knob', 'aria-hidden': 'true' })),
|
|
2660
|
+
React.createElement('span', { className: 'dshw_balFill' }),
|
|
2661
|
+
React.createElement('span', { className: 'dshw_muted', style: { flex: 'none' } }, permanentDeleteSupported ? '\u6c38\u4e45\u5220\u9664' : '\u6c38\u4e45\u5220\u9664(\u4e0d\u652f\u6301)'),
|
|
2662
|
+
React.createElement('label', { className: 'dshw_switch' },
|
|
2663
|
+
React.createElement('input', {
|
|
2664
|
+
type: 'checkbox',
|
|
2665
|
+
checked: permanentDeleteSupported && permanentDeleteEnabled,
|
|
2666
|
+
disabled: !permanentDeleteSupported,
|
|
2667
|
+
'aria-label': '\u5f00\u542f\u6c38\u4e45\u5220\u9664\u4f1a\u8bdd',
|
|
2668
|
+
title: permanentDeleteSupported ? '\u5728\u4f1a\u8bdd\u83dc\u5355\u4e2d\u663e\u793a\u6c38\u4e45\u5220\u9664' : '\u5f53\u524d\u5bbf\u4e3b\u672a\u63d0\u4f9b\u6c38\u4e45\u5220\u9664\u80fd\u529b',
|
|
2669
|
+
onChange: function (event) {
|
|
2670
|
+
if (!permanentDeleteSupported) return
|
|
2671
|
+
var enabled = event.target.checked
|
|
2672
|
+
setPermanentDeleteEnabled(enabled)
|
|
2673
|
+
try { compatibility.storage.setItem(PERMANENT_DELETE_KEY, String(enabled)) } catch (e) { /* ignore */ }
|
|
2674
|
+
compatibility.dispatch(PERMANENT_DELETE_EVENT)
|
|
2675
|
+
}
|
|
2676
|
+
}),
|
|
2677
|
+
React.createElement('span', { className: 'dshw_track', 'aria-hidden': 'true' }),
|
|
2678
|
+
React.createElement('span', { className: 'dshw_knob', 'aria-hidden': 'true' }))))
|
|
2475
2679
|
return React.createElement('div', { className: 'dshw_setCard' }, cells)
|
|
2476
2680
|
}
|
|
2477
2681
|
|
|
@@ -2485,7 +2689,7 @@ function fmtCurrency(value, currency) {
|
|
|
2485
2689
|
},
|
|
2486
2690
|
floatBtnRow,
|
|
2487
2691
|
showOfficial ? React.createElement(React.Fragment, null,
|
|
2488
|
-
React.createElement('div', { className: 'dshw_title' }, '\u5b98\u65b9 DeepSeek'),
|
|
2692
|
+
React.createElement('div', { className: 'dshw_title' }, (snapshot.accounts && snapshot.accounts.activeName) ? '\u5b98\u65b9 DeepSeek \u00b7 ' + snapshot.accounts.activeName : '\u5b98\u65b9 DeepSeek'),
|
|
2489
2693
|
balanceCard(),
|
|
2490
2694
|
official.tokens ? React.createElement('div', { key: 'o-t', className: 'dshw_row' },
|
|
2491
2695
|
React.createElement('span', { className: 'dshw_muted' }, '\u5b98\u65b9 token'),
|
|
@@ -2497,23 +2701,25 @@ function fmtCurrency(value, currency) {
|
|
|
2497
2701
|
React.createElement('div', { className: 'dshw_divider' })) : null,
|
|
2498
2702
|
settingsCard(),
|
|
2499
2703
|
showOfficial ? React.createElement(React.Fragment, null,
|
|
2500
|
-
React.createElement('div', { className: 'dshw_actionRow' },
|
|
2704
|
+
React.createElement('div', { className: 'dshw_actionRow', style: { gridTemplateColumns: '1fr 1fr 1fr' } },
|
|
2501
2705
|
React.createElement('button', {
|
|
2502
2706
|
type: 'button',
|
|
2503
2707
|
className: 'dshw_btn dshw_btnPrimary',
|
|
2504
2708
|
onClick: onRechargeClick
|
|
2505
|
-
}, '\u2197 \
|
|
2506
|
-
React.createElement('button', { type: 'button', className: 'dshw_btn', onClick: refreshBalance }, '\u5237\u65b0\u4f59\u989d')
|
|
2507
|
-
React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end' } },
|
|
2709
|
+
}, '\u2197 \u5145\u503c'),
|
|
2710
|
+
React.createElement('button', { type: 'button', className: 'dshw_btn', onClick: refreshBalance }, '\u5237\u65b0\u4f59\u989d'),
|
|
2508
2711
|
React.createElement('button', {
|
|
2509
2712
|
type: 'button',
|
|
2510
|
-
className: '
|
|
2713
|
+
className: 'dshw_btn',
|
|
2714
|
+
style: { color: 'var(--dsw-alias-state-error-primary,#e5534b)' },
|
|
2715
|
+
title: '\u6e05\u9664\u672c\u4f1a\u8bdd\u7684\u4f59\u989d\u4e0e token \u6570\u636e\uff0c\u4e0d\u53ef\u6062\u590d',
|
|
2511
2716
|
onClick: function () {
|
|
2512
2717
|
if (window.confirm('确认清除本会话的余额与 token 数据?不可恢复。')) clearSession()
|
|
2513
2718
|
}
|
|
2514
|
-
}, '\u6e05\u9664
|
|
2719
|
+
}, '\u6e05\u9664')),
|
|
2515
2720
|
React.createElement('div', { className: 'dshw_divider' })) : null,
|
|
2516
|
-
accountsSection()
|
|
2721
|
+
accountsSection(),
|
|
2722
|
+
React.createElement('div', { style: { marginTop: '8px', textAlign: 'right', fontSize: '10px', color: 'var(--dsw-alias-label-quaternary,rgba(31,35,40,.45))', userSelect: 'none' } }, 'DeepSeek Harness Control Center v' + WALLET_VERSION)
|
|
2517
2723
|
)
|
|
2518
2724
|
|
|
2519
2725
|
if (floated) {
|
|
@@ -2587,7 +2793,8 @@ function fmtCurrency(value, currency) {
|
|
|
2587
2793
|
}
|
|
2588
2794
|
}, '清除余额与 token'),
|
|
2589
2795
|
React.createElement('div', { className: 'dshw_divider' }),
|
|
2590
|
-
accountsSection()
|
|
2796
|
+
accountsSection(),
|
|
2797
|
+
React.createElement('div', { style: { marginTop: '8px', textAlign: 'right', fontSize: '10px', color: 'var(--dsw-alias-label-quaternary,rgba(31,35,40,.45))', userSelect: 'none' } }, 'DeepSeek Harness Control Center v' + WALLET_VERSION)
|
|
2591
2798
|
)
|
|
2592
2799
|
return React.createElement(React.Fragment, null, floatPanel, confirmOverlay)
|
|
2593
2800
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepseek-harness-wallet",
|
|
3
3
|
"description": "Local-first account monitoring, usage accounting, official recharge, completion reminders, flexible layout, host-gated session controls, and multi-account management with hot account switching for DeepSeek Harness.",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"exports": {
|