@lynn123411/dsh-a6api 1.2.0 → 1.3.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/lib/client.js CHANGED
@@ -1,8 +1,10 @@
1
1
  window.__ModuleLoader__.load({ id: "@lynn123411/dsh-a6api", factory: (require) => { var module = { exports: {} }; var exports = module.exports;
2
2
  "use strict";
3
+ var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
9
  var __export = (target, all) => {
8
10
  for (var name2 in all)
@@ -16,6 +18,14 @@ var __copyProps = (to, from, except, desc) => {
16
18
  }
17
19
  return to;
18
20
  };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
19
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
30
 
21
31
  // src/client/index.ts
@@ -26,9 +36,10 @@ __export(index_exports, {
26
36
  name: () => name
27
37
  });
28
38
  module.exports = __toCommonJS(index_exports);
39
+ var import_react7 = __toESM(require("react"), 1);
29
40
 
30
41
  // src/client/components/A6ApiSettings.tsx
31
- var import_react4 = require("react");
42
+ var import_react5 = require("react");
32
43
 
33
44
  // src/client/store.ts
34
45
  function formatRelativeNow(tsSec) {
@@ -38,6 +49,8 @@ function formatRelativeNow(tsSec) {
38
49
  if (diff < 86400) return `${Math.floor(diff / 3600)} \u5C0F\u65F6\u524D`;
39
50
  return `${Math.floor(diff / 86400)} \u5929\u524D`;
40
51
  }
52
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
53
+ var RATE_LIMIT_RE = /\b429\b|Too Many Requests|rate\s*limit/i;
41
54
  var A6ApiStore = class {
42
55
  state = {
43
56
  loading: true,
@@ -52,12 +65,28 @@ var A6ApiStore = class {
52
65
  dshConfiguredModels: [],
53
66
  recentLogs: [],
54
67
  probingModelNames: /* @__PURE__ */ new Set(),
68
+ actionBusyModels: /* @__PURE__ */ new Set(),
69
+ probeAllActive: false,
70
+ probeAllTotal: 0,
71
+ probeAllDoneCount: 0,
72
+ pins: [],
73
+ catalog: [],
74
+ catalogBusy: null,
55
75
  error: null,
56
76
  priceFluctuation: { pendingCount: 0, unseenCount: 0, totalCount: 0, updatedAt: null }
57
77
  };
58
78
  listeners = /* @__PURE__ */ new Set();
59
79
  autoRefreshTimer = null;
60
- pricePollTimer = null;
80
+ /** 启动预热已触发(幂等):插件随 DSH 启动即后台拉一次完整状态 */
81
+ warmedUp = false;
82
+ /** 全量探测取消标志:置位后不再从队列取新任务,在途探测正常完成 */
83
+ probeCancelled = false;
84
+ /** 本轮全量探测的模型名快照(null = 未在运行),用于进度计数与 /state 刷新后重挂状态 */
85
+ probeAllSnapshot = null;
86
+ /** 本轮已完成探测的模型(幂等集合,驱动 probeAllDoneCount) */
87
+ probeAllDone = /* @__PURE__ */ new Set();
88
+ /** 入队前各模型的 probeError 暂存,取消时恢复历史错误提示 */
89
+ probeQueuedPrevError = /* @__PURE__ */ new Map();
61
90
  constructor() {
62
91
  this.startAutoRefresh();
63
92
  }
@@ -89,7 +118,22 @@ var A6ApiStore = class {
89
118
  this.state.config = data.config;
90
119
  this.state.balance = data.balance;
91
120
  this.state.models = data.models;
121
+ const snapshot = this.probeAllSnapshot;
122
+ if (this.state.probeAllActive && snapshot) {
123
+ this.state.models = this.state.models.map((m) => {
124
+ if (this.state.probingModelNames.has(m.model_name)) {
125
+ return { ...m, probeStatus: "probing" };
126
+ }
127
+ if (snapshot.includes(m.model_name) && !this.probeAllDone.has(m.model_name)) {
128
+ return { ...m, probeStatus: "queued", probeError: void 0 };
129
+ }
130
+ return m;
131
+ });
132
+ }
92
133
  this.state.dshConfiguredModels = data.dshConfiguredModels;
134
+ if (Array.isArray(data.pins)) {
135
+ this.state.pins = data.pins;
136
+ }
93
137
  if (data.recentLogs) {
94
138
  this.state.recentLogs = data.recentLogs;
95
139
  }
@@ -143,6 +187,120 @@ var A6ApiStore = class {
143
187
  } catch {
144
188
  }
145
189
  }
190
+ // ===== 模型目录 =====
191
+ async fetchCatalog() {
192
+ try {
193
+ const res = await fetch("/api/dsh-a6api/catalog");
194
+ if (res.ok) {
195
+ const json = await res.json();
196
+ if (Array.isArray(json?.catalog)) {
197
+ this.state.catalog = json.catalog;
198
+ this.notify();
199
+ }
200
+ }
201
+ } catch {
202
+ }
203
+ }
204
+ /** 从 A6API 市场拉取全部模型 ID 并入目录(仅新增/补品牌,不动已有参数) */
205
+ async fetchMarketModels() {
206
+ if (this.state.catalogBusy) return { ok: false, error: "\u76EE\u5F55\u64CD\u4F5C\u8FDB\u884C\u4E2D" };
207
+ this.state.catalogBusy = "fetch";
208
+ this.notify();
209
+ try {
210
+ const res = await fetch("/api/dsh-a6api/catalog/fetch-models", {
211
+ method: "POST",
212
+ headers: { "Content-Type": "application/json" },
213
+ body: "{}"
214
+ });
215
+ const json = await res.json().catch(() => null);
216
+ if (res.ok && json?.ok) {
217
+ await this.fetchCatalog();
218
+ return { ok: true, total: json.total, added: json.added, failedPages: json.failedPages || 0 };
219
+ }
220
+ const errText = json?.error || `HTTP ${res.status}`;
221
+ this.state.error = errText;
222
+ return { ok: false, error: errText };
223
+ } catch (err) {
224
+ const msg = err?.message || String(err);
225
+ this.state.error = msg;
226
+ return { ok: false, error: msg };
227
+ } finally {
228
+ this.state.catalogBusy = null;
229
+ this.notify();
230
+ }
231
+ }
232
+ /** 对全部(或指定)目录模型查 OpenRouter 并填充参数 */
233
+ async queryOpenRouter(modelIds) {
234
+ if (this.state.catalogBusy) return { ok: false, error: "\u76EE\u5F55\u64CD\u4F5C\u8FDB\u884C\u4E2D" };
235
+ this.state.catalogBusy = "query";
236
+ this.notify();
237
+ try {
238
+ const res = await fetch("/api/dsh-a6api/catalog/query-openrouter", {
239
+ method: "POST",
240
+ headers: { "Content-Type": "application/json" },
241
+ body: JSON.stringify({ modelIds })
242
+ });
243
+ const json = await res.json().catch(() => null);
244
+ if (res.ok && json?.ok) {
245
+ await this.fetchCatalog();
246
+ return { ok: true, updated: json.updated, notFound: json.notFound || [] };
247
+ }
248
+ const errText = json?.error || `HTTP ${res.status}`;
249
+ this.state.error = errText;
250
+ return { ok: false, error: errText };
251
+ } catch (err) {
252
+ const msg = err?.message || String(err);
253
+ this.state.error = msg;
254
+ return { ok: false, error: msg };
255
+ } finally {
256
+ this.state.catalogBusy = null;
257
+ this.notify();
258
+ }
259
+ }
260
+ /** 修改目录条目参数;已启用模型由服务端即时重写 settings.yaml */
261
+ async updateCatalogEntry(id, patch) {
262
+ try {
263
+ const res = await fetch("/api/dsh-a6api/catalog/update", {
264
+ method: "POST",
265
+ headers: { "Content-Type": "application/json" },
266
+ body: JSON.stringify({ id, ...patch })
267
+ });
268
+ const json = await res.json().catch(() => null);
269
+ if (res.ok && json?.ok) {
270
+ await this.fetchCatalog();
271
+ return { ok: true };
272
+ }
273
+ const errText = json?.error || `HTTP ${res.status}`;
274
+ this.state.error = errText;
275
+ return { ok: false, error: errText };
276
+ } catch (err) {
277
+ const msg = err?.message || String(err);
278
+ this.state.error = msg;
279
+ return { ok: false, error: msg };
280
+ }
281
+ }
282
+ /** 清空模型目录(随后可重新从 A6API 拉取 / OpenRouter 填充) */
283
+ async clearCatalog() {
284
+ try {
285
+ const res = await fetch("/api/dsh-a6api/catalog/clear", {
286
+ method: "POST",
287
+ headers: { "Content-Type": "application/json" },
288
+ body: "{}"
289
+ });
290
+ const json = await res.json().catch(() => null);
291
+ if (res.ok && json?.ok) {
292
+ await this.fetchCatalog();
293
+ return { ok: true };
294
+ }
295
+ const errText = json?.error || `HTTP ${res.status}`;
296
+ this.state.error = errText;
297
+ return { ok: false, error: errText };
298
+ } catch (err) {
299
+ const msg = err?.message || String(err);
300
+ this.state.error = msg;
301
+ return { ok: false, error: msg };
302
+ }
303
+ }
146
304
  async fetchPriceFluctuation() {
147
305
  try {
148
306
  const res = await fetch("/api/dsh-a6api/price-fluctuation");
@@ -175,12 +333,8 @@ var A6ApiStore = class {
175
333
  } catch {
176
334
  }
177
335
  }
178
- async probeModel(modelName) {
179
- this.state.probingModelNames.add(modelName);
180
- this.state.models = this.state.models.map(
181
- (m) => m.model_name === modelName ? { ...m, probeStatus: "probing" } : m
182
- );
183
- this.notify();
336
+ /** 单次探测请求(不修改状态,供限流重试循环复用) */
337
+ async probeOnce(modelName) {
184
338
  try {
185
339
  const res = await fetch("/api/dsh-a6api/probe", {
186
340
  method: "POST",
@@ -189,76 +343,161 @@ var A6ApiStore = class {
189
343
  });
190
344
  if (res.ok) {
191
345
  const json = await res.json();
192
- if (json?.result?.merchant) {
193
- this.state.models = this.state.models.map(
194
- (m) => m.model_name === modelName ? {
195
- ...m,
196
- merchant: json.result.merchant,
197
- probeStatus: "success",
198
- probeLatencyMs: json.result.durationMs,
199
- probeError: void 0,
200
- lastProbedAt: Date.now(),
201
- // 探测请求本身会写路由日志,乐观更新路由快照时效,下次 /state 以日志为准
202
- lastRoutedAt: Math.floor(Date.now() / 1e3),
203
- lastRoutedText: formatRelativeNow(Math.floor(Date.now() / 1e3))
204
- } : m
205
- );
206
- } else if (json?.result?.error) {
346
+ return { kind: "ok", json };
347
+ }
348
+ return { kind: "http", status: res.status };
349
+ } catch (err) {
350
+ return { kind: "network", error: err?.message || String(err) };
351
+ }
352
+ }
353
+ isRateLimitedOutcome(o) {
354
+ return o.kind === "ok" && Boolean(o.json?.result?.error && RATE_LIMIT_RE.test(String(o.json.result.error))) || o.kind === "http" && o.status === 429;
355
+ }
356
+ /** 把一次探测结果应用到卡片(按结果类型走原有映射逻辑) */
357
+ applyProbeResult(modelName, outcome) {
358
+ const patch = (p) => {
359
+ this.state.models = this.state.models.map((m) => m.model_name === modelName ? { ...m, ...p } : m);
360
+ this.notify();
361
+ };
362
+ if (outcome.kind === "ok") {
363
+ const json = outcome.json;
364
+ if (json?.result?.merchant) {
365
+ patch({
366
+ merchant: json.result.merchant,
367
+ probeStatus: "success",
368
+ probeLatencyMs: json.result.durationMs,
369
+ probeError: void 0,
370
+ lastProbedAt: Date.now(),
371
+ // 探测请求本身会写路由日志,乐观更新路由快照时效,下次 /state 以日志为准
372
+ lastRoutedAt: Math.floor(Date.now() / 1e3),
373
+ lastRoutedText: formatRelativeNow(Math.floor(Date.now() / 1e3))
374
+ });
375
+ } else if (json?.result?.error) {
376
+ patch({
377
+ merchant: void 0,
378
+ probeStatus: "error",
379
+ probeError: json.result.error,
380
+ lastProbedAt: Date.now()
381
+ });
382
+ } else {
383
+ patch({
384
+ probeStatus: json?.result?.success ? "success" : "idle",
385
+ probeLatencyMs: json?.result?.durationMs,
386
+ probeError: json?.result?.success ? "\u63A2\u6D4B\u6210\u529F,\u4F46\u672A\u6355\u83B7\u5546\u6237\u4FE1\u606F(\u9700\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C)" : void 0,
387
+ lastProbedAt: Date.now()
388
+ });
389
+ }
390
+ } else if (outcome.kind === "http") {
391
+ patch({
392
+ merchant: void 0,
393
+ probeStatus: "error",
394
+ probeError: `HTTP ${outcome.status}`,
395
+ lastProbedAt: Date.now()
396
+ });
397
+ } else {
398
+ patch({
399
+ merchant: void 0,
400
+ probeStatus: "error",
401
+ probeError: outcome.error,
402
+ lastProbedAt: Date.now()
403
+ });
404
+ }
405
+ }
406
+ async probeModel(modelName) {
407
+ this.state.probingModelNames.add(modelName);
408
+ this.state.models = this.state.models.map(
409
+ (m) => m.model_name === modelName ? { ...m, probeStatus: "probing" } : m
410
+ );
411
+ this.notify();
412
+ try {
413
+ let outcome = await this.probeOnce(modelName);
414
+ if (this.isRateLimitedOutcome(outcome)) {
415
+ for (let attempt = 2; attempt <= 3; attempt++) {
416
+ await sleep(attempt === 2 ? 800 : 2e3);
417
+ outcome = await this.probeOnce(modelName);
418
+ if (!this.isRateLimitedOutcome(outcome)) break;
419
+ }
420
+ if (this.isRateLimitedOutcome(outcome)) {
207
421
  this.state.models = this.state.models.map(
208
422
  (m) => m.model_name === modelName ? {
209
423
  ...m,
210
424
  merchant: void 0,
211
425
  probeStatus: "error",
212
- probeError: json.result.error,
213
- lastProbedAt: Date.now()
214
- } : m
215
- );
216
- } else {
217
- this.state.models = this.state.models.map(
218
- (m) => m.model_name === modelName ? {
219
- ...m,
220
- probeStatus: json?.result?.success ? "success" : "idle",
221
- probeLatencyMs: json?.result?.durationMs,
222
- probeError: json?.result?.success ? "\u63A2\u6D4B\u6210\u529F,\u4F46\u672A\u6355\u83B7\u5546\u6237\u4FE1\u606F(\u9700\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C)" : void 0,
426
+ probeError: "\u8BF7\u6C42\u88AB\u9650\u6D41(429),\u5DF2\u81EA\u52A8\u91CD\u8BD5 3 \u6B21\u4ECD\u5931\u8D25,\u8BF7\u7A0D\u540E\u518D\u8BD5",
223
427
  lastProbedAt: Date.now()
224
428
  } : m
225
429
  );
430
+ return;
226
431
  }
227
- } else {
228
- this.state.models = this.state.models.map(
229
- (m) => m.model_name === modelName ? {
230
- ...m,
231
- merchant: void 0,
232
- probeStatus: "error",
233
- probeError: `HTTP ${res.status}`,
234
- lastProbedAt: Date.now()
235
- } : m
236
- );
237
432
  }
238
- } catch (err) {
239
- this.state.models = this.state.models.map(
240
- (m) => m.model_name === modelName ? {
241
- ...m,
242
- merchant: void 0,
243
- probeStatus: "error",
244
- probeError: err?.message || String(err),
245
- lastProbedAt: Date.now()
246
- } : m
247
- );
433
+ this.applyProbeResult(modelName, outcome);
248
434
  } finally {
249
435
  this.state.probingModelNames.delete(modelName);
436
+ if (this.probeAllSnapshot?.includes(modelName)) {
437
+ this.probeAllDone.add(modelName);
438
+ this.state.probeAllDoneCount = this.probeAllDone.size;
439
+ }
250
440
  this.notify();
251
441
  this.refreshBalance().catch(() => {
252
442
  });
253
443
  }
254
444
  }
255
445
  async probeAll() {
256
- const allNames = this.state.models.map((m) => m.model_name);
257
- const CONCURRENCY = 3;
258
- for (let i = 0; i < allNames.length; i += CONCURRENCY) {
259
- await Promise.all(allNames.slice(i, i + CONCURRENCY).map((n) => this.probeModel(n)));
446
+ if (this.state.probeAllActive) return;
447
+ const names = this.state.models.map((m) => m.model_name);
448
+ if (names.length === 0) return;
449
+ this.probeCancelled = false;
450
+ this.probeAllSnapshot = names;
451
+ this.probeAllDone.clear();
452
+ this.probeQueuedPrevError = new Map(this.state.models.map((m) => [m.model_name, m.probeError]));
453
+ this.state.probeAllActive = true;
454
+ this.state.probeAllTotal = names.length;
455
+ this.state.probeAllDoneCount = 0;
456
+ this.state.models = this.state.models.map((m) => ({
457
+ ...m,
458
+ probeStatus: "queued",
459
+ probeError: void 0
460
+ }));
461
+ this.notify();
462
+ const CONCURRENCY = Math.min(8, names.length);
463
+ let idx = 0;
464
+ const worker = async () => {
465
+ while (idx < names.length && !this.probeCancelled) {
466
+ const name2 = names[idx++];
467
+ if (this.state.probingModelNames.has(name2)) continue;
468
+ await this.probeModel(name2);
469
+ }
470
+ };
471
+ try {
472
+ await Promise.all(Array.from({ length: CONCURRENCY }, () => worker()));
473
+ } finally {
474
+ this.state.probeAllActive = false;
475
+ this.probeAllSnapshot = null;
476
+ this.probeAllDone.clear();
477
+ this.state.probeAllDoneCount = 0;
478
+ this.restoreQueuedModels();
479
+ this.notify();
260
480
  }
261
481
  }
482
+ /** 把仍处于 queued 的模型复位为 idle 并恢复入队前的错误文案 */
483
+ restoreQueuedModels() {
484
+ const prev = this.probeQueuedPrevError;
485
+ this.state.models = this.state.models.map(
486
+ (m) => m.probeStatus === "queued" ? { ...m, probeStatus: "idle", probeError: prev.get(m.model_name) } : m
487
+ );
488
+ this.probeQueuedPrevError = /* @__PURE__ */ new Map();
489
+ }
490
+ /** 取消全量探测:立即复位排队模型,不再取新任务,已在途的探测正常完成并回填卡片 */
491
+ cancelProbeAll() {
492
+ if (!this.state.probeAllActive) return;
493
+ this.probeCancelled = true;
494
+ this.state.probeAllActive = false;
495
+ this.probeAllSnapshot = null;
496
+ this.probeAllDone.clear();
497
+ this.state.probeAllDoneCount = 0;
498
+ this.restoreQueuedModels();
499
+ this.notify();
500
+ }
262
501
  async toggleDshModel(modelName) {
263
502
  const currentSet = new Set(this.state.dshConfiguredModels);
264
503
  if (currentSet.has(modelName)) {
@@ -288,32 +527,89 @@ var A6ApiStore = class {
288
527
  this.notify();
289
528
  }
290
529
  }
530
+ /**
531
+ * 固定 / 取消固定 / 禁用 / 恢复 的统一执行器。
532
+ * 成功后会刷新 /state(服务端会把平台固定记录叠加回卡片,跟随官网状态)。
533
+ */
534
+ async runMarketplaceAction(modelName, endpoint, busySet) {
535
+ if (busySet.has(modelName)) return { ok: false, error: "\u64CD\u4F5C\u8FDB\u884C\u4E2D" };
536
+ busySet.add(modelName);
537
+ this.notify();
538
+ try {
539
+ const res = await fetch(`/api/dsh-a6api/${endpoint}`, {
540
+ method: "POST",
541
+ headers: { "Content-Type": "application/json" },
542
+ body: JSON.stringify({ modelName })
543
+ });
544
+ const json = await res.json().catch(() => null);
545
+ if (res.ok && json?.ok) {
546
+ if (Array.isArray(json.pins)) {
547
+ this.state.pins = json.pins;
548
+ }
549
+ await this.fetchState();
550
+ return { ok: true };
551
+ }
552
+ const errText = json?.error || `HTTP ${res.status}`;
553
+ this.state.error = errText;
554
+ this.notify();
555
+ return { ok: false, error: errText };
556
+ } catch (err) {
557
+ const msg = err?.message || String(err);
558
+ this.state.error = msg;
559
+ this.notify();
560
+ return { ok: false, error: msg };
561
+ } finally {
562
+ busySet.delete(modelName);
563
+ this.notify();
564
+ }
565
+ }
566
+ /** 固定卡片当前商家到该模型 */
567
+ pinModel(modelName) {
568
+ return this.runMarketplaceAction(modelName, "pin", this.state.actionBusyModels);
569
+ }
570
+ /** 取消该模型的固定 */
571
+ unpinModel(modelName) {
572
+ return this.runMarketplaceAction(modelName, "unpin", this.state.actionBusyModels);
573
+ }
574
+ /** 禁用卡片当前商家对该模型的服务 */
575
+ disableModel(modelName) {
576
+ return this.runMarketplaceAction(modelName, "disable", this.state.actionBusyModels);
577
+ }
578
+ /** 恢复被禁用的商家 */
579
+ restoreModel(modelName) {
580
+ return this.runMarketplaceAction(modelName, "restore", this.state.actionBusyModels);
581
+ }
582
+ /**
583
+ * 启动预热:插件随 DSH 启动即后台拉取一次完整状态。
584
+ * 侧边栏按钮在应用启动时就已挂载,预热让用户打开浮层/设置页时数据早已就绪 → 秒开无 spinner。
585
+ * 未配置凭据时 /state 返回默认回退数据,无害;后续保存配置/轮询会持续刷新。
586
+ * 目录一并预热(模型目录 tab 徽标/首屏不等待首次进入)。
587
+ */
588
+ warmUp() {
589
+ if (this.warmedUp) return;
590
+ this.warmedUp = true;
591
+ this.fetchState().catch(() => {
592
+ });
593
+ this.fetchCatalog().catch(() => {
594
+ });
595
+ }
291
596
  startAutoRefresh() {
292
597
  if (this.autoRefreshTimer) clearInterval(this.autoRefreshTimer);
293
598
  this.autoRefreshTimer = setInterval(() => {
294
- this.refreshBalance().catch(() => {
295
- });
296
- }, 6e4);
297
- if (this.pricePollTimer) clearInterval(this.pricePollTimer);
298
- this.pricePollTimer = setInterval(() => {
299
- if (this.state.config?.hasToken) {
300
- this.fetchPriceFluctuation().catch(() => {
599
+ if (this.state.config?.hasApiKey) {
600
+ this.fetchState().catch(() => {
301
601
  });
302
602
  }
303
- }, 60 * 1e3);
603
+ }, 6e4);
304
604
  }
305
605
  stopAutoRefresh() {
306
606
  if (this.autoRefreshTimer) {
307
607
  clearInterval(this.autoRefreshTimer);
308
608
  this.autoRefreshTimer = null;
309
609
  }
310
- if (this.pricePollTimer) {
311
- clearInterval(this.pricePollTimer);
312
- this.pricePollTimer = null;
313
- }
314
610
  }
315
611
  initPricePolling() {
316
- if (this.pricePollTimer) return;
612
+ if (this.autoRefreshTimer) return;
317
613
  this.startAutoRefresh();
318
614
  if (this.state.config?.hasToken) {
319
615
  this.fetchPriceFluctuation().catch(() => {
@@ -336,8 +632,23 @@ var formatAbsolute = (tsSec) => {
336
632
  };
337
633
  var MerchantCard = ({ model }) => {
338
634
  const [expanded, setExpanded] = (0, import_react.useState)(false);
635
+ const [pinConfirmOpen, setPinConfirmOpen] = (0, import_react.useState)(false);
636
+ const [actionError, setActionError] = (0, import_react.useState)(null);
637
+ const errorTimerRef = (0, import_react.useRef)(null);
339
638
  const isProbing = model.probeStatus === "probing";
639
+ const isQueued = model.probeStatus === "queued";
340
640
  const merchant = model.merchant;
641
+ const isBusy = store.getState().actionBusyModels.has(model.model_name);
642
+ const canWebAction = Boolean(store.getState().config?.hasToken);
643
+ const hasMerchant = Boolean(merchant?.channel_id);
644
+ const isPinnedHere = model.pinStatus === "pin_here";
645
+ const isPinnedElsewhere = model.pinStatus === "pin_elsewhere";
646
+ const isChannelDisabled = Boolean(merchant?.user_channel_disabled);
647
+ const flashActionError = (msg) => {
648
+ if (errorTimerRef.current) clearTimeout(errorTimerRef.current);
649
+ setActionError(msg);
650
+ errorTimerRef.current = setTimeout(() => setActionError(null), 6e3);
651
+ };
341
652
  const handleProbe = (e) => {
342
653
  e.stopPropagation();
343
654
  store.probeModel(model.model_name);
@@ -346,6 +657,38 @@ var MerchantCard = ({ model }) => {
346
657
  e.stopPropagation();
347
658
  store.toggleDshModel(model.model_name);
348
659
  };
660
+ const handleOpenPinConfirm = (e) => {
661
+ e.stopPropagation();
662
+ setActionError(null);
663
+ setPinConfirmOpen(true);
664
+ };
665
+ const handleConfirmPin = async () => {
666
+ setActionError(null);
667
+ const r = await store.pinModel(model.model_name);
668
+ if (!r.ok) {
669
+ flashActionError(r.error || "\u56FA\u5B9A\u5931\u8D25");
670
+ } else {
671
+ setPinConfirmOpen(false);
672
+ }
673
+ };
674
+ const handleUnpin = async (e) => {
675
+ e.stopPropagation();
676
+ setActionError(null);
677
+ const r = await store.unpinModel(model.model_name);
678
+ if (!r.ok) flashActionError(r.error || "\u53D6\u6D88\u56FA\u5B9A\u5931\u8D25");
679
+ };
680
+ const handleDisable = async (e) => {
681
+ e.stopPropagation();
682
+ setActionError(null);
683
+ const r = await store.disableModel(model.model_name);
684
+ if (!r.ok) flashActionError(r.error || "\u7981\u7528\u5931\u8D25");
685
+ };
686
+ const handleRestore = async (e) => {
687
+ e.stopPropagation();
688
+ setActionError(null);
689
+ const r = await store.restoreModel(model.model_name);
690
+ if (!r.ok) flashActionError(r.error || "\u6062\u590D\u5931\u8D25");
691
+ };
349
692
  const renderRealtimeDots = () => {
350
693
  if (merchant?.success_buckets && merchant.success_buckets.length > 0) {
351
694
  return merchant.success_buckets.slice(0, 10).map((b, i) => {
@@ -412,7 +755,26 @@ var MerchantCard = ({ model }) => {
412
755
  "\u5546\u6237ID ",
413
756
  merchant.channel_id
414
757
  ] })
415
- ] })
758
+ ] }),
759
+ isPinnedHere && !isChannelDisabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
760
+ "span",
761
+ {
762
+ className: "dsh-a6-pin-badge here",
763
+ "data-tooltip": `\u8BE5\u6A21\u578B\u5DF2\u56FA\u5B9A\u5230\u5F53\u524D\u5546\u5BB6${model.pinnedFallback === false ? "\uFF08\u4E25\u683C\u56FA\u5B9A\uFF09" : "\uFF0C\u5F02\u5E38\u65F6\u81EA\u52A8\u5207\u6362\u667A\u80FD\u4F18\u9009"}${model.pinTokenMatched === false ? "\uFF1B\u8BE5\u56FA\u5B9A\u5C5E\u4E8E\u5176\u4ED6\u4EE4\u724C\uFF0C\u4EC5\u4F9B\u53C2\u8003" : ""}`,
764
+ "data-tooltip-pos": "down",
765
+ children: "\u5DF2\u56FA\u5B9A"
766
+ }
767
+ ),
768
+ isPinnedElsewhere && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
769
+ "span",
770
+ {
771
+ className: "dsh-a6-pin-badge elsewhere",
772
+ "data-tooltip": `\u8BE5\u6A21\u578B\u5DF2\u56FA\u5B9A\u5230${model.pinnedChannelId ? `\u5546\u6237 #${model.pinnedChannelId}` : "\u5176\u4ED6\u5546\u5BB6"}${model.pinnedSupplierName ? `\uFF08${model.pinnedSupplierName}\uFF09` : ""}${model.pinTokenMatched === false ? "\uFF1B\u8BE5\u56FA\u5B9A\u5C5E\u4E8E\u5176\u4ED6\u4EE4\u724C\uFF0C\u4EC5\u4F9B\u53C2\u8003" : ""}`,
773
+ "data-tooltip-pos": "down",
774
+ children: "\u5DF2\u56FA\u5B9A\u5230\u5176\u4ED6\u5546\u5BB6"
775
+ }
776
+ ),
777
+ isChannelDisabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-a6-pin-badge disabled", "data-tooltip": "\u5F53\u524D\u5546\u5BB6\u5DF2\u5BF9\u8BE5\u6A21\u578B\u7981\u7528\uFF0C\u8DEF\u7531\u4E0D\u4F1A\u547D\u4E2D\u6B64\u6E20\u9053", "data-tooltip-pos": "down", children: "\u5DF2\u7981\u7528" })
416
778
  ] }),
417
779
  merchant?.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-sub-desc", children: merchant.description })
418
780
  ] }) }),
@@ -432,7 +794,7 @@ var MerchantCard = ({ model }) => {
432
794
  className: `dsh-a6-unprobed-hint ${model.probeError ? "error" : ""}`,
433
795
  "data-tooltip": model.probeError || void 0,
434
796
  "data-tooltip-pos": "down",
435
- children: isProbing ? "\u5546\u5BB6\u63A2\u6D4B\u4E2D..." : model.probeError ? "\u63A2\u6D4B\u5931\u8D25" : "\u5C1A\u672A\u63A2\u6D4B\u5546\u5BB6"
797
+ children: isProbing ? "\u5546\u5BB6\u63A2\u6D4B\u4E2D..." : isQueued ? "\u6392\u961F\u7B49\u5F85\u63A2\u6D4B..." : model.probeError ? "\u63A2\u6D4B\u5931\u8D25" : "\u5C1A\u672A\u63A2\u6D4B\u5546\u5BB6"
436
798
  }
437
799
  ) }),
438
800
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-bar-uptime", children: [
@@ -466,67 +828,110 @@ var MerchantCard = ({ model }) => {
466
828
  }
467
829
  ) })
468
830
  ] }) }),
469
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-bar-tags", children: (merchant?.labels || ["\u7A33\u5B9A", "\u4F4E\u4EF7", "\u9AD8\u901F", "\u9AD8\u8D28"]).map((lbl, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `dsh-a6-smart-pill ${getTagClass(lbl)}`, children: lbl }, idx)) }),
470
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-bar-actions", onClick: (e) => e.stopPropagation(), children: [
471
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-time-stack", children: [
472
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
473
- "span",
474
- {
475
- className: "dsh-a6-time-ago",
476
- "data-tooltip": "\u8BE5\u5546\u6237\u8DEF\u7EBF\u5168\u7F51\u6700\u8FD1\u4E00\u6B21\u6210\u529F\u54CD\u5E94\u65F6\u95F4",
477
- children: [
478
- "\u5168\u7F51\u6700\u8FD1\uFF1A",
479
- merchant?.last_success_text || "\u521A\u521A"
480
- ]
481
- }
482
- ),
483
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
484
- "span",
485
- {
486
- className: `dsh-a6-time-ago dsh-a6-route-snapshot${model.lastRoutedAt ? "" : " never"}`,
487
- "data-tooltip": model.lastRoutedAt ? `\u4E2A\u4EBA\u6700\u540E\u4E00\u6B21\u8BF7\u6C42\u8BE5\u6A21\u578B\u7684\u65F6\u95F4\uFF08\u5546\u5BB6\u8DEF\u7531\u60C5\u51B5\u7684\u622A\u6B62\u65F6\u6548\uFF09${formatAbsolute(model.lastRoutedAt)}` : "\u65E5\u5FD7\u4E2D\u6682\u65E0\u8BE5\u6A21\u578B\u7684\u8DEF\u7531\u8BB0\u5F55",
488
- children: [
489
- "\u4E2A\u4EBA\u6700\u8FD1\uFF1A",
490
- model.lastRoutedText || "\u4ECE\u672A\u8DEF\u7531"
491
- ]
492
- }
493
- )
494
- ] }),
495
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-bar-actions-btns", children: [
496
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
497
- "button",
498
- {
499
- type: "button",
500
- className: "dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm",
501
- onClick: handleProbe,
502
- disabled: isProbing,
503
- "data-tooltip": "\u5411\u8BE5\u6A21\u578B\u53D1\u9001\u4E00\u6B21\u8BF7\u6C42\u4EE5\u63A2\u6D4B\u5E76\u6355\u83B7\u5176\u5B9E\u9645\u547D\u4E2D\u7684\u5546\u6237 ID\u3001\u4EF7\u683C\u53CA\u5065\u5EB7\u5EA6\u6307\u6807\uFF08\u6D88\u8017\u5C11\u91CFToken\uFF09",
504
- children: isProbing ? "\u63A2\u6D4B\u4E2D..." : "\u63A2\u6D4B\u5546\u5BB6"
505
- }
506
- ),
507
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
508
- "button",
509
- {
510
- type: "button",
511
- className: `dsh-a6-btn dsh-a6-btn-sm ${model.inDsh ? "dsh-a6-btn-in-dsh" : "dsh-a6-btn-primary"}`,
512
- onClick: handleToggleDsh,
513
- "data-tooltip": model.inDsh ? "\u5DF2\u52A0\u5165 DSH \u6A21\u578B\u9009\u62E9\u5668 (\u70B9\u51FB\u79FB\u9664)" : "\u6DFB\u52A0\u81F3 DSH \u6A21\u578B\u9009\u62E9\u5668",
514
- children: model.inDsh ? "\u79FB\u9664\u6A21\u578B" : "\u6DFB\u52A0\u6A21\u578B"
515
- }
516
- ),
517
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
518
- "button",
519
- {
520
- type: "button",
521
- className: `dsh-a6-expand-toggle-btn ${expanded ? "open" : ""}`,
522
- onClick: () => setExpanded(!expanded),
523
- "data-tooltip": expanded ? "\u6536\u8D77\u4EF7\u683C\u8BE6\u60C5" : "\u5C55\u5F00\u5B98\u65B9\u57FA\u51C6\u4EF7\u4E0E\u5546\u6237\u5B9E\u65F6\u4EF7\u5BF9\u6BD4\u8868",
524
- "data-tooltip-pos": "left",
525
- children: expanded ? "\u6536\u8D77" : "\u8BE6\u60C5"
526
- }
527
- )
528
- ] })
529
- ] })
831
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-bar-tags", children: (merchant?.labels || ["\u7A33\u5B9A", "\u4F4E\u4EF7", "\u9AD8\u901F", "\u9AD8\u8D28"]).map((lbl, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `dsh-a6-smart-pill ${getTagClass(lbl)}`, children: lbl }, idx)) })
832
+ ] }),
833
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-card-footer", children: [
834
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-time-stack", children: [
835
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
836
+ "span",
837
+ {
838
+ className: "dsh-a6-time-ago",
839
+ "data-tooltip": "\u8BE5\u5546\u6237\u8DEF\u7EBF\u5168\u7F51\u6700\u8FD1\u4E00\u6B21\u6210\u529F\u54CD\u5E94\u65F6\u95F4",
840
+ children: [
841
+ "\u5168\u7F51\u6700\u8FD1\uFF1A",
842
+ merchant?.last_success_text || "\u521A\u521A"
843
+ ]
844
+ }
845
+ ),
846
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
847
+ "span",
848
+ {
849
+ className: `dsh-a6-time-ago dsh-a6-route-snapshot${model.lastRoutedAt ? "" : " never"}`,
850
+ "data-tooltip": model.lastRoutedAt ? `\u4E2A\u4EBA\u6700\u540E\u4E00\u6B21\u8BF7\u6C42\u8BE5\u5546\u5BB6\u7684\u8BE5\u6A21\u578B ${formatAbsolute(model.lastRoutedAt)}` : "\u65E5\u5FD7\u4E2D\u6682\u65E0\u8BE5\u5546\u5BB6\u7684\u8BE5\u6A21\u578B\u8DEF\u7531\u8BB0\u5F55",
851
+ children: [
852
+ "\u4E2A\u4EBA\u6700\u8FD1\uFF1A",
853
+ model.lastRoutedText || "\u4ECE\u672A\u8DEF\u7531"
854
+ ]
855
+ }
856
+ )
857
+ ] }),
858
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-bar-actions", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-bar-actions-btns", children: [
859
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
860
+ "button",
861
+ {
862
+ type: "button",
863
+ className: "dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm",
864
+ onClick: handleProbe,
865
+ disabled: isProbing || isQueued,
866
+ "data-tooltip": isQueued ? "\u6B63\u5728\u5168\u91CF\u63A2\u6D4B\u961F\u5217\u4E2D\u7B49\u5F85\uFF0C\u8BF7\u52FF\u91CD\u590D\u70B9\u51FB" : "\u5411\u8BE5\u6A21\u578B\u53D1\u9001\u4E00\u6B21\u8BF7\u6C42\u4EE5\u63A2\u6D4B\u5E76\u6355\u83B7\u5176\u5B9E\u9645\u547D\u4E2D\u7684\u5546\u6237 ID\u3001\u4EF7\u683C\u53CA\u5065\u5EB7\u5EA6\u6307\u6807\uFF08\u6D88\u8017\u5C11\u91CFToken\uFF09",
867
+ children: isProbing ? "\u63A2\u6D4B\u4E2D..." : isQueued ? "\u7B49\u5F85\u63A2\u6D4B" : "\u63A2\u6D4B\u5546\u5BB6"
868
+ }
869
+ ),
870
+ isPinnedHere ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
871
+ "button",
872
+ {
873
+ type: "button",
874
+ className: "dsh-a6-btn dsh-a6-btn-danger dsh-a6-btn-sm",
875
+ onClick: handleUnpin,
876
+ disabled: isBusy || !canWebAction || model.pinTokenMatched === false || isProbing || isQueued,
877
+ "data-tooltip": isProbing || isQueued ? "\u63A2\u6D4B\u5B8C\u6210\u540E\u518D\u53D6\u6D88\u56FA\u5B9A" : model.pinTokenMatched === false ? "\u8BE5\u56FA\u5B9A\u5C5E\u4E8E\u5176\u4ED6\u4EE4\u724C\uFF0C\u65E0\u6CD5\u5728\u6B64\u53D6\u6D88\uFF1B\u5982\u9700\u53D6\u6D88\u8BF7\u5230\u5B98\u7F51\u6216\u5148\u4E3A\u5F53\u524D\u4EE4\u724C\u56FA\u5B9A\u6B64\u5546\u5BB6" : canWebAction ? "\u53D6\u6D88\u56FA\u5B9A\u540E\u6062\u590D\u667A\u80FD\u4F18\u9009\u8DEF\u7531\uFF0C\u53EF\u91CD\u65B0\u63A2\u6D4B\u540E\u518D\u51B3\u5B9A\u662F\u5426\u56FA\u5B9A" : "\u9700\u5148\u5728\u300C\u57FA\u7840\u914D\u7F6E\u300D\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C/\u4F1A\u8BDD",
878
+ children: isBusy ? "\u5904\u7406\u4E2D..." : "\u53D6\u6D88\u56FA\u5B9A"
879
+ }
880
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
881
+ "button",
882
+ {
883
+ type: "button",
884
+ className: "dsh-a6-btn dsh-a6-btn-primary dsh-a6-btn-sm",
885
+ onClick: handleOpenPinConfirm,
886
+ disabled: isBusy || !hasMerchant || !canWebAction || isProbing || isQueued,
887
+ "data-tooltip": isProbing || isQueued ? "\u63A2\u6D4B\u5B8C\u6210\u540E\u518D\u56FA\u5B9A\u5546\u5BB6" : !hasMerchant ? "\u8BE5\u6A21\u578B\u6682\u65E0\u5546\u5BB6\u6570\u636E\uFF0C\u8BF7\u5148\u300C\u63A2\u6D4B\u5546\u5BB6\u300D" : !canWebAction ? "\u9700\u5148\u5728\u300C\u57FA\u7840\u914D\u7F6E\u300D\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C/\u4F1A\u8BDD" : "\u628A\u5F53\u524D\u5546\u5BB6\u56FA\u5B9A\u4E3A\u8BE5\u6A21\u578B\u7684\u670D\u52A1\u6E20\u9053\uFF08\u4F18\u5148\u8DEF\u7531\uFF0C\u5F02\u5E38\u65F6\u81EA\u52A8\u5207\u6362\u667A\u80FD\u4F18\u9009\uFF09",
888
+ children: isBusy ? "\u5904\u7406\u4E2D..." : "\u56FA\u5B9A\u5546\u5BB6"
889
+ }
890
+ ),
891
+ isChannelDisabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
892
+ "button",
893
+ {
894
+ type: "button",
895
+ className: "dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm",
896
+ onClick: handleRestore,
897
+ disabled: isBusy || !canWebAction || isProbing || isQueued,
898
+ "data-tooltip": isProbing || isQueued ? "\u63A2\u6D4B\u5B8C\u6210\u540E\u518D\u6062\u590D" : canWebAction ? "\u6062\u590D\u8BE5\u5546\u5BB6\u5BF9\u6B64\u6A21\u578B\u7684\u670D\u52A1" : "\u9700\u5148\u5728\u300C\u57FA\u7840\u914D\u7F6E\u300D\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C/\u4F1A\u8BDD",
899
+ children: isBusy ? "\u5904\u7406\u4E2D..." : "\u6062\u590D"
900
+ }
901
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
902
+ "button",
903
+ {
904
+ type: "button",
905
+ className: "dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm",
906
+ onClick: handleDisable,
907
+ disabled: isBusy || !hasMerchant || !canWebAction || isProbing || isQueued,
908
+ "data-tooltip": isProbing || isQueued ? "\u63A2\u6D4B\u5B8C\u6210\u540E\u518D\u7981\u7528" : !hasMerchant ? "\u8BE5\u6A21\u578B\u6682\u65E0\u5546\u5BB6\u6570\u636E\uFF0C\u8BF7\u5148\u300C\u63A2\u6D4B\u5546\u5BB6\u300D" : !canWebAction ? "\u9700\u5148\u5728\u300C\u57FA\u7840\u914D\u7F6E\u300D\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C/\u4F1A\u8BDD" : "\u7981\u7528\u5F53\u524D\u5546\u5BB6\u5BF9\u8BE5\u6A21\u578B\u7684\u670D\u52A1\uFF0C\u8DEF\u7531\u5C06\u4E0D\u518D\u547D\u4E2D\u6B64\u6E20\u9053",
909
+ children: isBusy ? "\u5904\u7406\u4E2D..." : "\u7981\u7528"
910
+ }
911
+ ),
912
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
913
+ "button",
914
+ {
915
+ type: "button",
916
+ className: `dsh-a6-btn dsh-a6-btn-sm ${model.inDsh ? "dsh-a6-btn-in-dsh" : "dsh-a6-btn-primary"}`,
917
+ onClick: handleToggleDsh,
918
+ "data-tooltip": model.inDsh ? "\u5DF2\u52A0\u5165 DSH \u6A21\u578B\u9009\u62E9\u5668 (\u70B9\u51FB\u79FB\u9664)" : "\u6DFB\u52A0\u81F3 DSH \u6A21\u578B\u9009\u62E9\u5668",
919
+ children: model.inDsh ? "\u79FB\u9664\u6A21\u578B" : "\u6DFB\u52A0\u6A21\u578B"
920
+ }
921
+ ),
922
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
923
+ "button",
924
+ {
925
+ type: "button",
926
+ className: `dsh-a6-expand-toggle-btn ${expanded ? "open" : ""}`,
927
+ onClick: () => setExpanded(!expanded),
928
+ "data-tooltip": expanded ? "\u6536\u8D77\u4EF7\u683C\u8BE6\u60C5" : "\u5C55\u5F00\u5B98\u65B9\u57FA\u51C6\u4EF7\u4E0E\u5546\u6237\u5B9E\u65F6\u4EF7\u5BF9\u6BD4\u8868",
929
+ "data-tooltip-pos": "left",
930
+ children: expanded ? "\u6536\u8D77" : "\u8BE6\u60C5"
931
+ }
932
+ )
933
+ ] }) }),
934
+ actionError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-action-error", role: "alert", children: actionError })
530
935
  ] }),
531
936
  expanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-detail-container", children: [
532
937
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-detail-top-row", children: [
@@ -570,7 +975,78 @@ var MerchantCard = ({ model }) => {
570
975
  ] })
571
976
  ] })
572
977
  ] }) })
573
- ] })
978
+ ] }),
979
+ pinConfirmOpen && merchant && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
980
+ "div",
981
+ {
982
+ className: "dsh-a6-pin-modal-overlay",
983
+ onClick: (e) => {
984
+ e.stopPropagation();
985
+ setPinConfirmOpen(false);
986
+ },
987
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
988
+ "div",
989
+ {
990
+ className: "dsh-a6-pin-modal",
991
+ role: "dialog",
992
+ "aria-modal": "true",
993
+ "aria-label": "\u56FA\u5B9A\u5546\u5BB6\u786E\u8BA4",
994
+ onClick: (e) => e.stopPropagation(),
995
+ children: [
996
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-pin-modal-title", children: "\u56FA\u5B9A\u5546\u5BB6" }),
997
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-pin-modal-body", children: [
998
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-pin-modal-row", children: [
999
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-a6-pin-modal-label", children: "\u6A21\u578B" }),
1000
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-a6-pin-modal-value", children: model.model_name })
1001
+ ] }),
1002
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-pin-modal-row", children: [
1003
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-a6-pin-modal-label", children: "\u5546\u5BB6" }),
1004
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dsh-a6-pin-modal-value", children: [
1005
+ merchant.channel_name,
1006
+ " (ID: ",
1007
+ merchant.channel_id,
1008
+ ")"
1009
+ ] })
1010
+ ] }),
1011
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-pin-modal-row", children: [
1012
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-a6-pin-modal-label", children: "\u5F53\u524D\u4EF7" }),
1013
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dsh-a6-pin-modal-value", children: [
1014
+ "\u8F93\u5165 ",
1015
+ merchant.input_price_cny,
1016
+ " \xB7 \u8F93\u51FA ",
1017
+ merchant.output_price_cny
1018
+ ] })
1019
+ ] }),
1020
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dsh-a6-pin-modal-note", children: "\u56FA\u5B9A\u540E\u8BE5\u6A21\u578B\u7684\u6D41\u91CF\u4F18\u5148\u8D70\u6B64\u5546\u5BB6\uFF1B\u5546\u5BB6\u5F02\u5E38\u65F6\u81EA\u52A8\u5207\u6362\u667A\u80FD\u4F18\u9009\uFF08\u5E73\u53F0\u9ED8\u8BA4\uFF09\u3002\u56FA\u5B9A\u751F\u6548\u4E8E\u5F53\u524D API Key \u4EE4\u724C\uFF0C\u53EF\u968F\u65F6\u53D6\u6D88\u3002" }),
1021
+ actionError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-action-error", children: actionError })
1022
+ ] }),
1023
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-pin-modal-foot", children: [
1024
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1025
+ "button",
1026
+ {
1027
+ type: "button",
1028
+ className: "dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm",
1029
+ onClick: () => setPinConfirmOpen(false),
1030
+ disabled: isBusy,
1031
+ children: "\u53D6\u6D88"
1032
+ }
1033
+ ),
1034
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1035
+ "button",
1036
+ {
1037
+ type: "button",
1038
+ className: "dsh-a6-btn dsh-a6-btn-primary dsh-a6-btn-sm",
1039
+ onClick: handleConfirmPin,
1040
+ disabled: isBusy,
1041
+ children: isBusy ? "\u56FA\u5B9A\u4E2D..." : "\u786E\u8BA4\u56FA\u5B9A"
1042
+ }
1043
+ )
1044
+ ] })
1045
+ ]
1046
+ }
1047
+ )
1048
+ }
1049
+ )
574
1050
  ] });
575
1051
  };
576
1052
 
@@ -717,15 +1193,15 @@ var import_jsx_runtime3 = require("react/jsx-runtime");
717
1193
  var MASK = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
718
1194
  var ConfigPanel = ({ config, dshConfiguredModels }) => {
719
1195
  const [apiKey, setApiKey] = (0, import_react3.useState)(config.apiKey || "");
720
- const [accessToken, setAccessToken] = (0, import_react3.useState)(
721
- config.accessToken || config.sessionCookie || ""
722
- );
1196
+ const [accessToken, setAccessToken] = (0, import_react3.useState)(config.accessToken || "");
723
1197
  const [clearKey, setClearKey] = (0, import_react3.useState)(false);
724
1198
  const [clearToken, setClearToken] = (0, import_react3.useState)(false);
725
1199
  const [selectedNode, setSelectedNode] = (0, import_react3.useState)(
726
1200
  config.baseURL || "https://api.a6api.com"
727
1201
  );
728
- const [customNode, setCustomNode] = (0, import_react3.useState)(config.customBaseURL || "");
1202
+ const [customNode, setCustomNode] = (0, import_react3.useState)(
1203
+ config.baseURL && config.baseURL !== "https://api.a6api.com" && config.baseURL !== "https://a6.a6api.com" ? config.baseURL : ""
1204
+ );
729
1205
  const [isCustom, setIsCustom] = (0, import_react3.useState)(
730
1206
  config.baseURL !== "https://api.a6api.com" && config.baseURL !== "https://a6.a6api.com"
731
1207
  );
@@ -738,11 +1214,13 @@ var ConfigPanel = ({ config, dshConfiguredModels }) => {
738
1214
  const tokenSet = accessToken === MASK;
739
1215
  (0, import_react3.useEffect)(() => {
740
1216
  setApiKey(config.apiKey || "");
741
- setAccessToken(config.accessToken || config.sessionCookie || "");
1217
+ setAccessToken(config.accessToken || "");
742
1218
  setClearKey(false);
743
1219
  setClearToken(false);
744
1220
  setSelectedNode(config.baseURL || "https://api.a6api.com");
745
- setCustomNode(config.customBaseURL || "");
1221
+ setCustomNode(
1222
+ config.baseURL && config.baseURL !== "https://api.a6api.com" && config.baseURL !== "https://a6.a6api.com" ? config.baseURL : ""
1223
+ );
746
1224
  setIsCustom(
747
1225
  config.baseURL !== "https://api.a6api.com" && config.baseURL !== "https://a6.a6api.com"
748
1226
  );
@@ -754,9 +1232,8 @@ var ConfigPanel = ({ config, dshConfiguredModels }) => {
754
1232
  const newToken = tokenSet ? clearToken ? "" : void 0 : accessToken.trim();
755
1233
  const ok = await store.saveConfig({
756
1234
  ...newApiKey !== void 0 ? { apiKey: newApiKey } : {},
757
- ...newToken !== void 0 ? { accessToken: newToken, sessionCookie: newToken } : {},
758
- baseURL: finalBaseUrl,
759
- customBaseURL: customNode.trim()
1235
+ ...newToken !== void 0 ? { accessToken: newToken } : {},
1236
+ baseURL: finalBaseUrl
760
1237
  });
761
1238
  setSaving(false);
762
1239
  if (ok) {
@@ -973,27 +1450,615 @@ var ConfigPanel = ({ config, dshConfiguredModels }) => {
973
1450
  ] });
974
1451
  };
975
1452
 
976
- // src/client/components/A6ApiSettings.tsx
1453
+ // src/client/components/PricePill.tsx
977
1454
  var import_jsx_runtime4 = require("react/jsx-runtime");
978
- var A6ApiSettingsPanel = () => {
979
- const [state, setState] = (0, import_react4.useState)(store.getState());
980
- const [activeTab, setActiveTab] = (0, import_react4.useState)("models");
981
- const [filterMode, setFilterMode] = (0, import_react4.useState)("all");
982
- const [searchQuery, setSearchQuery] = (0, import_react4.useState)("");
983
- const [probingAll, setProbingAll] = (0, import_react4.useState)(false);
984
- const [refreshing, setRefreshing] = (0, import_react4.useState)(false);
985
- const [refreshSuccess, setRefreshSuccess] = (0, import_react4.useState)(false);
1455
+ var PricePill = ({ pf, hasToken, compact }) => {
1456
+ const n = Number(pf?.pendingCount ?? 0);
1457
+ const hasAuth = pf?.hasAuth !== false && !pf?.authError && Boolean(hasToken);
1458
+ const isAuthError = Boolean(pf?.authError);
1459
+ const isZero = n === 0;
1460
+ const isDisabled = !hasAuth || isZero;
1461
+ const compactCls = compact ? " compact" : "";
1462
+ const cls = isDisabled ? !hasAuth ? `dsh-a6-price-pill disabled${compactCls}` : `dsh-a6-price-pill is-zero is-disabled-zero${compactCls}` : `dsh-a6-price-pill has-change${compactCls}`;
1463
+ const title = !hasAuth ? isAuthError ? "\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C\u5DF2\u5931\u6548\uFF0C\u8BF7\u524D\u5F80\u57FA\u7840\u914D\u7F6E\u66F4\u65B0" : "\u672A\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C\uFF0C\u65E0\u6CD5\u83B7\u53D6\u4EF7\u683C\u53D8\u52A8" : isZero ? "\u6682\u65E0\u4EF7\u683C\u53D8\u52A8" : `\u6709 ${n} \u6761\u4EF7\u683C\u53D8\u52A8\u5F85\u5904\u7406\uFF0C\u70B9\u51FB\u524D\u5F80\u5B98\u7F51\u5904\u7406`;
1464
+ const onClick = () => {
1465
+ if (isDisabled) return;
1466
+ window.open("https://a6api.com/console/token", "_blank", "noopener");
1467
+ };
1468
+ const onKeyDown = (e) => {
1469
+ if (isDisabled) return;
1470
+ if (e.key === "Enter" || e.key === " ") {
1471
+ e.preventDefault();
1472
+ onClick();
1473
+ }
1474
+ };
1475
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1476
+ "div",
1477
+ {
1478
+ className: cls,
1479
+ onClick: isDisabled ? void 0 : onClick,
1480
+ onKeyDown,
1481
+ tabIndex: isDisabled ? -1 : 0,
1482
+ title,
1483
+ role: "button",
1484
+ "aria-disabled": isDisabled,
1485
+ style: isDisabled ? { cursor: "not-allowed" } : void 0,
1486
+ children: [
1487
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-price-pill-label", children: "\u4EF7\u683C\u6CE2\u52A8\uFF1A" }),
1488
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-price-pill-count", children: !hasAuth ? "--" : n })
1489
+ ]
1490
+ }
1491
+ );
1492
+ };
1493
+
1494
+ // src/client/components/ModelCatalogPanel.tsx
1495
+ var import_react4 = require("react");
1496
+
1497
+ // src/types.ts
1498
+ var THINKING_LEVEL_KEYS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
1499
+ function validateReasoningEfforts(value) {
1500
+ if (value === false) return { ok: true, value: false };
1501
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1502
+ return { ok: false, error: "reasoningEfforts \u5FC5\u987B\u662F\u6863\u4F4D\u5B57\u5178\u6216 false" };
1503
+ }
1504
+ const dict = value;
1505
+ const keys = Object.keys(dict);
1506
+ if (keys.length === 0) return { ok: false, error: "reasoningEfforts \u4E0D\u80FD\u4E3A\u7A7A\u5B57\u5178" };
1507
+ const out = {};
1508
+ for (const k of keys) {
1509
+ if (!THINKING_LEVEL_KEYS.includes(k)) {
1510
+ return { ok: false, error: `reasoningEfforts \u952E "${k}" \u4E0D\u662F DSH \u652F\u6301\u7684\u6863\u4F4D\uFF08off/minimal/low/medium/high/xhigh/max\uFF09` };
1511
+ }
1512
+ const v = dict[k];
1513
+ if (v === null) {
1514
+ if (k !== "off") {
1515
+ return { ok: false, error: `reasoningEfforts.${k} \u5FC5\u987B\u63D0\u4F9B wire \u503C\uFF0C\u4EC5 off \u5141\u8BB8\u7559\u7A7A` };
1516
+ }
1517
+ out[k] = null;
1518
+ } else if (typeof v === "string" && v.length > 0) {
1519
+ out[k] = v;
1520
+ } else {
1521
+ return { ok: false, error: `reasoningEfforts.${k} \u7684\u503C\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u6216 null` };
1522
+ }
1523
+ }
1524
+ if (!keys.some((k) => k !== "off")) {
1525
+ return { ok: false, error: "reasoningEfforts \u9664 off \u5916\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u601D\u8003\u6863\u4F4D\uFF08\u975E\u63A8\u7406\u6A21\u578B\u8BF7\u7528 false\uFF09" };
1526
+ }
1527
+ return { ok: true, value: out };
1528
+ }
1529
+
1530
+ // src/client/components/ModelCatalogPanel.tsx
1531
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1532
+ var ModelCatalogPanel = () => {
1533
+ const [catalog, setCatalog] = (0, import_react4.useState)(store.getState().catalog);
1534
+ const [models, setModels] = (0, import_react4.useState)(store.getState().models);
1535
+ const [busy, setBusy] = (0, import_react4.useState)(store.getState().catalogBusy);
1536
+ const [search, setSearch] = (0, import_react4.useState)("");
1537
+ const [availFilter, setAvailFilter] = (0, import_react4.useState)("all");
1538
+ const [paramFilter, setParamFilter] = (0, import_react4.useState)("all");
1539
+ const [editingId, setEditingId] = (0, import_react4.useState)(null);
1540
+ const [queryingId, setQueryingId] = (0, import_react4.useState)(null);
1541
+ const [confirmClear, setConfirmClear] = (0, import_react4.useState)(false);
1542
+ const confirmClearTimer = (0, import_react4.useRef)(null);
1543
+ const [msg, setMsg] = (0, import_react4.useState)(null);
1544
+ const [draft, setDraft] = (0, import_react4.useState)({ name: "", contextWindow: "", maxTokens: "", inputText: false, inputImage: false, reasoningText: "", reasoningFalse: false });
986
1545
  (0, import_react4.useEffect)(() => {
1546
+ const unsub = store.subscribe(() => {
1547
+ const s = store.getState();
1548
+ setCatalog(s.catalog);
1549
+ setModels(s.models);
1550
+ setBusy(s.catalogBusy);
1551
+ });
1552
+ store.fetchCatalog();
1553
+ return unsub;
1554
+ }, []);
1555
+ const availableSet = (0, import_react4.useMemo)(
1556
+ () => new Set(models.map((m) => m.model_name.toLowerCase())),
1557
+ [models]
1558
+ );
1559
+ const flash = (kind, text) => {
1560
+ setMsg({ kind, text });
1561
+ setTimeout(() => setMsg(null), 5e3);
1562
+ };
1563
+ const handleFetchMarket = async () => {
1564
+ const r = await store.fetchMarketModels();
1565
+ if (r.ok) {
1566
+ if (r.failedPages && r.failedPages > 0) {
1567
+ flash("err", `\u5DF2\u83B7\u53D6 ${r.total} \u4E2A\u6A21\u578B\uFF08\u65B0\u589E ${r.added} \u4E2A\uFF09\uFF0C\u4F46\u6709 ${r.failedPages} \u9875\u62C9\u53D6\u5931\u8D25\uFF0C\u76EE\u5F55\u53EF\u80FD\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u91CD\u8BD5`);
1568
+ } else {
1569
+ flash("ok", `\u5DF2\u83B7\u53D6 ${r.total} \u4E2A\u6A21\u578B\uFF08\u65B0\u589E ${r.added} \u4E2A\uFF09`);
1570
+ }
1571
+ } else flash("err", r.error || "\u83B7\u53D6\u5931\u8D25");
1572
+ };
1573
+ const handleQueryAll = async () => {
1574
+ const r = await store.queryOpenRouter();
1575
+ if (r.ok) {
1576
+ const nf = r.notFound?.length || 0;
1577
+ flash("ok", `\u5DF2\u66F4\u65B0 ${r.updated} \u4E2A\u6A21\u578B\u53C2\u6570${nf > 0 ? `\uFF0C${nf} \u4E2A\u672A\u5728 OpenRouter \u67E5\u5230\uFF08\u53C2\u6570\u7559\u7A7A\u53EF\u624B\u52A8\u586B\u5199\uFF09` : ""}`);
1578
+ } else flash("err", r.error || "\u67E5\u8BE2\u5931\u8D25");
1579
+ };
1580
+ const handleQueryOne = async (id) => {
1581
+ setQueryingId(id);
1582
+ const r = await store.queryOpenRouter([id]);
1583
+ setQueryingId(null);
1584
+ if (r.ok) {
1585
+ if ((r.updated || 0) > 0) flash("ok", `\u300C${id}\u300D\u5DF2\u4ECE OpenRouter \u586B\u5145\u53C2\u6570`);
1586
+ else flash("ok", `\u300C${id}\u300D\u5728 OpenRouter \u672A\u67E5\u5230\uFF0C\u53EF\u624B\u52A8\u586B\u5199\u53C2\u6570`);
1587
+ } else flash("err", r.error || "\u67E5\u8BE2\u5931\u8D25");
1588
+ };
1589
+ const handleClear = async () => {
1590
+ if (!confirmClear) {
1591
+ setConfirmClear(true);
1592
+ if (confirmClearTimer.current) clearTimeout(confirmClearTimer.current);
1593
+ confirmClearTimer.current = setTimeout(() => setConfirmClear(false), 3e3);
1594
+ return;
1595
+ }
1596
+ if (confirmClearTimer.current) clearTimeout(confirmClearTimer.current);
1597
+ setConfirmClear(false);
1598
+ setEditingId(null);
1599
+ const r = await store.clearCatalog();
1600
+ if (r.ok) flash("ok", "\u6A21\u578B\u76EE\u5F55\u5DF2\u6E05\u7A7A\uFF0C\u53EF\u91CD\u65B0\u300C\u4ECE A6API \u83B7\u53D6\u5E02\u573A\u6A21\u578B\u300D");
1601
+ else flash("err", r.error || "\u6E05\u7A7A\u5931\u8D25");
1602
+ };
1603
+ const startEdit = (entry) => {
1604
+ const re = entry.reasoningEfforts && typeof entry.reasoningEfforts === "object" ? entry.reasoningEfforts : {};
1605
+ setDraft({
1606
+ name: entry.name || "",
1607
+ contextWindow: entry.contextWindow != null ? String(entry.contextWindow) : "",
1608
+ maxTokens: entry.maxTokens != null ? String(entry.maxTokens) : "",
1609
+ inputText: entry.input ? entry.input.includes("text") : false,
1610
+ inputImage: entry.input ? entry.input.includes("image") : false,
1611
+ // 保留 off 等 null 值项(显示为 "off: "),避免编辑保存后档位静默丢失
1612
+ reasoningText: Object.entries(re).map(([k, v]) => `${k}: ${v === null ? "" : v}`).join(", "),
1613
+ reasoningFalse: entry.reasoningEfforts === false
1614
+ });
1615
+ setEditingId(entry.id);
1616
+ };
1617
+ const handleSave = async (id) => {
1618
+ const patch = {};
1619
+ const name2 = draft.name.trim();
1620
+ patch.name = name2 || null;
1621
+ const ctx = Number(draft.contextWindow);
1622
+ if (draft.contextWindow.trim() !== "") {
1623
+ if (!Number.isInteger(ctx) || ctx < 1) {
1624
+ flash("err", "contextWindow \u5FC5\u987B\u662F\u6B63\u6574\u6570");
1625
+ return;
1626
+ }
1627
+ patch.contextWindow = ctx;
1628
+ } else {
1629
+ patch.contextWindow = null;
1630
+ }
1631
+ const maxT = Number(draft.maxTokens);
1632
+ if (draft.maxTokens.trim() !== "") {
1633
+ if (!Number.isInteger(maxT) || maxT < 1) {
1634
+ flash("err", "maxTokens \u5FC5\u987B\u662F\u6B63\u6574\u6570");
1635
+ return;
1636
+ }
1637
+ patch.maxTokens = maxT;
1638
+ } else {
1639
+ patch.maxTokens = null;
1640
+ }
1641
+ const mods = [];
1642
+ if (draft.inputText) mods.push("text");
1643
+ if (draft.inputImage) mods.push("image");
1644
+ patch.input = mods.length > 0 ? mods : null;
1645
+ if (draft.reasoningFalse) {
1646
+ patch.reasoningEfforts = false;
1647
+ } else {
1648
+ const text = draft.reasoningText.trim();
1649
+ if (text) {
1650
+ const parsed = {};
1651
+ let bad = false;
1652
+ for (const seg of text.split(",")) {
1653
+ const idx = seg.indexOf(":");
1654
+ if (idx < 0) {
1655
+ bad = true;
1656
+ break;
1657
+ }
1658
+ const k = seg.slice(0, idx).trim();
1659
+ const v = seg.slice(idx + 1).trim();
1660
+ if (!k) {
1661
+ bad = true;
1662
+ break;
1663
+ }
1664
+ parsed[k] = v || null;
1665
+ }
1666
+ if (bad) {
1667
+ flash("err", 'reasoningEfforts \u683C\u5F0F\u5E94\u4E3A "low: low, medium: medium"');
1668
+ return;
1669
+ }
1670
+ const checked = validateReasoningEfforts(parsed);
1671
+ if (!checked.ok) {
1672
+ flash("err", checked.error);
1673
+ return;
1674
+ }
1675
+ patch.reasoningEfforts = checked.value;
1676
+ } else {
1677
+ patch.reasoningEfforts = null;
1678
+ }
1679
+ }
1680
+ const r = await store.updateCatalogEntry(id, patch);
1681
+ if (r.ok) {
1682
+ setEditingId(null);
1683
+ flash("ok", `\u300C${id}\u300D\u5DF2\u4FDD\u5B58${store.getState().dshConfiguredModels.some((m) => m.toLowerCase() === id.toLowerCase()) ? "\uFF0C\u5E76\u5DF2\u540C\u6B65\u5230 DSH \u914D\u7F6E" : ""}`);
1684
+ } else {
1685
+ flash("err", r.error || "\u4FDD\u5B58\u5931\u8D25");
1686
+ }
1687
+ };
1688
+ const filtered = (0, import_react4.useMemo)(() => {
1689
+ const q = search.trim().toLowerCase();
1690
+ return catalog.filter((e) => {
1691
+ if (q && !e.id.toLowerCase().includes(q) && !(e.name || "").toLowerCase().includes(q)) return false;
1692
+ const isAvail = availableSet.has(e.id.toLowerCase());
1693
+ if (availFilter === "available" && !isAvail) return false;
1694
+ if (availFilter === "unavailable" && isAvail) return false;
1695
+ const filled = e.contextWindow != null || e.maxTokens != null || e.input && e.input.length > 0;
1696
+ if (paramFilter === "filled" && !filled) return false;
1697
+ if (paramFilter === "empty" && filled) return false;
1698
+ return true;
1699
+ }).sort((a, b) => a.id.localeCompare(b.id));
1700
+ }, [catalog, search, availFilter, paramFilter, availableSet]);
1701
+ const filledCount = catalog.filter((e) => e.contextWindow != null || e.maxTokens != null || e.input && e.input.length > 0).length;
1702
+ const availCount = catalog.filter((e) => availableSet.has(e.id.toLowerCase())).length;
1703
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-page", children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-section-header", children: [
1705
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-toolbar", children: [
1706
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1707
+ "button",
1708
+ {
1709
+ type: "button",
1710
+ className: "dsh-a6-btn dsh-a6-btn-primary dsh-a6-btn-sm",
1711
+ onClick: handleFetchMarket,
1712
+ disabled: busy !== null,
1713
+ "data-tooltip": "\u4ECE A6API \u5E02\u573A\u7FFB\u9875\u62C9\u53D6\u5168\u90E8\u652F\u6301\u6A21\u578B\u7684 ID\uFF08\u542B\u54C1\u724C\uFF09\uFF0C\u53C2\u6570\u521D\u59CB\u4E3A\u7A7A\uFF0C\u968F\u540E\u53EF\u7528 OpenRouter \u67E5\u8BE2\u586B\u5145",
1714
+ "data-tooltip-pos": "down",
1715
+ children: busy === "fetch" ? "\u83B7\u53D6\u4E2D..." : "\u4ECE A6API \u83B7\u53D6\u5E02\u573A\u6A21\u578B"
1716
+ }
1717
+ ),
1718
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1719
+ "button",
1720
+ {
1721
+ type: "button",
1722
+ className: "dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm",
1723
+ onClick: handleQueryAll,
1724
+ disabled: busy !== null || catalog.length === 0,
1725
+ "data-tooltip": "\u5BF9\u76EE\u5F55\u4E2D\u5168\u90E8\u6A21\u578B\u67E5\u8BE2 OpenRouter \u5E76\u586B\u5145 contextWindow / maxTokens / input\uFF1B\u67E5\u4E0D\u5230\u7684\u4FDD\u6301\u7559\u7A7A\u53EF\u624B\u52A8\u586B\u5199",
1726
+ "data-tooltip-pos": "down",
1727
+ children: busy === "query" ? "\u67E5\u8BE2\u4E2D..." : "\u4ECE OpenRouter \u4E00\u952E\u67E5\u8BE2"
1728
+ }
1729
+ ),
1730
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1731
+ "button",
1732
+ {
1733
+ type: "button",
1734
+ className: `dsh-a6-btn dsh-a6-btn-danger dsh-a6-btn-sm${confirmClear ? " dsh-a6-btn-clear-confirm" : ""}`,
1735
+ onClick: handleClear,
1736
+ disabled: busy !== null || catalog.length === 0,
1737
+ "data-tooltip": "\u6E05\u7A7A\u6A21\u578B\u76EE\u5F55\u5168\u90E8\u6761\u76EE\uFF0C\u53EF\u91CD\u65B0\u4ECE A6API \u83B7\u53D6\u5E76\u91CD\u65B0\u7528 OpenRouter \u586B\u5145\uFF08\u4E0D\u5F71\u54CD\u5DF2\u5199\u5165 DSH \u914D\u7F6E\u7684\u6A21\u578B\uFF09",
1738
+ "data-tooltip-pos": "down",
1739
+ children: confirmClear ? "\u786E\u8BA4\u6E05\u7A7A\uFF1F" : "\u6E05\u7A7A\u76EE\u5F55"
1740
+ }
1741
+ ),
1742
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-count", children: [
1743
+ "\u5171 ",
1744
+ catalog.length,
1745
+ " \u4E2A \xB7 \u53EF\u7528 ",
1746
+ availCount,
1747
+ " \u4E2A \xB7 \u5DF2\u586B\u53C2\u6570 ",
1748
+ filledCount,
1749
+ " \u4E2A"
1750
+ ] })
1751
+ ] }),
1752
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-filters", children: [
1753
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-filter-group", children: [
1754
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1755
+ "button",
1756
+ {
1757
+ type: "button",
1758
+ className: `dsh-a6-filter-btn ${availFilter === "all" ? "active" : ""}`,
1759
+ onClick: () => setAvailFilter("all"),
1760
+ children: [
1761
+ "\u5168\u90E8 (",
1762
+ catalog.length,
1763
+ ")"
1764
+ ]
1765
+ }
1766
+ ),
1767
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1768
+ "button",
1769
+ {
1770
+ type: "button",
1771
+ className: `dsh-a6-filter-btn ${availFilter === "available" ? "active" : ""}`,
1772
+ onClick: () => setAvailFilter("available"),
1773
+ children: [
1774
+ "\u53EF\u7528 (",
1775
+ availCount,
1776
+ ")"
1777
+ ]
1778
+ }
1779
+ ),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1781
+ "button",
1782
+ {
1783
+ type: "button",
1784
+ className: `dsh-a6-filter-btn ${availFilter === "unavailable" ? "active" : ""}`,
1785
+ onClick: () => setAvailFilter("unavailable"),
1786
+ children: [
1787
+ "\u4E0D\u53EF\u7528 (",
1788
+ catalog.length - availCount,
1789
+ ")"
1790
+ ]
1791
+ }
1792
+ )
1793
+ ] }),
1794
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-filter-group", children: [
1795
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1796
+ "button",
1797
+ {
1798
+ type: "button",
1799
+ className: `dsh-a6-filter-btn ${paramFilter === "all" ? "active" : ""}`,
1800
+ onClick: () => setParamFilter("all"),
1801
+ children: "\u5168\u90E8\u53C2\u6570"
1802
+ }
1803
+ ),
1804
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1805
+ "button",
1806
+ {
1807
+ type: "button",
1808
+ className: `dsh-a6-filter-btn ${paramFilter === "filled" ? "active" : ""}`,
1809
+ onClick: () => setParamFilter("filled"),
1810
+ children: [
1811
+ "\u5DF2\u586B (",
1812
+ filledCount,
1813
+ ")"
1814
+ ]
1815
+ }
1816
+ ),
1817
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1818
+ "button",
1819
+ {
1820
+ type: "button",
1821
+ className: `dsh-a6-filter-btn ${paramFilter === "empty" ? "active" : ""}`,
1822
+ onClick: () => setParamFilter("empty"),
1823
+ children: [
1824
+ "\u672A\u586B (",
1825
+ catalog.length - filledCount,
1826
+ ")"
1827
+ ]
1828
+ }
1829
+ )
1830
+ ] }),
1831
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-search-wrapper", children: [
1832
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1833
+ "input",
1834
+ {
1835
+ type: "text",
1836
+ className: "dsh-a6-input dsh-a6-search-input",
1837
+ placeholder: "\u641C\u7D22\u6A21\u578B ID / \u540D\u79F0...",
1838
+ value: search,
1839
+ onChange: (e) => setSearch(e.target.value)
1840
+ }
1841
+ ),
1842
+ search && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1843
+ "button",
1844
+ {
1845
+ type: "button",
1846
+ className: "dsh-a6-clear-btn",
1847
+ onClick: () => setSearch(""),
1848
+ title: "\u6E05\u7A7A\u641C\u7D22",
1849
+ children: "\xD7"
1850
+ }
1851
+ )
1852
+ ] })
1853
+ ] })
1854
+ ] }),
1855
+ msg && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: `dsh-a6-catalog-msg ${msg.kind}`, children: msg.text }),
1856
+ catalog.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-empty-state", children: [
1857
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u6A21\u578B\u76EE\u5F55\u4E3A\u7A7A\u3002" }),
1858
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-side-popup-hint", children: "\u70B9\u51FB\u300C\u4ECE A6API \u83B7\u53D6\u5E02\u573A\u6A21\u578B\u300D\u62C9\u53D6\u5168\u90E8\u652F\u6301\u7684\u6A21\u578B ID\uFF0C\u518D\u7528\u300C\u4ECE OpenRouter \u4E00\u952E\u67E5\u8BE2\u300D\u81EA\u52A8\u586B\u5145\u53C2\u6570\u3002" })
1859
+ ] }) : filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-a6-empty-state", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u5F53\u524D\u7B5B\u9009\u6761\u4EF6\u4E0B\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B" }) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-a6-catalog-list", children: filtered.map((entry) => {
1860
+ const editing = editingId === entry.id;
1861
+ const isAvail = availableSet.has(entry.id.toLowerCase());
1862
+ const re = entry.reasoningEfforts && typeof entry.reasoningEfforts === "object" ? entry.reasoningEfforts : null;
1863
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `dsh-a6-catalog-row${editing ? " editing" : ""}`, children: [
1864
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-row-head", children: [
1865
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-id", children: [
1866
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: entry.id }),
1867
+ isAvail && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-catalog-badge avail", children: "\u53EF\u7528" }),
1868
+ entry.name && entry.name !== entry.id && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-catalog-name", children: entry.name })
1869
+ ] }),
1870
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-row-actions", children: [
1871
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1872
+ "button",
1873
+ {
1874
+ type: "button",
1875
+ className: "dsh-a6-btn-text",
1876
+ onClick: () => handleQueryOne(entry.id),
1877
+ disabled: busy !== null,
1878
+ "data-tooltip": "\u4ECE OpenRouter \u67E5\u8BE2\u8BE5\u6A21\u578B\u53C2\u6570\u5E76\u586B\u5145",
1879
+ children: queryingId === entry.id ? "\u67E5\u8BE2\u4E2D..." : "\u67E5\u8BE2\u53C2\u6570"
1880
+ }
1881
+ ),
1882
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1883
+ "button",
1884
+ {
1885
+ type: "button",
1886
+ className: "dsh-a6-btn-text",
1887
+ onClick: () => editing ? setEditingId(null) : startEdit(entry),
1888
+ children: editing ? "\u53D6\u6D88" : "\u7F16\u8F91"
1889
+ }
1890
+ )
1891
+ ] })
1892
+ ] }),
1893
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-meta", children: [
1894
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: `dsh-a6-catalog-param${entry.contextWindow != null ? "" : " empty"}`, children: [
1895
+ "\u4E0A\u4E0B\u6587 ",
1896
+ entry.contextWindow != null ? entry.contextWindow.toLocaleString() : "\u2014"
1897
+ ] }),
1898
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: `dsh-a6-catalog-param${entry.maxTokens != null ? "" : " empty"}`, children: [
1899
+ "\u8F93\u51FA ",
1900
+ entry.maxTokens != null ? entry.maxTokens.toLocaleString() : "\u2014"
1901
+ ] }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: `dsh-a6-catalog-param${entry.input && entry.input.length > 0 ? "" : " empty"}`, children: [
1903
+ "\u8F93\u5165 ",
1904
+ entry.input && entry.input.length > 0 ? entry.input.join("+") : "\u2014"
1905
+ ] }),
1906
+ re && Object.keys(re).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "dsh-a6-catalog-param", children: [
1907
+ "\u63A8\u7406 ",
1908
+ Object.keys(re).length,
1909
+ " \u6863"
1910
+ ] }),
1911
+ entry.reasoningEfforts === false && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-catalog-param", children: "\u975E\u63A8\u7406" })
1912
+ ] }),
1913
+ editing && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-catalog-edit", children: [
1914
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-edit-grid", children: [
1915
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-edit-field", children: [
1916
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-label", children: "\u540D\u79F0 (name)" }),
1917
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1918
+ "input",
1919
+ {
1920
+ type: "text",
1921
+ className: "dsh-a6-input",
1922
+ value: draft.name,
1923
+ onChange: (e) => setDraft({ ...draft, name: e.target.value }),
1924
+ placeholder: "\u4EC5\u7528\u6237\u586B\u5199\uFF0C\u7559\u7A7A\u5219\u4E0D\u5199\u5165 DSH \u914D\u7F6E"
1925
+ }
1926
+ )
1927
+ ] }),
1928
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-edit-field", children: [
1929
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-label", children: "\u4E0A\u4E0B\u6587\u7A97\u53E3 (contextWindow)" }),
1930
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1931
+ "input",
1932
+ {
1933
+ type: "number",
1934
+ min: 1,
1935
+ className: "dsh-a6-input",
1936
+ value: draft.contextWindow,
1937
+ onChange: (e) => setDraft({ ...draft, contextWindow: e.target.value }),
1938
+ placeholder: "\u5982 1048576\uFF08\u7559\u7A7A = \u4E0D\u586B\uFF0CDSH \u7528\u9ED8\u8BA4\uFF09"
1939
+ }
1940
+ )
1941
+ ] }),
1942
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-edit-field", children: [
1943
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-label", children: "\u6700\u5927\u8F93\u51FA (maxTokens)" }),
1944
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1945
+ "input",
1946
+ {
1947
+ type: "number",
1948
+ min: 1,
1949
+ className: "dsh-a6-input",
1950
+ value: draft.maxTokens,
1951
+ onChange: (e) => setDraft({ ...draft, maxTokens: e.target.value }),
1952
+ placeholder: "\u5982 65536\uFF08\u7559\u7A7A = \u4E0D\u586B\uFF0CDSH \u7528\u9ED8\u8BA4\uFF09"
1953
+ }
1954
+ )
1955
+ ] }),
1956
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-edit-field", children: [
1957
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-label", children: "\u8F93\u5165\u6A21\u6001 (input)" }),
1958
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-checkbox-group", children: [
1959
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-checkbox", children: [
1960
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1961
+ "input",
1962
+ {
1963
+ type: "checkbox",
1964
+ checked: draft.inputText,
1965
+ onChange: (e) => setDraft({ ...draft, inputText: e.target.checked })
1966
+ }
1967
+ ),
1968
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "text" })
1969
+ ] }),
1970
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-checkbox", children: [
1971
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1972
+ "input",
1973
+ {
1974
+ type: "checkbox",
1975
+ checked: draft.inputImage,
1976
+ onChange: (e) => setDraft({ ...draft, inputImage: e.target.checked })
1977
+ }
1978
+ ),
1979
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "image" })
1980
+ ] })
1981
+ ] })
1982
+ ] }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-edit-field dsh-a6-edit-wide", children: [
1984
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "dsh-a6-label", children: [
1985
+ "\u63A8\u7406\u6863\u4F4D (reasoningEfforts)",
1986
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-field-hint", style: { marginLeft: 6 }, children: "\u683C\u5F0F\uFF1Alow: low, medium: medium\uFF1B\u503C\u4E3A\u7A7A\u8868\u793A\u8BE5\u6863\u4F4D\u65E0 wire \u503C" })
1987
+ ] }),
1988
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1989
+ "input",
1990
+ {
1991
+ type: "text",
1992
+ className: "dsh-a6-input",
1993
+ value: draft.reasoningText,
1994
+ disabled: draft.reasoningFalse,
1995
+ onChange: (e) => setDraft({ ...draft, reasoningText: e.target.value }),
1996
+ placeholder: "\u9ED8\u8BA4\u5DF2\u542B DSH \u5168\u90E8 7 \u6863\uFF08off/minimal/low/medium/high/xhigh/max\uFF09\uFF0C\u53EF\u4FEE\u6539\u6216\u7559\u7A7A\u5220\u9664\u8BE5\u5B57\u6BB5"
1997
+ }
1998
+ )
1999
+ ] }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-edit-field", children: [
2001
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-a6-label", children: "\u63A8\u7406\u80FD\u529B" }),
2002
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dsh-a6-checkbox", children: [
2003
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2004
+ "input",
2005
+ {
2006
+ type: "checkbox",
2007
+ checked: draft.reasoningFalse,
2008
+ onChange: (e) => setDraft({ ...draft, reasoningFalse: e.target.checked })
2009
+ }
2010
+ ),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u975E\u63A8\u7406\u6A21\u578B (reasoningEfforts: false)" })
2012
+ ] })
2013
+ ] })
2014
+ ] }),
2015
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-a6-edit-actions", children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2017
+ "button",
2018
+ {
2019
+ type: "button",
2020
+ className: "dsh-a6-btn dsh-a6-btn-primary dsh-a6-btn-sm",
2021
+ onClick: () => handleSave(entry.id),
2022
+ children: "\u4FDD\u5B58"
2023
+ }
2024
+ ),
2025
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2026
+ "button",
2027
+ {
2028
+ type: "button",
2029
+ className: "dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm",
2030
+ onClick: () => setEditingId(null),
2031
+ children: "\u53D6\u6D88"
2032
+ }
2033
+ )
2034
+ ] })
2035
+ ] })
2036
+ ] }, entry.id);
2037
+ }) })
2038
+ ] });
2039
+ };
2040
+
2041
+ // src/client/components/A6ApiSettings.tsx
2042
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2043
+ var A6ApiSettingsPanel = () => {
2044
+ const [state, setState] = (0, import_react5.useState)(store.getState());
2045
+ const [activeTab, setActiveTab] = (0, import_react5.useState)("models");
2046
+ const [filterMode, setFilterMode] = (0, import_react5.useState)("all");
2047
+ const [searchQuery, setSearchQuery] = (0, import_react5.useState)("");
2048
+ const [refreshing, setRefreshing] = (0, import_react5.useState)(false);
2049
+ const [refreshSuccess, setRefreshSuccess] = (0, import_react5.useState)(false);
2050
+ (0, import_react5.useEffect)(() => {
987
2051
  const unsub = store.subscribe(() => {
988
2052
  setState({ ...store.getState() });
989
2053
  });
990
2054
  store.fetchState();
991
2055
  return unsub;
992
2056
  }, []);
993
- const handleProbeAll = async () => {
994
- setProbingAll(true);
995
- await store.probeAll();
996
- setProbingAll(false);
2057
+ const handleProbeAll = () => {
2058
+ store.probeAll();
2059
+ };
2060
+ const handleCancelProbeAll = () => {
2061
+ store.cancelProbeAll();
997
2062
  };
998
2063
  const handleRefreshState = async () => {
999
2064
  setRefreshing(true);
@@ -1019,104 +2084,80 @@ var A6ApiSettingsPanel = () => {
1019
2084
  }
1020
2085
  return a.model_name.localeCompare(b.model_name);
1021
2086
  });
1022
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-container", children: [
1023
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-main-header", children: [
1024
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-header-text", children: [
1025
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "dsh-a6-main-title", children: "A6api" }),
1026
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "dsh-a6-main-subtitle", children: "\u805A\u5408\u5168\u7403\u4E3B\u6D41\u4E0E\u9AD8\u6027\u4EF7\u6BD4\u6A21\u578B\uFF0C\u5B9E\u65F6\u76D1\u63A7\u5546\u6237\u6307\u6807\u3001\u4EF7\u683C\u500D\u7387\u4E0E\u8D26\u6237\u8D44\u4EA7\u3002" })
2087
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-container", children: [
2088
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-main-header", children: [
2089
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-header-text", children: [
2090
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "dsh-a6-main-title", children: "A6api" }),
2091
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "dsh-a6-main-subtitle", children: "\u805A\u5408\u5168\u7403\u4E3B\u6D41\u4E0E\u9AD8\u6027\u4EF7\u6BD4\u6A21\u578B\uFF0C\u5B9E\u65F6\u76D1\u63A7\u5546\u6237\u6307\u6807\u3001\u4EF7\u683C\u500D\u7387\u4E0E\u8D26\u6237\u8D44\u4EA7\u3002" })
1027
2092
  ] }),
1028
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-header-badges", children: [
1029
- state.balance?.hasAccountAuth && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2093
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-header-badges", children: [
2094
+ state.balance?.hasAccountAuth && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1030
2095
  "div",
1031
2096
  {
1032
2097
  className: "dsh-a6-header-balance-badge",
1033
2098
  onClick: () => setActiveTab("account"),
1034
2099
  title: "\u70B9\u51FB\u5207\u6362\u81F3\u300C\u8D26\u6237\u8D44\u4EA7\u300D\u9875\u9762",
1035
2100
  children: [
1036
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-hb-label", children: "\u8D26\u6237\u4F59\u989D:" }),
1037
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-hb-amount", children: state.balance.accountBalanceFormatted })
2101
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-a6-hb-label", children: "\u8D26\u6237\u4F59\u989D:" }),
2102
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-a6-hb-amount", children: state.balance.accountBalanceFormatted })
1038
2103
  ]
1039
2104
  }
1040
2105
  ),
1041
- (() => {
1042
- const n = state.priceFluctuation?.pendingCount ?? 0;
1043
- const pf = state.priceFluctuation;
1044
- const hasAuth = pf?.hasAuth !== false && !pf?.authError && Boolean(state.config?.hasToken);
1045
- const isAuthError = Boolean(pf?.authError);
1046
- const isZero = n === 0;
1047
- const isDisabled = !hasAuth || isZero;
1048
- const cls = isDisabled ? !hasAuth ? "dsh-a6-price-pill disabled" : "dsh-a6-price-pill is-zero is-disabled-zero" : "dsh-a6-price-pill has-change";
1049
- const title = !hasAuth ? isAuthError ? "\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C\u5DF2\u5931\u6548\uFF0C\u8BF7\u524D\u5F80\u57FA\u7840\u914D\u7F6E\u66F4\u65B0" : "\u672A\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C\uFF0C\u65E0\u6CD5\u83B7\u53D6\u4EF7\u683C\u53D8\u52A8" : isZero ? "\u6682\u65E0\u4EF7\u683C\u53D8\u52A8" : `\u6709 ${n} \u6761\u4EF7\u683C\u53D8\u52A8\u5F85\u5904\u7406\uFF0C\u70B9\u51FB\u524D\u5F80\u5B98\u7F51\u5904\u7406`;
1050
- const onClick = () => {
1051
- if (isDisabled) return;
1052
- window.open("https://a6api.com/console/token", "_blank", "noopener");
1053
- };
1054
- const onKeyDown = (e) => {
1055
- if (isDisabled) return;
1056
- if (e.key === "Enter" || e.key === " ") {
1057
- e.preventDefault();
1058
- onClick();
1059
- }
1060
- };
1061
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1062
- "div",
1063
- {
1064
- className: cls,
1065
- onClick: isDisabled ? void 0 : onClick,
1066
- onKeyDown,
1067
- tabIndex: isDisabled ? -1 : 0,
1068
- title,
1069
- role: "button",
1070
- "aria-disabled": isDisabled,
1071
- style: isDisabled ? { cursor: "not-allowed" } : void 0,
1072
- children: [
1073
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-price-pill-label", children: "\u4EF7\u683C\u6CE2\u52A8\uFF1A" }),
1074
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-price-pill-count", children: !hasAuth ? "--" : n })
1075
- ]
1076
- }
1077
- );
1078
- })()
2106
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PricePill, { pf: state.priceFluctuation, hasToken: Boolean(state.config?.hasToken) })
1079
2107
  ] })
1080
2108
  ] }),
1081
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-nav-tabs", children: [
1082
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2109
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-nav-tabs", children: [
2110
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1083
2111
  "button",
1084
2112
  {
1085
2113
  type: "button",
1086
2114
  className: `dsh-a6-nav-tab ${activeTab === "models" ? "active" : ""}`,
1087
2115
  onClick: () => setActiveTab("models"),
1088
2116
  children: [
1089
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u53EF\u7528\u6A21\u578B" }),
1090
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-tab-badge", children: state.models.length })
2117
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u53EF\u7528\u6A21\u578B" }),
2118
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-a6-tab-badge", children: state.models.length })
1091
2119
  ]
1092
2120
  }
1093
2121
  ),
1094
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2122
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2123
+ "button",
2124
+ {
2125
+ type: "button",
2126
+ className: `dsh-a6-nav-tab ${activeTab === "catalog" ? "active" : ""}`,
2127
+ onClick: () => setActiveTab("catalog"),
2128
+ children: [
2129
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u6A21\u578B\u76EE\u5F55" }),
2130
+ state.catalog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-a6-tab-badge", children: state.catalog.length })
2131
+ ]
2132
+ }
2133
+ ),
2134
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1095
2135
  "button",
1096
2136
  {
1097
2137
  type: "button",
1098
2138
  className: `dsh-a6-nav-tab ${activeTab === "account" ? "active" : ""}`,
1099
2139
  onClick: () => setActiveTab("account"),
1100
2140
  children: [
1101
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u8D26\u6237\u8D44\u4EA7" }),
1102
- state.balance?.hasAccountAuth && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-tab-badge success", children: state.balance.accountBalanceFormatted })
2141
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u8D26\u6237\u8D44\u4EA7" }),
2142
+ state.balance?.hasAccountAuth && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-a6-tab-badge success", children: state.balance.accountBalanceFormatted })
1103
2143
  ]
1104
2144
  }
1105
2145
  ),
1106
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2146
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1107
2147
  "button",
1108
2148
  {
1109
2149
  type: "button",
1110
2150
  className: `dsh-a6-nav-tab ${activeTab === "config" ? "active" : ""}`,
1111
2151
  onClick: () => setActiveTab("config"),
1112
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u57FA\u7840\u914D\u7F6E" })
2152
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u57FA\u7840\u914D\u7F6E" })
1113
2153
  }
1114
2154
  )
1115
2155
  ] }),
1116
- activeTab === "models" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-tab-page models-page", children: [
1117
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-section-header", children: [
1118
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-filter-group", children: [
1119
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2156
+ activeTab === "catalog" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-a6-tab-page catalog-page", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ModelCatalogPanel, {}) }),
2157
+ activeTab === "models" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-tab-page models-page", children: [
2158
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-section-header", children: [
2159
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-filter-group", children: [
2160
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1120
2161
  "button",
1121
2162
  {
1122
2163
  type: "button",
@@ -1129,7 +2170,7 @@ var A6ApiSettingsPanel = () => {
1129
2170
  ]
1130
2171
  }
1131
2172
  ),
1132
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2173
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1133
2174
  "button",
1134
2175
  {
1135
2176
  type: "button",
@@ -1142,7 +2183,7 @@ var A6ApiSettingsPanel = () => {
1142
2183
  ]
1143
2184
  }
1144
2185
  ),
1145
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2186
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1146
2187
  "button",
1147
2188
  {
1148
2189
  type: "button",
@@ -1156,9 +2197,9 @@ var A6ApiSettingsPanel = () => {
1156
2197
  }
1157
2198
  )
1158
2199
  ] }),
1159
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-toolbar-right", children: [
1160
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-search-wrapper", children: [
1161
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2200
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-toolbar-right", children: [
2201
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-search-wrapper", children: [
2202
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1162
2203
  "input",
1163
2204
  {
1164
2205
  type: "text",
@@ -1168,7 +2209,7 @@ var A6ApiSettingsPanel = () => {
1168
2209
  onChange: (e) => setSearchQuery(e.target.value)
1169
2210
  }
1170
2211
  ),
1171
- searchQuery && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2212
+ searchQuery && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1172
2213
  "button",
1173
2214
  {
1174
2215
  type: "button",
@@ -1179,42 +2220,70 @@ var A6ApiSettingsPanel = () => {
1179
2220
  }
1180
2221
  )
1181
2222
  ] }),
1182
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2223
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1183
2224
  "button",
1184
2225
  {
1185
2226
  type: "button",
1186
2227
  className: `dsh-a6-btn dsh-a6-btn-secondary dsh-a6-btn-sm ${refreshSuccess ? "dsh-a6-btn-refresh-ok" : ""}`,
1187
2228
  onClick: handleRefreshState,
1188
- disabled: refreshing,
1189
- "data-tooltip": "\u91CD\u65B0\u5411 A6API \u63A5\u53E3\u62C9\u53D6\u5F53\u524D\u4EE4\u724C\u7684\u53EF\u7528\u6A21\u578B\u5217\u8868\u53CA\u5DF2\u7F13\u5B58\u5546\u6237\u6307\u6807\uFF08\u4E0D\u6D88\u8017 Token\uFF09",
2229
+ disabled: refreshing || state.probeAllActive,
2230
+ "data-tooltip": state.probeAllActive ? "\u5168\u91CF\u63A2\u6D4B\u8FDB\u884C\u4E2D\uFF0C\u5B8C\u6210\u540E\u53EF\u5237\u65B0" : "\u91CD\u65B0\u5411 A6API \u63A5\u53E3\u62C9\u53D6\u5F53\u524D\u4EE4\u724C\u7684\u53EF\u7528\u6A21\u578B\u5217\u8868\u53CA\u5DF2\u7F13\u5B58\u5546\u6237\u6307\u6807\uFF08\u4E0D\u6D88\u8017 Token\uFF09",
1190
2231
  "data-tooltip-pos": "down",
1191
2232
  children: refreshing ? "\u5237\u65B0\u4E2D..." : refreshSuccess ? "\u5DF2\u5237\u65B0 \u2713" : "\u5237\u65B0\u5217\u8868"
1192
2233
  }
1193
2234
  ),
1194
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2235
+ state.probeAllActive ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2236
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2237
+ "button",
2238
+ {
2239
+ type: "button",
2240
+ className: "dsh-a6-btn dsh-a6-btn-primary dsh-a6-btn-sm",
2241
+ disabled: true,
2242
+ "data-tooltip": "\u6B63\u5728\u5E76\u53D1\u63A2\u6D4B\u5168\u90E8\u6A21\u578B\uFF0C\u5361\u7247\u9010\u4E2A\u56DE\u586B\u7ED3\u679C",
2243
+ "data-tooltip-pos": "down-left",
2244
+ children: [
2245
+ "\u5168\u91CF\u63A2\u6D4B\u4E2D ",
2246
+ state.probeAllDoneCount,
2247
+ "/",
2248
+ state.probeAllTotal
2249
+ ]
2250
+ }
2251
+ ),
2252
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2253
+ "button",
2254
+ {
2255
+ type: "button",
2256
+ className: "dsh-a6-btn dsh-a6-btn-danger dsh-a6-btn-sm",
2257
+ onClick: handleCancelProbeAll,
2258
+ "data-tooltip": "\u505C\u6B62\u53D6\u65B0\u4EFB\u52A1\uFF0C\u5DF2\u5728\u63A2\u6D4B\u4E2D\u7684\u6A21\u578B\u4F1A\u6B63\u5E38\u5B8C\u6210\u5E76\u56DE\u586B",
2259
+ "data-tooltip-pos": "down-left",
2260
+ children: "\u53D6\u6D88"
2261
+ }
2262
+ )
2263
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1195
2264
  "button",
1196
2265
  {
1197
2266
  type: "button",
1198
2267
  className: "dsh-a6-btn dsh-a6-btn-primary dsh-a6-btn-sm",
1199
2268
  onClick: handleProbeAll,
1200
- disabled: probingAll || state.models.length === 0,
1201
- "data-tooltip": "\u5BF9\u5F53\u524D\u4EE4\u724C\u652F\u6301\u7684\u6240\u6709\u6A21\u578B\u9010\u4E2A\u53D1\u9001\u4E00\u6B21\u8BF7\u6C42\uFF0C\u6279\u91CF\u6355\u83B7\u5546\u6237\u8DEF\u7531\u4E0E\u6700\u65B0\u884C\u60C5\uFF08\u6BCF\u4E2A\u6A21\u578B\u6D88\u8017\u5C11\u91CFToken\uFF09",
2269
+ disabled: state.models.length === 0,
2270
+ "data-tooltip": "\u5BF9\u5F53\u524D\u4EE4\u724C\u652F\u6301\u7684\u6240\u6709\u6A21\u578B\u5E76\u53D1\u53D1\u9001\u8BF7\u6C42\uFF0C\u6279\u91CF\u6355\u83B7\u5546\u6237\u8DEF\u7531\u4E0E\u6700\u65B0\u884C\u60C5\uFF08\u6BCF\u4E2A\u6A21\u578B\u6D88\u8017\u5C11\u91CFToken\uFF0C\u9047\u9650\u6D41\u81EA\u52A8\u91CD\u8BD5\uFF09",
1202
2271
  "data-tooltip-pos": "down-left",
1203
- children: probingAll ? "\u5168\u91CF\u63A2\u6D4B\u4E2D..." : "\u4E00\u952E\u5168\u91CF\u63A2\u6D4B"
2272
+ children: "\u4E00\u952E\u5168\u91CF\u63A2\u6D4B"
1204
2273
  }
1205
2274
  )
1206
2275
  ] })
1207
2276
  ] }),
1208
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-a6-cards-list", children: state.loading && state.models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-empty-state", children: [
1209
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-a6-spinner" }),
1210
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u6B63\u5728\u8FDE\u63A5 A6API \u805A\u5408\u7AD9\u5E76\u52A0\u8F7D\u6A21\u578B\u884C\u60C5..." })
1211
- ] }) : sortedModels.length > 0 ? sortedModels.map((m) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MerchantCard, { model: m }, m.model_name)) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-a6-empty-state", children: searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
2277
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-a6-cards-list", children: state.loading && state.models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-a6-empty-state", children: [
2278
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-a6-spinner" }),
2279
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u6B63\u5728\u8FDE\u63A5 A6API \u805A\u5408\u7AD9\u5E76\u52A0\u8F7D\u6A21\u578B\u884C\u60C5..." })
2280
+ ] }) : sortedModels.length > 0 ? sortedModels.map((m) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MerchantCard, { model: m }, m.model_name)) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-a6-empty-state", children: searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
1212
2281
  "\u672A\u641C\u7D22\u5230\u5339\u914D\u300C",
1213
2282
  searchQuery,
1214
2283
  "\u300D\u7684\u6A21\u578B"
1215
- ] }) : filterMode === "enabled" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u5F53\u524D\u5C1A\u672A\u5728 DSH \u4E2D\u542F\u7528\u4EFB\u4F55 A6API \u6A21\u578B\uFF0C\u70B9\u51FB\u6A21\u578B\u5361\u7247\u53F3\u4FA7\u300C\u6DFB\u52A0\u5230 DSH\u300D\u5373\u53EF\u542F\u7528\u3002" }) : filterMode === "probed" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u5C1A\u672A\u63A2\u6D4B\u4EFB\u4F55\u6A21\u578B\u5546\u6237\u7EBF\u8DEF\uFF0C\u70B9\u51FB\u6A21\u578B\u5361\u7247\u4E0A\u7684\u300C\u63A2\u6D4B\u5546\u5BB6\u300D\u6216\u4E0A\u65B9\u300C\u4E00\u952E\u5168\u91CF\u63A2\u6D4B\u300D\u5373\u53EF\u5F00\u59CB\u3002" }) : !state.config.hasApiKey ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u8BF7\u524D\u5F80\u300C\u57FA\u7840\u914D\u7F6E\u300D\u9875\u9762\u586B\u5165\u60A8\u7684 A6API \u4EE4\u724C (API Key) \u5E76\u4FDD\u5B58\uFF0C\u5373\u53EF\u81EA\u52A8\u52A0\u8F7D\u53EF\u7528\u6A21\u578B\u5217\u8868\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u5F53\u524D\u4EE4\u724C\u6682\u65E0\u53EF\u7528\u6A21\u578B\uFF0C\u8BF7\u68C0\u67E5 A6API \u63A7\u5236\u53F0\u4E2D\u7684\u4EE4\u724C\u9650\u5236\u8BBE\u7F6E\u3002" }) }) })
2284
+ ] }) : filterMode === "enabled" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u5F53\u524D\u5C1A\u672A\u5728 DSH \u4E2D\u542F\u7528\u4EFB\u4F55 A6API \u6A21\u578B\uFF0C\u70B9\u51FB\u6A21\u578B\u5361\u7247\u53F3\u4FA7\u300C\u6DFB\u52A0\u5230 DSH\u300D\u5373\u53EF\u542F\u7528\u3002" }) : filterMode === "probed" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u5C1A\u672A\u63A2\u6D4B\u4EFB\u4F55\u6A21\u578B\u5546\u6237\u7EBF\u8DEF\uFF0C\u70B9\u51FB\u6A21\u578B\u5361\u7247\u4E0A\u7684\u300C\u63A2\u6D4B\u5546\u5BB6\u300D\u6216\u4E0A\u65B9\u300C\u4E00\u952E\u5168\u91CF\u63A2\u6D4B\u300D\u5373\u53EF\u5F00\u59CB\u3002" }) : !state.config.hasApiKey ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u8BF7\u524D\u5F80\u300C\u57FA\u7840\u914D\u7F6E\u300D\u9875\u9762\u586B\u5165\u60A8\u7684 A6API \u4EE4\u724C (API Key) \u5E76\u4FDD\u5B58\uFF0C\u5373\u53EF\u81EA\u52A8\u52A0\u8F7D\u53EF\u7528\u6A21\u578B\u5217\u8868\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u5F53\u524D\u4EE4\u724C\u6682\u65E0\u53EF\u7528\u6A21\u578B\uFF0C\u8BF7\u68C0\u67E5 A6API \u63A7\u5236\u53F0\u4E2D\u7684\u4EE4\u724C\u9650\u5236\u8BBE\u7F6E\u3002" }) }) })
1216
2285
  ] }),
1217
- activeTab === "account" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-a6-tab-page account-page", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2286
+ activeTab === "account" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-a6-tab-page account-page", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1218
2287
  AccountPanel,
1219
2288
  {
1220
2289
  balance: state.balance,
@@ -1223,7 +2292,7 @@ var A6ApiSettingsPanel = () => {
1223
2292
  onNavigateToConfig: () => setActiveTab("config")
1224
2293
  }
1225
2294
  ) }),
1226
- activeTab === "config" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-a6-tab-page config-page", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2295
+ activeTab === "config" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-a6-tab-page config-page", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1227
2296
  ConfigPanel,
1228
2297
  {
1229
2298
  config: state.config,
@@ -1233,52 +2302,334 @@ var A6ApiSettingsPanel = () => {
1233
2302
  ] });
1234
2303
  };
1235
2304
 
1236
- // src/client/styles/main.css
1237
- var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme Integration */
1238
-
1239
- .dsh-a6-container {
1240
- display: flex;
1241
- flex-direction: column;
1242
- color: var(--dsw-alias-label-primary, var(--ds-text-primary, #1e293b));
1243
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1244
- padding-bottom: 28px;
1245
- }
1246
-
1247
- /* ==========================================================================
1248
- 1. Master Header & Navigation Tabs (Image 2 Style)
1249
- ========================================================================== */
1250
- .dsh-a6-main-header {
1251
- display: flex;
1252
- justify-content: space-between;
1253
- align-items: flex-start;
1254
- gap: 16px;
1255
- margin-bottom: 12px;
1256
- flex-wrap: wrap;
1257
- }
1258
-
1259
- .dsh-a6-header-text {
1260
- display: flex;
1261
- flex-direction: column;
1262
- gap: 4px;
1263
- }
1264
-
1265
- .dsh-a6-main-title {
1266
- font-size: 20px;
1267
- font-weight: 700;
1268
- color: var(--dsw-alias-label-primary, #0f172a);
1269
- margin: 0;
1270
- line-height: 1.2;
1271
- }
1272
-
1273
- .dsh-a6-main-subtitle {
1274
- font-size: 13px;
1275
- color: var(--dsw-alias-label-secondary, #64748b);
1276
- margin: 0;
1277
- line-height: 1.5;
1278
- }
1279
-
1280
- .dsh-a6-header-balance-badge {
1281
- display: inline-flex;
2305
+ // src/client/components/A6ApiSidebarCard.tsx
2306
+ var import_react6 = require("react");
2307
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2308
+ var POPUP_MAX_WIDTH = 500;
2309
+ var normalizeModelId = (id) => id.replace(/^[^/]+\//, "");
2310
+ var A6ApiSidebarCard = ({
2311
+ wide,
2312
+ useSessions,
2313
+ getModelDirectories
2314
+ }) => {
2315
+ if (useSessions) {
2316
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2317
+ A6ApiSidebarCardInner,
2318
+ {
2319
+ wide,
2320
+ useSessions,
2321
+ getModelDirectories
2322
+ }
2323
+ );
2324
+ }
2325
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(A6ApiSidebarCardBody, { wide, getModelDirectories });
2326
+ };
2327
+ var A6ApiSidebarCardInner = ({ wide, useSessions, getModelDirectories }) => {
2328
+ const currentId = useSessions((s) => s?.current);
2329
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2330
+ A6ApiSidebarCardBody,
2331
+ {
2332
+ wide,
2333
+ currentId,
2334
+ getModelDirectories
2335
+ }
2336
+ );
2337
+ };
2338
+ var A6ApiSidebarCardBody = ({
2339
+ wide,
2340
+ currentId,
2341
+ getModelDirectories
2342
+ }) => {
2343
+ const [open, setOpen] = (0, import_react6.useState)(false);
2344
+ const [selection, setSelection] = (0, import_react6.useState)(null);
2345
+ const [state, setState] = (0, import_react6.useState)(store.getState());
2346
+ const [pos, setPos] = (0, import_react6.useState)(null);
2347
+ const buttonRef = (0, import_react6.useRef)(null);
2348
+ const popupRef = (0, import_react6.useRef)(null);
2349
+ const flippedRef = (0, import_react6.useRef)(false);
2350
+ const fetchedRef = (0, import_react6.useRef)(false);
2351
+ const lastPosRef = (0, import_react6.useRef)(null);
2352
+ (0, import_react6.useEffect)(() => {
2353
+ let disposed = false;
2354
+ let unsub = null;
2355
+ let tries = 0;
2356
+ const connect = () => {
2357
+ if (disposed) return;
2358
+ const md = getModelDirectories?.();
2359
+ if (!md || typeof md.directoryFor !== "function") {
2360
+ if (tries++ < 6) setTimeout(connect, 500);
2361
+ return;
2362
+ }
2363
+ let dir;
2364
+ try {
2365
+ dir = md.directoryFor(currentId);
2366
+ } catch {
2367
+ dir = void 0;
2368
+ }
2369
+ if (!dir) {
2370
+ setSelection(null);
2371
+ return;
2372
+ }
2373
+ const update = () => {
2374
+ try {
2375
+ const snap = dir.store?.getSnapshot?.();
2376
+ setSelection(snap?.current ?? null);
2377
+ } catch {
2378
+ setSelection(null);
2379
+ }
2380
+ };
2381
+ update();
2382
+ try {
2383
+ unsub = dir.store?.subscribe?.(update) ?? null;
2384
+ } catch {
2385
+ unsub = null;
2386
+ }
2387
+ };
2388
+ connect();
2389
+ return () => {
2390
+ disposed = true;
2391
+ if (unsub) {
2392
+ try {
2393
+ unsub();
2394
+ } catch {
2395
+ }
2396
+ }
2397
+ };
2398
+ }, [currentId, getModelDirectories]);
2399
+ (0, import_react6.useEffect)(() => {
2400
+ const unsub = store.subscribe(() => setState({ ...store.getState() }));
2401
+ return unsub;
2402
+ }, []);
2403
+ const isA6api = Boolean(selection && selection.provider === "a6api");
2404
+ const modelName = normalizeModelId(selection?.model || "");
2405
+ const canOpen = isA6api && Boolean(modelName);
2406
+ const card = canOpen ? state.models.find((m) => m.model_name.toLowerCase() === modelName.toLowerCase()) : void 0;
2407
+ const toggle = () => {
2408
+ if (!canOpen) return;
2409
+ setOpen((v) => !v);
2410
+ };
2411
+ (0, import_react6.useEffect)(() => {
2412
+ if (open && !canOpen) setOpen(false);
2413
+ }, [open, canOpen]);
2414
+ (0, import_react6.useEffect)(() => {
2415
+ if (!open) {
2416
+ setPos(null);
2417
+ lastPosRef.current = null;
2418
+ flippedRef.current = false;
2419
+ return;
2420
+ }
2421
+ if (state.models.length === 0 && !fetchedRef.current) {
2422
+ fetchedRef.current = true;
2423
+ store.fetchState().catch(() => {
2424
+ });
2425
+ }
2426
+ const place = () => {
2427
+ const btn = buttonRef.current;
2428
+ if (!btn) return;
2429
+ const r = btn.getBoundingClientRect();
2430
+ const vw = window.innerWidth;
2431
+ const width = Math.min(POPUP_MAX_WIDTH, vw - 16);
2432
+ const left = Math.max(8, Math.min(r.left, vw - width - 8));
2433
+ const flipped = flippedRef.current || r.top < 8;
2434
+ if (flipped) flippedRef.current = true;
2435
+ const next = flipped ? { left, top: r.bottom + 8 } : { left, bottom: window.innerHeight - r.top + 8 };
2436
+ const last = lastPosRef.current;
2437
+ if (last && last.left === next.left && (last.top ?? null) === (next.top ?? null) && (last.bottom ?? null) === (next.bottom ?? null)) {
2438
+ return;
2439
+ }
2440
+ lastPosRef.current = next;
2441
+ setPos(next);
2442
+ };
2443
+ place();
2444
+ window.addEventListener("resize", place);
2445
+ window.addEventListener("scroll", place, true);
2446
+ return () => {
2447
+ window.removeEventListener("resize", place);
2448
+ window.removeEventListener("scroll", place, true);
2449
+ };
2450
+ }, [open]);
2451
+ (0, import_react6.useEffect)(() => {
2452
+ if (!open || !popupRef.current) return;
2453
+ const checkFlip = () => {
2454
+ if (flippedRef.current || !popupRef.current) return;
2455
+ const rect = popupRef.current.getBoundingClientRect();
2456
+ if (rect.top < 8) {
2457
+ flippedRef.current = true;
2458
+ const btn = buttonRef.current;
2459
+ if (btn) {
2460
+ const r = btn.getBoundingClientRect();
2461
+ setPos({ left: lastPosRef.current?.left ?? 8, top: r.bottom + 8 });
2462
+ }
2463
+ }
2464
+ };
2465
+ checkFlip();
2466
+ const ro = new ResizeObserver(checkFlip);
2467
+ ro.observe(popupRef.current);
2468
+ return () => ro.disconnect();
2469
+ }, [open, pos]);
2470
+ (0, import_react6.useEffect)(() => {
2471
+ if (!open) return;
2472
+ const onKey = (e) => {
2473
+ if (e.key === "Escape") setOpen(false);
2474
+ };
2475
+ const onPointerDown = (e) => {
2476
+ const t = e.target;
2477
+ if (popupRef.current?.contains(t)) return;
2478
+ if (buttonRef.current?.contains(t)) return;
2479
+ setOpen(false);
2480
+ };
2481
+ document.addEventListener("keydown", onKey);
2482
+ document.addEventListener("pointerdown", onPointerDown, true);
2483
+ return () => {
2484
+ document.removeEventListener("keydown", onKey);
2485
+ document.removeEventListener("pointerdown", onPointerDown, true);
2486
+ };
2487
+ }, [open]);
2488
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2489
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2490
+ "span",
2491
+ {
2492
+ className: "dsh-a6-side-btn-wrap",
2493
+ "data-tooltip": !canOpen ? "\u5F53\u524D\u4F1A\u8BDD\u672A\u4F7F\u7528 A6api \u6A21\u578B" : void 0,
2494
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2495
+ "button",
2496
+ {
2497
+ ref: buttonRef,
2498
+ type: "button",
2499
+ className: `dsh-a6-side-btn${wide ? "" : " rail"}`,
2500
+ onClick: toggle,
2501
+ disabled: !canOpen,
2502
+ "aria-expanded": open,
2503
+ "aria-label": wide ? void 0 : "A6api",
2504
+ "data-tooltip": canOpen ? open ? "\u6536\u8D77 A6api \u6A21\u578B\u5361\u7247" : "\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u7684 A6api \u6A21\u578B\u5361\u7247" : void 0,
2505
+ children: [
2506
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2507
+ "svg",
2508
+ {
2509
+ className: "dsh-a6-side-btn-badge",
2510
+ width: "16",
2511
+ height: "16",
2512
+ viewBox: "0 0 16 16",
2513
+ fill: "none",
2514
+ xmlns: "http://www.w3.org/2000/svg",
2515
+ "aria-hidden": "true",
2516
+ children: [
2517
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2518
+ "path",
2519
+ {
2520
+ d: "M14.0861 5.51366C13.8717 5.0575 13.588 4.58542 13.2889 4.18108C13.208 4.07172 13.1596 4.04373 13.0243 4.03054C12.4277 3.97255 11.8245 4.05527 11.2269 3.9972C10.7224 3.94816 10.3133 3.71661 10.0115 3.30919C9.66986 2.84777 9.43973 2.31343 9.09824 1.85234C9.01771 1.74365 8.96805 1.71589 8.83354 1.70282C8.29432 1.65044 7.70402 1.65061 7.16656 1.70282C7.03205 1.71589 6.98239 1.74365 6.90186 1.85234C6.56067 2.31303 6.33025 2.84774 5.98855 3.30919C5.68681 3.71661 5.27774 3.94816 4.77317 3.9972C4.17564 4.05527 3.57239 3.97255 2.97585 4.03054C2.84046 4.04373 2.79208 4.07172 2.71115 4.18108C2.41212 4.58542 2.12835 5.0575 1.91403 5.51366C1.85299 5.64359 1.85286 5.7018 1.91403 5.8319C2.14865 6.33077 2.49748 6.76892 2.73237 7.26854C2.9594 7.7515 2.96041 8.24717 2.73338 8.73044C2.49837 9.23061 2.14891 9.66837 1.91403 10.1681C1.85291 10.2982 1.85299 10.3564 1.91403 10.4863C2.12856 10.9429 2.41185 11.4142 2.71115 11.8189C2.79208 11.9283 2.84046 11.9563 2.97585 11.9694C3.57239 12.0274 4.17564 11.9447 4.77317 12.0028C5.27774 12.0518 5.68681 12.2834 5.98855 12.6908C6.33024 13.1522 6.56037 13.6866 6.90186 14.1476C6.98239 14.2563 7.03205 14.2841 7.16656 14.2972C7.70402 14.3494 8.29432 14.3495 8.83354 14.2972C8.96805 14.2841 9.01771 14.2563 9.09824 14.1476C9.43944 13.687 9.66985 13.1522 10.0115 12.6908C10.3133 12.2834 10.7224 12.0518 11.2269 12.0028C11.8244 11.9447 12.4271 12.0275 13.0243 11.9694C13.1596 11.9563 13.208 11.9283 13.2889 11.8189C13.5891 11.4131 13.872 10.942 14.0861 10.4863C14.1471 10.3564 14.1472 10.2982 14.0861 10.1681C13.8513 9.66861 13.5017 9.23061 13.2667 8.73044C13.0397 8.24717 13.0407 7.7515 13.2677 7.26854C13.5026 6.7689 13.8513 6.33106 14.0861 5.8319C14.1472 5.7018 14.1471 5.64359 14.0861 5.51366ZM15.3035 6.40373C15.0685 6.90359 14.7188 7.34119 14.4841 7.84037C14.4231 7.97025 14.423 8.02855 14.4841 8.15861C14.7189 8.65833 15.0685 9.09611 15.3035 9.59626C15.5308 10.0801 15.5308 10.5744 15.3035 11.0582C15.052 11.5933 14.7225 12.1426 14.37 12.6191C14.0685 13.0265 13.6581 13.259 13.1536 13.3081C12.5566 13.366 11.9541 13.2835 11.3573 13.3414C11.2228 13.3545 11.1731 13.3823 11.0926 13.491C10.7511 13.9521 10.521 14.4864 10.1793 14.9478C9.87828 15.3542 9.46719 15.5869 8.96387 15.6358C8.34008 15.6964 7.66194 15.6966 7.03623 15.6358C6.53291 15.5869 6.12182 15.3542 5.82084 14.9478C5.47911 14.4863 5.24878 13.9517 4.90753 13.491C4.82701 13.3823 4.77734 13.3545 4.64284 13.3414C4.04647 13.2835 3.44373 13.366 2.84653 13.3081C2.34201 13.259 1.93164 13.0265 1.63013 12.6191C1.27867 12.144 0.948453 11.5941 0.696621 11.0582C0.469315 10.5744 0.469279 10.0801 0.696621 9.59626C0.931628 9.09613 1.2813 8.65807 1.51597 8.15861C1.57708 8.02855 1.57702 7.97025 1.51597 7.84037C1.28117 7.34095 0.931635 6.9036 0.696621 6.40373C0.469213 5.91992 0.469367 5.42562 0.696621 4.94183C0.948441 4.40587 1.27868 3.85598 1.63013 3.38092C1.93164 2.97349 2.34201 2.74095 2.84653 2.6919C3.44353 2.63397 4.04599 2.71649 4.64284 2.65856C4.77734 2.64549 4.82701 2.61774 4.90753 2.50904C5.24905 2.04792 5.47913 1.51362 5.82084 1.05219C6.12182 0.645806 6.53291 0.413119 7.03623 0.364178C7.66002 0.303556 8.33816 0.303369 8.96387 0.364178C9.46719 0.413119 9.87828 0.645806 10.1793 1.05219C10.521 1.51365 10.7513 2.04828 11.0926 2.50904C11.1731 2.61774 11.2228 2.64549 11.3573 2.65856C11.9541 2.71649 12.5566 2.63397 13.1536 2.6919C13.6581 2.74095 14.0685 2.97349 14.37 3.38092C14.7214 3.85598 15.0517 4.40587 15.3035 4.94183C15.5307 5.42562 15.5309 5.91992 15.3035 6.40373Z",
2521
+ fill: "currentColor"
2522
+ }
2523
+ ),
2524
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2525
+ "path",
2526
+ {
2527
+ d: "M9.13764 7.99999C9.13764 7.3715 8.62855 6.8624 8.00005 6.8624C7.37155 6.8624 6.86246 7.3715 6.86246 7.99999C6.86246 8.62849 7.37155 9.13759 8.00005 9.13759C8.62855 9.13759 9.13764 8.62849 9.13764 7.99999ZM10.4834 7.99999C10.4834 9.37126 9.37132 10.4833 8.00005 10.4833C6.62878 10.4833 5.51674 9.37126 5.51674 7.99999C5.51674 6.62873 6.62878 5.51669 8.00005 5.51669C9.37132 5.51669 10.4834 6.62873 10.4834 7.99999Z",
2528
+ fill: "currentColor"
2529
+ }
2530
+ )
2531
+ ]
2532
+ }
2533
+ ),
2534
+ wide && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-a6-side-btn-label", children: "A6api" })
2535
+ ]
2536
+ }
2537
+ )
2538
+ }
2539
+ ),
2540
+ open && pos && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2541
+ "div",
2542
+ {
2543
+ ref: popupRef,
2544
+ className: "dsh-a6-side-popup",
2545
+ role: "dialog",
2546
+ "aria-label": "\u5F53\u524D\u4F1A\u8BDD A6api \u6A21\u578B\u5361\u7247",
2547
+ style: { left: pos.left, ...pos.top !== void 0 ? { top: pos.top } : { bottom: pos.bottom } },
2548
+ children: [
2549
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-a6-side-pills", children: [
2550
+ state.balance?.hasAccountAuth && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2551
+ "div",
2552
+ {
2553
+ className: "dsh-a6-header-balance-badge dsh-a6-side-balance-pill",
2554
+ title: "\u8D26\u6237\u4F59\u989D\uFF08\u6BCF 60 \u79D2\u81EA\u52A8\u540C\u6B65\uFF09",
2555
+ children: [
2556
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-a6-hb-label", children: "\u8D26\u6237\u4F59\u989D:" }),
2557
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-a6-hb-amount", children: state.balance.accountBalanceFormatted })
2558
+ ]
2559
+ }
2560
+ ),
2561
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2562
+ PricePill,
2563
+ {
2564
+ pf: state.priceFluctuation,
2565
+ hasToken: Boolean(state.config?.hasToken),
2566
+ compact: true
2567
+ }
2568
+ )
2569
+ ] }),
2570
+ card ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MerchantCard, { model: card }) : state.loading && state.models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-a6-side-popup-empty", children: [
2571
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-a6-spinner" }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u6B63\u5728\u52A0\u8F7D A6api \u6570\u636E..." })
2573
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-a6-side-popup-empty", children: [
2574
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
2575
+ "\u672A\u627E\u5230\u300C",
2576
+ modelName,
2577
+ "\u300D\u7684\u5546\u6237\u6570\u636E"
2578
+ ] }),
2579
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-a6-side-popup-hint", children: "\u53EF\u5728\u300C\u8BBE\u7F6E \u2192 A6api\u300D\u4E2D\u63A2\u6D4B\u8BE5\u6A21\u578B" })
2580
+ ] })
2581
+ ]
2582
+ }
2583
+ )
2584
+ ] });
2585
+ };
2586
+
2587
+ // src/client/styles/main.css
2588
+ var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme Integration */
2589
+
2590
+ .dsh-a6-container {
2591
+ display: flex;
2592
+ flex-direction: column;
2593
+ color: var(--dsw-alias-label-primary, var(--ds-text-primary, #1e293b));
2594
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
2595
+ padding-bottom: 28px;
2596
+ }
2597
+
2598
+ /* ==========================================================================
2599
+ 1. Master Header & Navigation Tabs (Image 2 Style)
2600
+ ========================================================================== */
2601
+ .dsh-a6-main-header {
2602
+ display: flex;
2603
+ justify-content: space-between;
2604
+ align-items: flex-start;
2605
+ gap: 16px;
2606
+ margin-bottom: 12px;
2607
+ flex-wrap: wrap;
2608
+ }
2609
+
2610
+ .dsh-a6-header-text {
2611
+ display: flex;
2612
+ flex-direction: column;
2613
+ gap: 4px;
2614
+ }
2615
+
2616
+ .dsh-a6-main-title {
2617
+ font-size: 20px;
2618
+ font-weight: 700;
2619
+ color: var(--dsw-alias-label-primary, #0f172a);
2620
+ margin: 0;
2621
+ line-height: 1.2;
2622
+ }
2623
+
2624
+ .dsh-a6-main-subtitle {
2625
+ font-size: 13px;
2626
+ color: var(--dsw-alias-label-secondary, #64748b);
2627
+ margin: 0;
2628
+ line-height: 1.5;
2629
+ }
2630
+
2631
+ .dsh-a6-header-balance-badge {
2632
+ display: inline-flex;
1282
2633
  align-items: center;
1283
2634
  gap: 6px;
1284
2635
  padding: 5px 12px;
@@ -1863,12 +3214,23 @@ var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme
1863
3214
  text-align: left;
1864
3215
  }
1865
3216
 
3217
+ /* \u5361\u7247\u5E95\u90E8\u884C\uFF1A\u65F6\u95F4\u6233\u5DE6\u4E0B\u89D2\u5DE6\u5BF9\u9F50\uFF0C\u64CD\u4F5C\u6309\u94AE\u53F3\u4E0B\u89D2\u53F3\u5BF9\u9F50 */
3218
+ .dsh-a6-card-footer {
3219
+ display: flex;
3220
+ align-items: flex-start;
3221
+ justify-content: space-between;
3222
+ gap: 12px;
3223
+ padding-top: 2px;
3224
+ flex-wrap: wrap;
3225
+ }
3226
+
1866
3227
  /* \u53F3\u4FA7\u4E09\u6309\u94AE\u7EC4 */
1867
3228
  .dsh-a6-bar-actions-btns {
1868
3229
  display: flex;
1869
3230
  align-items: center;
1870
3231
  gap: 8px;
1871
3232
  flex-shrink: 0;
3233
+ flex-wrap: wrap;
1872
3234
  }
1873
3235
 
1874
3236
  .dsh-a6-route-snapshot.never {
@@ -2774,6 +4136,495 @@ body.dsh-a6api-tooltip-active [data-tooltip]::before {
2774
4136
  opacity: 0 !important;
2775
4137
  visibility: hidden !important;
2776
4138
  }
4139
+
4140
+ /* ==========================================================================
4141
+ 8. \u56FA\u5B9A / \u7981\u7528 \u72B6\u6001\u5FBD\u6807\u3001\u64CD\u4F5C\u6309\u94AE\u4E0E\u56FA\u5B9A\u786E\u8BA4\u5F39\u7A97
4142
+ ========================================================================== */
4143
+ .dsh-a6-pin-badge {
4144
+ display: inline-flex;
4145
+ align-items: center;
4146
+ height: 18px;
4147
+ padding: 0 6px;
4148
+ margin-left: 6px;
4149
+ border-radius: 9px;
4150
+ font-size: 10px;
4151
+ font-weight: 600;
4152
+ line-height: 1;
4153
+ vertical-align: middle;
4154
+ white-space: nowrap;
4155
+ }
4156
+
4157
+ .dsh-a6-pin-badge.here {
4158
+ background: rgba(16, 185, 129, 0.12);
4159
+ color: #059669;
4160
+ border: 1px solid rgba(16, 185, 129, 0.35);
4161
+ }
4162
+
4163
+ .dsh-a6-pin-badge.elsewhere {
4164
+ background: rgba(245, 158, 11, 0.12);
4165
+ color: #d97706;
4166
+ border: 1px solid rgba(245, 158, 11, 0.35);
4167
+ }
4168
+
4169
+ .dsh-a6-pin-badge.disabled {
4170
+ background: rgba(100, 116, 139, 0.14);
4171
+ color: #64748b;
4172
+ border: 1px solid rgba(100, 116, 139, 0.3);
4173
+ }
4174
+
4175
+ .dsh-a6-btn-danger {
4176
+ background: #ffffff;
4177
+ border-color: #ef4444;
4178
+ color: #ef4444;
4179
+ }
4180
+
4181
+ .dsh-a6-btn-danger:hover {
4182
+ background: #fef2f2;
4183
+ border-color: #dc2626;
4184
+ color: #dc2626;
4185
+ }
4186
+
4187
+ .dsh-a6-btn:disabled {
4188
+ opacity: 0.45;
4189
+ cursor: not-allowed;
4190
+ }
4191
+
4192
+ .dsh-a6-action-error {
4193
+ /* footer \u5185\u72EC\u7ACB\u6574\u884C\u5C55\u793A\uFF08footer \u4E3A flex-wrap\uFF09\uFF0C\u4E0D\u4E0E\u6309\u94AE\u5E76\u6392\u6491\u5BBD */
4194
+ flex-basis: 100%;
4195
+ margin-top: 6px;
4196
+ padding: 4px 8px;
4197
+ border-radius: 6px;
4198
+ background: rgba(239, 68, 68, 0.08);
4199
+ border: 1px solid rgba(239, 68, 68, 0.25);
4200
+ color: #dc2626;
4201
+ font-size: 11px;
4202
+ line-height: 1.5;
4203
+ }
4204
+
4205
+ /* \u56FA\u5B9A\u786E\u8BA4\u5F39\u7A97 */
4206
+ .dsh-a6-pin-modal-overlay {
4207
+ position: fixed;
4208
+ inset: 0;
4209
+ z-index: 2147483000;
4210
+ background: rgba(15, 23, 42, 0.45);
4211
+ display: flex;
4212
+ align-items: center;
4213
+ justify-content: center;
4214
+ padding: 16px;
4215
+ }
4216
+
4217
+ .dsh-a6-pin-modal {
4218
+ width: min(420px, 92vw);
4219
+ background: var(--dsw-alias-bg-layer-2, #ffffff);
4220
+ border: 1px solid var(--dsw-alias-border-l3, #cbd5e1);
4221
+ border-radius: 10px;
4222
+ box-shadow: 0 12px 32px rgba(15, 23, 42, 0.25);
4223
+ overflow: hidden;
4224
+ }
4225
+
4226
+ .dsh-a6-pin-modal-title {
4227
+ padding: 12px 16px;
4228
+ font-size: 14px;
4229
+ font-weight: 600;
4230
+ color: var(--dsw-alias-label-primary, #1e293b);
4231
+ border-bottom: 1px solid var(--dsw-alias-border-l3, #e2e8f0);
4232
+ background: var(--dsw-alias-bg-layer-1, #f8fafc);
4233
+ }
4234
+
4235
+ .dsh-a6-pin-modal-body {
4236
+ padding: 14px 16px;
4237
+ display: flex;
4238
+ flex-direction: column;
4239
+ gap: 8px;
4240
+ }
4241
+
4242
+ .dsh-a6-pin-modal-row {
4243
+ display: flex;
4244
+ align-items: baseline;
4245
+ gap: 10px;
4246
+ font-size: 12px;
4247
+ }
4248
+
4249
+ .dsh-a6-pin-modal-label {
4250
+ flex: 0 0 48px;
4251
+ color: var(--dsw-alias-label-secondary, #64748b);
4252
+ }
4253
+
4254
+ .dsh-a6-pin-modal-value {
4255
+ color: var(--dsw-alias-label-primary, #1e293b);
4256
+ font-weight: 500;
4257
+ word-break: break-all;
4258
+ }
4259
+
4260
+ .dsh-a6-pin-modal-note {
4261
+ margin: 4px 0 0;
4262
+ font-size: 11px;
4263
+ line-height: 1.6;
4264
+ color: var(--dsw-alias-label-secondary, #64748b);
4265
+ background: rgba(59, 130, 246, 0.06);
4266
+ border: 1px solid rgba(59, 130, 246, 0.15);
4267
+ border-radius: 6px;
4268
+ padding: 6px 8px;
4269
+ }
4270
+
4271
+ .dsh-a6-pin-modal-foot {
4272
+ display: flex;
4273
+ justify-content: flex-end;
4274
+ gap: 8px;
4275
+ padding: 10px 16px;
4276
+ border-top: 1px solid var(--dsw-alias-border-l3, #e2e8f0);
4277
+ background: var(--dsw-alias-bg-layer-1, #f8fafc);
4278
+ }
4279
+
4280
+ /* ==========================================================================
4281
+ Sidebar Footer Action: \u5F53\u524D\u4F1A\u8BDD A6api \u6A21\u578B\u5361\u7247\u5165\u53E3(\u5DE6\u4E0B\u89D2\u8BBE\u7F6E\u6309\u94AE\u4E0A\u65B9)
4282
+ ========================================================================== */
4283
+ .dsh-a6-side-btn-wrap {
4284
+ display: flex;
4285
+ min-width: 0;
4286
+ }
4287
+
4288
+ /* \u539F\u751F\u98CE\u683C:\u5BF9\u9F50\u8BBE\u7F6E\u6309\u94AE(42px \u900F\u660E\u5E7D\u7075\u6309\u94AE,\u65E0\u8FB9\u6846\u65E0\u5E95\u8272,label-primary \u6587\u5B57,
4289
+ hover \u7528 shell \u4EA4\u4E92\u5E95\u8272;rail \u6298\u53E0\u6001 36px \u5706) */
4290
+ .dsh-a6-side-btn {
4291
+ box-sizing: border-box;
4292
+ display: inline-flex;
4293
+ align-items: center;
4294
+ gap: 8px;
4295
+ width: calc(100% + 4px);
4296
+ min-width: 0;
4297
+ height: 42px;
4298
+ margin: 4px -2px;
4299
+ padding: 0 10px 0 8px;
4300
+ border: none;
4301
+ border-radius: 12px;
4302
+ background: transparent;
4303
+ color: var(--dsw-alias-label-primary, #0f172a);
4304
+ cursor: pointer;
4305
+ font-family: inherit;
4306
+ font-size: 14px;
4307
+ font-weight: 500;
4308
+ line-height: 22px;
4309
+ transition: background 0.15s;
4310
+ }
4311
+
4312
+ .dsh-a6-side-btn:hover:not(:disabled) {
4313
+ background: var(--dsw-alias-interactive-bg-hover, rgba(148, 163, 184, 0.16));
4314
+ }
4315
+
4316
+ .dsh-a6-side-btn:disabled {
4317
+ cursor: default;
4318
+ opacity: 0.4;
4319
+ }
4320
+
4321
+ /* rail(\u4FA7\u8FB9\u680F\u6298\u53E0)\u6001:36px \u5706\u5F62\u5355\u8272\u56FE\u6807,\u4E0E\u8BBE\u7F6E\u6309\u94AE\u4E00\u81F4 */
4322
+ .dsh-a6-side-btn.rail {
4323
+ width: 36px;
4324
+ height: 36px;
4325
+ margin: 0;
4326
+ padding: 0;
4327
+ justify-content: center;
4328
+ gap: 0;
4329
+ border-radius: 50%;
4330
+ }
4331
+
4332
+ .dsh-a6-side-btn.rail:hover:not(:disabled) {
4333
+ background: var(--dsw-alias-interactive-bg-hover, rgba(148, 163, 184, 0.16));
4334
+ }
4335
+
4336
+ /* \u9F7F\u8F6E\u56FE\u6807:\u4E0E\u8BBE\u7F6E\u6309\u94AE\u540C\u6B3E(currentColor \u8DDF\u968F\u6587\u5B57\u8272;rail \u6001 18px \u4E0E\u8BBE\u7F6E\u4E00\u81F4) */
4337
+ .dsh-a6-side-btn-badge {
4338
+ flex: none;
4339
+ width: 16px;
4340
+ height: 16px;
4341
+ }
4342
+
4343
+ .dsh-a6-side-btn.rail .dsh-a6-side-btn-badge {
4344
+ width: 18px;
4345
+ height: 18px;
4346
+ }
4347
+
4348
+ .dsh-a6-side-btn-label {
4349
+ overflow: hidden;
4350
+ text-overflow: ellipsis;
4351
+ white-space: nowrap;
4352
+ }
4353
+
4354
+ /* \u5F39\u51FA\u5361\u7247\u6D6E\u5C42:\u951A\u5B9A\u6309\u94AE,\u5411\u4E0A\u5C55\u5F00 */
4355
+ .dsh-a6-side-popup {
4356
+ position: fixed;
4357
+ z-index: 2147483000;
4358
+ width: min(500px, calc(100vw - 16px));
4359
+ max-height: calc(100vh - 16px);
4360
+ overflow-y: auto;
4361
+ overscroll-behavior: contain;
4362
+ background: var(--dsw-alias-bg-layer-1, #ffffff);
4363
+ border: 1px solid var(--dsw-alias-border-l1, #e2e8f0);
4364
+ border-radius: 12px;
4365
+ box-shadow: 0 12px 36px rgba(0, 0, 0, 0.16), 0 2px 8px rgba(0, 0, 0, 0.06);
4366
+ padding: 10px;
4367
+ animation: dsh-a6-popup-up 0.18s ease-out;
4368
+ }
4369
+
4370
+ @keyframes dsh-a6-popup-up {
4371
+ from {
4372
+ opacity: 0;
4373
+ transform: translateY(10px);
4374
+ }
4375
+ to {
4376
+ opacity: 1;
4377
+ transform: none;
4378
+ }
4379
+ }
4380
+
4381
+ .dsh-a6-side-popup-empty {
4382
+ display: flex;
4383
+ flex-direction: column;
4384
+ align-items: center;
4385
+ justify-content: center;
4386
+ gap: 10px;
4387
+ padding: 28px 16px;
4388
+ color: var(--dsw-alias-label-secondary, #64748b);
4389
+ font-size: 13px;
4390
+ }
4391
+
4392
+ .dsh-a6-side-popup-hint {
4393
+ font-size: 12px;
4394
+ color: var(--dsw-alias-label-tertiary, #94a3b8);
4395
+ }
4396
+
4397
+ /* \u6D6E\u5C42\u5185\u7981\u7528 CSS \u4F2A\u5143\u7D20 tooltip:JS portal tooltip \u6709 30ms \u5EF6\u8FDF,\u907F\u514D\u53CC\u63D0\u793A\u4E14\u4F2A\u5143\u7D20\u4F1A\u88AB overflow \u88C1\u526A */
4398
+ .dsh-a6-side-popup [data-tooltip]::after,
4399
+ .dsh-a6-side-popup [data-tooltip]::before {
4400
+ display: none;
4401
+ }
4402
+
4403
+ /* \u6D6E\u5C42\u9876\u90E8\u8D26\u6237\u901F\u89C8\u80F6\u56CA\u884C:\u4E0E\u8BBE\u7F6E\u9875\u5934\u90E8\u540C\u6B3E\u89C6\u89C9,\u7F29\u7A84\u7D27\u51D1\u7248(\u4F59\u989D\u7EAF\u5C55\u793A + \u4EF7\u683C\u6CE2\u52A8\u53EF\u8DF3) */
4404
+ .dsh-a6-side-pills {
4405
+ display: flex;
4406
+ align-items: center;
4407
+ gap: 8px;
4408
+ flex-wrap: wrap;
4409
+ padding: 2px 2px 10px;
4410
+ margin-bottom: 10px;
4411
+ border-bottom: 1px solid var(--dsw-alias-border-l2, #e2e8f0);
4412
+ }
4413
+
4414
+ .dsh-a6-side-pills .dsh-a6-header-balance-badge,
4415
+ .dsh-a6-side-pills .dsh-a6-price-pill {
4416
+ padding: 3px 10px;
4417
+ min-height: 24px;
4418
+ font-size: 11px;
4419
+ /* \u4F59\u989D\u80F6\u56CA\u57FA\u7C7B\u65E0 border-box/line-height\uFF0C\u8865\u4E0A\u4E0E\u4EF7\u683C\u80F6\u56CA\u4E00\u81F4\uFF0C\u4FDD\u8BC1\u4E24\u679A\u80F6\u56CA\u7B49\u9AD8 */
4420
+ box-sizing: border-box;
4421
+ line-height: 1;
4422
+ }
4423
+
4424
+ .dsh-a6-side-pills .dsh-a6-price-pill-count,
4425
+ .dsh-a6-side-pills .dsh-a6-price-pill-label,
4426
+ .dsh-a6-side-pills .dsh-a6-hb-amount,
4427
+ .dsh-a6-side-pills .dsh-a6-hb-label {
4428
+ font-size: 12px;
4429
+ line-height: 1;
4430
+ }
4431
+
4432
+ /* \u6D6E\u5C42\u5185\u4F59\u989D\u80F6\u56CA\u4E3A\u7EAF\u5C55\u793A:\u7981\u6389\u8BBE\u7F6E\u9875\u7684 hover \u53CD\u9988\u4E0E\u624B\u578B(\u9700\u5199\u5728\u901A\u7528 hover \u89C4\u5219\u4E4B\u540E) */
4433
+ .dsh-a6-side-balance-pill,
4434
+ .dsh-a6-side-balance-pill:hover {
4435
+ cursor: default;
4436
+ border-color: var(--dsw-alias-border-l2, #e2e8f0);
4437
+ background: var(--dsw-alias-bg-layer-2, #ffffff);
4438
+ }
4439
+
4440
+
4441
+ /* ===== \u6A21\u578B\u76EE\u5F55\u9875 ===== */
4442
+ .dsh-a6-catalog-page {
4443
+ display: flex;
4444
+ flex-direction: column;
4445
+ gap: 12px;
4446
+ }
4447
+
4448
+ .dsh-a6-catalog-toolbar {
4449
+ display: inline-flex;
4450
+ align-items: center;
4451
+ gap: 8px;
4452
+ flex-wrap: wrap;
4453
+ }
4454
+
4455
+ .dsh-a6-catalog-count {
4456
+ font-size: 12px;
4457
+ color: var(--dsw-alias-label-tertiary, #94a3b8);
4458
+ margin-left: 4px;
4459
+ }
4460
+
4461
+ .dsh-a6-catalog-msg {
4462
+ padding: 8px 12px;
4463
+ border-radius: 8px;
4464
+ font-size: 12px;
4465
+ line-height: 1.5;
4466
+ }
4467
+ .dsh-a6-catalog-msg.ok {
4468
+ background: rgba(16, 185, 129, 0.08);
4469
+ border: 1px solid rgba(16, 185, 129, 0.3);
4470
+ color: #047857;
4471
+ }
4472
+ .dsh-a6-catalog-msg.err {
4473
+ background: rgba(239, 68, 68, 0.08);
4474
+ border: 1px solid rgba(239, 68, 68, 0.3);
4475
+ color: #b91c1c;
4476
+ }
4477
+
4478
+ .dsh-a6-catalog-list {
4479
+ display: flex;
4480
+ flex-direction: column;
4481
+ gap: 8px;
4482
+ }
4483
+
4484
+ .dsh-a6-catalog-row {
4485
+ background: var(--dsw-alias-bg-layer-1, #ffffff);
4486
+ border: 1px solid var(--dsw-alias-border-l2, #e2e8f0);
4487
+ border-radius: 10px;
4488
+ padding: 10px 12px;
4489
+ display: flex;
4490
+ flex-direction: column;
4491
+ gap: 8px;
4492
+ }
4493
+ .dsh-a6-catalog-row.editing {
4494
+ border-color: #10b981;
4495
+ }
4496
+
4497
+ /* \u7B2C\u4E00\u884C\uFF1A\u6A21\u578B ID + \u53EF\u7528\u5FBD\u7AE0 + \u540D\u79F0 + \u64CD\u4F5C\uFF08\u53C2\u6570\u7EDF\u4E00\u5728 ID \u4E0B\u65B9\uFF09 */
4498
+ .dsh-a6-catalog-row-head {
4499
+ display: flex;
4500
+ align-items: center;
4501
+ justify-content: space-between;
4502
+ gap: 12px;
4503
+ flex-wrap: wrap;
4504
+ }
4505
+
4506
+ .dsh-a6-catalog-badge {
4507
+ font-size: 10px;
4508
+ font-weight: 600;
4509
+ padding: 1px 7px;
4510
+ border-radius: 9px;
4511
+ vertical-align: middle;
4512
+ white-space: nowrap;
4513
+ }
4514
+ .dsh-a6-catalog-badge.avail {
4515
+ background: rgba(16, 185, 129, 0.12);
4516
+ border: 1px solid rgba(16, 185, 129, 0.35);
4517
+ color: #047857;
4518
+ }
4519
+
4520
+ .dsh-a6-catalog-filters {
4521
+ display: flex;
4522
+ align-items: center;
4523
+ gap: 10px;
4524
+ flex-wrap: wrap;
4525
+ margin-top: 4px;
4526
+ }
4527
+
4528
+ .dsh-a6-catalog-id {
4529
+ display: inline-flex;
4530
+ align-items: baseline;
4531
+ gap: 8px;
4532
+ min-width: 0;
4533
+ }
4534
+ .dsh-a6-catalog-id code {
4535
+ font-size: 13px;
4536
+ font-weight: 600;
4537
+ color: var(--dsw-alias-label-primary, #0f172a);
4538
+ }
4539
+ .dsh-a6-catalog-name {
4540
+ font-size: 12px;
4541
+ color: var(--dsw-alias-label-secondary, #64748b);
4542
+ overflow: hidden;
4543
+ text-overflow: ellipsis;
4544
+ white-space: nowrap;
4545
+ }
4546
+
4547
+ .dsh-a6-catalog-meta {
4548
+ display: inline-flex;
4549
+ align-items: center;
4550
+ gap: 6px;
4551
+ flex-wrap: wrap;
4552
+ }
4553
+ .dsh-a6-catalog-param {
4554
+ font-size: 11px;
4555
+ padding: 2px 8px;
4556
+ border-radius: 10px;
4557
+ background: rgba(16, 185, 129, 0.08);
4558
+ border: 1px solid rgba(16, 185, 129, 0.25);
4559
+ color: #047857;
4560
+ white-space: nowrap;
4561
+ }
4562
+ .dsh-a6-catalog-param.empty {
4563
+ background: var(--dsw-alias-bg-layer-1, rgba(0, 0, 0, 0.04));
4564
+ border-color: var(--dsw-alias-border-l3, #cbd5e1);
4565
+ color: var(--dsw-alias-label-tertiary, #94a3b8);
4566
+ }
4567
+
4568
+ .dsh-a6-catalog-row-actions {
4569
+ display: inline-flex;
4570
+ align-items: center;
4571
+ gap: 12px;
4572
+ margin-left: auto;
4573
+ }
4574
+
4575
+ /* \u884C\u5185\u7F16\u8F91\u8868\u5355 */
4576
+ .dsh-a6-catalog-edit {
4577
+ border-top: 1px dashed var(--dsw-alias-border-l2, #e2e8f0);
4578
+ padding-top: 10px;
4579
+ display: flex;
4580
+ flex-direction: column;
4581
+ gap: 10px;
4582
+ }
4583
+
4584
+ .dsh-a6-edit-grid {
4585
+ display: grid;
4586
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
4587
+ gap: 10px;
4588
+ }
4589
+
4590
+ .dsh-a6-edit-field {
4591
+ display: flex;
4592
+ flex-direction: column;
4593
+ gap: 4px;
4594
+ min-width: 0;
4595
+ }
4596
+ .dsh-a6-edit-wide {
4597
+ grid-column: 1 / -1;
4598
+ }
4599
+
4600
+ .dsh-a6-checkbox-group {
4601
+ display: inline-flex;
4602
+ gap: 14px;
4603
+ align-items: center;
4604
+ padding: 6px 0;
4605
+ }
4606
+ .dsh-a6-checkbox {
4607
+ display: inline-flex;
4608
+ align-items: center;
4609
+ gap: 5px;
4610
+ font-size: 12px;
4611
+ color: var(--dsw-alias-label-primary, #0f172a);
4612
+ cursor: pointer;
4613
+ user-select: none;
4614
+ }
4615
+
4616
+ .dsh-a6-edit-actions {
4617
+ display: inline-flex;
4618
+ gap: 8px;
4619
+ justify-content: flex-end;
4620
+ }
4621
+
4622
+ /* \u6E05\u7A7A\u76EE\u5F55\u786E\u8BA4\u6001\uFF1A\u7EA2\u8272\u9AD8\u4EAE\u63D0\u793A\u4E8C\u6B21\u70B9\u51FB\u751F\u6548 */
4623
+ .dsh-a6-btn-clear-confirm {
4624
+ background: #ef4444 !important;
4625
+ border-color: #ef4444 !important;
4626
+ color: #ffffff !important;
4627
+ }
2777
4628
  `;
2778
4629
 
2779
4630
  // src/client/index.ts
@@ -2980,6 +4831,10 @@ function apply(ctx) {
2980
4831
  if (typeof window === "undefined") return;
2981
4832
  try {
2982
4833
  setTimeout(() => {
4834
+ try {
4835
+ store.warmUp();
4836
+ } catch {
4837
+ }
2983
4838
  try {
2984
4839
  store.initPricePolling();
2985
4840
  } catch {
@@ -3001,8 +4856,23 @@ function apply(ctx) {
3001
4856
  A6ApiSettingsPanel
3002
4857
  );
3003
4858
  });
4859
+ const getModelDirectories = () => ctx && typeof ctx.get === "function" ? ctx.get("modelDirectories") : void 0;
4860
+ slots.inject("sidebar.footer.action", () => {
4861
+ return slots.register(
4862
+ {
4863
+ name: "sidebar.footer.action",
4864
+ id: "dsh-a6api-current-model",
4865
+ order: -1,
4866
+ label: () => "A6api"
4867
+ },
4868
+ (props) => import_react7.default.createElement(A6ApiSidebarCard, {
4869
+ ...props || {},
4870
+ getModelDirectories
4871
+ })
4872
+ );
4873
+ });
3004
4874
  } catch (err) {
3005
- console.warn("[dsh-a6api] Failed to inject settings section:", err);
4875
+ console.warn("[dsh-a6api] Failed to inject slots:", err);
3006
4876
  }
3007
4877
  }
3008
4878
  return module.exports; } });