@lynn123411/dsh-a6api 1.0.0 → 1.1.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @lynn123411/dsh-a6api
2
2
 
3
- A6API 多模型聚合站深度接入插件:将 A6API 聚合网关无缝注册为 DSH 原生 LLM 提供商,提供多标签页分类视图(可用模型 / 账户资产 / 基础配置)、实时美元与人民币真实余额监控、Token 授权模型白名单自动拉取、实时路由探针,以及全真 1:1 复刻 A6API 官方模型市场维度的全景商户指标卡片与官方 vs 商户价格比对表。
3
+ A6API 多模型聚合站深度接入插件:将 A6API 聚合网关无缝注册为 DSH 原生 LLM 提供商,提供多标签页分类视图(可用模型 / 账户资产 / 基础配置)、实时美元与人民币真实余额监控、Token 授权模型白名单自动拉取、实时路由探针、全真 1:1 复刻 A6API 官方模型市场维度的全景商户指标卡片与官方 vs 商户价格比对表,以及标题栏价格波动实时胶囊一键直达官网。
4
4
 
5
5
  ## 特性
6
6
 
@@ -10,9 +10,10 @@ A6API 多模型聚合站深度接入插件:将 A6API 聚合网关无缝注册
10
10
  - **真实账户资产看板与调用明细**:在「账户资产」页面实时呈现真实可用余额(美元及折合人民币)、历史总消耗、累计请求次数,并实时捕获展示近期模型请求的路由明细快照(时间、模型、命中商户渠道、总耗时、Token 消耗及状态)。
11
11
  - **原生提供商动态注册与一键加入 DSH**:自动向 DSH LLM 运行时注入 `a6api` 目录,在「可用模型」列表点击「添加到 DSH」即可将模型自动增量同步至 `settings.yaml` 与 DSH 对话选择器。
12
12
  - **节点切换与凭据一站式配置**:在「基础配置」页面支持 CDN 推荐节点(`https://api.a6api.com`)、直连备用节点(`https://a6.a6api.com`)与自定义网关节点自由切换,提供 API Key 与系统访问令牌密码显隐切换及获取教程。
13
+ - **价格波动实时胶囊**:标题栏余额右侧常驻「价格波动:n」胶囊(白底,仅数字变色:`0` 绿/`n>0` 红/`--` 灰),基于 `GET /api/marketplace/price-notices` 的待处理数 `pendingCount` 每 60s 轻轮询(与余额同频,仅计不处置),`n>0` 时一键新标签跳 `https://a6api.com/console/token`,未配置/失效或 `0` 时置灰不可点,满足“只监听不处置”的轻量诉求。
13
14
 
14
15
  ## 安装
15
16
 
16
17
  ```bash
17
18
  dsh plugin --profile web add @lynn123411/dsh-a6api
18
- ```
19
+ ```
package/lib/client.js CHANGED
@@ -45,10 +45,12 @@ var A6ApiStore = class {
45
45
  dshConfiguredModels: [],
46
46
  recentLogs: [],
47
47
  probingModelNames: /* @__PURE__ */ new Set(),
48
- error: null
48
+ error: null,
49
+ priceFluctuation: { pendingCount: 0, unseenCount: 0, totalCount: 0, updatedAt: null }
49
50
  };
50
51
  listeners = /* @__PURE__ */ new Set();
51
52
  autoRefreshTimer = null;
53
+ pricePollTimer = null;
52
54
  constructor() {
53
55
  this.startAutoRefresh();
54
56
  }
@@ -85,6 +87,13 @@ var A6ApiStore = class {
85
87
  this.state.recentLogs = data.recentLogs;
86
88
  }
87
89
  this.state.error = null;
90
+ if (this.state.config?.hasToken) {
91
+ const last = this.state.priceFluctuation?.updatedAt;
92
+ if (!last || Date.now() - last > 1e4) {
93
+ this.fetchPriceFluctuation().catch(() => {
94
+ });
95
+ }
96
+ }
88
97
  }
89
98
  }
90
99
  } catch (err) {
@@ -127,6 +136,38 @@ var A6ApiStore = class {
127
136
  } catch {
128
137
  }
129
138
  }
139
+ async fetchPriceFluctuation() {
140
+ try {
141
+ const res = await fetch("/api/dsh-a6api/price-fluctuation");
142
+ if (res.ok) {
143
+ const json = await res.json();
144
+ if (json?.data) {
145
+ const d = json.data;
146
+ const hasAuth = d.hasAuth !== false && !d.authError;
147
+ if (!hasAuth) {
148
+ const next2 = { pendingCount: 0, unseenCount: 0, totalCount: 0, updatedAt: Date.now(), hasAuth: false, authError: Boolean(d.authError) };
149
+ if (JSON.stringify(next2) !== JSON.stringify(this.state.priceFluctuation)) {
150
+ this.state.priceFluctuation = next2;
151
+ this.notify();
152
+ }
153
+ return;
154
+ }
155
+ const pending = Number(d.pendingCount ?? 0);
156
+ const unseen = Number(d.unseenCount ?? 0);
157
+ const total = Number(d.totalCount ?? 0);
158
+ const next = { pendingCount: pending, unseenCount: unseen, totalCount: total, updatedAt: Date.now(), hasAuth: true, authError: false };
159
+ if (pending !== this.state.priceFluctuation.pendingCount || unseen !== this.state.priceFluctuation.unseenCount || this.state.priceFluctuation.hasAuth === false || this.state.priceFluctuation.updatedAt === null) {
160
+ this.state.priceFluctuation = next;
161
+ this.notify();
162
+ } else if (this.state.priceFluctuation.updatedAt === null) {
163
+ this.state.priceFluctuation = next;
164
+ this.notify();
165
+ }
166
+ }
167
+ }
168
+ } catch {
169
+ }
170
+ }
130
171
  async probeModel(modelName) {
131
172
  this.state.probingModelNames.add(modelName);
132
173
  this.state.models = this.state.models.map(
@@ -156,6 +197,7 @@ var A6ApiStore = class {
156
197
  this.state.models = this.state.models.map(
157
198
  (m) => m.model_name === modelName ? {
158
199
  ...m,
200
+ merchant: void 0,
159
201
  probeStatus: "error",
160
202
  probeError: json.result.error,
161
203
  lastProbedAt: Date.now()
@@ -167,7 +209,7 @@ var A6ApiStore = class {
167
209
  ...m,
168
210
  probeStatus: json?.result?.success ? "success" : "idle",
169
211
  probeLatencyMs: json?.result?.durationMs,
170
- probeError: void 0,
212
+ 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,
171
213
  lastProbedAt: Date.now()
172
214
  } : m
173
215
  );
@@ -176,6 +218,7 @@ var A6ApiStore = class {
176
218
  this.state.models = this.state.models.map(
177
219
  (m) => m.model_name === modelName ? {
178
220
  ...m,
221
+ merchant: void 0,
179
222
  probeStatus: "error",
180
223
  probeError: `HTTP ${res.status}`,
181
224
  lastProbedAt: Date.now()
@@ -186,6 +229,7 @@ var A6ApiStore = class {
186
229
  this.state.models = this.state.models.map(
187
230
  (m) => m.model_name === modelName ? {
188
231
  ...m,
232
+ merchant: void 0,
189
233
  probeStatus: "error",
190
234
  probeError: err?.message || String(err),
191
235
  lastProbedAt: Date.now()
@@ -200,8 +244,9 @@ var A6ApiStore = class {
200
244
  }
201
245
  async probeAll() {
202
246
  const allNames = this.state.models.map((m) => m.model_name);
203
- for (const name2 of allNames) {
204
- await this.probeModel(name2);
247
+ const CONCURRENCY = 3;
248
+ for (let i = 0; i < allNames.length; i += CONCURRENCY) {
249
+ await Promise.all(allNames.slice(i, i + CONCURRENCY).map((n) => this.probeModel(n)));
205
250
  }
206
251
  }
207
252
  async toggleDshModel(modelName) {
@@ -239,6 +284,31 @@ var A6ApiStore = class {
239
284
  this.refreshBalance().catch(() => {
240
285
  });
241
286
  }, 6e4);
287
+ if (this.pricePollTimer) clearInterval(this.pricePollTimer);
288
+ this.pricePollTimer = setInterval(() => {
289
+ if (this.state.config?.hasToken) {
290
+ this.fetchPriceFluctuation().catch(() => {
291
+ });
292
+ }
293
+ }, 60 * 1e3);
294
+ }
295
+ stopAutoRefresh() {
296
+ if (this.autoRefreshTimer) {
297
+ clearInterval(this.autoRefreshTimer);
298
+ this.autoRefreshTimer = null;
299
+ }
300
+ if (this.pricePollTimer) {
301
+ clearInterval(this.pricePollTimer);
302
+ this.pricePollTimer = null;
303
+ }
304
+ }
305
+ initPricePolling() {
306
+ if (this.pricePollTimer) return;
307
+ this.startAutoRefresh();
308
+ if (this.state.config?.hasToken) {
309
+ this.fetchPriceFluctuation().catch(() => {
310
+ });
311
+ }
242
312
  }
243
313
  };
244
314
  var store = new A6ApiStore();
@@ -338,7 +408,15 @@ var MerchantCard = ({ model }) => {
338
408
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-a6-price-btm", title: "\u7F13\u5B58\u5199 (1M)", children: merchant.cache_write_price_cny })
339
409
  ] }),
340
410
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-ratio-pill", title: "\u5B9E\u65F6\u500D\u7387\u6BD4\u5B98\u65B9\u4EF7", children: ratioText })
341
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-bar-pricing unprobed", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-unprobed-hint", children: isProbing ? "\u5546\u5BB6\u63A2\u6D4B\u4E2D..." : "\u5C1A\u672A\u63A2\u6D4B\u5546\u5BB6" }) }),
411
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-a6-bar-pricing unprobed", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
412
+ "div",
413
+ {
414
+ className: `dsh-a6-unprobed-hint ${model.probeError ? "error" : ""}`,
415
+ "data-tooltip": model.probeError || void 0,
416
+ "data-tooltip-pos": "down",
417
+ children: isProbing ? "\u5546\u5BB6\u63A2\u6D4B\u4E2D..." : model.probeError ? "\u63A2\u6D4B\u5931\u8D25" : "\u5C1A\u672A\u63A2\u6D4B\u5546\u5BB6"
418
+ }
419
+ ) }),
342
420
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-bar-uptime", children: [
343
421
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-a6-uptime-row", children: [
344
422
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-a6-uptime-label", children: "\u5B9E\u65F6" }),
@@ -398,7 +476,7 @@ var MerchantCard = ({ model }) => {
398
476
  className: `dsh-a6-btn dsh-a6-btn-sm ${model.inDsh ? "dsh-a6-btn-in-dsh" : "dsh-a6-btn-primary"}`,
399
477
  onClick: handleToggleDsh,
400
478
  "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",
401
- children: model.inDsh ? "\u5DF2\u5728 DSH" : "\u6DFB\u52A0\u5230 DSH"
479
+ children: model.inDsh ? "\u79FB\u9664\u6A21\u578B" : "\u6DFB\u52A0\u6A21\u578B"
402
480
  }
403
481
  ),
404
482
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -600,11 +678,14 @@ var AccountPanel = ({ balance, config, recentLogs = [], onNavigateToConfig }) =>
600
678
  // src/client/components/ConfigPanel.tsx
601
679
  var import_react3 = require("react");
602
680
  var import_jsx_runtime3 = require("react/jsx-runtime");
681
+ var MASK = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
603
682
  var ConfigPanel = ({ config, dshConfiguredModels }) => {
604
683
  const [apiKey, setApiKey] = (0, import_react3.useState)(config.apiKey || "");
605
684
  const [accessToken, setAccessToken] = (0, import_react3.useState)(
606
685
  config.accessToken || config.sessionCookie || ""
607
686
  );
687
+ const [clearKey, setClearKey] = (0, import_react3.useState)(false);
688
+ const [clearToken, setClearToken] = (0, import_react3.useState)(false);
608
689
  const [selectedNode, setSelectedNode] = (0, import_react3.useState)(
609
690
  config.baseURL || "https://api.a6api.com"
610
691
  );
@@ -617,9 +698,13 @@ var ConfigPanel = ({ config, dshConfiguredModels }) => {
617
698
  const [showHelp, setShowHelp] = (0, import_react3.useState)(false);
618
699
  const [saving, setSaving] = (0, import_react3.useState)(false);
619
700
  const [saveSuccess, setSaveSuccess] = (0, import_react3.useState)(false);
701
+ const apiKeySet = apiKey === MASK;
702
+ const tokenSet = accessToken === MASK;
620
703
  (0, import_react3.useEffect)(() => {
621
704
  setApiKey(config.apiKey || "");
622
705
  setAccessToken(config.accessToken || config.sessionCookie || "");
706
+ setClearKey(false);
707
+ setClearToken(false);
623
708
  setSelectedNode(config.baseURL || "https://api.a6api.com");
624
709
  setCustomNode(config.customBaseURL || "");
625
710
  setIsCustom(
@@ -629,10 +714,11 @@ var ConfigPanel = ({ config, dshConfiguredModels }) => {
629
714
  const handleSave = async () => {
630
715
  setSaving(true);
631
716
  const finalBaseUrl = isCustom ? customNode.trim() || "https://api.a6api.com" : selectedNode;
717
+ const newApiKey = apiKeySet ? clearKey ? "" : void 0 : apiKey.trim();
718
+ const newToken = tokenSet ? clearToken ? "" : void 0 : accessToken.trim();
632
719
  const ok = await store.saveConfig({
633
- apiKey: apiKey.trim(),
634
- accessToken: accessToken.trim(),
635
- sessionCookie: accessToken.trim(),
720
+ ...newApiKey !== void 0 ? { apiKey: newApiKey } : {},
721
+ ...newToken !== void 0 ? { accessToken: newToken, sessionCookie: newToken } : {},
636
722
  baseURL: finalBaseUrl,
637
723
  customBaseURL: customNode.trim()
638
724
  });
@@ -704,53 +790,81 @@ var ConfigPanel = ({ config, dshConfiguredModels }) => {
704
790
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-a6-field", children: [
705
791
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-a6-field-header", children: [
706
792
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "dsh-a6-label", children: "A6API \u4EE4\u724C (API Key)" }),
707
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
708
- "button",
709
- {
710
- type: "button",
711
- className: "dsh-a6-btn-text",
712
- onClick: () => setShowKey(!showKey),
713
- children: showKey ? "\u9690\u85CF" : "\u663E\u793A"
714
- }
715
- )
793
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-a6-field-header-actions", children: [
794
+ apiKeySet && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
795
+ "button",
796
+ {
797
+ type: "button",
798
+ className: "dsh-a6-btn-text",
799
+ onClick: () => {
800
+ setClearKey(true);
801
+ setApiKey("");
802
+ },
803
+ children: "\u6E05\u9664"
804
+ }
805
+ ),
806
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
807
+ "button",
808
+ {
809
+ type: "button",
810
+ className: "dsh-a6-btn-text",
811
+ onClick: () => setShowKey(!showKey),
812
+ children: showKey ? "\u9690\u85CF" : "\u663E\u793A"
813
+ }
814
+ )
815
+ ] })
716
816
  ] }),
717
817
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-a6-input-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
718
818
  "input",
719
819
  {
720
820
  type: showKey ? "text" : "password",
721
821
  className: "dsh-a6-input",
722
- placeholder: "sk-xxxxxxxxxxxxxxxxxxxxxxxx",
723
- value: apiKey,
822
+ placeholder: apiKeySet ? "\u5DF2\u4FDD\u5B58 \xB7 \u8F93\u5165\u65B0 Key \u53EF\u66FF\u6362" : "sk-xxxxxxxxxxxxxxxxxxxxxxxx",
823
+ value: apiKeySet ? "" : apiKey,
724
824
  onChange: (e) => setApiKey(e.target.value)
725
825
  }
726
826
  ) }),
727
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-a6-field-hint", children: "\u7528\u4E8E\u5411 A6API \u53D1\u8D77\u6A21\u578B\u5BF9\u8BDD\u8BF7\u6C42\u4E0E\u62C9\u53D6\u767D\u540D\u5355\u6A21\u578B\u3002" })
827
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-a6-field-hint", children: apiKeySet ? "\u5DF2\u914D\u7F6E API Key\uFF08\u4EC5\u4FDD\u5B58\u5728\u672C\u673A ~/.dsh/.credentials.yaml\uFF0C\u4E0D\u56DE\u4F20\u754C\u9762\uFF09\u3002" : "\u7528\u4E8E\u5411 A6API \u53D1\u8D77\u6A21\u578B\u5BF9\u8BDD\u8BF7\u6C42\u4E0E\u62C9\u53D6\u767D\u540D\u5355\u6A21\u578B\u3002" })
728
828
  ] }),
729
829
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-a6-field", children: [
730
830
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-a6-field-header", children: [
731
831
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "dsh-a6-label", children: "\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C (Access Token)" }),
732
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
733
- "button",
734
- {
735
- type: "button",
736
- className: "dsh-a6-btn-text",
737
- onClick: () => setShowToken(!showToken),
738
- children: showToken ? "\u9690\u85CF" : "\u663E\u793A"
739
- }
740
- )
832
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-a6-field-header-actions", children: [
833
+ tokenSet && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
834
+ "button",
835
+ {
836
+ type: "button",
837
+ className: "dsh-a6-btn-text",
838
+ onClick: () => {
839
+ setClearToken(true);
840
+ setAccessToken("");
841
+ },
842
+ children: "\u6E05\u9664"
843
+ }
844
+ ),
845
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
846
+ "button",
847
+ {
848
+ type: "button",
849
+ className: "dsh-a6-btn-text",
850
+ onClick: () => setShowToken(!showToken),
851
+ children: showToken ? "\u9690\u85CF" : "\u663E\u793A"
852
+ }
853
+ )
854
+ ] })
741
855
  ] }),
742
856
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-a6-input-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
743
857
  "input",
744
858
  {
745
859
  type: showToken ? "text" : "password",
746
860
  className: "dsh-a6-input",
747
- placeholder: "\u5728\u63A7\u5236\u53F0\u5B89\u5168\u8BBE\u7F6E\u4E2D\u590D\u5236\uFF0C\u4F8B\u5982 eyJhbGciOi...",
748
- value: accessToken,
861
+ placeholder: tokenSet ? "\u5DF2\u4FDD\u5B58 \xB7 \u8F93\u5165\u65B0\u4EE4\u724C\u53EF\u66FF\u6362" : "\u5728\u63A7\u5236\u53F0\u5B89\u5168\u8BBE\u7F6E\u4E2D\u590D\u5236\uFF0C\u4F8B\u5982 eyJhbGciOi...",
862
+ value: tokenSet ? "" : accessToken,
749
863
  onChange: (e) => setAccessToken(e.target.value)
750
864
  }
751
865
  ) }),
752
866
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-a6-field-footer", children: [
753
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-a6-field-hint", children: "\u7528\u4E8E\u514D\u5931\u6548\u540C\u6B65\u8D26\u6237\u771F\u5B9E\u4F59\u989D\u4E0E\u5546\u6237\u6307\u6807\u3002" }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-a6-field-hint", children: tokenSet ? "\u5DF2\u914D\u7F6E\u7CFB\u7EDF\u8BBF\u95EE\u4EE4\u724C\uFF08\u4EC5\u4FDD\u5B58\u5728\u672C\u673A\uFF0C\u4E0D\u56DE\u4F20\u754C\u9762\uFF09\u3002" : "\u7528\u4E8E\u514D\u5931\u6548\u540C\u6B65\u8D26\u6237\u771F\u5B9E\u4F59\u989D\u4E0E\u5546\u6237\u6307\u6807\u3002" }),
754
868
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
755
869
  "button",
756
870
  {
@@ -872,21 +986,61 @@ var A6ApiSettingsPanel = () => {
872
986
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-container", children: [
873
987
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-main-header", children: [
874
988
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-header-text", children: [
875
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "dsh-a6-main-title", children: "A6API \u805A\u5408\u7AD9" }),
989
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "dsh-a6-main-title", children: "A6api" }),
876
990
  /* @__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" })
877
991
  ] }),
878
- state.balance?.hasAccountAuth && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
879
- "div",
880
- {
881
- className: "dsh-a6-header-balance-badge",
882
- onClick: () => setActiveTab("account"),
883
- title: "\u70B9\u51FB\u5207\u6362\u81F3\u300C\u8D26\u6237\u8D44\u4EA7\u300D\u9875\u9762",
884
- children: [
885
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-hb-label", children: "\u8D26\u6237\u4F59\u989D:" }),
886
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-hb-amount", children: state.balance.accountBalanceFormatted })
887
- ]
888
- }
889
- )
992
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-header-badges", children: [
993
+ state.balance?.hasAccountAuth && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
994
+ "div",
995
+ {
996
+ className: "dsh-a6-header-balance-badge",
997
+ onClick: () => setActiveTab("account"),
998
+ title: "\u70B9\u51FB\u5207\u6362\u81F3\u300C\u8D26\u6237\u8D44\u4EA7\u300D\u9875\u9762",
999
+ children: [
1000
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-hb-label", children: "\u8D26\u6237\u4F59\u989D:" }),
1001
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-hb-amount", children: state.balance.accountBalanceFormatted })
1002
+ ]
1003
+ }
1004
+ ),
1005
+ (() => {
1006
+ const n = state.priceFluctuation?.pendingCount ?? 0;
1007
+ const pf = state.priceFluctuation;
1008
+ const hasAuth = pf?.hasAuth !== false && !pf?.authError && Boolean(state.config?.hasToken);
1009
+ const isAuthError = Boolean(pf?.authError);
1010
+ const isZero = n === 0;
1011
+ const isDisabled = !hasAuth || isZero;
1012
+ const cls = isDisabled ? !hasAuth ? "dsh-a6-price-pill disabled" : "dsh-a6-price-pill is-zero is-disabled-zero" : "dsh-a6-price-pill has-change";
1013
+ 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`;
1014
+ const onClick = () => {
1015
+ if (isDisabled) return;
1016
+ window.open("https://a6api.com/console/token", "_blank", "noopener");
1017
+ };
1018
+ const onKeyDown = (e) => {
1019
+ if (isDisabled) return;
1020
+ if (e.key === "Enter" || e.key === " ") {
1021
+ e.preventDefault();
1022
+ onClick();
1023
+ }
1024
+ };
1025
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1026
+ "div",
1027
+ {
1028
+ className: cls,
1029
+ onClick: isDisabled ? void 0 : onClick,
1030
+ onKeyDown,
1031
+ tabIndex: isDisabled ? -1 : 0,
1032
+ title,
1033
+ role: "button",
1034
+ "aria-disabled": isDisabled,
1035
+ style: isDisabled ? { cursor: "not-allowed" } : void 0,
1036
+ children: [
1037
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-price-pill-label", children: "\u4EF7\u683C\u6CE2\u52A8\uFF1A" }),
1038
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-a6-price-pill-count", children: !hasAuth ? "--" : n })
1039
+ ]
1040
+ }
1041
+ );
1042
+ })()
1043
+ ] })
890
1044
  ] }),
891
1045
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-a6-nav-tabs", children: [
892
1046
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -1022,7 +1176,7 @@ var A6ApiSettingsPanel = () => {
1022
1176
  "\u672A\u641C\u7D22\u5230\u5339\u914D\u300C",
1023
1177
  searchQuery,
1024
1178
  "\u300D\u7684\u6A21\u578B"
1025
- ] }) : 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.apiKey ? /* @__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" }) }) })
1179
+ ] }) : 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" }) }) })
1026
1180
  ] }),
1027
1181
  activeTab === "account" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-a6-tab-page account-page", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1028
1182
  AccountPanel,
@@ -1100,6 +1254,13 @@ var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme
1100
1254
  transition: all 0.15s;
1101
1255
  }
1102
1256
 
1257
+ .dsh-a6-header-badges {
1258
+ display: inline-flex;
1259
+ align-items: center;
1260
+ gap: 8px;
1261
+ flex-wrap: wrap;
1262
+ }
1263
+
1103
1264
  .dsh-a6-header-balance-badge:hover {
1104
1265
  border-color: #10b981;
1105
1266
  background: rgba(16, 185, 129, 0.04);
@@ -1110,6 +1271,91 @@ var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme
1110
1271
  color: var(--dsw-alias-label-secondary, #64748b);
1111
1272
  }
1112
1273
 
1274
+ .dsh-a6-price-pill {
1275
+ display: inline-flex;
1276
+ align-items: center;
1277
+ gap: 6px;
1278
+ padding: 5px 12px;
1279
+ border-radius: 16px;
1280
+ border: 1px solid var(--dsw-alias-border-l2, #e2e8f0);
1281
+ cursor: pointer;
1282
+ font-size: 12px;
1283
+ font-weight: 500;
1284
+ line-height: 1;
1285
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
1286
+ transition: all 0.15s;
1287
+ user-select: none;
1288
+ /* \u4E0E\u8D26\u6237\u4F59\u989D\u80F6\u56CA\u7B49\u9AD8\uFF1A\u7EE7\u627F\u540C\u6837\u5185\u8FB9\u8DDD\u4E0E\u884C\u9AD8\uFF0C\u907F\u514D\u89C6\u89C9\u5927\u5C0F\u5DEE\u5F02 */
1289
+ min-height: 28px;
1290
+ box-sizing: border-box;
1291
+ }
1292
+
1293
+ .dsh-a6-price-pill.is-zero {
1294
+ background: var(--dsw-alias-bg-layer-2, #ffffff);
1295
+ border-color: var(--dsw-alias-border-l2, #e2e8f0);
1296
+ color: var(--dsw-alias-label-secondary, #64748b);
1297
+ }
1298
+
1299
+ .dsh-a6-price-pill.is-zero:hover {
1300
+ border-color: #10b981;
1301
+ background: rgba(16, 185, 129, 0.04);
1302
+ }
1303
+
1304
+ .dsh-a6-price-pill.is-zero.is-disabled-zero:hover {
1305
+ border-color: var(--dsw-alias-border-l2, #e2e8f0);
1306
+ background: var(--dsw-alias-bg-layer-2, #ffffff);
1307
+ }
1308
+
1309
+ .dsh-a6-price-pill.has-change {
1310
+ background: var(--dsw-alias-bg-layer-2, #ffffff);
1311
+ border-color: var(--dsw-alias-border-l2, #e2e8f0);
1312
+ color: var(--dsw-alias-label-secondary, #64748b);
1313
+ }
1314
+
1315
+ .dsh-a6-price-pill.has-change:hover {
1316
+ border-color: #ef4444;
1317
+ background: rgba(239, 68, 68, 0.03);
1318
+ }
1319
+
1320
+ .dsh-a6-price-pill.is-disabled-zero {
1321
+ cursor: not-allowed;
1322
+ opacity: 0.9;
1323
+ }
1324
+
1325
+ .dsh-a6-price-pill.disabled {
1326
+ background: var(--dsw-alias-bg-layer-1, rgba(0,0,0,0.04));
1327
+ border-color: var(--dsw-alias-border-l3, #cbd5e1);
1328
+ color: var(--dsw-alias-label-tertiary, #94a3b8);
1329
+ cursor: not-allowed;
1330
+ opacity: 0.85;
1331
+ }
1332
+
1333
+ .dsh-a6-price-pill-label {
1334
+ font-size: 12px;
1335
+ font-weight: 500;
1336
+ color: var(--dsw-alias-label-secondary, #64748b);
1337
+ }
1338
+
1339
+ .dsh-a6-price-pill-count {
1340
+ font-size: 13px;
1341
+ font-weight: 700;
1342
+ min-width: 8px;
1343
+ text-align: center;
1344
+ line-height: 1;
1345
+ }
1346
+
1347
+ .dsh-a6-price-pill.is-zero .dsh-a6-price-pill-count {
1348
+ color: #10b981;
1349
+ }
1350
+
1351
+ .dsh-a6-price-pill.has-change .dsh-a6-price-pill-count {
1352
+ color: #ef4444;
1353
+ }
1354
+
1355
+ .dsh-a6-price-pill.disabled .dsh-a6-price-pill-count {
1356
+ color: var(--dsw-alias-label-tertiary, #94a3b8);
1357
+ }
1358
+
1113
1359
  .dsh-a6-hb-amount {
1114
1360
  font-size: 13px;
1115
1361
  font-weight: 700;
@@ -1339,6 +1585,19 @@ var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme
1339
1585
  color: var(--dsw-alias-label-secondary, #475569);
1340
1586
  }
1341
1587
 
1588
+ .dsh-a6-probe-fail-chip {
1589
+ margin-left: 8px;
1590
+ font-size: 11px;
1591
+ font-weight: 600;
1592
+ color: #dc2626;
1593
+ background: rgba(220, 38, 38, 0.08);
1594
+ border: 1px solid rgba(220, 38, 38, 0.35);
1595
+ border-radius: 999px;
1596
+ padding: 1px 8px;
1597
+ white-space: nowrap;
1598
+ cursor: help;
1599
+ }
1600
+
1342
1601
  .dsh-a6-sub-desc {
1343
1602
  font-size: 11px;
1344
1603
  color: var(--dsw-alias-label-tertiary, #94a3b8);
@@ -1357,6 +1616,11 @@ var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme
1357
1616
  font-size: 12px;
1358
1617
  }
1359
1618
 
1619
+ .dsh-a6-unprobed-hint.error {
1620
+ color: #dc2626;
1621
+ font-weight: 600;
1622
+ }
1623
+
1360
1624
  .dsh-a6-price-col {
1361
1625
  display: flex;
1362
1626
  flex-direction: column;
@@ -2051,6 +2315,12 @@ var main_default = `/* A6API Plugin Styles - Clean Professional DSH Native Theme
2051
2315
  align-items: center;
2052
2316
  }
2053
2317
 
2318
+ .dsh-a6-field-header-actions {
2319
+ display: flex;
2320
+ align-items: center;
2321
+ gap: 8px;
2322
+ }
2323
+
2054
2324
  .dsh-a6-label {
2055
2325
  font-size: 12px;
2056
2326
  font-weight: 600;
@@ -2440,6 +2710,15 @@ function injectStyles() {
2440
2710
  function apply(ctx) {
2441
2711
  injectStyles();
2442
2712
  if (typeof window === "undefined") return;
2713
+ try {
2714
+ setTimeout(() => {
2715
+ try {
2716
+ store.initPricePolling();
2717
+ } catch {
2718
+ }
2719
+ }, 1500);
2720
+ } catch {
2721
+ }
2443
2722
  try {
2444
2723
  const slots = ctx?.slots || (ctx?.get ? ctx.get("slots") : null);
2445
2724
  if (!slots || typeof slots.inject !== "function") return;
@@ -2448,8 +2727,8 @@ function apply(ctx) {
2448
2727
  {
2449
2728
  name: "settings.section",
2450
2729
  id: "dsh-a6api",
2451
- order: 4,
2452
- label: () => "A6API \u805A\u5408\u7AD9"
2730
+ order: 11,
2731
+ label: () => "A6api"
2453
2732
  },
2454
2733
  A6ApiSettingsPanel
2455
2734
  );