@loommii/dsh-provider-usage 0.8.0 → 0.11.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 +4 -2
- package/docs/CHANGELOG.md +33 -0
- package/lib/assets/amd-radeon-logo.svg +18 -0
- package/lib/assets/cmdsymbol-light-black-bg.svg +5 -0
- package/lib/client.js +249 -47
- package/lib/index.js +120 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dsh-provider-usage — DSH「用量中心」
|
|
2
2
|
|
|
3
|
-
> 当前版本 **v0.
|
|
3
|
+
> 当前版本 **v0.11.0** · npm `@loommii/dsh-provider-usage` · [更新历史](docs/CHANGELOG.md)
|
|
4
4
|
|
|
5
5
|
DSH Web GUI 插件 **「用量中心」**:一个常驻右下角的用量卡片,实时显示你的 AI 服务用量 / 余额,不用再打开网页查;附带本地 Token 统计页,不联网也能看自己今天用了多少。
|
|
6
6
|
|
|
@@ -28,6 +28,7 @@ DSH Web GUI 插件 **「用量中心」**:一个常驻右下角的用量卡片
|
|
|
28
28
|
| OpenCode Go(订阅) | 5 小时 / 7 天 / 月度三个窗口的已用百分比 + 进度条 + 重置倒计时 |
|
|
29
29
|
| DeepSeek(余额) | 账户余额(CNY) |
|
|
30
30
|
| Command Code(订阅+余额,自定义) | 5 小时 / 周 / 月窗口使用量 + 月度剩余额度(USD),主数字为本月剩余百分比(3 位小数向下取整) |
|
|
31
|
+
| AMD Radeon Cloud (中国)(余额+配额,自定义) | 今日剩余额度(pts)+ 今日已用/限额 + 单日窗口进度条 + 重置倒计时(无周/月窗口;国际版位置预留) |
|
|
31
32
|
|
|
32
33
|
## 功能
|
|
33
34
|
|
|
@@ -84,7 +85,8 @@ dsh plugin --profile web remove @loommii/dsh-provider-usage
|
|
|
84
85
|
新添加的提供方默认启用。暂停后该实例**不再轮询查询**(卡片 30s 自动刷新跳过它),
|
|
85
86
|
卡片切换菜单里也**不可选**;暂停的若是当前卡片实例会自动切到其他启用实例,全部暂停时卡片隐藏。
|
|
86
87
|
启用/暂停只影响查询与卡片选择,编辑 / 删除 / Key 配置都原样保留
|
|
87
|
-
-
|
|
88
|
+
- 设置页有三个标签:「提供方」管理实例,「用量统计」查看本地 Token 统计,「卡片设置」自定义卡片显示
|
|
89
|
+
- **卡片设置**:可分别开关卡片上的信息模块(主数字 / 副行信息 / 窗口进度条 / 状态 chip / 提供方名称),也可整体「显示卡片」开关隐藏整卡;隐藏后不再轮询查询。全部模块关闭时卡片视为隐藏,并提供「恢复默认」一键还原
|
|
88
90
|
- 设置保存在本机浏览器中;删掉实例不会上传或泄露任何 Key
|
|
89
91
|
- 卡片拖动后的位置会自动保存,下次打开还是老位置
|
|
90
92
|
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.11.0(未发布)
|
|
4
|
+
|
|
5
|
+
### 新功能:卡片设置(用量中心第三页)
|
|
6
|
+
|
|
7
|
+
- **新增「卡片设置」页**(用量中心二级菜单变为「提供方 / 用量统计 / 卡片设置」三页):
|
|
8
|
+
5 个开关分别控制卡片信息模块——主数字、副行信息、窗口进度条、状态 chip、提供方名称;
|
|
9
|
+
另有「显示卡片」总开关隐藏整卡;改动即时生效并持久化到 localStorage
|
|
10
|
+
- **隐藏即停轮询**:`visible=false` 或全部信息模块关闭时卡片完全隐藏(不再渲染空壳),
|
|
11
|
+
30s 自动刷新与查询请求随之停止,重新显示后立即恢复
|
|
12
|
+
- **持久化健壮性**:设置版本升 v6,v3~v5 旧配置自动迁移;card 子项逐项布尔归一化,
|
|
13
|
+
脏数据/非布尔值回落默认(杜绝开关显示与实际渲染分裂);新增跨页签 `storage` 同步,
|
|
14
|
+
避免多页签 last-write-wins 覆盖丢配置;localStorage 写入失败时设置页内联提示(4s 自动消失)
|
|
15
|
+
- **恢复默认**:卡片设置页新增两段式确认「恢复默认」按钮,一键还原全部开关并重新显示卡片
|
|
16
|
+
- **全关空态引导**:所有模块关闭时,设置页提供方/卡片设置页显示「卡片已隐藏」提示
|
|
17
|
+
- **可访问性修正**:设置开关行由 `label` 包裹 `button` 改为语义化 `div + role="switch"` 结构
|
|
18
|
+
- README 使用说明同步更新(两个标签 → 三个标签,补充卡片设置说明)
|
|
19
|
+
|
|
20
|
+
## v0.10.0(2026-09-09)
|
|
21
|
+
|
|
22
|
+
- **新增提供方 AMD Radeon Cloud (中国)(余额+配额卡)**:实测端点 `GET {baseUrl}/usage`(`https://developer.amd.com.cn/radeon/api/v1/usage`,Bearer API Key)——今日剩余 pts 为主数字(3 位小数向下取整百分比)、副行已用/限额 + 剩余(pts)、单日窗口进度条 + 重置倒计时;透传今日/近24h/近30天/累计时间段汇总与按模型拆分(`by_model`)、单次调用明细(`recent`)
|
|
23
|
+
- **无周/月窗口**:AMD 只按日限额计(`daily_cost_limit/used/remaining_usd`),接口无 weekly/monthly 字段;适配器只画「今日」一行进度条
|
|
24
|
+
- **仅自定义添加**:`customOnly`(同 Command Code),Key 加密存插件私有库,默认引用 `RADEON_API_KEY`
|
|
25
|
+
- **国内 / 国际版本**:AMD Radeon Cloud 分两个版本——当前仅接入**中国版**(`developer.amd.com.cn`,显示名「AMD Radeon Cloud (中国)」),国际版 baseUrl/端点不同,适配器位置已预留(后续新增 `amd-radeon-usage-intl` 条目即可)
|
|
26
|
+
- 调研文档:`tmp/AmDRadeonCloud_usage调研.md`(含实测 curl 与字段表;官方文档页路径 404 已记录)
|
|
27
|
+
|
|
28
|
+
## v0.9.0(2026-09-08)
|
|
29
|
+
|
|
30
|
+
### 小功能
|
|
31
|
+
|
|
32
|
+
- **Command Code 官方 logo 替换「CC」文字占位**:卡片头部与切换菜单里的 Command Code 图标
|
|
33
|
+
由紫色渐变底 + 「CC」文字改为官方 ⌘ 符号(白符号·黑底,viewBox 446×446),SVG 内联渲染、
|
|
34
|
+
随容器裁切圆角;原始素材归档到 `lib/assets/cmdsymbol-light-black-bg.svg`(随包发布便于溯源)。
|
|
35
|
+
|
|
3
36
|
## v0.8.0(2026-09-03)
|
|
4
37
|
|
|
5
38
|
### 修复:重启/存储丢失后提供方清单被静默重建(严重数据丢失)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
2
|
+
viewBox="580 280 200 200" style="display:block" xml:space="preserve">
|
|
3
|
+
<style type="text/css">
|
|
4
|
+
.st0{fill-rule:evenodd;clip-rule:evenodd;}
|
|
5
|
+
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
|
|
6
|
+
</style>
|
|
7
|
+
<g>
|
|
8
|
+
<polygon class="st0" points="586,288 778.8,288 778.8,480.8 586,480.8 586,288 "/>
|
|
9
|
+
<path class="st1" d="M658.2,461.3h-10.5l-3.2-7.7h-17.4l-2.9,7.7h-10.3l15.7-39h11.3L658.2,461.3L658.2,461.3L658.2,461.3z
|
|
10
|
+
M635.4,431.6l-5.7,15.2h12L635.4,431.6L635.4,431.6z"/>
|
|
11
|
+
<polygon class="st1" points="696.2,422.3 704.7,422.3 704.7,461.3 695,461.3 695,437 684.4,449.2 682.9,449.2 672.4,437
|
|
12
|
+
672.4,461.3 662.7,461.3 662.7,422.3 671.2,422.3 683.7,436.8 696.2,422.3 "/>
|
|
13
|
+
<path class="st1" d="M729.3,422.3c14.2,0,21.6,8.9,21.6,19.6c0,11.2-7.1,19.4-22.7,19.4h-16.1v-39H729.3L729.3,422.3L729.3,422.3z
|
|
14
|
+
M721.8,454.2h6.3c9.8,0,12.7-6.6,12.7-12.4c0-6.7-3.6-12.4-12.8-12.4h-6.2V454.2L721.8,454.2z"/>
|
|
15
|
+
<polygon class="st1" points="702.5,333.4 660.1,333.4 634,307.5 728.8,307.4 728.8,402.1 702.5,375.6 702.5,333.4 "/>
|
|
16
|
+
<polygon class="st1" points="660.4,376.4 660.2,338.2 633.3,365 633.3,402.8 672.2,402.8 698.5,376.4 660.4,376.4 "/>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg width="446" height="446" viewBox="0 0 446 446" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="446" height="446" fill="black"/>
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M226.665 18.1979H218.375C166.389 18.1979 129.23 18.2366 100.991 22.0332C73.2761 25.7594 56.8935 32.8027 44.8481 44.8481C32.8027 56.8935 25.7594 73.2761 22.0332 100.991C18.2365 129.23 18.1979 166.389 18.1979 218.375V226.665C18.1979 278.651 18.2365 315.809 22.0332 344.048C25.7594 371.764 32.8027 388.146 44.8481 400.192C56.8935 412.237 73.276 419.28 100.991 423.007C129.23 426.803 166.389 426.842 218.375 426.842H226.665C278.651 426.842 315.809 426.803 344.048 423.007C371.764 419.28 388.146 412.237 400.191 400.192C412.237 388.146 419.28 371.764 423.006 344.048C426.803 315.809 426.842 278.651 426.842 226.665V218.375C426.842 166.389 426.803 129.23 423.006 100.991C419.28 73.2761 412.237 56.8935 400.191 44.8481C388.146 32.8027 371.764 25.7594 344.048 22.0332C315.809 18.2366 278.651 18.1979 226.665 18.1979ZM31.9803 31.9803C0 63.9605 0 115.432 0 218.375V226.665C0 329.608 0 381.079 31.9803 413.059C63.9605 445.04 115.432 445.04 218.375 445.04H226.665C329.608 445.04 381.079 445.04 413.059 413.059C445.04 381.079 445.04 329.608 445.04 226.665V218.375C445.04 115.432 445.04 63.9605 413.059 31.9803C381.079 0 329.608 0 226.665 0H218.375C115.432 0 63.9605 0 31.9803 31.9803Z" fill="white"/>
|
|
4
|
+
<path d="M306.202 85.5845C276.837 85.5845 252.95 109.472 252.95 138.837V161.66H192.09V138.837C192.09 109.472 168.202 85.5845 138.837 85.5845C109.472 85.5845 85.5845 109.472 85.5845 138.837C85.5845 168.202 109.472 192.09 138.837 192.09H161.66V252.95H138.837C109.472 252.95 85.5845 276.837 85.5845 306.202C85.5845 335.568 109.472 359.455 138.837 359.455C168.202 359.455 192.09 335.568 192.09 306.202V283.38H252.95V306.202C252.95 335.568 276.837 359.455 306.202 359.455C335.567 359.455 359.455 335.568 359.455 306.202C359.455 276.837 335.567 252.95 306.202 252.95H283.38V192.09H306.202C335.567 192.09 359.455 168.202 359.455 138.837C359.455 109.472 335.567 85.5845 306.202 85.5845ZM283.38 161.66V138.837C283.38 126.209 293.574 116.015 306.202 116.015C318.831 116.015 329.025 126.209 329.025 138.837C329.025 151.466 318.831 161.66 306.202 161.66H283.38ZM138.837 161.66C126.209 161.66 116.015 151.466 116.015 138.837C116.015 126.209 126.209 116.015 138.837 116.015C151.466 116.015 161.66 126.209 161.66 138.837V161.66H138.837ZM192.09 252.95V192.09H252.95V252.95H192.09ZM306.202 329.025C293.574 329.025 283.38 318.831 283.38 306.202V283.38H306.202C318.831 283.38 329.025 293.574 329.025 306.202C329.025 318.831 318.831 329.025 306.202 329.025ZM138.837 329.025C126.209 329.025 116.015 318.831 116.015 306.202C116.015 293.574 126.209 283.38 138.837 283.38H161.66V306.202C161.66 318.831 151.466 329.025 138.837 329.025Z" fill="white"/>
|
|
5
|
+
</svg>
|
package/lib/client.js
CHANGED
|
@@ -20,14 +20,47 @@ window.__ModuleLoader__.load({
|
|
|
20
20
|
|
|
21
21
|
const inject = ['slots'];
|
|
22
22
|
const SETTINGS_KEY = 'dsh-provider-usage.settings';
|
|
23
|
-
const
|
|
23
|
+
const SETTINGS_VERSION = 6;
|
|
24
|
+
// 卡片信息模块显示开关:单一数据源(渲染门控、设置面板、迁移归一化共用)。
|
|
25
|
+
// 默认全开;新增模块只需在此加一项并同步 zh 文案。
|
|
26
|
+
const CARD_MODULES = [
|
|
27
|
+
{ key: 'showMainNumber', default: true },
|
|
28
|
+
{ key: 'showSubRow', default: true },
|
|
29
|
+
{ key: 'showWindowBars', default: true },
|
|
30
|
+
{ key: 'showChip', default: true },
|
|
31
|
+
{ key: 'showProviderName', default: true },
|
|
32
|
+
];
|
|
33
|
+
function defaultCard() {
|
|
34
|
+
var out = {};
|
|
35
|
+
for (var i = 0; i < CARD_MODULES.length; i++) out[CARD_MODULES[i].key] = CARD_MODULES[i].default;
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
function normalizeCard(raw) {
|
|
39
|
+
var out = defaultCard();
|
|
40
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
41
|
+
for (var i = 0; i < CARD_MODULES.length; i++) {
|
|
42
|
+
var k = CARD_MODULES[i].key;
|
|
43
|
+
if (typeof raw[k] === 'boolean') out[k] = raw[k];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
function cardModuleOn(card, key) {
|
|
49
|
+
return (card && card[key]) !== false;
|
|
50
|
+
}
|
|
51
|
+
const DEFAULT_SETTINGS = { visible: true, refreshMs: 30000, providerId: 'opencode-go', right: 16, bottom: 16, settingsVersion: SETTINGS_VERSION,
|
|
52
|
+
card: defaultCard(),
|
|
53
|
+
};
|
|
24
54
|
// 卡片常驻 body 顶层(z-index 与 dsh-pet 同值,≈int32 上限)
|
|
25
55
|
const Z_INDEX = 2147483000;
|
|
26
56
|
// 适配器元数据(与 host ADAPTERS 对应;logo 与显示名用于设置页/菜单)
|
|
27
57
|
const ADAPTER_META = {
|
|
28
|
-
'usage-percent': { displayName: 'OpenCode Go
|
|
58
|
+
'usage-percent': { displayName: 'OpenCode Go' },
|
|
29
59
|
'balance-json': { displayName: 'DeepSeek' },
|
|
30
|
-
'commandcode-credits': { displayName: 'Command Code
|
|
60
|
+
'commandcode-credits': { displayName: 'Command Code' },
|
|
61
|
+
// AMD Radeon Cloud 分国内 / 国际两个版本(国内 = developer.amd.com.cn;国际版 baseUrl/端点不同)。
|
|
62
|
+
// 当前仅接入中国版「AMD Radeon Cloud (中国)」;国际版位置预留,后续接入时新增适配器条目即可。
|
|
63
|
+
'amd-radeon-usage': { displayName: 'AMD Radeon Cloud (中国)' },
|
|
31
64
|
};
|
|
32
65
|
// 供应商实例清单(用户可配置:名称可改、可增删、可同类型多个;key 引用走 DSH 凭证)
|
|
33
66
|
const PROVIDERS_KEY = 'dsh-provider-usage.providers';
|
|
@@ -47,6 +80,17 @@ window.__ModuleLoader__.load({
|
|
|
47
80
|
// DeepSeek:官方鲸 logo PNG(225×225 RGBA)→ data URI,透明底直接展示
|
|
48
81
|
const LOGO_DEEPSEEK = 'data:image/png;base64,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';
|
|
49
82
|
|
|
83
|
+
// Command Code:官方 ⌘ logo(白符号·黑底,viewBox 446×446)→ 内联 SVG(替换原「CC」文字占位)
|
|
84
|
+
const LOGO_CC = React.createElement('svg', { viewBox: '0 0 446 446', 'aria-hidden': 'true', style: { display: 'block', width: '100%', height: '100%' } },
|
|
85
|
+
React.createElement('rect', { width: '446', height: '446', fill: '#000000' }),
|
|
86
|
+
React.createElement('path', { fillRule: 'evenodd', clipRule: 'evenodd', fill: '#FFFFFF', d: 'M226.665 18.1979H218.375C166.389 18.1979 129.23 18.2366 100.991 22.0332C73.2761 25.7594 56.8935 32.8027 44.8481 44.8481C32.8027 56.8935 25.7594 73.2761 22.0332 100.991C18.2365 129.23 18.1979 166.389 18.1979 218.375V226.665C18.1979 278.651 18.2365 315.809 22.0332 344.048C25.7594 371.764 32.8027 388.146 44.8481 400.192C56.8935 412.237 73.276 419.28 100.991 423.007C129.23 426.803 166.389 426.842 218.375 426.842H226.665C278.651 426.842 315.809 426.803 344.048 423.007C371.764 419.28 388.146 412.237 400.191 400.192C412.237 388.146 419.28 371.764 423.006 344.048C426.803 315.809 426.842 278.651 426.842 226.665V218.375C426.842 166.389 426.803 129.23 423.006 100.991C419.28 73.2761 412.237 56.8935 400.191 44.8481C388.146 32.8027 371.764 25.7594 344.048 22.0332C315.809 18.2366 278.651 18.1979 226.665 18.1979ZM31.9803 31.9803C0 63.9605 0 115.432 0 218.375V226.665C0 329.608 0 381.079 31.9803 413.059C63.9605 445.04 115.432 445.04 218.375 445.04H226.665C329.608 445.04 381.079 445.04 413.059 413.059C445.04 381.079 445.04 329.608 445.04 226.665V218.375C445.04 115.432 445.04 63.9605 413.059 31.9803C381.079 0 329.608 0 226.665 0H218.375C115.432 0 63.9605 0 31.9803 31.9803Z' }),
|
|
87
|
+
React.createElement('path', { fill: '#FFFFFF', d: 'M306.202 85.5845C276.837 85.5845 252.95 109.472 252.95 138.837V161.66H192.09V138.837C192.09 109.472 168.202 85.5845 138.837 85.5845C109.472 85.5845 85.5845 109.472 85.5845 138.837C85.5845 168.202 109.472 192.09 138.837 192.09H161.66V252.95H138.837C109.472 252.95 85.5845 276.837 85.5845 306.202C85.5845 335.568 109.472 359.455 138.837 359.455C168.202 359.455 192.09 335.568 192.09 306.202V283.38H252.95V306.202C252.95 335.568 276.837 359.455 306.202 359.455C335.567 359.455 359.455 335.568 359.455 306.202C359.455 276.837 335.567 252.95 306.202 252.95H283.38V192.09H306.202C335.567 192.09 359.455 168.202 359.455 138.837C359.455 109.472 335.567 85.5845 306.202 85.5845ZM283.38 161.66V138.837C283.38 126.209 293.574 116.015 306.202 116.015C318.831 116.015 329.025 126.209 329.025 138.837C329.025 151.466 318.831 161.66 306.202 161.66H283.38ZM138.837 161.66C126.209 161.66 116.015 151.466 116.015 138.837C116.015 126.209 126.209 116.015 138.837 116.015C151.466 116.015 161.66 126.209 161.66 138.837V161.66H138.837ZM192.09 252.95V192.09H252.95V252.95H192.09ZM306.202 329.025C293.574 329.025 283.38 318.831 283.38 306.202V283.38H306.202C318.831 283.38 329.025 293.574 329.025 306.202C329.025 318.831 318.831 329.025 306.202 329.025ZM138.837 329.025C126.209 329.025 116.015 318.831 116.015 306.202C116.015 293.574 126.209 283.38 138.837 283.38H161.66V306.202C161.66 318.831 151.466 329.025 138.837 329.025Z' }));
|
|
88
|
+
|
|
89
|
+
// AMD Radeon Cloud:官方 SVG logo(黑色方块底 + 白色箭头/AMD 字标),viewBox 裁切为正方形
|
|
90
|
+
// 来源:lib/assets/amd-radeon-logo.svg(由 amd-seeklogo.svg 修正 viewBox 后生成)
|
|
91
|
+
const LOGO_AMD_SVG = 'data:image/svg+xml,' + encodeURIComponent(`<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="580 280 200 200" style="display:block"><style>.st0{fill-rule:evenodd;clip-rule:evenodd}.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FFF}</style><g><polygon class="st0" points="586,288 778.8,288 778.8,480.8 586,480.8"/><path class="st1" d="M658.2 461.3h-10.5l-3.2-7.7h-17.4l-2.9 7.7h-10.3l15.7-39h11.3l17.3 39zm-22.8-29.7l-5.7 15.2h12l-6.3-15.2z"/><polygon class="st1" points="696.2 422.3 704.7 422.3 704.7 461.3 695 461.3 695 437 684.4 449.2 682.9 449.2 672.4 437 672.4 461.3 662.7 461.3 662.7 422.3 671.2 422.3 683.7 436.8"/><path class="st1" d="M729.3 422.3c14.2 0 21.6 8.9 21.6 19.6 0 11.2-7.1 19.4-22.7 19.4h-16.1v-39h17.2zm-7.5 31.9h6.3c9.8 0 12.7-6.6 12.7-12.4 0-6.7-3.6-12.4-12.8-12.4h-6.2v24.8z"/><polygon class="st1" points="702.5 333.4 660.1 333.4 634 307.5 728.8 307.4 728.8 402.1 702.5 375.6 702.5 333.4"/><polygon class="st1" points="660.4 376.4 660.2 338.2 633.3 365 633.3 402.8 672.2 402.8 698.5 376.4 660.4 376.4"/></g></svg>`);
|
|
92
|
+
const LOGO_AMD = React.createElement('img', { src: LOGO_AMD_SVG, alt: '', style: { display: 'block', width: '100%', height: '100%' } });
|
|
93
|
+
|
|
50
94
|
const zh = {
|
|
51
95
|
loading: '查询中…',
|
|
52
96
|
refresh: '刷新',
|
|
@@ -55,9 +99,31 @@ window.__ModuleLoader__.load({
|
|
|
55
99
|
rolling: '5小时滚动',
|
|
56
100
|
weekly: '7天(每周)',
|
|
57
101
|
monthly: '每月',
|
|
102
|
+
daily: '今日',
|
|
58
103
|
used: '已用',
|
|
59
104
|
errorTitle: '无法获取用量',
|
|
60
105
|
nav: '用量中心',
|
|
106
|
+
// 卡片设置页
|
|
107
|
+
cardSettings: '卡片设置',
|
|
108
|
+
cardSettingsDesc: '自定义卡片上显示的信息模块。',
|
|
109
|
+
showCard: '显示卡片',
|
|
110
|
+
showCardHint: '关闭后卡片完全隐藏(设置页仍可正常管理提供方与用量统计)。',
|
|
111
|
+
showMainNumber: '主数字',
|
|
112
|
+
showMainNumberHint: '卡片核心数值(剩余额度或剩余百分比)。',
|
|
113
|
+
showSubRow: '副行信息',
|
|
114
|
+
showSubRowHint: '已用/总额 + 剩余额度(Command Code / AMD 等百分比卡)。',
|
|
115
|
+
showWindowBars: '窗口进度条',
|
|
116
|
+
showWindowBarsHint: '5小时滚动/7天/每月(或 AMD 今日)用量进度条。',
|
|
117
|
+
showChip: '状态 chip',
|
|
118
|
+
showChipHint: '卡片右上角状态标签(正常/查询中/未更新/注意)。',
|
|
119
|
+
showProviderName: '提供方名称',
|
|
120
|
+
showProviderNameHint: '卡片头部提供方名称与切换菜单。',
|
|
121
|
+
allModulesOff: '所有信息模块已关闭,卡片已隐藏(可在这里重新开启)。',
|
|
122
|
+
saveFailed: '设置保存失败:浏览器本地存储不可用,本次修改刷新后将丢失。',
|
|
123
|
+
resetCard: '恢复默认',
|
|
124
|
+
resetCardConfirm: '再次点击确认恢复默认',
|
|
125
|
+
// 用量中心副标题(随标签数量变化)
|
|
126
|
+
navDesc: '管理提供方、查看本地用量统计,并自定义卡片显示。',
|
|
61
127
|
};
|
|
62
128
|
|
|
63
129
|
var styleId = 'dsh-provider-usage/styles.css';
|
|
@@ -78,8 +144,8 @@ window.__ModuleLoader__.load({
|
|
|
78
144
|
'.dsh-pu-card-head{display:flex;align-items:center;gap:8px;margin-bottom:10px}',
|
|
79
145
|
'.dsh-pu-logo{width:30px;height:30px;border-radius:8px;flex:none;display:flex;align-items:center;justify-content:center;overflow:hidden;background:transparent}',
|
|
80
146
|
'.dsh-pu-logo.go svg,.dsh-pu-logo.deepseek img{display:block}',
|
|
81
|
-
'.dsh-pu-cc-logo{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:8px;
|
|
82
|
-
'.dsh-pu-cc-logo-sm{width:22px;height:22px;border-radius:6px
|
|
147
|
+
'.dsh-pu-cc-logo{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:8px;overflow:hidden;flex:none}',
|
|
148
|
+
'.dsh-pu-cc-logo-sm{width:22px;height:22px;border-radius:6px}',
|
|
83
149
|
'.dsh-pu-cc-sub{display:flex;align-items:center;gap:10px;margin:-6px 0 6px;font-size:11px;color:#C9B8BE;white-space:nowrap}',
|
|
84
150
|
'.dsh-pu-cc-sub .dsh-pu-cc-used{color:#EFE0E5;font-weight:600}',
|
|
85
151
|
'.dsh-pu-cc-sub .dsh-pu-cc-remain{color:#FFB3C6;font-weight:600}',
|
|
@@ -93,7 +159,7 @@ window.__ModuleLoader__.load({
|
|
|
93
159
|
'.dsh-pu-menu-item.active{background:rgba(255,179,198,.14);color:#FFB3C6}',
|
|
94
160
|
'.dsh-pu-menu-item .mini-logo{width:22px;height:22px;border-radius:6px;flex:none;display:flex;align-items:center;justify-content:center;overflow:hidden}',
|
|
95
161
|
'.dsh-pu-menu-item .check{margin-left:auto;color:#FFB3C6;font-size:12px}',
|
|
96
|
-
'.dsh-pu-card-title{font-size:14px;font-weight:600;color:#EFE0E5;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
|
|
162
|
+
'.dsh-pu-card-title{font-size:14px;font-weight:600;color:#EFE0E5;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}',
|
|
97
163
|
'.dsh-pu-chip{display:inline-flex;align-items:center;gap:5px;border-radius:999px;padding:2px 8px;font-size:10px;font-weight:600;flex:none}',
|
|
98
164
|
'.dsh-pu-chip.ok{background:rgba(102,187,106,.14);color:#7ED68A}',
|
|
99
165
|
'.dsh-pu-chip.warn{background:rgba(255,167,38,.15);color:#FFC46B}',
|
|
@@ -135,6 +201,10 @@ window.__ModuleLoader__.load({
|
|
|
135
201
|
'.zGbnIq_rowNameDim{color:var(--dsw-alias-label-tertiary)}',
|
|
136
202
|
'.zGbnIq_rowCard .zGbnIq_credentialDot.dsh-pu-dot-paused{background:var(--dsw-alias-label-tertiary,#8b93a7)}',
|
|
137
203
|
'.zGbnIq_rowPaused .zGbnIq_rowIdentity .zGbnIq_rowName{color:var(--dsw-alias-label-tertiary)}',
|
|
204
|
+
// ── 卡片设置页:开关行文本弹性(label 语义、flex 排布见 CardSettingsPanel)──
|
|
205
|
+
'.dsh-pu-switchRowText{flex-direction:column;gap:2px;min-width:0;flex:1;display:flex}',
|
|
206
|
+
'.dsh-pu-switchRowText .zGbnIq_advancedHint{margin:0}',
|
|
207
|
+
'.dsh-pu-cardEmpty{border:1px dashed var(--dsw-alias-border-l3);border-radius:10px;margin:2px 0 10px;padding:8px 10px;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}',
|
|
138
208
|
].join('');
|
|
139
209
|
var tag = document.createElement('style');
|
|
140
210
|
tag.dataset.plugin = 'dsh-provider-usage';
|
|
@@ -148,10 +218,11 @@ window.__ModuleLoader__.load({
|
|
|
148
218
|
try {
|
|
149
219
|
var s = JSON.parse(window.localStorage.getItem(SETTINGS_KEY) || 'null');
|
|
150
220
|
if (s && typeof s === 'object' &&
|
|
151
|
-
(s.settingsVersion ===
|
|
152
|
-
//
|
|
221
|
+
(s.settingsVersion === SETTINGS_VERSION || s.settingsVersion === 3 || s.settingsVersion === 4 || s.settingsVersion === 5)) {
|
|
222
|
+
// v5→v6 新增 card 显示开关(默认全开;仅布尔值生效),其余偏好保留
|
|
153
223
|
return Object.assign({}, DEFAULT_SETTINGS, s, {
|
|
154
224
|
providerId: typeof s.providerId === 'string' ? s.providerId : DEFAULT_SETTINGS.providerId,
|
|
225
|
+
card: normalizeCard(s.card),
|
|
155
226
|
});
|
|
156
227
|
}
|
|
157
228
|
// 设置结构升级:v2→v3 移除用户可配置的 zIndex(固定与 dsh-pet 一致),其余偏好保留
|
|
@@ -166,14 +237,21 @@ window.__ModuleLoader__.load({
|
|
|
166
237
|
}
|
|
167
238
|
var settingsState = loadSettings();
|
|
168
239
|
var settingsListeners = new Set();
|
|
240
|
+
// 保存失败时通知(先广播 onPersistFailed,再广播常规刷新):
|
|
241
|
+
// 订阅者根据回调结果展示“无法保存”提示;卡片渲染不依赖持久化结果,避免闪烁。
|
|
169
242
|
function saveSettings() {
|
|
170
|
-
|
|
243
|
+
var ok = true;
|
|
244
|
+
try { window.localStorage.setItem(SETTINGS_KEY, JSON.stringify(settingsState)); }
|
|
245
|
+
catch (e) { ok = false; }
|
|
246
|
+
return ok;
|
|
171
247
|
}
|
|
172
248
|
function getSettings() { return settingsState; }
|
|
173
249
|
function setSettings(patch) {
|
|
174
|
-
settingsState = Object.assign({}, settingsState, patch);
|
|
175
|
-
saveSettings();
|
|
176
|
-
settingsListeners.forEach(function (fn) {
|
|
250
|
+
settingsState = Object.assign({}, settingsState, typeof patch === 'function' ? patch(settingsState) : patch);
|
|
251
|
+
var ok = saveSettings();
|
|
252
|
+
settingsListeners.forEach(function (fn) {
|
|
253
|
+
try { fn(ok ? null : new Error('settings persist failed')); } catch (e) { /* ignore */ }
|
|
254
|
+
});
|
|
177
255
|
}
|
|
178
256
|
function subscribeSettings(fn) {
|
|
179
257
|
settingsListeners.add(fn);
|
|
@@ -184,6 +262,16 @@ window.__ModuleLoader__.load({
|
|
|
184
262
|
useEffect(function () { return subscribeSettings(function () { setS(getSettings()); }); }, []);
|
|
185
263
|
return s;
|
|
186
264
|
}
|
|
265
|
+
// 跨页签同步:其它页签写入后重读并广播(消除 last-write-wins 覆盖丢配置)
|
|
266
|
+
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
267
|
+
window.addEventListener('storage', function (e) {
|
|
268
|
+
if (e.key !== SETTINGS_KEY) return;
|
|
269
|
+
settingsState = loadSettings();
|
|
270
|
+
settingsListeners.forEach(function (fn) {
|
|
271
|
+
try { fn(null); } catch (err) { /* ignore */ }
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
}
|
|
187
275
|
|
|
188
276
|
// ── 供应商实例清单(v0.8.0:host 端 providers.json 为单一事实源,localStorage 只是写穿透缓存)──
|
|
189
277
|
// 修复「重启后提供方清单被静默重建」:此前清单只存 localStorage,存储 key 一旦丢失
|
|
@@ -332,6 +420,9 @@ window.__ModuleLoader__.load({
|
|
|
332
420
|
// ── 用量卡片(布局借鉴 Rainytoken 小组件卡片,常驻右下角)──────────
|
|
333
421
|
function UsageCard() {
|
|
334
422
|
var s = useSettings();
|
|
423
|
+
var card = s.card || {};
|
|
424
|
+
function cardOn(key) { return cardModuleOn(card, key); }
|
|
425
|
+
var allModulesOff = !cardOn('showMainNumber') && !cardOn('showSubRow') && !cardOn('showWindowBars') && !cardOn('showChip') && !cardOn('showProviderName');
|
|
335
426
|
var providers = useProviders();
|
|
336
427
|
var [data, setData] = useState(null);
|
|
337
428
|
var [loading, setLoading] = useState(false);
|
|
@@ -417,11 +508,14 @@ window.__ModuleLoader__.load({
|
|
|
417
508
|
.finally(function () { setLoading(false); });
|
|
418
509
|
}, [curKey]);
|
|
419
510
|
|
|
511
|
+
// 仅在卡片实际可见时轮询:s.visible=false 或全部模块关闭(空壳隐藏)时不发起请求
|
|
512
|
+
var pollActive = s.visible && !allModulesOff;
|
|
420
513
|
useEffect(function () {
|
|
514
|
+
if (!pollActive) return undefined;
|
|
421
515
|
load();
|
|
422
516
|
var timer = window.setInterval(load, s.refreshMs || 30000);
|
|
423
517
|
return function () { window.clearInterval(timer); };
|
|
424
|
-
}, [load, s.refreshMs]);
|
|
518
|
+
}, [load, pollActive, s.refreshMs]);
|
|
425
519
|
|
|
426
520
|
// 点击卡片外部关闭菜单
|
|
427
521
|
useEffect(function () {
|
|
@@ -434,7 +528,7 @@ window.__ModuleLoader__.load({
|
|
|
434
528
|
return function () { document.removeEventListener('mousedown', onDoc); };
|
|
435
529
|
}, [menuOpen]);
|
|
436
530
|
|
|
437
|
-
if (!s.visible || !current) return null;
|
|
531
|
+
if (!s.visible || allModulesOff || !current) return null;
|
|
438
532
|
|
|
439
533
|
// 状态语义:请求中=呼吸绿“查询中”(优先于旧数据状态);正常/注意(stale 或余额不足)/错误
|
|
440
534
|
var loadingCls = loading ? ' dsh-pu-chip-loading' : '';
|
|
@@ -448,12 +542,15 @@ window.__ModuleLoader__.load({
|
|
|
448
542
|
var meta = data && data.fetchedAt ? fmtTime(data.fetchedAt) + (data.stale ? ' · ' + zh.stale : '') : zh.loading;
|
|
449
543
|
var isBalance = current.adapter === 'balance-json';
|
|
450
544
|
var isCommandCode = current.adapter === 'commandcode-credits';
|
|
451
|
-
var
|
|
545
|
+
var isAmd = current.adapter === 'amd-radeon-usage';
|
|
546
|
+
var logoClass = isBalance ? 'deepseek' : (isCommandCode ? 'commandcode' : (isAmd ? 'amd' : 'go'));
|
|
452
547
|
var logoEl = isBalance
|
|
453
548
|
? React.createElement('img', { src: LOGO_DEEPSEEK, width: 24, height: 24, alt: '' })
|
|
454
549
|
: (isCommandCode
|
|
455
|
-
? React.createElement('span', { className: 'dsh-pu-cc-logo', 'aria-hidden': 'true' },
|
|
456
|
-
:
|
|
550
|
+
? React.createElement('span', { className: 'dsh-pu-cc-logo', 'aria-hidden': 'true' }, LOGO_CC)
|
|
551
|
+
: (isAmd
|
|
552
|
+
? React.createElement('span', { className: 'dsh-pu-cc-logo', 'aria-hidden': 'true' }, LOGO_AMD)
|
|
553
|
+
: LOGO_OCGO));
|
|
457
554
|
|
|
458
555
|
var body = null;
|
|
459
556
|
if (loading && !data) {
|
|
@@ -475,41 +572,47 @@ window.__ModuleLoader__.load({
|
|
|
475
572
|
(data.monthly && data.monthly.usedPct !== null
|
|
476
573
|
? React.createElement(WindowRow, { key: 'm', label: zh.monthly, win: data.monthly, bar: 'magenta' })
|
|
477
574
|
: null)].filter(Boolean)
|
|
478
|
-
:
|
|
479
|
-
|
|
480
|
-
|
|
575
|
+
: (isAmd
|
|
576
|
+
// AMD:单日窗口进度条(对齐网页 Today Used / Remaining;无周/月)
|
|
577
|
+
? [React.createElement(WindowRow, { key: 'd', label: zh.daily, win: data.windows.daily, bar: 'magenta' })]
|
|
578
|
+
: [React.createElement(WindowRow, { key: 'r', label: zh.rolling, win: data.windows.rolling, bar: 'pink' }),
|
|
579
|
+
React.createElement(WindowRow, { key: 'w', label: zh.weekly, win: data.windows.weekly, bar: 'orange' }),
|
|
580
|
+
React.createElement(WindowRow, { key: 'm', label: zh.monthly, win: data.windows.monthly, bar: 'magenta' })]))
|
|
481
581
|
: null;
|
|
482
582
|
var warn = data.isValid === false && data.invalidMessage
|
|
483
583
|
? React.createElement('div', { className: 'dsh-pu-error' }, data.invalidMessage)
|
|
484
584
|
: null;
|
|
485
|
-
// Command Code 混合卡:主数字 =
|
|
585
|
+
// Command Code / AMD 混合卡:主数字 = 剩余百分比(3 位小数向下取整),副行 = 已用/总额 + 剩余额度
|
|
586
|
+
// Command Code 读 monthly.remainingPct;AMD 读 windows.daily.remainingPct(今日)
|
|
486
587
|
var cc = null;
|
|
487
|
-
|
|
488
|
-
|
|
588
|
+
var remainPct = null;
|
|
589
|
+
if (isCommandCode || isAmd) {
|
|
590
|
+
var pctInfo = isAmd ? (data.windows && data.windows.daily) : (data.monthly || null);
|
|
489
591
|
// 新服务端直接给 remainingPct;旧服务端只有 usedPct → 按 100−usedPct 兜底(与 host 公式数学等价)
|
|
490
|
-
|
|
491
|
-
? (
|
|
492
|
-
?
|
|
493
|
-
: (
|
|
592
|
+
remainPct = pctInfo
|
|
593
|
+
? (pctInfo.remainingPct !== undefined && pctInfo.remainingPct !== null
|
|
594
|
+
? pctInfo.remainingPct
|
|
595
|
+
: (pctInfo.usedPct === undefined || pctInfo.usedPct === null
|
|
494
596
|
? null
|
|
495
|
-
: Math.floor(Math.max(0, Math.min(100, 100 -
|
|
597
|
+
: Math.floor(Math.max(0, Math.min(100, 100 - pctInfo.usedPct)) * 1000) / 1000))
|
|
496
598
|
: null;
|
|
497
|
-
var
|
|
498
|
-
var
|
|
499
|
-
var
|
|
599
|
+
var unitSym = isAmd ? '' : '$';
|
|
600
|
+
var usedStr = data.used === null ? '--' : Number(data.used).toFixed(isAmd ? 3 : 2);
|
|
601
|
+
var quotaStr = data.totalQuota === null ? '--' : Number(data.totalQuota).toFixed(isAmd ? 3 : 2);
|
|
602
|
+
var remainStr = data.remaining === null ? '--' : Number(data.remaining).toFixed(isAmd ? 3 : 2);
|
|
500
603
|
cc = React.createElement('div', { className: 'dsh-pu-cc-sub' },
|
|
501
|
-
React.createElement('span', { className: 'dsh-pu-cc-used' }, '已用
|
|
502
|
-
React.createElement('span', { className: 'dsh-pu-cc-remain' }, '剩余
|
|
604
|
+
React.createElement('span', { className: 'dsh-pu-cc-used' }, (isAmd ? zh.daily + ' ' : '') + '已用 ' + unitSym + usedStr + ' / ' + unitSym + quotaStr + (isAmd ? ' pts' : '')),
|
|
605
|
+
React.createElement('span', { className: 'dsh-pu-cc-remain' }, (isAmd ? zh.daily + ' ' : '') + '剩余 ' + unitSym + remainStr + (isAmd ? ' pts' : '')));
|
|
503
606
|
}
|
|
504
607
|
// 窗口行/主值/警告条已覆盖全部信息,extra 全文不再展示(保持卡片干净)
|
|
505
608
|
var extra = null;
|
|
506
609
|
body = React.createElement('div', null,
|
|
507
|
-
React.createElement('div', { className: 'dsh-pu-remain' },
|
|
508
|
-
React.createElement('span', { className: 'dsh-pu-remain-big' }, isCommandCode ? (remainPct === null ? '--' : remainPct.toFixed(3) + '%') : main),
|
|
509
|
-
React.createElement('span', { className: 'dsh-pu-remain-label' }, isCommandCode ? ' ' + zh.remaining + '(' + zh.monthly + ')' : ' ' + mainLabel)),
|
|
610
|
+
cardOn('showMainNumber') ? React.createElement('div', { className: 'dsh-pu-remain' },
|
|
611
|
+
React.createElement('span', { className: 'dsh-pu-remain-big' }, (isCommandCode || isAmd) ? (remainPct === null ? '--' : remainPct.toFixed(3) + '%') : main),
|
|
612
|
+
React.createElement('span', { className: 'dsh-pu-remain-label' }, (isCommandCode || isAmd) ? ' ' + zh.remaining + '(' + (isAmd ? zh.daily : zh.monthly) + ')' : ' ' + mainLabel)) : null,
|
|
510
613
|
warn,
|
|
511
|
-
cc,
|
|
512
|
-
winRows,
|
|
614
|
+
cardOn('showSubRow') ? cc : null,
|
|
615
|
+
cardOn('showWindowBars') ? winRows : null,
|
|
513
616
|
extra);
|
|
514
617
|
}
|
|
515
618
|
|
|
@@ -521,8 +624,10 @@ window.__ModuleLoader__.load({
|
|
|
521
624
|
var mini = p.adapter === 'balance-json'
|
|
522
625
|
? React.createElement('img', { src: LOGO_DEEPSEEK, width: 16, height: 16, alt: '' })
|
|
523
626
|
: (p.adapter === 'commandcode-credits'
|
|
524
|
-
? React.createElement('span', { className: 'dsh-pu-cc-logo dsh-pu-cc-logo-sm', 'aria-hidden': 'true' },
|
|
525
|
-
:
|
|
627
|
+
? React.createElement('span', { className: 'dsh-pu-cc-logo dsh-pu-cc-logo-sm', 'aria-hidden': 'true' }, LOGO_CC)
|
|
628
|
+
: (p.adapter === 'amd-radeon-usage'
|
|
629
|
+
? React.createElement('span', { className: 'dsh-pu-cc-logo dsh-pu-cc-logo-sm', 'aria-hidden': 'true' }, LOGO_AMD)
|
|
630
|
+
: LOGO_OCGO));
|
|
526
631
|
return React.createElement('button', {
|
|
527
632
|
key: p.id, type: 'button', className: 'dsh-pu-menu-item' + (active ? ' active' : ''),
|
|
528
633
|
onClick: function (e) { if (draggedRef.current) { draggedRef.current = false; return; } e.stopPropagation(); setSettings({ providerId: p.id }); setMenuOpen(false); },
|
|
@@ -545,9 +650,9 @@ window.__ModuleLoader__.load({
|
|
|
545
650
|
onClick: function (e) { if (draggedRef.current) { draggedRef.current = false; return; } e.stopPropagation(); if (multiple) setMenuOpen(!menuOpen); },
|
|
546
651
|
},
|
|
547
652
|
React.createElement('span', { className: 'dsh-pu-logo ' + logoClass }, logoEl),
|
|
548
|
-
React.createElement('span', { className: 'dsh-pu-card-title' }, title),
|
|
653
|
+
cardOn('showProviderName') ? React.createElement('span', { className: 'dsh-pu-card-title' }, title) : null,
|
|
549
654
|
multiple ? React.createElement('span', { className: 'caret' }, menuOpen ? '▴' : '▾') : null),
|
|
550
|
-
React.createElement('span', { className: 'dsh-pu-chip ' + level + loadingCls }, React.createElement('i', null), chipText)),
|
|
655
|
+
cardOn('showChip') ? React.createElement('span', { className: 'dsh-pu-chip ' + level + loadingCls }, React.createElement('i', null), chipText) : null),
|
|
551
656
|
menu,
|
|
552
657
|
body,
|
|
553
658
|
React.createElement('div', { className: 'dsh-pu-card-foot' },
|
|
@@ -835,6 +940,95 @@ window.__ModuleLoader__.load({
|
|
|
835
940
|
}
|
|
836
941
|
return { level: 'err', label: '查询失败' + (qs.err ? ':' + qs.err : ''), clickable: true, detailKind: 'err', dotCls: ' zGbnIq_credentialDotMissing', detailText: '查询失败:' + (qs.err || '未知错误') };
|
|
837
942
|
}
|
|
943
|
+
// 卡片设置页:5 个开关控制卡片信息模块显示;即时生效 + 保存失败反馈 + 恢复默认
|
|
944
|
+
function CardSettingsPanel() {
|
|
945
|
+
var s = useSettings();
|
|
946
|
+
var card = s.card || {};
|
|
947
|
+
// 持久化失败提示(setSettings 回调收到非空 err 时显示;下次成功自动清除)
|
|
948
|
+
var [persistFailed, setPersistFailed] = useState(false);
|
|
949
|
+
var persistErrTimer = useRef(null);
|
|
950
|
+
useEffect(function () {
|
|
951
|
+
var dispose = subscribeSettings(function (err) {
|
|
952
|
+
if (err) {
|
|
953
|
+
setPersistFailed(true);
|
|
954
|
+
window.clearTimeout(persistErrTimer.current);
|
|
955
|
+
persistErrTimer.current = window.setTimeout(function () { setPersistFailed(false); }, 4000);
|
|
956
|
+
} else {
|
|
957
|
+
setPersistFailed(false);
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
return function () {
|
|
961
|
+
dispose();
|
|
962
|
+
window.clearTimeout(persistErrTimer.current);
|
|
963
|
+
};
|
|
964
|
+
}, []);
|
|
965
|
+
var [resetArm, setResetArm] = useState(false);
|
|
966
|
+
var resetTimer = useRef(null);
|
|
967
|
+
useEffect(function () {
|
|
968
|
+
return function () { window.clearTimeout(resetTimer.current); };
|
|
969
|
+
}, []);
|
|
970
|
+
function armReset() {
|
|
971
|
+
setResetArm(true);
|
|
972
|
+
window.clearTimeout(resetTimer.current);
|
|
973
|
+
resetTimer.current = window.setTimeout(function () { setResetArm(false); }, 4000);
|
|
974
|
+
}
|
|
975
|
+
function doReset() {
|
|
976
|
+
setResetArm(false);
|
|
977
|
+
window.clearTimeout(resetTimer.current);
|
|
978
|
+
setSettings({ visible: true, card: defaultCard() });
|
|
979
|
+
}
|
|
980
|
+
function toggle(key) {
|
|
981
|
+
setSettings(function (prev) {
|
|
982
|
+
var cur = (prev && prev.card) || {};
|
|
983
|
+
var next = Object.assign({}, cur);
|
|
984
|
+
next[key] = !cardModuleOn(cur, key);
|
|
985
|
+
return { card: next };
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
var rows = [
|
|
989
|
+
{ key: 'showMainNumber', label: zh.showMainNumber, hint: zh.showMainNumberHint },
|
|
990
|
+
{ key: 'showSubRow', label: zh.showSubRow, hint: zh.showSubRowHint },
|
|
991
|
+
{ key: 'showWindowBars', label: zh.showWindowBars, hint: zh.showWindowBarsHint },
|
|
992
|
+
{ key: 'showChip', label: zh.showChip, hint: zh.showChipHint },
|
|
993
|
+
{ key: 'showProviderName', label: zh.showProviderName, hint: zh.showProviderNameHint },
|
|
994
|
+
];
|
|
995
|
+
var cardOn = s.visible !== false;
|
|
996
|
+
var allOff = !rows.some(function (r) { return cardModuleOn(card, r.key); });
|
|
997
|
+
function switchRow(id, on, ariaLabel, text, hint, onChange) {
|
|
998
|
+
return React.createElement('div', { className: 'zGbnIq_rowCard' },
|
|
999
|
+
React.createElement('div', { className: 'zGbnIq_editorSwitchRow', style: { justifyContent: 'space-between' } },
|
|
1000
|
+
React.createElement('div', { className: 'dsh-pu-switchRowText' },
|
|
1001
|
+
React.createElement('span', { className: 'dsh-pu-switchText' }, text),
|
|
1002
|
+
React.createElement('span', { className: 'zGbnIq_advancedHint' }, hint)),
|
|
1003
|
+
React.createElement('button', {
|
|
1004
|
+
type: 'button', role: 'switch', id: id,
|
|
1005
|
+
'aria-checked': on ? 'true' : 'false',
|
|
1006
|
+
'aria-label': ariaLabel,
|
|
1007
|
+
className: 'dsh-pu-switch' + (on ? ' dsh-pu-switch-on' : ''),
|
|
1008
|
+
onClick: onChange,
|
|
1009
|
+
}, React.createElement('span', { className: 'dsh-pu-switch-thumb' }))));
|
|
1010
|
+
}
|
|
1011
|
+
return React.createElement('div', { className: 'zGbnIq_section' },
|
|
1012
|
+
React.createElement('h2', { className: 'zGbnIq_title' }, zh.cardSettings),
|
|
1013
|
+
React.createElement('p', { className: 'zGbnIq_intro' }, zh.cardSettingsDesc),
|
|
1014
|
+
persistFailed ? React.createElement('p', { className: 'zGbnIq_error' }, zh.saveFailed) : null,
|
|
1015
|
+
React.createElement('div', { className: 'zGbnIq_rows' },
|
|
1016
|
+
switchRow('pu-switch-visible', cardOn, zh.showCard, zh.showCard, zh.showCardHint,
|
|
1017
|
+
function () { setSettings({ visible: !cardOn }); }),
|
|
1018
|
+
allOff ? React.createElement('p', { className: 'zGbnIq_advancedHint', style: { margin: '0' } }, zh.allModulesOff) : null,
|
|
1019
|
+
rows.map(function (r) {
|
|
1020
|
+
return switchRow('pu-switch-' + r.key, cardModuleOn(card, r.key), r.label, r.label, r.hint,
|
|
1021
|
+
function () { toggle(r.key); });
|
|
1022
|
+
})),
|
|
1023
|
+
React.createElement('div', { className: 'zGbnIq_editorActions', style: { marginTop: '4px' } },
|
|
1024
|
+
React.createElement('button', {
|
|
1025
|
+
type: 'button',
|
|
1026
|
+
className: 'zGbnIq_secondaryButton',
|
|
1027
|
+
'data-arm': resetArm ? 'true' : undefined,
|
|
1028
|
+
'aria-label': resetArm ? zh.resetCardConfirm : zh.resetCard,
|
|
1029
|
+
onClick: resetArm ? doReset : armReset,
|
|
1030
|
+
}, resetArm ? zh.resetCardConfirm : zh.resetCard)));
|
|
1031
|
+
}
|
|
838
1032
|
function SettingsCard() {
|
|
839
1033
|
var s = useSettings();
|
|
840
1034
|
var providers = useProviders();
|
|
@@ -893,7 +1087,7 @@ window.__ModuleLoader__.load({
|
|
|
893
1087
|
setMode('manual');
|
|
894
1088
|
setEdit(null);
|
|
895
1089
|
setFormError(null);
|
|
896
|
-
setForm({ provider: '', name: '
|
|
1090
|
+
setForm({ provider: '', name: 'AMD Radeon Cloud (中国)', adapter: 'amd-radeon-usage', key: '', nameTouched: false });
|
|
897
1091
|
}
|
|
898
1092
|
function cancelAdd() { setMode(null); setEdit(null); setFormError(null); }
|
|
899
1093
|
|
|
@@ -1120,7 +1314,7 @@ window.__ModuleLoader__.load({
|
|
|
1120
1314
|
className: 'zGbnIq_input zGbnIq_selectInput', value: form.adapter,
|
|
1121
1315
|
onChange: function (e) {
|
|
1122
1316
|
var next = Object.assign({}, form, { adapter: e.target.value });
|
|
1123
|
-
if (!form.nameTouched) next.name = e.target.value === 'balance-json' ? 'DeepSeek' : (e.target.value === 'commandcode-credits' ? 'Command Code' : 'OpenCode Go');
|
|
1317
|
+
if (!form.nameTouched) next.name = e.target.value === 'balance-json' ? 'DeepSeek' : (e.target.value === 'commandcode-credits' ? 'Command Code' : (e.target.value === 'amd-radeon-usage' ? 'AMD Radeon Cloud (中国)' : 'OpenCode Go'));
|
|
1124
1318
|
setForm(next);
|
|
1125
1319
|
},
|
|
1126
1320
|
}, adapterOptions)),
|
|
@@ -1186,12 +1380,15 @@ window.__ModuleLoader__.load({
|
|
|
1186
1380
|
React.createElement('button', { type: 'button', className: 'zGbnIq_primaryButton', disabled: busy, onClick: saveEdit }, '保存')));
|
|
1187
1381
|
}
|
|
1188
1382
|
|
|
1189
|
-
// 插件页同款二级菜单(官方 dsh-client-ui-settings-plugins 结构):提供方设置 / 用量统计
|
|
1383
|
+
// 插件页同款二级菜单(官方 dsh-client-ui-settings-plugins 结构):提供方设置 / 用量统计 / 卡片设置 三个互不影响的分页
|
|
1190
1384
|
var tabsList = [
|
|
1191
1385
|
{ id: 'providers', label: '提供方设置' },
|
|
1192
1386
|
{ id: 'usage', label: '用量统计' },
|
|
1387
|
+
{ id: 'card-settings', label: zh.cardSettings },
|
|
1193
1388
|
];
|
|
1194
1389
|
var [tab, setTab] = useState('providers');
|
|
1390
|
+
// 卡片因 visible=false 或全部模块关闭而隐藏时,在提供方页顶部给出可恢复的提示(卡片设置 tab 有恢复入口)
|
|
1391
|
+
var cardHidden = !s.visible || !CARD_MODULES.some(function (m) { return cardModuleOn(s.card, m.key); });
|
|
1195
1392
|
var tabsRef = useRef([]);
|
|
1196
1393
|
function onTabKey(e, idx) {
|
|
1197
1394
|
var len = tabsList.length;
|
|
@@ -1212,6 +1409,7 @@ window.__ModuleLoader__.load({
|
|
|
1212
1409
|
var providersPanel = React.createElement('div', { className: 'zGbnIq_section' },
|
|
1213
1410
|
React.createElement('h2', { className: 'zGbnIq_title' }, '提供方'),
|
|
1214
1411
|
React.createElement('p', { className: 'zGbnIq_intro' }, '填入各供应方的 Key 引用即可查询其用量与余额。'),
|
|
1412
|
+
cardHidden ? React.createElement('p', { className: 'dsh-pu-cardEmpty' }, zh.allModulesOff) : null,
|
|
1215
1413
|
React.createElement('ul', { className: 'zGbnIq_rows' },
|
|
1216
1414
|
providers.length === 0
|
|
1217
1415
|
? React.createElement('li', { className: 'zGbnIq_rowCard' },
|
|
@@ -1242,6 +1440,9 @@ window.__ModuleLoader__.load({
|
|
|
1242
1440
|
var usagePanel = React.createElement('div', { className: 'pbvGtq_panel', role: 'tabpanel', id: 'pu-tab-usage', 'aria-labelledby': 'pu-tab-btn-usage', hidden: tab !== 'usage' },
|
|
1243
1441
|
React.createElement(UsageStatsPage, { active: tab === 'usage' }));
|
|
1244
1442
|
|
|
1443
|
+
// 页面 3:卡片设置(卡片信息模块显示开关)
|
|
1444
|
+
var cardSettingsPanel = React.createElement('div', { className: 'pbvGtq_panel', role: 'tabpanel', id: 'pu-tab-card-settings', 'aria-labelledby': 'pu-tab-btn-card-settings', hidden: tab !== 'card-settings' },
|
|
1445
|
+
React.createElement(CardSettingsPanel));
|
|
1245
1446
|
// 二级菜单(插件页同款:下划线高亮 + 方向键切换)
|
|
1246
1447
|
var tabsBar = React.createElement('div', { className: 'pbvGtq_tabs', role: 'tablist', 'aria-label': '用量中心视图' },
|
|
1247
1448
|
tabsList.map(function (t, idx) {
|
|
@@ -1262,10 +1463,11 @@ window.__ModuleLoader__.load({
|
|
|
1262
1463
|
|
|
1263
1464
|
return React.createElement('div', { className: 'pbvGtq_section' },
|
|
1264
1465
|
React.createElement('h2', { className: 'pbvGtq_heading' }, '用量中心'),
|
|
1265
|
-
React.createElement('p', { className: 'pbvGtq_intro' },
|
|
1466
|
+
React.createElement('p', { className: 'pbvGtq_intro' }, zh.navDesc),
|
|
1266
1467
|
tabsBar,
|
|
1267
1468
|
React.createElement('div', { className: 'pbvGtq_panel', role: 'tabpanel', id: 'pu-tab-providers', 'aria-labelledby': 'pu-tab-btn-providers', hidden: tab !== 'providers' }, providersPanel),
|
|
1268
|
-
usagePanel
|
|
1469
|
+
usagePanel,
|
|
1470
|
+
cardSettingsPanel);
|
|
1269
1471
|
}
|
|
1270
1472
|
// 提供方单行:状态点 + 名称 + 编辑/删除 + 展开详情
|
|
1271
1473
|
// 状态判定全部交给 statusOf;本组件只做渲染;启用/暂停开关在编辑弹层里管理
|
package/lib/index.js
CHANGED
|
@@ -21,8 +21,8 @@ export const name = 'provider-usage'
|
|
|
21
21
|
|
|
22
22
|
/** 插件版本单一来源:package.json(UA 标识用;bundle 内嵌等读不到时回退字面量)。 */
|
|
23
23
|
const PLUGIN_VERSION = (() => {
|
|
24
|
-
try { return JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version || '0.
|
|
25
|
-
catch { return '0.
|
|
24
|
+
try { return JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version || '0.11.0' }
|
|
25
|
+
catch { return '0.11.0' }
|
|
26
26
|
})()
|
|
27
27
|
const USER_AGENT = 'dsh-provider-usage/' + PLUGIN_VERSION
|
|
28
28
|
|
|
@@ -51,7 +51,7 @@ const LOCAL_DEPS_CHECK_MS = 300000
|
|
|
51
51
|
const ADAPTERS = [
|
|
52
52
|
{
|
|
53
53
|
id: 'usage-percent',
|
|
54
|
-
displayName: 'OpenCode Go
|
|
54
|
+
displayName: 'OpenCode Go',
|
|
55
55
|
baseUrl: 'https://opencode.ai/zen/go',
|
|
56
56
|
usagePath: '/v1/usage',
|
|
57
57
|
defaultCredentialRef: 'OPENCODE_GO_API_KEY',
|
|
@@ -71,7 +71,7 @@ const ADAPTERS = [
|
|
|
71
71
|
// Command Code:DSH 非内置提供方(pi-ai 注册表无 commandcode),只允许「添加自定义提供方」
|
|
72
72
|
// (customOnly),Key 只存插件私有库(settingsProviderKey: null → 凭证链跳过 DSH 模型设置)。
|
|
73
73
|
id: 'commandcode-credits',
|
|
74
|
-
displayName: 'Command Code
|
|
74
|
+
displayName: 'Command Code',
|
|
75
75
|
baseUrl: 'https://api.commandcode.ai',
|
|
76
76
|
usagePath: '/alpha/billing/credits',
|
|
77
77
|
subscriptionPath: '/alpha/billing/subscriptions',
|
|
@@ -80,6 +80,21 @@ const ADAPTERS = [
|
|
|
80
80
|
customOnly: true,
|
|
81
81
|
description: 'Command Code 订阅使用量(5小时/周窗口)+ 月度剩余额度(USD)',
|
|
82
82
|
},
|
|
83
|
+
{
|
|
84
|
+
// AMD Radeon Cloud(Model API):DSH 非内置提供方,只允许「添加自定义提供方」(customOnly),
|
|
85
|
+
// Key 只存插件私有库。实测可用端点 = {baseUrl}/usage(文档页 /api/profile/model-usage 404,见 tmp 调研)。
|
|
86
|
+
// 返回今日剩余额度(pts)+ 今日/近24h/近30天/累计汇总 + 按模型拆分;无周/月窗口。
|
|
87
|
+
// AMD Radeon Cloud 分国内 / 国际两个版本:本条目 = 中国版(developer.amd.com.cn);国际版
|
|
88
|
+
// baseUrl/端点不同,预留位置——后续接入时新增一个 amd-radeon-usage-intl 适配器条目即可。
|
|
89
|
+
id: 'amd-radeon-usage',
|
|
90
|
+
displayName: 'AMD Radeon Cloud (中国)',
|
|
91
|
+
baseUrl: 'https://developer.amd.com.cn/radeon/api/v1',
|
|
92
|
+
usagePath: '/usage',
|
|
93
|
+
defaultCredentialRef: 'RADEON_API_KEY',
|
|
94
|
+
settingsProviderKey: null,
|
|
95
|
+
customOnly: true,
|
|
96
|
+
description: 'AMD Radeon Cloud (中国) Model API 用量/余额(今日剩余 pts + 时间窗口汇总)',
|
|
97
|
+
},
|
|
83
98
|
]
|
|
84
99
|
|
|
85
100
|
/** 旧 provider id → 适配器 id(向后兼容 /api/provider-usage/opencode-go 与 query?provider=…)。 */
|
|
@@ -88,6 +103,9 @@ const LEGACY_PROVIDER_MAP = { 'opencode-go': 'usage-percent', 'deepseek-balance'
|
|
|
88
103
|
/** Command Code 混合卡适配器(模块级常量,避免每次查询重复 find)。 */
|
|
89
104
|
const COMMANDCODE_ADAPTER = ADAPTERS.find((a) => a.id === 'commandcode-credits') || null
|
|
90
105
|
|
|
106
|
+
/** AMD Radeon Cloud 余额卡适配器(模块级常量,避免每次查询重复 find)。 */
|
|
107
|
+
const AMD_RADEON_ADAPTER = ADAPTERS.find((a) => a.id === 'amd-radeon-usage') || null
|
|
108
|
+
|
|
91
109
|
function isLoopbackRequest(req) {
|
|
92
110
|
const addr = req.socket && req.socket.remoteAddress
|
|
93
111
|
if (addr !== '127.0.0.1' && addr !== '::1' && addr !== '::ffff:127.0.0.1') return false
|
|
@@ -385,6 +403,95 @@ function parseCommandCodeCredits(creditsBody, subBody) {
|
|
|
385
403
|
}
|
|
386
404
|
}
|
|
387
405
|
|
|
406
|
+
// ── AMD Radeon Cloud(v0.10 调研新增):余额+配额卡 ─────────────────────
|
|
407
|
+
// 官方接口(实测):GET {baseUrl}/usage → 今日剩余 pts + 四个时间段汇总 + 按模型拆分。
|
|
408
|
+
// 无周/月窗口(文档页 /api/profile/model-usage 404;接入以实测 /usage 为准,见 tmp 调研)。
|
|
409
|
+
// 数据形态对齐 Command Code 混合卡:主数字 = 今日剩余百分比(3 位小数向下取整),
|
|
410
|
+
// 副行 = 已用/限额 + 剩余(单位 pts,等价 USD,网页用 pts 表述),单日窗口进度条。
|
|
411
|
+
|
|
412
|
+
/** 今日剩余百分比:钳制 [0,100] 后保留 3 位小数向下取整(与 commandcodeMonthlyRemainingPct 同语义)。 */
|
|
413
|
+
function amdRadeonRemainingPct(limitUsd, remainingUsd) {
|
|
414
|
+
const limit = Number(limitUsd)
|
|
415
|
+
if (!Number.isFinite(limit) || !(limit > 0)) return null
|
|
416
|
+
const remaining = Number(remainingUsd)
|
|
417
|
+
if (!Number.isFinite(remaining)) return null
|
|
418
|
+
const pct = Math.max(0, Math.min(100, (remaining / limit) * 100))
|
|
419
|
+
return Math.floor(pct * 1000) / 1000
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** 把 /usage 响应换算成结构化结果(余额 + 单日窗口 + 时间段/按模型汇总透传)。 */
|
|
423
|
+
function parseAmdRadeonUsage(body) {
|
|
424
|
+
let data = body
|
|
425
|
+
if (typeof data === 'string') {
|
|
426
|
+
try { data = JSON.parse(data) } catch { return { error: 'bad-json' } }
|
|
427
|
+
}
|
|
428
|
+
const limitUsd = data && data.daily_cost_limit_usd
|
|
429
|
+
const usedUsd = data && data.daily_cost_used_usd
|
|
430
|
+
const remainingUsd = data && data.daily_cost_remaining_usd
|
|
431
|
+
// 文档说 502 时汇总字段全 0 且 status 说明原因;字段缺失视为不可用
|
|
432
|
+
if (limitUsd === undefined || limitUsd === null || usedUsd === undefined || usedUsd === null || remainingUsd === undefined || remainingUsd === null) {
|
|
433
|
+
return { error: 'no-usage' }
|
|
434
|
+
}
|
|
435
|
+
const toNum = (v) => { const n = Number(v); return Number.isFinite(n) ? n : null }
|
|
436
|
+
const limit = toNum(limitUsd)
|
|
437
|
+
const used = toNum(usedUsd)
|
|
438
|
+
const remaining = toNum(remainingUsd)
|
|
439
|
+
const remainingPct = amdRadeonRemainingPct(limit, remaining)
|
|
440
|
+
const usedPct = (limit !== null && used !== null && limit > 0) ? Math.max(0, Math.min(100, (used / limit) * 100)) : null
|
|
441
|
+
const nextResetAt = typeof data.daily_reset_at === 'string' && data.daily_reset_at ? data.daily_reset_at : null
|
|
442
|
+
const periodStartedAt = typeof data.period_started_at === 'string' && data.period_started_at ? data.period_started_at : null
|
|
443
|
+
|
|
444
|
+
// 时间段汇总(today / last_24_hours / last_30_days / all_time 同构)→ 透传原始字段
|
|
445
|
+
const windowOf = (name) => {
|
|
446
|
+
const w = data && data[name]
|
|
447
|
+
if (!w || typeof w !== 'object') return null
|
|
448
|
+
return {
|
|
449
|
+
requests: w.requests,
|
|
450
|
+
errors: w.errors,
|
|
451
|
+
totalTokens: w.total_tokens,
|
|
452
|
+
promptTokens: w.prompt_tokens,
|
|
453
|
+
completionTokens: w.completion_tokens,
|
|
454
|
+
reasoningTokens: w.reasoning_tokens,
|
|
455
|
+
cachedTokens: w.cached_tokens,
|
|
456
|
+
kvCacheHitRate: w.kv_cache_hit_rate,
|
|
457
|
+
cost: w.cost,
|
|
458
|
+
lastRequestAt: w.last_request_at,
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const extraParts = []
|
|
463
|
+
if (used !== null && limit !== null) extraParts.push('今日已用 ' + used.toFixed(3) + ' / ' + limit.toFixed(3) + ' pts')
|
|
464
|
+
if (remaining !== null) extraParts.push('今日剩余 ' + remaining.toFixed(3) + ' pts')
|
|
465
|
+
if (nextResetAt) extraParts.push('重置 ' + formatCountdown(nextResetAt))
|
|
466
|
+
if (data.rpm_limit !== undefined) extraParts.push('RPM ' + data.rpm_limit)
|
|
467
|
+
|
|
468
|
+
return {
|
|
469
|
+
planName: 'AMD Radeon Cloud (中国)',
|
|
470
|
+
remaining,
|
|
471
|
+
unit: 'pts',
|
|
472
|
+
used,
|
|
473
|
+
totalQuota: limit,
|
|
474
|
+
nextResetAt,
|
|
475
|
+
extra: extraParts.join(';'),
|
|
476
|
+
// 单日窗口:卡片只有一行进度条(对齐网页 "Today Used / Today Remaining / RPM Limit")
|
|
477
|
+
windows: {
|
|
478
|
+
daily: { usedPct, remainingPct, used, cap: limit, resetsAt: nextResetAt, periodStartedAt },
|
|
479
|
+
},
|
|
480
|
+
// 透传时间段汇总与按模型拆分(供副行/展开/本地统计对照)
|
|
481
|
+
periods: {
|
|
482
|
+
today: windowOf('today'),
|
|
483
|
+
last_24_hours: windowOf('last_24_hours'),
|
|
484
|
+
last_30_days: windowOf('last_30_days'),
|
|
485
|
+
all_time: windowOf('all_time'),
|
|
486
|
+
},
|
|
487
|
+
byModel: (Array.isArray(data.by_model) ? data.by_model : null),
|
|
488
|
+
recent: (Array.isArray(data.recent) ? data.recent : null),
|
|
489
|
+
cards: null,
|
|
490
|
+
isValid: true,
|
|
491
|
+
invalidMessage: null,
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
388
495
|
// ── 插件主体 ────────────────────────────────────────────────────────
|
|
389
496
|
|
|
390
497
|
export function apply(ctx, rawConfig) {
|
|
@@ -546,6 +653,9 @@ export function apply(ctx, rawConfig) {
|
|
|
546
653
|
totalQuota: value.totalQuota,
|
|
547
654
|
nextResetAt: value.nextResetAt,
|
|
548
655
|
monthly: value.monthly,
|
|
656
|
+
periods: value.periods,
|
|
657
|
+
byModel: value.byModel,
|
|
658
|
+
recent: value.recent,
|
|
549
659
|
extra: value.extra,
|
|
550
660
|
windows: value.windows,
|
|
551
661
|
cards: value.cards,
|
|
@@ -685,10 +795,14 @@ export function apply(ctx, rawConfig) {
|
|
|
685
795
|
return fail(cfg, state, 'parse', '接口响应不是有效 JSON', res.status)
|
|
686
796
|
}
|
|
687
797
|
|
|
688
|
-
const parsed = cfg.id === 'balance-json'
|
|
798
|
+
const parsed = cfg.id === 'balance-json'
|
|
799
|
+
? parseBalance(body)
|
|
800
|
+
: (AMD_RADEON_ADAPTER && cfg.id === AMD_RADEON_ADAPTER.id ? parseAmdRadeonUsage(body) : parseUsage(body))
|
|
689
801
|
if (parsed.error === 'no-usage') {
|
|
690
802
|
recordSnapshot(key, { attemptAt, httpStatus: res.status, error: 'no-usage' })
|
|
691
|
-
return fail(cfg, state, 'parse',
|
|
803
|
+
return fail(cfg, state, 'parse', (AMD_RADEON_ADAPTER && cfg.id === AMD_RADEON_ADAPTER.id)
|
|
804
|
+
? '没有找到 AMD Radeon Cloud (中国) 用量数据(daily_cost_*)'
|
|
805
|
+
: '没有找到 OpenCode Go 用量数据', res.status)
|
|
692
806
|
}
|
|
693
807
|
if (parsed.error === 'no-balance') {
|
|
694
808
|
recordSnapshot(key, { attemptAt, httpStatus: res.status, error: 'no-balance' })
|
package/package.json
CHANGED