dsh-composer-ux 0.10.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/CHANGELOG.md +82 -0
- package/README.md +25 -12
- package/lib/client.js +118 -35
- package/lib/client.js.map +2 -2
- package/lib/index.js +205 -17
- package/lib/index.js.map +4 -4
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,90 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [0.11.0] — 2026-09-29(节假日自动获取 + 金额浮层瘦身 + 官方价格页 URL 事故修复)
|
|
6
|
+
|
|
7
|
+
> 起因:用户重启到 0.10.0 后说"**图里这些说明放到设置页面,使点开胶囊变得更简洁**;**添加一个
|
|
8
|
+
> 自动检测国家法定节假日与星期天的功能**"。一问一答定下四件事:① 只搬"说明"三行,两行单价留在浮层;
|
|
9
|
+
> ② 节假日走**联网自动获取 + 内置兜底**(源:`holiday-cn`,数据带国务院办公厅通知原文链接);
|
|
10
|
+
> ③ **补班日照样算谷价**(官方原文说的是"周六、周日全天谷价",与 `dsh-cost-meter` 一致);
|
|
11
|
+
> ④ 复用现有"自动同步"那把开关,不新增开关。
|
|
12
|
+
> 顺带说明一点:**周末本来就是自动的**(0.10.0 就有,周六周日全天谷价),这次补的是"法定节假日"那一半。
|
|
13
|
+
|
|
14
|
+
### 修正(先看这条:0.10.0 的「同步官方价」当时已经坏了)
|
|
15
|
+
|
|
16
|
+
- **官方英文价格页在"不带结尾斜杠"的路径上开始返回另一页**(2026-09-29 真机复核时抓到):
|
|
17
|
+
`https://api-docs.deepseek.com/quick_start/pricing` 现在返回 **200 OK + 4.8 万字节的"快速开始"
|
|
18
|
+
内容、没有价格表**,于是 `parseOfficialPricingPage` 返回 `undefined`、同步直接报"抓官方价格页失败"。
|
|
19
|
+
好在纪律是"**抓不到就不覆盖本地价**",所以只是同步不工作,**没有把价格算错**(本地价目仍是 0.10.0
|
|
20
|
+
那份正确的快照)。修法两条:
|
|
21
|
+
1. 两个官方页 URL 都补上结尾斜杠(中文页本来就是 302 跳到带斜杠的路径,英文页则是**静默返回另一页**);
|
|
22
|
+
2. 新增 `officialPricingCandidates()`:每一页按"带斜杠 → 不带斜杠"依次尝试,**解析成功才算到手**
|
|
23
|
+
(只在抓不到/解析不出时换候选,绝不拿半份数据凑合)。站点以后再对调这两个形状,同步不用改代码
|
|
24
|
+
就能自愈 —— 有两条变异条目(`CL`/`CM`)守着它。
|
|
25
|
+
复核:改完后两页都解析得出,12 格价格与我们写死的现役档**逐格相同**(`node scripts/live-smoke.mjs`)。
|
|
26
|
+
|
|
27
|
+
### 新增
|
|
28
|
+
|
|
29
|
+
- **法定节假日自动获取(`src/holiday-sync.ts` + 宿主半同步路由)**。中国的法定节假日**算不出来**:
|
|
30
|
+
清明/端午/中秋走农历,放几天与哪天调休补班是国务院办公厅每年年底才公布的政策决定。所以本插件
|
|
31
|
+
的做法是"**日期表来自公开数据源,判定规则留在自己手里**":
|
|
32
|
+
- **数据源**:`NateScarlet/holiday-cn`(MIT)每年一个 `{year}.json`,字段
|
|
33
|
+
`{"name":"中秋节","date":"2026-09-25","isOffDay":true}`,并自带 `papers` 指向**国务院办公厅
|
|
34
|
+
通知原文**(2026 那份指到 `www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm`),可自行核对。
|
|
35
|
+
主用 GitHub raw、失败退 jsDelivr 镜像(同一份文件的两个入口)。
|
|
36
|
+
- **只取 `isOffDay:true`**:`isOffDay:false` 是**调休补班日**(2026 年就有 09-20 周日、10-10 周六),
|
|
37
|
+
官方公告写的是"**周六、周日**全天谷价",所以补班日**照样全天谷价** —— 把补班日当工作日算高峰
|
|
38
|
+
会让那两天的金额**翻倍**。这条是用户 2026-09-29 拍板的,变异条目 `CD` 守着它。
|
|
39
|
+
- **抓取范围 = 今年 + 明年**(按**北京**年判,跨年那一刻用 UTC 年会算错,变异条目 `CE`)。
|
|
40
|
+
2027 那份现在只有 `{"year":2027,"days":[]}`(国务院年底才发),**"还没公布"不是"失败"**:
|
|
41
|
+
界面说的是"20xx 年的安排还没公布",不是"网络坏了"。
|
|
42
|
+
- **优先级:你手填的 > 自动获取的 ∪ 内置表**。手填**整份覆盖**(你的意思不该被后台悄悄改掉);
|
|
43
|
+
自动那份与内置表**取并集**而不是替换 —— 自动获取只覆盖"今年+明年",到了 2027 年 1 月,2026 年
|
|
44
|
+
中秋/国庆那几天就不在里面了,拿它替换会让**2026 年 9 月的旧会话被重新按高峰价显示(2 倍)**。
|
|
45
|
+
- **开关复用**「自动同步」那把(默认仍**关**):同一个语义"这个插件可以自己出网",没必要两个开关。
|
|
46
|
+
打开后每个年份最多 **30 天**复核一次(进程启动先查一次 + 每 30 分钟查一次"到期没有");
|
|
47
|
+
也可以随时点设置页的「获取法定节假日」立即取一次(手动点击 = 明确的同意,不受 30 天窗口限制)。
|
|
48
|
+
- **纪律**:抓不到就什么都不改(两个入口都失败 → `ok:false`,本地表原样不动);抓到后写设置时
|
|
49
|
+
立刻 `invalidateMoney()`(不然后台取回新表、峰谷却仍按旧表判)。
|
|
50
|
+
- **设置页「计价说明」块**:把金额浮层里那三行静态说明搬了过来 —— 刊例价快照日期、价格档机制
|
|
51
|
+
("每笔用量按发生时刻的档结算")、峰谷判定(工作日 09:00–12:00 / 14:00–18:00 为高峰、不含法定
|
|
52
|
+
节假日、周末与节假日全天谷价)、非 DeepSeek 口径(未含中转加价、以各家账单为准)。
|
|
53
|
+
节假日那块还多了"当前生效:N 个日期 —— 来源:自定义 / 自动获取(时间)/ 内置"以及可展开的
|
|
54
|
+
**生效日期清单**。
|
|
55
|
+
|
|
56
|
+
### 变更
|
|
57
|
+
|
|
58
|
+
- **金额浮层瘦身**(用户要的"点开胶囊更简洁"):原来最后三行的去留**各不相同**:
|
|
59
|
+
- **峰谷判定段**:设置页本来就有一份同义文字 → 从浮层删掉(纯去重);
|
|
60
|
+
- **刊例价快照行**:整行搬去设置页;"这份价是**你自己填的**"缩成单价行上的 `· 已自定义` 小标
|
|
61
|
+
(只在你覆盖过价时出现,默认不占字);
|
|
62
|
+
- **价格档说明**:改成**只在非默认时出现** —— 本会话用到的档 ≠ 当前生效的档才显示。这条不能
|
|
63
|
+
简单删:跨了 9-10 调价的会话,浮层上的单价是今天的价、金额却是当时的价,不说反而是误导。
|
|
64
|
+
- 浮层现在只剩:各 route 分列、合计、两档小计、三分项、缓存命中率、**峰谷状态行**、**两行单价**。
|
|
65
|
+
- 设置页「金额」卡从五块变六块(多「计价说明」);「同步价目」改名「同步」,多第三个按钮
|
|
66
|
+
「获取法定节假日」,自动同步开关的文案改成「自动同步(价格每天一次、节假日每 30 天复核)」。
|
|
67
|
+
- 节假日输入框改成**只放手填那一份**(留空 = 用自动获取/内置),并给了灰字说明 —— 以前它会把
|
|
68
|
+
内置表预填进去,让"留空 = 用默认"这件事看不出来。
|
|
69
|
+
|
|
70
|
+
### 验证
|
|
71
|
+
|
|
72
|
+
- `npm test`:**18 个套件 / 1736 条全绿**(新增 `test/holiday-sync.mjs` 86 条:解析、脏输入、
|
|
73
|
+
北京年边界、开关门控、并集上限、优先级、镜像兜底、失败不改动,以及**真宿主半**的路由 / 用量路由 /
|
|
74
|
+
自动 tick 端到端)。
|
|
75
|
+
- 变异测试 `node test/mutation-guards.mjs`:**89/89 全部被咬住**(新增 `CD`–`CM` 共 10 条)。
|
|
76
|
+
- `node scripts/live-smoke.mjs`:官方两页 12 格价格与现役档逐格相同(URL 修好后恢复通过);
|
|
77
|
+
节假日源实测 2026 年拿到 33 天、**补班日不在表里**、内置那 10 天口径一致;余额端点 401。
|
|
78
|
+
- 真机:本机 profile 装的 0.11.0 由用户重启后生效(本版**有宿主半改动**,必须重启)。
|
|
79
|
+
|
|
5
80
|
## [0.10.0] — 2026-09-29(节假日 / 峰谷提醒 / 余额 / 官方价同步 / 非 DeepSeek 定价 / 价格历史档)
|
|
6
81
|
|
|
82
|
+
> **发布记录(2026-09-29)**:`npm publish` → **dsh-composer-ux@0.10.0**(shasum `701cbed53887a7ba75dd94206997f89c1720fa7c`);
|
|
83
|
+
> git tag **`v0.10.0`**(提交 `38d0d0d`,与 npm 产物内容一致)与补打的 **`v0.9.1`**(`77cc306`)已推送;
|
|
84
|
+
> GitHub Release:[v0.10.0](https://github.com/fangwen9527/dsh-composer-ux/releases/tag/v0.10.0)。
|
|
85
|
+
> npm 上从 **0.6.2** 直接跳到这里(0.7.0~0.9.1 未在 npm 发布,内容都在本版里);
|
|
86
|
+
> 本机 profile 已从"钉 git commit"改成从 **npm 装 0.10.0**,组合预检 `[A]` 干净。
|
|
87
|
+
> 注意:**本版有宿主半改动,必须重启 DSH 才会加载**。
|
|
88
|
+
|
|
7
89
|
> 起因:用户要求"联网搜一下最新峰谷价格,解析 `dsh-context` 与 `dsh-cost-meter` 这两个插件
|
|
8
90
|
> 怎么算钱,与我们的对比,并补上我们没有的功能"。一问一答定下范围:**A 节假日、B 峰谷提醒、
|
|
9
91
|
> C 余额、D 官方价同步、E 非 DeepSeek 定价**;随后他又选了 **F 价格历史档**("旧账要按当时的价
|
package/README.md
CHANGED
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
> built-in cache-hit percentage with **three decimals** (keeping upstream's "never round a partial hit up to 100%"
|
|
12
12
|
> rule), a **cost capsule** whose peak/off-peak prices you can edit **per model** in settings (empty field =
|
|
13
13
|
> official list price; peak/off-peak is decided by **each usage event's own timestamp**, not by when you look
|
|
14
|
-
> at the panel),
|
|
14
|
+
> at the panel), with **Chinese public holidays fetched automatically** (State-Council schedule via
|
|
15
|
+
> `holiday-cn`, GitHub raw + jsDelivr mirror, built-in table as offline fallback; your own date list always
|
|
16
|
+
> wins), plus a **one-click "restart DSH"** button
|
|
15
17
|
> in the settings-card header (market-proven self-restart: detached node helper, port-release wait,
|
|
16
18
|
> hidden-console relaunch, same-origin fence, boot-id reload).
|
|
17
|
-
> Install with `dsh plugin --profile <name> add
|
|
18
|
-
> ships in this repository, so there is **no build step and no build authorization**. License: MIT.
|
|
19
|
+
> Install with `dsh plugin --profile <name> add dsh-composer-ux` (npm) — the built `lib/`
|
|
20
|
+
> ships in the package **and** in this repository, so there is **no build step and no build authorization**. License: MIT.
|
|
19
21
|
|
|
20
22
|
DeepSeek Harness Web 输入体验增强插件:
|
|
21
23
|
|
|
@@ -250,26 +252,36 @@ Windows 上 DSH 给模型的终端工具是 **PowerShell**(工具名 `pwsh`)
|
|
|
250
252
|
|
|
251
253
|
## 金额(输入框下方显示本会话费用 + 设置页可改峰谷单价)
|
|
252
254
|
|
|
253
|
-
- **设置页位置**:第 8
|
|
255
|
+
- **设置页位置**:第 8 张卡「金额」(**没有卡级开关**:胶囊常驻显示)。卡里分六块:**单价**、**节假日**、**峰谷提醒**、**账号余额**、**同步**、**计价说明**。
|
|
254
256
|
- **单价**:按模型改单价(未缓存输入 / 缓存命中 / 输出,元每 1M tokens)。**DeepSeek 系模型有高峰 / 空闲两档**(内置 `deepseek-flash`、`deepseek-v4-pro` 两行常显,官方现役就这两个;`deepseek-v4-flash` 等旧名是别名,不单列),**非 DeepSeek 模型只有一档「平坦价」**(它们没有峰谷概念,摆两档会让人以为谷价时段还能再省一半)。下面一行「再加一个模型」可以填**任意模型名**(中转/自建路由的名字),同名模型在不同渠道价不同时写成 **`provider:model`**(例如 `opencode:gpt-5.6-luna`)。
|
|
255
257
|
- **留空=沿用官方价**:输入框里的灰字占位就是官方价(DeepSeek 行来自官方价目表)。清空的传播是往上收的:一档三项全空 → 那一档消失;一个模型全部档位都空 → 那一整行消失;整表全空 → 设置里这个键直接删掉。
|
|
256
258
|
- **非法文本不静默清空**:`1,02`、`2元`、`-1` 会留在框里**标红**(`parsePriceText` 三态),不写进设置 —— 把它当"清空"的话,价格会悄悄回到官方价,而用户以为改成功了。
|
|
257
259
|
- 写入是**合并 + 认回声**:连改几格只发一次设置写入(300ms 合并);用规范化比对分辨"设置里来的新值"与"自己刚写进去的回声",否则回声会把还没写完的第二格编辑冲掉。「恢复默认」会清掉这张表与节假日/提醒/余额开关,但**不清同步来的价格档**(那是历史账单)。
|
|
258
260
|
- 改价**即时生效**(胶囊与明细页当场跟着变),不用刷新页面、不用重启。
|
|
259
|
-
- **长什么样**:不点击时是输入框下方一颗极简胶囊(`¥0.42`,与官方那行统计**同排、排在其后**,order 100);点开后是贴在它上方的浮层 —— 各 route 的 token 与花费、合计、**高峰档 / 空闲档各自的小计**、三分项(未缓存输入 / 缓存命中 / 输出)各自的 token
|
|
261
|
+
- **长什么样**:不点击时是输入框下方一颗极简胶囊(`¥0.42`,与官方那行统计**同排、排在其后**,order 100);点开后是贴在它上方的浮层 —— 各 route 的 token 与花费、合计、**高峰档 / 空闲档各自的小计**、三分项(未缓存输入 / 缓存命中 / 输出)各自的 token 数与花费、缓存命中率、**峰谷状态行**(`空闲档 · 2 小时 15 分钟后转高峰`)、**两档生效单价**。
|
|
262
|
+
- **0.11.0 起浮层只留"数字 + 状态"**:原来最后三行静态说明(刊例价快照行 / 价格档段 / 峰谷判定段)搬去设置页的「计价说明」块。三行的去留各不相同:**峰谷判定段**在设置页本来就有一份同义文字,直接删(纯去重);**快照行**整行搬走,但"这份价是你自己填的"缩成单价行上的 `· 已自定义` 小标(只在你覆盖过价时出现);**价格档段**改成**只在非默认时出现** —— 本会话用到的档 ≠ 当前生效的档才显示。最后这条不能简单删:跨了 9-10 调价的会话,浮层上的单价是今天的价、金额却是当时的价,不说明反而是误导。用户 2026-09-29 的原话是"图里这些说明放到设置页面,使点开胶囊变得更简洁"。
|
|
260
263
|
- **字号与亮度照抄官方那颗胶囊,不自己定**:文字大小/行高取官方 `StatsPills.module.css` 里 **`.root`** 的两条(`calc(var(--dsh-content-font-size-secondary, 13px) - 1px)` 与 `calc(20px + var(--dsh-content-font-delta-secondary, 0px))`),亮度取 `.pill` 的"静止 `label-tertiary`、hover/展开 `label-secondary`"。**坑**:那两条在 `.root` 上,不在 `.pill` 上 —— `.pill` 里的 `font: inherit` 只是为了抵消 button 的 UA 字体;本条目是同一槽位里的另一条记录,不在那颗 `.root` 里,只写 `font: inherit` 会继承输入框那一层(默认 14px),真机上看就是"插件输入框下方的字比官方的大"(2026-09-28 用户反馈)。所以这里显式写 `.root` 的两条,并**不用 `font:` 简写**(简写会把字号重置回继承)。
|
|
261
264
|
- **为什么是浮层而不是就地展开**:输入卡片会裁掉溢出内容,官方那几颗胶囊(ContextMeter、时间胶囊)也都是浮层;这里用 React portal 挂到 `document.body`,位置由胶囊的视口矩形算出,点别处或按 Esc 关闭。
|
|
262
265
|
- **钱是怎么算的**:`未缓存输入 × miss价 + 缓存命中 × hit价 + 输出 × out价`(每 1M tokens)。`cacheWriteTokens` **不单独计价**(官方价表只有"缓存命中/未命中"两行输入价,且实测本机投影里恒为 0,所以它只进"计费输入"的显示、不进费用)。**峰谷按每笔用量真正发生的时间判定**,高峰价是空闲价的 2 倍;用户覆盖价由设置页「金额」栏提供。
|
|
263
|
-
- **峰谷规则(0.10.0 补全)**:北京时间**工作日** 09:00–12:00、14:00–18:00 为高峰(UTC 01–04、06–10);**中国法定节假日全天谷价**(官方规则明写"不含法定节假日");**周末全天谷价**——但注意这条是 2026-08-23(周日)00:00 起才生效的,**在那之前的周六周日仍有高峰时段**(2026-08-22
|
|
266
|
+
- **峰谷规则(0.10.0 补全)**:北京时间**工作日** 09:00–12:00、14:00–18:00 为高峰(UTC 01–04、06–10);**中国法定节假日全天谷价**(官方规则明写"不含法定节假日");**周末全天谷价**——但注意这条是 2026-08-23(周日)00:00 起才生效的,**在那之前的周六周日仍有高峰时段**(2026-08-22 那个周六就是),所以历史账要按当时的规则算。**调休补班的周末仍按谷价**(官方说的是"周六、周日全天谷价",2026-10-10 那个周六也算谷价),所以自动获取只收"放假"那几天。
|
|
267
|
+
- **法定节假日自动获取(0.11.0)**:中国的法定节假日**算不出来**(清明/端午/中秋走农历,放几天、哪天调休补班是国务院办公厅每年年底才公布的政策决定),所以本插件的做法是"**日期表来自公开数据源,判定规则留在自己手里**":
|
|
268
|
+
- **数据源**:[`NateScarlet/holiday-cn`](https://github.com/NateScarlet/holiday-cn)(MIT)每年一个 `{year}.json`,条目形如 `{"name":"中秋节","date":"2026-09-25","isOffDay":true}`,并自带 `papers` 字段指向**国务院办公厅通知原文**(2026 那份指到 `www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm`)—— 数据可自行核对。主用 GitHub raw,失败自动退 **jsDelivr 镜像**(同一份文件的两个入口)。
|
|
269
|
+
- **覆盖范围**:**今年 + 明年**(按**北京**年判)。次年安排通常在前一年 11 月前后公布,所以**国务院一公布就会被自动取回**,不用等插件发版。2027 那份现在只有 `{"year":2027,"days":[]}` —— "还没公布"与"抓不到"是**两种不同的话**,界面分别说"20xx 年的安排还没公布"和"抓取失败"。
|
|
270
|
+
- **优先级:你手填的 > 自动获取的 ∪ 内置表**。手填**整份覆盖**(你的意思不该被后台悄悄改掉);自动那份与内置表**取并集**而不是替换 —— 自动获取只覆盖"今年+明年",到了 2027 年 1 月,2026 年中秋/国庆那几天就不在里面了,拿它替换会让**2026 年 9 月的旧会话被重新按高峰价显示(整整 2 倍)**。内置表(`DEFAULT_PEAK_HOLIDAYS`,2026 中秋 09-25~27、国庆 10-01~07)永远在兜底,离线也不会瞎算。
|
|
271
|
+
- **开关复用**「自动同步」那把(默认仍**关**):同一个语义"这个插件可以自己出网",没必要再加一个开关。打开后每个年份最多 **30 天**复核一次(进程启动先查一次 + 每 30 分钟查一次"到期没有"),没有到期的年份**一个请求都不发**。也可以随时点设置页「同步」里的「获取法定节假日」立即取一次(手动点击 = 明确的同意,不受 30 天窗口限制)。
|
|
272
|
+
- **纪律**:抓不到就什么都不改(两个入口都失败 → 报失败、本地表原样不动);抓到并写入设置后立刻 `invalidateMoney()`(不然后台取回新表、峰谷却仍按旧表判 —— 折叠结果里固化的是判定当时的事实)。
|
|
273
|
+
- **设置页看得见什么**:节假日那块显示「当前生效:N 个日期 —— 来源:自定义 / 自动获取(含获取时间)/ 内置」,并有一个可展开的**生效日期清单**;「同步」区显示"法定节假日上次获取:… (已有 2026、2027 年)"。输入框里**只放你手填的那一份**,留空才代表"用自动获取的"。卡片的标题行概览也会写 `节假日自动 N 天`。
|
|
264
274
|
- **价格历史档:旧账按当时的价固定(0.10.0)**:官方 2026-09-10 12:00(北京)调过 Flash 的价(未缓存输入 0.22→0.15、输出 0.66→0.60、命中 0.007→0.003,美元/1M)。如果一律用"当前价"重算,8 月跑的会话金额会跟着变、跟当时的真实账单对不上。所以价目表按**生效时刻**分档(`legacy` 峰谷制之前 / `peak-2026-08` / `flash-2026-09-10`),折叠时给每条用量打上那一刻的档位 id,route key 因此多一维:同一模型在调价前后是**两条**分列,各按当时的价结算。Pro 那次**没调价**(腾讯云公告只列了 Flash 两个型号,官方页今天仍单列 Pro 价),所以它两档同值。
|
|
265
275
|
- **峰谷为什么必须按事件时间判(0.9.1 修的既有缺陷)**:官方按**请求发生时刻**计费,而 0.8.0 拿"你打开面板的那一秒"当所有用量的时刻 —— 昨晚(空闲档)跑的会话今天上午 10 点看,整份会按高峰价显示,差 2 倍而屏幕上只是个数字。现在宿主半折叠时用每条事件的 `time` 判档、按 `(provider, model, 档位, 价格档)` 拆桶,**同一步的替换增量沿用该步第一次判定的档**(否则一次跨过 09:00 的请求会被拆成两档、凭空多出一个"高峰用量");事件既没有 `request/header` 时间、自己也没有 `time` 时,判定函数收到 `NaN`,宿主半退回"现在"(=旧行为),绝不静默判成空闲档。
|
|
266
276
|
- **峰谷提醒(0.10.0)**:明细页常显一行「现在哪一档、还有多久切换」(例如 `空闲档 · 2 小时 15 分钟后转高峰`,因节假日/周末而谷价时会写明原因),胶囊的 `title` 也带上;设置里可调**提前几分钟**(1–60,默认 5)、**进峰前/离峰前**分别提不提醒,以及要不要额外发**浏览器系统通知**(需要授权;去重放在**模块级**按切换点记 —— 放组件里会因为设置一变、组件重挂而连发几条同样的通知)。相位规则与宿主半**同源**(节假日表由 `/composer-ux/usage` 回给客户端),不会出现"胶囊说还有 3 分钟进峰、面板说不是"。
|
|
267
277
|
- **账号余额(0.10.0)**:查官方 `GET https://api.deepseek.com/user/balance`。**API Key 只在宿主半**读:从 `llm-deepseek` 那一行的 `apiKeyEnv`(默认 `DEEPSEEK_API_KEY`)经 `credentials.resolve()` 取,与官方适配器同一条路,浏览器拿不到。**安全底线**:端点白名单只放行 `api.deepseek.com`(拒子域名、伪装域、`http://`、非 443 端口),baseURL 被指向第三方时**一个请求都不发**、也**不把 baseURL 原文回给浏览器**(只回主机名)。余额总额用分项相加(`granted + topped_up`,不用平台自己的 `total_balance`);拿不准就不显示(不显示 0、也不显示旧值)。
|
|
268
|
-
-
|
|
278
|
+
- **一键同步(0.10.0 两条路,0.11.0 加第三条)**:卡里三个按钮,代价差两个数量级所以分开:
|
|
269
279
|
- **同步官方价**:抓官方中英文两页(各约 24 KB)解析成人民币/美元两列,**只有和当前档不同才新增一个价格档**(原地改档 = 把历史账重算)。解析器对着真页面夹具逐项钉住(`test/official-pricing.mjs`,45 条)。
|
|
280
|
+
- ⚠️ **2026-09-29 事故与修法**:官方英文价格页在**不带结尾斜杠**的路径上开始返回**另一页**(200 OK、4.8 万字节的"快速开始"内容、没有价格表),于是同步直接报失败。好在纪律是"抓不到就不覆盖本地价",**只是同步不工作、没有算错钱**。修法:两个 URL 都补结尾斜杠,并新增 `officialPricingCandidates()` —— 每页按"带斜杠 → 不带斜杠"依次试,**解析成功才算到手**;站点以后再对调两个形状,同步不用改代码就能自愈(变异条目 `CL`/`CM`)。
|
|
270
281
|
- **同步第三方价目**:抓 [models.dev](https://models.dev) 的 `api.json`(**5.2 MB**、215 个 provider、7831 个模型),压成约 **450 KB** 落 `$DSH_HOME/storages/composer-ux/prices.json`(设置文档里只留"什么时候同步的、多少条",不然 settings.yaml 要被撑大)。models.dev 里的 DeepSeek 行**整块丢掉** —— 它只有平坦的谷价、没有峰谷与历史档语义,留着迟早被谁误用成"DeepSeek 单价",结果是所有峰价被静默算成谷价。
|
|
271
|
-
-
|
|
272
|
-
-
|
|
282
|
+
- **获取法定节假日**(0.11.0):抓 `holiday-cn` 的"今年 + 明年"两个 JSON,只收 `isOffDay:true`。手动点击 = 明确的同意,不受 30 天复核窗口限制。
|
|
283
|
+
- **自动同步**(默认**关**):勾上后宿主半每天最多自动抓一次官方价格页,并**每个年份最多 30 天复核一次节假日**(进程启动先查一次 + 每 30 分钟查一次"到期没有")。"该不该出网"由纯函数判定(`autoSyncDue` / `holidaySyncDue`):开关不是真 `true`、时间读不到、距上次成功不够久 —— 都不发请求。失败只写日志,界面仍显示上次成功的时间。
|
|
284
|
+
- 三条都守同一条纪律:**抓失败绝不覆盖本地数据**(网络抛错 / 非 2xx / 正文过短 / 只有一页成功 / 节假日两个入口都失败,各种情形都有断言)。
|
|
273
285
|
- **写完价目要立刻生效,靠的是"写的人通知",不是设置变更事件**:0.1.7 的 `settings/document-updated` 只在 `describe()` 里比对 raw 变化后发出,而我们自己 `mutate` 写设置时并不调 `describe()` —— 设置页开着时会被界面刷新顺带触发,**设置页没开着**(例如后台的自动同步跑完)就不会发;而折叠缓存按 `seq` 去重、改规则不会重折旧事件,金额会**静静地停在旧价格档**上、界面上看不出。所以宿主半加了模块级 `moneyInvalidators` 注册表:用量路由登记"重读规则 + 作废价目缓存 + 作废折叠缓存",两条同步路径写完设置直接调 `invalidateMoney()`,事件只作补充。
|
|
274
286
|
- **内置第三方价目快照(0.10.0)**:`src/provider-prices.ts`(**生成**的,别手改:`node scripts/gen-provider-prices.mjs <models.dev-api.json>`)收了 **11 个 provider / 346 个模型**,快照日期写在文件头。**没点过同步时**就是非 DeepSeek 模型的兜底价;点过一次「同步第三方价目」后最新数据会盖住同名条目,界面分别标明"内置快照价"还是已同步。查价优先级:**用户覆盖价 > 已同步价目 > 内置快照 > 未定价**。
|
|
275
287
|
- **非 DeepSeek 模型定价(0.10.0)**:按 `(provider, model)` 查价 —— 精确 provider → `PROVIDER_ALIASES` 别名(`deepseek-official`→`deepseek`、`kimi-coding`→`moonshotai`…)→ **按模型 id 全局唯一匹配**(`glm-5` 在两家都有的价时**拒绝猜**)。**认不出价就说"未定价"**(单价全 0,明细页写明"去同步第三方价目或给这行填个价"),**不再把 DeepSeek 的 flash 价静默套到第三方模型头上** —— 编一个看着合理的假数字,比承认不知道更糟。
|
|
@@ -320,7 +332,7 @@ dsh-composer-ux/
|
|
|
320
332
|
├── build.mjs # esbuild 构建:lib/index.js(Host)+ lib/client.js(浏览器),并做发行后处理
|
|
321
333
|
├── scripts/
|
|
322
334
|
│ ├── gen-provider-prices.mjs # 从 models.dev 的 api.json 生成 src/provider-prices.ts(内置第三方价目快照)
|
|
323
|
-
│ ├── live-smoke.mjs # 手动联网复核:官方页 / models.dev /
|
|
335
|
+
│ ├── live-smoke.mjs # 手动联网复核:官方页 / models.dev / 余额端点 / 节假日数据源(只读;不进 npm test)
|
|
324
336
|
│ └── dsh-shape-check.mjs # 手动形状核对:我们依赖的宿主服务名/方法/事件是否还在(对着 DSH 源码检;只读)
|
|
325
337
|
├── src/
|
|
326
338
|
│ ├── host.ts # Host 半:settings namespace + 请求头镜像 + 「默认终端」+ 金额三条路由(用量/价目同步/余额)+ 「重启 DSH」
|
|
@@ -330,6 +342,7 @@ dsh-composer-ux/
|
|
|
330
342
|
│ ├── usage-fold.ts # 金额:会话事件按 (provider, model, 峰谷档, 价格档) 归因折叠 + 增量缓存(零 import,宿主半用)
|
|
331
343
|
│ ├── official-pricing.ts # 金额:官方价格页 HTML → 人民币/美元两列价(真页面夹具逐项钉住,零 import)
|
|
332
344
|
│ ├── price-sync.ts # 金额:抓官方两页合成价格档 + models.dev 压成第三方价目 + 落盘 + autoSyncDue(宿主半,允许 node API)
|
|
345
|
+
│ ├── holiday-sync.ts # 金额:法定节假日自动获取(holiday-cn 今年+明年 → 日期表;补班日不收;到期判定/镜像兜底/失败不改动)
|
|
333
346
|
│ ├── provider-prices.ts # 金额:内置第三方价目**快照**(生成物,11 provider / 346 模型;由 scripts/gen-provider-prices.mjs 生成)
|
|
334
347
|
│ ├── balance.ts # 金额:官方余额响应消毒 + 查询端点白名单(零 import,两半共用)
|
|
335
348
|
│ ├── client.tsx # Browser 半:设置页 + 菜单浮层 + 拦截器
|
|
@@ -384,8 +397,8 @@ dsh-composer-ux/
|
|
|
384
397
|
|
|
385
398
|
```sh
|
|
386
399
|
node build.mjs # 产出 lib/index.js + lib/client.js
|
|
387
|
-
npm test #
|
|
388
|
-
node test/mutation-guards.mjs # 手动跑:变异测试,证明那套护栏真的在咬人(
|
|
400
|
+
npm test # 18 个套件;当前 1736 passed, 0 failed(2026-09-29 实测)
|
|
401
|
+
node test/mutation-guards.mjs # 手动跑:变异测试,证明那套护栏真的在咬人(89 条,须单独跑)
|
|
389
402
|
node test/settings-render.mjs # 已进 npm test:把设置页真渲染成 HTML,断言版式与互斥显示、以及"非默认设置"下的「金额」卡(78 条)
|
|
390
403
|
node test/cost-panel-render.mjs # 已进 npm test:把「金额浮层」真渲染成 HTML,断言分列 / 峰谷行 / 未定价 / 内置快照价 / 明文没混进 markdown 记号(19 条)
|
|
391
404
|
node scripts/live-smoke.mjs # 手动跑:**联网复核**(官方页 vs 写死的价目表逐格对比 / models.dev vs 内置快照逐条对比 / 余额端点白名单与状态码);只读,不写任何文件
|
package/lib/client.js
CHANGED
|
@@ -448,6 +448,20 @@ function parseHolidays(raw) {
|
|
|
448
448
|
if (dates.length === 0) return void 0;
|
|
449
449
|
return dates.slice(0, 400);
|
|
450
450
|
}
|
|
451
|
+
function effectiveHolidays(manual, auto) {
|
|
452
|
+
const manualDays = parseHolidays(manual) ?? [];
|
|
453
|
+
const autoDays = parseHolidays(auto) ?? [];
|
|
454
|
+
const manualCount = manualDays.length;
|
|
455
|
+
const autoCount = autoDays.length;
|
|
456
|
+
if (manualCount > 0) {
|
|
457
|
+
return { days: manualDays, source: "manual", autoCount, manualCount };
|
|
458
|
+
}
|
|
459
|
+
if (autoCount === 0) {
|
|
460
|
+
return { days: DEFAULT_PEAK_HOLIDAYS, source: "builtin", autoCount, manualCount };
|
|
461
|
+
}
|
|
462
|
+
const merged = [.../* @__PURE__ */ new Set([...DEFAULT_PEAK_HOLIDAYS, ...autoDays])].sort().slice(-400);
|
|
463
|
+
return { days: merged, source: "auto", autoCount, manualCount };
|
|
464
|
+
}
|
|
451
465
|
function isPeakAt(at, options = {}) {
|
|
452
466
|
const ms = typeof at === "number" ? at : at.getTime();
|
|
453
467
|
if (!Number.isFinite(ms)) return false;
|
|
@@ -566,6 +580,9 @@ function eraAt(timeMs, extra) {
|
|
|
566
580
|
}
|
|
567
581
|
return found;
|
|
568
582
|
}
|
|
583
|
+
function eraIdAt(timeMs, extra) {
|
|
584
|
+
return eraAt(timeMs, extra).id;
|
|
585
|
+
}
|
|
569
586
|
function eraById(id, extra) {
|
|
570
587
|
const eras = allEras(extra);
|
|
571
588
|
const key = typeof id === "string" ? id : "";
|
|
@@ -998,6 +1015,7 @@ var TERMINAL_ENABLED_FIELD = "terminalEnabled";
|
|
|
998
1015
|
var STATS_ENABLED_FIELD = "statsEnabled";
|
|
999
1016
|
var PRICE_OVERRIDES_FIELD = "priceOverrides";
|
|
1000
1017
|
var PEAK_HOLIDAYS_FIELD = "peakHolidays";
|
|
1018
|
+
var HOLIDAY_SOURCE_LABEL = "holiday-cn\uFF08\u6570\u636E\u53D6\u81EA\u56FD\u52A1\u9662\u529E\u516C\u5385\u901A\u77E5\uFF09";
|
|
1001
1019
|
var PEAK_ALERT_FIELD = "peakAlert";
|
|
1002
1020
|
var PRICE_AUTO_SYNC_FIELD2 = "priceAutoSync";
|
|
1003
1021
|
var BALANCE_ENABLED_FIELD = "balanceEnabled";
|
|
@@ -1333,14 +1351,27 @@ function parseSyncedPrices(raw) {
|
|
|
1333
1351
|
const modelsDevAt = stamp("modelsDevAt");
|
|
1334
1352
|
const modelsDevCount = count2("modelsDevCount");
|
|
1335
1353
|
const eras = parsePriceEras(row2.eras);
|
|
1354
|
+
const holidays = parseHolidays(row2.holidays);
|
|
1355
|
+
const holidaysAt = stamp("holidaysAt");
|
|
1356
|
+
const holidayYears = parseHolidayYears(row2.holidayYears);
|
|
1336
1357
|
const out = {
|
|
1337
1358
|
...fetchedAt === void 0 ? {} : { fetchedAt },
|
|
1338
1359
|
...eras === void 0 ? {} : { eras },
|
|
1339
1360
|
...modelsDevAt === void 0 ? {} : { modelsDevAt },
|
|
1340
|
-
...modelsDevCount === void 0 ? {} : { modelsDevCount }
|
|
1361
|
+
...modelsDevCount === void 0 ? {} : { modelsDevCount },
|
|
1362
|
+
...holidays === void 0 ? {} : { holidays },
|
|
1363
|
+
...holidaysAt === void 0 ? {} : { holidaysAt },
|
|
1364
|
+
...holidayYears === void 0 ? {} : { holidayYears }
|
|
1341
1365
|
};
|
|
1342
1366
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
1343
1367
|
}
|
|
1368
|
+
function parseHolidayYears(raw) {
|
|
1369
|
+
if (!Array.isArray(raw)) return void 0;
|
|
1370
|
+
const years = [...new Set(raw.filter(
|
|
1371
|
+
(item) => typeof item === "number" && Number.isInteger(item) && item >= 2e3 && item <= 2100
|
|
1372
|
+
))].sort((left, right) => left - right);
|
|
1373
|
+
return years.length === 0 ? void 0 : years.slice(0, 12);
|
|
1374
|
+
}
|
|
1344
1375
|
function sanitizeSettings(value) {
|
|
1345
1376
|
const source = typeof value === "object" && value !== null ? value : {};
|
|
1346
1377
|
const asString = (field) => {
|
|
@@ -3181,7 +3212,7 @@ function usePriceSync(onDone) {
|
|
|
3181
3212
|
if (busyRef.current) return;
|
|
3182
3213
|
busyRef.current = true;
|
|
3183
3214
|
setBusy(target);
|
|
3184
|
-
setNote(target === "official" ? "\u6B63\u5728\u6293\u5B98\u65B9\u4EF7\u683C\u9875\u2026" : "\u6B63\u5728\u6293 models.dev\uFF08\u7EA6 5 MB\uFF0C\u7A0D\u7B49\uFF09\u2026");
|
|
3215
|
+
setNote(target === "official" ? "\u6B63\u5728\u6293\u5B98\u65B9\u4EF7\u683C\u9875\u2026" : target === "holidays" ? "\u6B63\u5728\u6293\u6CD5\u5B9A\u8282\u5047\u65E5\uFF08\u6BCF\u5E74\u4E00\u4E2A\u51E0 KB \u7684 JSON\uFF09\u2026" : "\u6B63\u5728\u6293 models.dev\uFF08\u7EA6 5 MB\uFF0C\u7A0D\u7B49\uFF09\u2026");
|
|
3185
3216
|
setOk(true);
|
|
3186
3217
|
void fetch(SYNC_API_PATH, {
|
|
3187
3218
|
method: "POST",
|
|
@@ -3285,7 +3316,7 @@ function CostCardBody(props) {
|
|
|
3285
3316
|
const [name2, setName] = import_react5.default.useState("");
|
|
3286
3317
|
const [addNote, setAddNote] = import_react5.default.useState("");
|
|
3287
3318
|
const [pending, setPending] = import_react5.default.useState([]);
|
|
3288
|
-
const [holidayText, setHolidayText] = import_react5.default.useState(() => (settings.peakHolidays ??
|
|
3319
|
+
const [holidayText, setHolidayText] = import_react5.default.useState(() => (settings.peakHolidays ?? []).join("\n"));
|
|
3289
3320
|
const [holidayNote, setHolidayNote] = import_react5.default.useState("");
|
|
3290
3321
|
const lastWritten = import_react5.default.useRef(settings.priceOverrides);
|
|
3291
3322
|
const tableRef = import_react5.default.useRef(table);
|
|
@@ -3300,7 +3331,7 @@ function CostCardBody(props) {
|
|
|
3300
3331
|
tableRef.current = settings.priceOverrides;
|
|
3301
3332
|
setTable(settings.priceOverrides);
|
|
3302
3333
|
}, [settings.priceOverrides]);
|
|
3303
|
-
const savedHolidayText = (settings.peakHolidays ??
|
|
3334
|
+
const savedHolidayText = (settings.peakHolidays ?? []).join("\n");
|
|
3304
3335
|
import_react5.default.useEffect(() => {
|
|
3305
3336
|
setHolidayText(savedHolidayText);
|
|
3306
3337
|
}, [savedHolidayText]);
|
|
@@ -3416,6 +3447,7 @@ function CostCardBody(props) {
|
|
|
3416
3447
|
};
|
|
3417
3448
|
const synced = settings.syncedPrices;
|
|
3418
3449
|
const alert = settings.peakAlert;
|
|
3450
|
+
const holidayInfo = effectiveHolidays(settings.peakHolidays, synced?.holidays);
|
|
3419
3451
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
3420
3452
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: hintInfo, children: [
|
|
3421
3453
|
"\u8FD9\u91CC\u6539\u7684",
|
|
@@ -3426,15 +3458,31 @@ function CostCardBody(props) {
|
|
|
3426
3458
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u5143 / 1M tokens" }),
|
|
3427
3459
|
"\uFF1BDeepSeek \u9AD8\u5CF0\u4EF7\u662F\u7A7A\u95F2\u4EF7\u7684 2 \u500D\u3002"
|
|
3428
3460
|
] }),
|
|
3429
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("
|
|
3430
|
-
"\
|
|
3431
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3461
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...row, alignItems: "flex-start", marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowText, children: [
|
|
3462
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: rowTitle, children: "\u8BA1\u4EF7\u8BF4\u660E" }),
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowDesc, children: [
|
|
3464
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u520A\u4F8B\u4EF7\u5FEB\u7167\uFF1A" }),
|
|
3465
|
+
PRICE_VERIFIED_AT,
|
|
3466
|
+
"\uFF08\u5B98\u65B9\u4EF7\u683C\u9875\u7684\u6838\u5BF9\u65E5\u671F\uFF1B\u4F60\u586B\u4E86\u8986\u76D6\u4EF7\u5C31\u4EE5\u4F60\u586B\u7684\u4E3A\u51C6\uFF09\u3002",
|
|
3467
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
|
|
3468
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u4EF7\u683C\u6863\uFF1A" }),
|
|
3469
|
+
"\u6309\u6BCF\u7B14\u7528\u91CF",
|
|
3470
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u53D1\u751F\u65F6\u523B" }),
|
|
3471
|
+
'\u751F\u6548\u7684\u6863\u7ED3\u7B97 \u2014\u2014 \u5B98\u65B9 2026-09-10 \u8C03\u8FC7\u4E00\u6B21 Flash \u7684\u4EF7\uFF0C\u6240\u4EE5 8 \u6708\u8DD1\u7684\u4F1A\u8BDD\u6C38\u8FDC\u6309 8 \u6708\u7684\u4EF7\u7B97\uFF0C\u4E0D\u4F1A\u56E0\u4E3A\u4F60\u4ECA\u5929 \u540C\u6B65\u4E86\u65B0\u4EF7\u800C\u53D8\u3002\u8DE8\u4E86\u6863\u7684\u4F1A\u8BDD\u5728\u91D1\u989D\u80F6\u56CA\u91CC\u4F1A\u591A\u4E00\u884C"\u6309\u5404\u81EA\u53D1\u751F\u65F6\u523B"\u7684\u8BF4\u660E\u3002',
|
|
3472
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
|
|
3473
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u5CF0\u8C37\uFF1A" }),
|
|
3474
|
+
"\u5317\u4EAC\u65F6\u95F4\u5DE5\u4F5C\u65E5 09:00\u201312:00\u300114:00\u201318:00 \u4E3A\u9AD8\u5CF0\uFF08",
|
|
3475
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u4E0D\u542B\u6CD5\u5B9A\u8282\u5047\u65E5" }),
|
|
3476
|
+
"\uFF09\uFF1B\u5468\u672B\u4E0E\u6CD5\u5B9A\u8282\u5047\u65E5",
|
|
3477
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u5168\u5929\u8C37\u4EF7" }),
|
|
3478
|
+
"\u3002",
|
|
3479
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
|
|
3480
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u975E DeepSeek\uFF1A" }),
|
|
3481
|
+
"\u6309\u540C\u6B65\u6765\u7684\u7B2C\u4E09\u65B9\u4EF7\u76EE\u7B97\uFF0C\u672A\u542B\u4E2D\u8F6C\u52A0\u4EF7\uFF0C",
|
|
3482
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u5B9E\u9645\u6263\u8D39\u4EE5\u5404\u5BB6\u8D26\u5355\u4E3A\u51C6" }),
|
|
3483
|
+
"\uFF1B\u4EF7\u76EE\u91CC\u6CA1\u6709\u7684\u6A21\u578B\u4F1A\u663E\u793A\u300C\u672A\u5B9A\u4EF7\u300D\uFF08\u6309 0 \u8BA1\uFF09\uFF0C \u70B9\u4E0B\u9762\u300C\u540C\u6B65\u7B2C\u4E09\u65B9\u4EF7\u76EE\u300D\u6216\u76F4\u63A5\u7ED9\u90A3\u4E00\u884C\u586B\u4EF7\u5373\u53EF\u3002"
|
|
3484
|
+
] })
|
|
3485
|
+
] }) }),
|
|
3438
3486
|
rows.map((key) => {
|
|
3439
3487
|
const builtin = BUILTIN_PRICING_MODELS.includes(key);
|
|
3440
3488
|
const { provider, model } = splitRowKey(key);
|
|
@@ -3539,13 +3587,22 @@ function CostCardBody(props) {
|
|
|
3539
3587
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowDesc, children: [
|
|
3540
3588
|
"\u547D\u4E2D\u7684\u4E00\u5929",
|
|
3541
3589
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u5168\u5929\u6309\u8C37\u4EF7" }),
|
|
3542
|
-
"\u3002\u5B98\u65B9\u89C4\u5219\u628A\u4E2D\u56FD\u6CD5\u5B9A\u8282\u5047\u65E5\u6392\u9664\u5728\u9AD8\u5CF0\u4E4B\u5916\uFF0C \u4E0D\u7B97\u7684\u8BDD\u56FD\u5E86\u90A3\u79CD\u65E5\u5B50\u4F1A\u628A\u5DE5\u4F5C\u65E5\u7684\u9AD8\u5CF0\u4E24\u6BB5\
|
|
3590
|
+
"\u3002\u5B98\u65B9\u89C4\u5219\u628A\u4E2D\u56FD\u6CD5\u5B9A\u8282\u5047\u65E5\u6392\u9664\u5728\u9AD8\u5CF0\u4E4B\u5916\uFF0C \u4E0D\u7B97\u7684\u8BDD\u56FD\u5E86\u90A3\u79CD\u65E5\u5B50\u4F1A\u628A\u5DE5\u4F5C\u65E5\u7684\u9AD8\u5CF0\u4E24\u6BB5\u6309\u5CF0\u4EF7\u7B97\u2014\u2014",
|
|
3543
3591
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u6574\u6574 2 \u500D" }),
|
|
3544
|
-
"\u3002
|
|
3592
|
+
"\u3002",
|
|
3545
3593
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
|
|
3546
|
-
"\
|
|
3547
|
-
|
|
3548
|
-
|
|
3594
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u7559\u7A7A = \u7528\u81EA\u52A8\u83B7\u53D6\u7684\u90A3\u4EFD" }),
|
|
3595
|
+
"\uFF08",
|
|
3596
|
+
HOLIDAY_SOURCE_LABEL,
|
|
3597
|
+
'\uFF0C\u6BCF\u6B21\u53D6"\u4ECA\u5E74 + \u660E\u5E74"\uFF0C\u56FD\u52A1\u9662\u5E74\u5E95\u4E00\u516C\u5E03\u6B21\u5E74\u5B89\u6392\u5C31\u4F1A\u88AB\u53D6\u56DE\uFF09\uFF1B\u6CA1\u53D6\u5230\u8FC7\u5C31\u7528',
|
|
3598
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u5185\u7F6E" }),
|
|
3599
|
+
"\u90A3\u4EFD \uFF082026 \u4E2D\u79CB 09-25\uFF5E27\u3001\u56FD\u5E86 10-01\uFF5E07\uFF09\u3002\u8FD9\u91CC\u586B\u4E86\u5219",
|
|
3600
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u6574\u4EFD\u8986\u76D6" }),
|
|
3601
|
+
"\u81EA\u52A8\u83B7\u53D6\u4E0E\u5185\u7F6E\u90A3\u4E24\u4EFD\u3002",
|
|
3602
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
|
|
3603
|
+
"\u6CE8\uFF1A",
|
|
3604
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u8C03\u4F11\u8865\u73ED\u7684\u5468\u672B\u4ECD\u6309\u8C37\u4EF7" }),
|
|
3605
|
+
'\uFF08\u5B98\u65B9\u8BF4\u7684\u662F"\u5468\u516D\u3001\u5468\u65E5\u5168\u5929\u8C37\u4EF7"\uFF0C 2026-10-10 \u90A3\u4E2A\u5468\u516D\u4E5F\u7B97\u8C37\u4EF7\uFF09\uFF0C\u6240\u4EE5\u81EA\u52A8\u83B7\u53D6\u53EA\u6536"\u653E\u5047"\u7684\u90A3\u51E0\u5929\u3002'
|
|
3549
3606
|
] })
|
|
3550
3607
|
] }),
|
|
3551
3608
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -3553,6 +3610,7 @@ function CostCardBody(props) {
|
|
|
3553
3610
|
{
|
|
3554
3611
|
style: { ...textInput, width: 260, height: 96, flex: "none", fontFamily: "monospace" },
|
|
3555
3612
|
"aria-label": "\u6CD5\u5B9A\u8282\u5047\u65E5\u65E5\u671F\u8868",
|
|
3613
|
+
placeholder: "\u7559\u7A7A = \u7528\u81EA\u52A8\u83B7\u53D6\u7684\u90A3\u4EFD\uFF08\u6CA1\u53D6\u5230\u5C31\u7528\u5185\u7F6E\uFF09",
|
|
3556
3614
|
value: holidayText,
|
|
3557
3615
|
onChange: (event) => setHolidayText(event.target.value),
|
|
3558
3616
|
spellCheck: false
|
|
@@ -3567,9 +3625,9 @@ function CostCardBody(props) {
|
|
|
3567
3625
|
style: pill,
|
|
3568
3626
|
onClick: () => {
|
|
3569
3627
|
clearField(PEAK_HOLIDAYS_FIELD);
|
|
3570
|
-
setHolidayNote("\u5DF2\
|
|
3628
|
+
setHolidayNote("\u5DF2\u6E05\u7A7A = \u7528\u81EA\u52A8\u83B7\u53D6\u7684\u90A3\u4EFD\u8282\u5047\u65E5\u8868");
|
|
3571
3629
|
},
|
|
3572
|
-
children: "\u6062\u590D\
|
|
3630
|
+
children: "\u6062\u590D\u9ED8\u8BA4"
|
|
3573
3631
|
}
|
|
3574
3632
|
)
|
|
3575
3633
|
] })
|
|
@@ -3577,9 +3635,29 @@ function CostCardBody(props) {
|
|
|
3577
3635
|
holidayNote !== "" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: hintInfo, children: holidayNote }),
|
|
3578
3636
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: hintInfo, children: [
|
|
3579
3637
|
"\u5F53\u524D\u751F\u6548\uFF1A",
|
|
3580
|
-
(
|
|
3581
|
-
|
|
3582
|
-
|
|
3638
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("strong", { children: [
|
|
3639
|
+
holidayInfo.days.length,
|
|
3640
|
+
" \u4E2A\u65E5\u671F"
|
|
3641
|
+
] }),
|
|
3642
|
+
" \u2014\u2014 \u6765\u6E90\uFF1A",
|
|
3643
|
+
holidayInfo.source === "manual" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
3644
|
+
"\u4F60\u4E0A\u9762\u586B\u7684\u90A3\u4EFD\uFF08\u81EA\u5B9A\u4E49\uFF1B\u81EA\u52A8\u83B7\u53D6\u90A3\u4EFD\u6709 ",
|
|
3645
|
+
holidayInfo.autoCount,
|
|
3646
|
+
" \u4E2A\u65E5\u671F\uFF0C\u73B0\u5728\u4E0D\u53C2\u4E0E\uFF09"
|
|
3647
|
+
] }) : holidayInfo.source === "auto" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
3648
|
+
"\u81EA\u52A8\u83B7\u53D6\uFF08",
|
|
3649
|
+
stampText(synced?.holidaysAt),
|
|
3650
|
+
"\uFF0C\u5171 ",
|
|
3651
|
+
holidayInfo.autoCount,
|
|
3652
|
+
" \u4E2A\u65E5\u671F\uFF1B \u4E0E\u5185\u7F6E\u8868\u53D6\u5E76\u96C6\u540E\u662F ",
|
|
3653
|
+
holidayInfo.days.length,
|
|
3654
|
+
" \u4E2A\uFF09"
|
|
3655
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: "\u5185\u7F6E\uFF08\u56FD\u52A1\u9662\u529E\u516C\u5385 2026 \u5E74\u5B89\u6392\uFF09" }),
|
|
3656
|
+
holidayInfo.source !== "manual" && settings.priceAutoSync !== true ? "\uFF1B\u6253\u5F00\u4E0B\u9762\u300C\u540C\u6B65\u4EF7\u76EE\u300D\u91CC\u7684\u81EA\u52A8\u540C\u6B65\u540E\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u5DF1\u53D6\u6B21\u5E74\u5B89\u6392" : ""
|
|
3657
|
+
] }),
|
|
3658
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("details", { style: { ...rowDesc, cursor: "pointer" }, children: [
|
|
3659
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("summary", { children: "\u770B\u5F53\u524D\u751F\u6548\u7684\u65E5\u671F" }),
|
|
3660
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontFamily: "monospace", wordBreak: "break-all" }, children: holidayInfo.days.join("\u3001") })
|
|
3583
3661
|
] }),
|
|
3584
3662
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...row, alignItems: "flex-start", flexWrap: "wrap", marginTop: 6 }, children: [
|
|
3585
3663
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowText, children: [
|
|
@@ -3694,12 +3772,14 @@ function CostCardBody(props) {
|
|
|
3694
3772
|
] }),
|
|
3695
3773
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...row, alignItems: "flex-start", flexWrap: "wrap", marginTop: 6 }, children: [
|
|
3696
3774
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowText, children: [
|
|
3697
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: rowTitle, children: "\u540C\u6B65
|
|
3775
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: rowTitle, children: "\u540C\u6B65" }),
|
|
3698
3776
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowDesc, children: [
|
|
3699
3777
|
"\u300C\u5B98\u65B9\u4EF7\u300D\u6293\u5B98\u65B9\u4EF7\u683C\u9875\u4E24\u9875\uFF08\u7EA6 24 KB\uFF09\uFF1A",
|
|
3700
3778
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u6709\u53D8\u5316\u624D\u65B0\u589E\u4E00\u4E2A\u4EF7\u683C\u6863" }),
|
|
3701
|
-
"\uFF0C \u5386\u53F2\u7528\u91CF\u4ECD\u6309\u53D1\u751F\u65F6\u523B\u7684\u65E7\u6863\u7ED3\u7B97\u3002\u300C\u7B2C\u4E09\u65B9\u4EF7\u76EE\u300D\u6293 models.dev\uFF08\u7EA6 5 MB\uFF0C \u538B\u7F29\u540E\u7EA6 450 KB \u843D\u76D8\uFF09\uFF0C\u7ED9\u975E DeepSeek \u6A21\u578B\u7528\u3002",
|
|
3702
|
-
|
|
3779
|
+
"\uFF0C \u5386\u53F2\u7528\u91CF\u4ECD\u6309\u53D1\u751F\u65F6\u523B\u7684\u65E7\u6863\u7ED3\u7B97\u3002\u300C\u7B2C\u4E09\u65B9\u4EF7\u76EE\u300D\u6293 models.dev\uFF08\u7EA6 5 MB\uFF0C \u538B\u7F29\u540E\u7EA6 450 KB \u843D\u76D8\uFF09\uFF0C\u7ED9\u975E DeepSeek \u6A21\u578B\u7528\u3002\u300C\u6CD5\u5B9A\u8282\u5047\u65E5\u300D\u6293",
|
|
3780
|
+
HOLIDAY_SOURCE_LABEL,
|
|
3781
|
+
'\uFF08\u6BCF\u5E74\u4E00\u4E2A\u51E0 KB \u7684 JSON\uFF0C\u53EA\u6536"\u653E\u5047"\u90A3\u51E0\u5929\uFF09\u3002',
|
|
3782
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u4E09\u4E2A\u90FD\u662F\u6293\u5931\u8D25\u4E0D\u4F1A\u8986\u76D6\u672C\u5730\u6570\u636E\u3002" }),
|
|
3703
3783
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
|
|
3704
3784
|
"\u6CA1\u70B9\u8FC7\u300C\u540C\u6B65\u7B2C\u4E09\u65B9\u4EF7\u76EE\u300D\u65F6\uFF0C\u975E DeepSeek \u6A21\u578B\u4F1A\u7528",
|
|
3705
3785
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u5185\u7F6E\u5FEB\u7167\u4EF7" }),
|
|
@@ -3711,17 +3791,18 @@ function CostCardBody(props) {
|
|
|
3711
3791
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
3712
3792
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: pill, disabled: sync.busy !== null, onClick: () => sync.sync("official"), children: sync.busy === "official" ? "\u540C\u6B65\u4E2D\u2026" : "\u540C\u6B65\u5B98\u65B9\u4EF7" }),
|
|
3713
3793
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: pill, disabled: sync.busy !== null, onClick: () => sync.sync("modelsDev"), children: sync.busy === "modelsDev" ? "\u540C\u6B65\u4E2D\u2026" : "\u540C\u6B65\u7B2C\u4E09\u65B9\u4EF7\u76EE" }),
|
|
3794
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: pill, disabled: sync.busy !== null, onClick: () => sync.sync("holidays"), children: sync.busy === "holidays" ? "\u83B7\u53D6\u4E2D\u2026" : "\u83B7\u53D6\u6CD5\u5B9A\u8282\u5047\u65E5" }),
|
|
3714
3795
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
3715
3796
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3716
3797
|
"input",
|
|
3717
3798
|
{
|
|
3718
3799
|
type: "checkbox",
|
|
3719
3800
|
checked: settings.priceAutoSync,
|
|
3720
|
-
"aria-label": "\u81EA\u52A8\u540C\u6B65\u5B98\u65B9\u4EF7",
|
|
3801
|
+
"aria-label": "\u81EA\u52A8\u540C\u6B65\u5B98\u65B9\u4EF7\u4E0E\u8282\u5047\u65E5",
|
|
3721
3802
|
onChange: (event) => setField(PRICE_AUTO_SYNC_FIELD2, event.target.checked)
|
|
3722
3803
|
}
|
|
3723
3804
|
),
|
|
3724
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { title: "\u6253\u5F00\u540E\u5BBF\u4E3B\u534A\u6BCF\u5929\u6700\u591A\u81EA\u52A8\u6293\u4E00\u6B21\u5B98\u65B9\u4EF7\u683C\u9875\uFF1B\u6293\u5931\u8D25\u53EA\u5199\u65E5\u5FD7\uFF0C\u4E0D\u4F1A\u6539\u672C\u5730\
|
|
3805
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { title: "\u6253\u5F00\u540E\u5BBF\u4E3B\u534A\u6BCF\u5929\u6700\u591A\u81EA\u52A8\u6293\u4E00\u6B21\u5B98\u65B9\u4EF7\u683C\u9875\uFF0C\u5E76\u6BCF 30 \u5929\u590D\u6838\u4E00\u6B21\u6CD5\u5B9A\u8282\u5047\u65E5\uFF1B\u6293\u5931\u8D25\u53EA\u5199\u65E5\u5FD7\uFF0C\u4E0D\u4F1A\u6539\u672C\u5730\u6570\u636E", children: "\u81EA\u52A8\u540C\u6B65\uFF08\u4EF7\u683C\u6BCF\u5929\u4E00\u6B21\u3001\u8282\u5047\u65E5\u6BCF 30 \u5929\u590D\u6838\uFF09" })
|
|
3725
3806
|
] })
|
|
3726
3807
|
] }),
|
|
3727
3808
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...rowDesc, flexBasis: "100%" }, children: [
|
|
@@ -3730,6 +3811,9 @@ function CostCardBody(props) {
|
|
|
3730
3811
|
"\uFF1B \u7B2C\u4E09\u65B9\u4EF7\u76EE\u4E0A\u6B21\u540C\u6B65\uFF1A",
|
|
3731
3812
|
stampText(synced?.modelsDevAt),
|
|
3732
3813
|
typeof synced?.modelsDevCount === "number" ? `\uFF08${synced.modelsDevCount} \u4E2A\u6A21\u578B\uFF09` : "",
|
|
3814
|
+
"\uFF1B\u6CD5\u5B9A\u8282\u5047\u65E5\u4E0A\u6B21\u83B7\u53D6\uFF1A",
|
|
3815
|
+
stampText(synced?.holidaysAt),
|
|
3816
|
+
Array.isArray(synced?.holidayYears) && synced.holidayYears.length > 0 ? `\uFF08\u5DF2\u6709 ${synced.holidayYears.join("\u3001")} \u5E74\uFF09` : "",
|
|
3733
3817
|
typeof synced?.eras?.length === "number" && synced.eras.length > 0 ? `\uFF1B\u5DF2\u7D2F\u79EF ${synced.eras.length} \u4E2A\u540C\u6B65\u6765\u7684\u4EF7\u683C\u6863` : ""
|
|
3734
3818
|
] })
|
|
3735
3819
|
] }),
|
|
@@ -4816,11 +4900,12 @@ function SettingsSection({ useLive, useBook, useBookStatus, useWriteNotice, acti
|
|
|
4816
4900
|
const costSummary = (() => {
|
|
4817
4901
|
const models = settings.priceOverrides === void 0 ? [] : Object.keys(settings.priceOverrides);
|
|
4818
4902
|
const price = models.length === 0 ? "\u6309\u5B98\u65B9\u520A\u4F8B\u4EF7\u4F30\u7B97" : `\u5DF2\u8986\u76D6 ${models.length} \u4E2A\u6A21\u578B\u7684\u5355\u4EF7`;
|
|
4819
|
-
const holidays = settings.peakHolidays
|
|
4903
|
+
const holidays = effectiveHolidays(settings.peakHolidays, settings.syncedPrices?.holidays);
|
|
4904
|
+
const holidayText = holidays.source === "manual" ? ` \xB7 \u81EA\u5B9A\u4E49\u8282\u5047\u65E5 ${holidays.days.length} \u5929` : holidays.source === "auto" ? ` \xB7 \u8282\u5047\u65E5\u81EA\u52A8 ${holidays.autoCount} \u5929` : "";
|
|
4820
4905
|
const synced = settings.syncedPrices;
|
|
4821
4906
|
const count2 = synced?.modelsDevCount;
|
|
4822
4907
|
const sync = count2 === void 0 ? synced?.eras === void 0 || synced.eras.length === 0 ? "" : ` \xB7 \u5DF2\u540C\u6B65 ${synced.eras.length} \u4E2A\u4EF7\u683C\u6863` : ` \xB7 \u7B2C\u4E09\u65B9\u4EF7\u76EE ${count2} \u4E2A\u6A21\u578B`;
|
|
4823
|
-
return `${price}${
|
|
4908
|
+
return `${price}${holidayText}${sync}`;
|
|
4824
4909
|
})();
|
|
4825
4910
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { padding: "4px 2px" }, children: [
|
|
4826
4911
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "dsh-ux-card", children: [
|
|
@@ -5790,12 +5875,10 @@ function CostChipEntry({ useLive, sessionId, useProjection }) {
|
|
|
5790
5875
|
] }),
|
|
5791
5876
|
detail("\u7F13\u5B58\u547D\u4E2D\u7387", viewHitRate === null ? "\u2014" : `${viewHitRate}%`),
|
|
5792
5877
|
detail("\u5CF0\u8C37", peakText),
|
|
5793
|
-
detail(
|
|
5794
|
-
detail(
|
|
5795
|
-
note((model === void 0 || model === "" ? "\u672A\u77E5\u6A21\u578B\uFF08\u6309\u9ED8\u8BA4\u6A21\u578B\u8BA1\u4EF7\uFF09" : model) + ` \xB7 \u520A\u4F8B\u4EF7\u5FEB\u7167 ${PRICE_VERIFIED_AT}` + (overridden ? " \xB7 \u5DF2\u7528\u4F60\u5728\u8BBE\u7F6E\u9875\u300C\u91D1\u989D\u300D\u91CC\u586B\u7684\u4EF7" : "")),
|
|
5878
|
+
detail(`\u9AD8\u5CF0\u5355\u4EF7\uFF08\u6BCF 1M${overridden ? " \xB7 \u5DF2\u81EA\u5B9A\u4E49" : ""}\uFF09`, peakPrice.unpriced ? "\u672A\u5B9A\u4EF7" : priceText(peakPrice.prices)),
|
|
5879
|
+
detail(`\u7A7A\u95F2\u5355\u4EF7\uFF08\u6BCF 1M${overridden ? " \xB7 \u5DF2\u81EA\u5B9A\u4E49" : ""}\uFF09`, offPrice.unpriced ? "\u672A\u5B9A\u4EF7" : priceText(offPrice.prices)),
|
|
5796
5880
|
viewUnpriced ? note("\u8FD9\u4E2A\u6A21\u578B\u4E0D\u662F DeepSeek \u7CFB\u3001\u540C\u6B65\u6765\u7684\u7B2C\u4E09\u65B9\u4EF7\u76EE\u91CC\u4E5F\u6CA1\u6709\u5B83\uFF0C\u6240\u4EE5\u91D1\u989D\u7ED9\u4E0D\u51FA\u6765\u3002\u53BB\u8BBE\u7F6E\u9875\u300C\u91D1\u989D\u300D\u70B9\u4E00\u6B21\u300C\u540C\u6B65\u7B2C\u4E09\u65B9\u4EF7\u76EE\u300D\uFF0C\u6216\u7ED9\u8FD9\u4E2A\u6A21\u578B\u76F4\u63A5\u586B\u4E00\u884C\u5355\u4EF7\u3002", "__unpriced__") : null,
|
|
5797
|
-
erasUsed.length
|
|
5798
|
-
note("\u5CF0\u8C37\u6309\u6BCF\u7B14\u7528\u91CF\u53D1\u751F\u7684\u65F6\u95F4\u5224\u5B9A\uFF08\u5DE5\u4F5C\u65E5 09:00\u201312:00\u300114:00\u201318:00 \u4E3A\u9AD8\u5CF0\uFF0C\u6CD5\u5B9A\u8282\u5047\u65E5\u4E0E\u5468\u672B\u5168\u5929\u8C37\u4EF7\uFF09\uFF1B\u975E DeepSeek \u8DEF\u7531\u6309\u540C\u6B65\u6765\u7684\u7B2C\u4E09\u65B9\u4EF7\u76EE\u7B97\uFF0C\u672A\u542B\u4E2D\u8F6C\u52A0\u4EF7\uFF0C\u5B9E\u9645\u6263\u8D39\u4EE5\u5404\u5BB6\u8D26\u5355\u4E3A\u51C6\u3002")
|
|
5881
|
+
erasUsed.length > 0 && (erasUsed.length > 1 || erasUsed[0] !== eraIdAt(Date.now(), eras)) ? note("\u8FD9\u6279\u7528\u91CF\u6309\u5404\u81EA\u53D1\u751F\u65F6\u523B\u7684\u4EF7\u683C\u6863\u7ED3\u7B97\uFF1A" + erasUsed.map((id) => eraById(id, eras).label).join(" \xB7 ") + "\uFF08\u5B98\u65B9\u8C03\u4EF7\u4E0D\u4F1A\u6539\u52A8\u5386\u53F2\u91D1\u989D\uFF09", "__eras__") : null
|
|
5799
5882
|
] })
|
|
5800
5883
|
]
|
|
5801
5884
|
}
|