dsh-notify-say 0.4.40 → 0.4.45
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 +187 -0
- package/lib/client.js +127 -41
- package/lib/dev-reload.js +746 -647
- package/lib/http-guard.js +238 -239
- package/lib/index.js +15 -2
- package/lib/voice-pack-download.js +26 -17
- package/lib/voice-regions.js +29 -20
- package/package.json +2 -1
- package/test/client-contract.test.mjs +95 -2
- package/test/docs-consistency.test.mjs +82 -1
- package/test/reload-review.test.mjs +158 -0
- package/test/review-fixes.test.mjs +20 -5
- package/test/review3-fixes.test.mjs +232 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
> 本文件由 `tools/release-build.ps1` 从开发提交自动生成,**请勿手工编辑**。
|
|
4
|
+
> 只列面向使用者的变更(新增功能与修复),不含内部维护提交。
|
|
5
|
+
|
|
6
|
+
## v0.4.45 — 2026-10-18
|
|
7
|
+
|
|
8
|
+
- feat(release): v0.4.45 —— CHANGELOG 自动生成 + 垃圾文件闸
|
|
9
|
+
|
|
10
|
+
## v0.4.44 — 2026-10-18
|
|
11
|
+
|
|
12
|
+
- feat(reload): v0.4.44 —— watcher 可观测诊断 + 确认热重载已修好
|
|
13
|
+
|
|
14
|
+
## v0.4.43 — 2026-10-18
|
|
15
|
+
|
|
16
|
+
- fix(gui): v0.4.43 —— 条款确认改成居中覆盖弹窗
|
|
17
|
+
|
|
18
|
+
## v0.4.42 — 2026-10-18
|
|
19
|
+
|
|
20
|
+
- fix: v0.4.42 —— 第三轮审阅 5 项全部属实
|
|
21
|
+
|
|
22
|
+
## v0.4.41 — 2026-10-18
|
|
23
|
+
|
|
24
|
+
- fix(reload): v0.4.41 —— 第二轮审阅 6 项,全部属实,逐项修复
|
|
25
|
+
|
|
26
|
+
## v0.4.40 — 2026-10-18
|
|
27
|
+
|
|
28
|
+
- feat: v0.4.40 —— 下载前条款确认 + 语音包索引改用固定 tag
|
|
29
|
+
|
|
30
|
+
## v0.4.39 — 2026-10-18
|
|
31
|
+
|
|
32
|
+
- fix!: v0.4.39 —— 外部审阅 4 项全部属实,逐项修复
|
|
33
|
+
|
|
34
|
+
## v0.4.38 — 2026-10-18
|
|
35
|
+
|
|
36
|
+
- fix(reload): v0.4.38 —— 修热重载「改了代码却说代码没变」
|
|
37
|
+
|
|
38
|
+
## v0.4.37 — 2026-10-18
|
|
39
|
+
|
|
40
|
+
- fix(guard): v0.4.37 —— 修「无 Origin 写请求被拒」,GUI 之前根本存不了配置
|
|
41
|
+
|
|
42
|
+
## v0.4.36 — 2026-10-18
|
|
43
|
+
|
|
44
|
+
- fix(gui): v0.4.36 —— 修音量等滑杆"改了没保存"(状态字段被清掉)
|
|
45
|
+
|
|
46
|
+
## v0.4.35 — 2026-10-18
|
|
47
|
+
|
|
48
|
+
- feat(gui): 日志级别开关(高级区)+ L15 测试
|
|
49
|
+
- feat(diag): v0.4.35 —— 接通「导出诊断文件」出口
|
|
50
|
+
|
|
51
|
+
## v0.4.34 — 2026-10-18
|
|
52
|
+
|
|
53
|
+
- feat(privacy): v0.4.34 —— 日志分级,默认不记用户内容
|
|
54
|
+
|
|
55
|
+
## v0.4.33 — 2026-10-18
|
|
56
|
+
|
|
57
|
+
- feat(gui): v0.4.33 —— 语音包管理界面
|
|
58
|
+
|
|
59
|
+
## v0.4.32 — 2026-10-18
|
|
60
|
+
|
|
61
|
+
- feat(route): v0.4.32 —— 语音包管理 HTTP 路由
|
|
62
|
+
|
|
63
|
+
## v0.4.31 — 2026-10-18
|
|
64
|
+
|
|
65
|
+
- feat(store)!: v0.4.31 —— 改为一音色一目录 + 下载安装模块
|
|
66
|
+
|
|
67
|
+
## v0.4.30 — 2026-10-18
|
|
68
|
+
|
|
69
|
+
- fix(test): v0.4.30 —— D1 区分开发/发布环境(CI 抓到)
|
|
70
|
+
|
|
71
|
+
## v0.4.29 — 2026-10-18
|
|
72
|
+
|
|
73
|
+
- feat(store): v0.4.29 —— 语音包双区域存储层 + 修 4 项审阅问题
|
|
74
|
+
|
|
75
|
+
## v0.4.28 — 2026-10-18
|
|
76
|
+
|
|
77
|
+
- fix(test): v0.4.28 —— R4 改为按能力 skip(Node 20 第三轮)
|
|
78
|
+
|
|
79
|
+
## v0.4.27 — 2026-10-18
|
|
80
|
+
|
|
81
|
+
- fix(compat): v0.4.27 —— 补上上一版漏掉的测试文件(Node 20 仍失败)
|
|
82
|
+
|
|
83
|
+
## v0.4.26 — 2026-10-18
|
|
84
|
+
|
|
85
|
+
- fix(compat): v0.4.26 —— 修 Node 20 兼容性(CI 首跑就抓到)
|
|
86
|
+
|
|
87
|
+
## v0.4.25 — 2026-10-18
|
|
88
|
+
|
|
89
|
+
- feat(ci): v0.4.25 —— 修 P0 回归 + 公开测试与 CI
|
|
90
|
+
|
|
91
|
+
## v0.4.24 — 2026-10-18
|
|
92
|
+
|
|
93
|
+
- feat(security): v0.4.24 —— 插件路由补上本地来源防护(实测有洞)
|
|
94
|
+
|
|
95
|
+
## v0.4.23 — 2026-10-18
|
|
96
|
+
|
|
97
|
+
- fix(client): v0.4.23 —— 修 P0 会话跳转 bug + 3 项审阅问题
|
|
98
|
+
|
|
99
|
+
## v0.4.22 — 2026-10-18
|
|
100
|
+
|
|
101
|
+
- fix(compliance)!: v0.4.22 —— 按外部审阅意见修复 5 项合规问题
|
|
102
|
+
- feat(audit): v0.4.22 —— 音色许可审核体系 + 新增 2 个禁止项
|
|
103
|
+
|
|
104
|
+
## v0.4.21 — 2026-10-18
|
|
105
|
+
|
|
106
|
+
- feat(release)!: v0.4.21 —— 硬性阻断个人声音样本进发布包 + 语音包分发方案
|
|
107
|
+
|
|
108
|
+
## v0.4.20 — 2026-10-18
|
|
109
|
+
|
|
110
|
+
- feat(tools): 一键发版脚本 tools/release.ps1
|
|
111
|
+
- fix(reload): v0.4.20 —— 热重载终于「报 ok 就真生效」
|
|
112
|
+
|
|
113
|
+
## v0.4.19 — 2026-10-18
|
|
114
|
+
|
|
115
|
+
- fix(release): v0.4.19 —— 版本号补齐 + 加自动化一致性检查
|
|
116
|
+
- refactor!: 改名 dsh-notify-desktop → dsh-notify-say(npm 原名已被占用)
|
|
117
|
+
- fix: 补完改名遗漏 + 第三方声明进发布包
|
|
118
|
+
|
|
119
|
+
## v0.4.18 — 2026-10-18
|
|
120
|
+
|
|
121
|
+
- fix(notify): v0.4.18 —— 补 voiceGain 映射 + 加"配置键全覆盖"元测试
|
|
122
|
+
|
|
123
|
+
## v0.4.17 — 2026-10-18
|
|
124
|
+
|
|
125
|
+
- feat(notify): v0.4.17 —— 补上试听(只出声、不弹窗)
|
|
126
|
+
|
|
127
|
+
## v0.4.16 — 2026-10-18
|
|
128
|
+
|
|
129
|
+
- feat(notify): v0.4.16 —— 语音包音量增益(可调)+ 自定义音频可选标准化
|
|
130
|
+
|
|
131
|
+
## v0.4.15 — 2026-10-18
|
|
132
|
+
|
|
133
|
+
- fix(notify): v0.4.15 —— 修"选了语音包却只听到蜂鸣"(宿主沙箱导致误判)
|
|
134
|
+
|
|
135
|
+
## v0.4.13 — 2026-10-17
|
|
136
|
+
|
|
137
|
+
- fix(notify): v0.4.13 —— 修"[object Object]"导致 SAPI 静默失败(弹窗有、无声音)
|
|
138
|
+
|
|
139
|
+
## v0.4.10 — 2026-10-17
|
|
140
|
+
|
|
141
|
+
- fix(notify): v0.4.10 —— 修"改了设置却不生效/显示默认值"
|
|
142
|
+
|
|
143
|
+
## v0.4.9 — 2026-10-17
|
|
144
|
+
|
|
145
|
+
- feat(notify): v0.4.9 —— 高级区每行展开该音源的完整子设置
|
|
146
|
+
|
|
147
|
+
## v0.4.8 — 2026-10-17
|
|
148
|
+
|
|
149
|
+
- feat(notify): v0.4.8 —— 台词随机 + 用户自定义台词 + 音频时长/体积闸
|
|
150
|
+
|
|
151
|
+
## v0.4.7 — 2026-10-17
|
|
152
|
+
|
|
153
|
+
- feat(notify): v0.4.7 —— 冷却可调:同会话可关、跨会话新增
|
|
154
|
+
|
|
155
|
+
## v0.4.6 — 2026-10-17
|
|
156
|
+
|
|
157
|
+
- feat(notify): v0.4.6 —— 跳回会话的开关进 GUI(常规区,非折叠区)
|
|
158
|
+
|
|
159
|
+
## v0.4.5 — 2026-10-17
|
|
160
|
+
|
|
161
|
+
- feat(notify): v0.4.5 —— 高级区:按事件覆盖音源 + 热重载开关
|
|
162
|
+
|
|
163
|
+
## v0.4.4 — 2026-10-17
|
|
164
|
+
|
|
165
|
+
- feat(notify): v0.4.4 —— GUI 音源选择 / 弹窗开关 / TTS 设置 / 自定义音频
|
|
166
|
+
|
|
167
|
+
## v0.4.3 — 2026-10-17
|
|
168
|
+
|
|
169
|
+
- feat(notify): v0.4.3 —— 开发期自热重载(devReload,默认关)
|
|
170
|
+
|
|
171
|
+
## v0.4.2 — 2026-10-17
|
|
172
|
+
|
|
173
|
+
- feat(notify): v0.4.2 —— TTS 接线 / Toast 开关 / 系统提示音 / 配置键补齐
|
|
174
|
+
|
|
175
|
+
## v0.4.1 — 2026-10-17
|
|
176
|
+
|
|
177
|
+
- feat(notify): v0.4.1 —— 设置页 GUI / 音源抽象 / 会话跳转 / 可观测性
|
|
178
|
+
|
|
179
|
+
## v0.4.0 — 2026-10-17
|
|
180
|
+
|
|
181
|
+
- feat(notify): v0.4.0 —— 官方 Config schema(设置页)+ 语音包 CLI + 发布派生
|
|
182
|
+
|
|
183
|
+
## v0.3.1 — 2026-10-17
|
|
184
|
+
|
|
185
|
+
- feat(notify): 空闲门——子代理/后台任务在跑时不再误报「任务完成」
|
|
186
|
+
- feat(notify): v0.3.1 失败语音——error 回合播日语道歉语音
|
|
187
|
+
|
package/lib/client.js
CHANGED
|
@@ -477,6 +477,9 @@ window.__ModuleLoader__.load({
|
|
|
477
477
|
return {
|
|
478
478
|
loaded: p.loaded, values: p.values, packs: p.packs, advOpen: p.advOpen, busy: p.busy, msg: p.msg, err: p.err,
|
|
479
479
|
packs: { loading: true, list: null, error: null },
|
|
480
|
+
// ⚠️ 2026-10-18 第三轮审阅:原来 termsAck / termsPending
|
|
481
|
+
// 被写在这里(packs 子对象内层),层级错了 → 刷新列表后
|
|
482
|
+
// 顶层确认状态被清掉,用户被反复要求确认同一音色。
|
|
480
483
|
termsAck: p.termsAck, termsPending: p.termsPending,
|
|
481
484
|
}
|
|
482
485
|
})
|
|
@@ -486,11 +489,12 @@ window.__ModuleLoader__.load({
|
|
|
486
489
|
return {
|
|
487
490
|
loaded: p.loaded, values: p.values, packs: p.packs, advOpen: p.advOpen, busy: p.busy, msg: p.msg, err: p.err,
|
|
488
491
|
packs: {
|
|
489
|
-
termsAck: p.termsAck, termsPending: p.termsPending,
|
|
490
492
|
loading: false,
|
|
491
493
|
list: ok ? doc.packs : null,
|
|
492
494
|
error: ok ? null : ((doc && (doc.indexError || doc.reason)) || "无法获取"),
|
|
493
495
|
},
|
|
496
|
+
// 顶层状态:必须与 packs 平级,不能被塞进 packs 内层
|
|
497
|
+
termsAck: p.termsAck, termsPending: p.termsPending,
|
|
494
498
|
}
|
|
495
499
|
})
|
|
496
500
|
})
|
|
@@ -564,6 +568,113 @@ window.__ModuleLoader__.load({
|
|
|
564
568
|
// · 过很久后忘了条款内容
|
|
565
569
|
// 每次都问又很烦。折中:**只在本次会话内记住**。
|
|
566
570
|
// 浏览器刷新后重新问一次 —— 成本很低(点一下),收益是条款不会被遗忘。
|
|
571
|
+
// ── 条款确认弹窗(v0.4.43)──────────────────────────────────────
|
|
572
|
+
//
|
|
573
|
+
// ## 为什么从「内联面板」改成「居中覆盖」
|
|
574
|
+
//
|
|
575
|
+
// v0.4.40 把确认面板放在语音包列表**下面**。2026-10-18 用户实测反馈:
|
|
576
|
+
// 点列表上面几个音色时,面板在下面看不见 ——
|
|
577
|
+
// 用户以为已经在下载,实际在等一个他没看见的确认。
|
|
578
|
+
//
|
|
579
|
+
// 这不只是「位置靠下」,而是**不阻断**:后面所有按钮照常可点。
|
|
580
|
+
// 覆盖式遮罩能挡住交互,用户必须先处理这个确认。
|
|
581
|
+
//
|
|
582
|
+
// ## 为什么用 position:fixed 而不是 portal
|
|
583
|
+
//
|
|
584
|
+
// 这个渲染环境没有 portal API。fixed 相对视口居中,
|
|
585
|
+
// 不受设置卡片滚动影响。
|
|
586
|
+
//
|
|
587
|
+
// ## 为什么点遮罩就取消
|
|
588
|
+
//
|
|
589
|
+
// 弹窗惯例,也避免用户被「卡住不知道怎么办」。
|
|
590
|
+
// 只有点遮罩本身才关(判断 target === currentTarget),点卡片内部不关。
|
|
591
|
+
function renderTermsModal(tp) {
|
|
592
|
+
return h('div', {
|
|
593
|
+
key: 'terms-backdrop',
|
|
594
|
+
style: {
|
|
595
|
+
position: 'fixed',
|
|
596
|
+
top: 0, right: 0, bottom: 0, left: 0,
|
|
597
|
+
background: 'rgba(0,0,0,.45)',
|
|
598
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
599
|
+
zIndex: 9999,
|
|
600
|
+
},
|
|
601
|
+
onClick: function (e) {
|
|
602
|
+
if (e && e.target === e.currentTarget) cancelTerms()
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
h('div', {
|
|
606
|
+
key: 'terms-card',
|
|
607
|
+
style: {
|
|
608
|
+
width: 'min(430px, calc(100vw - 48px))',
|
|
609
|
+
maxHeight: 'calc(100vh - 64px)',
|
|
610
|
+
overflowY: 'auto',
|
|
611
|
+
background: '#2b2b2b',
|
|
612
|
+
color: '#eee',
|
|
613
|
+
border: '1px solid rgba(255,200,80,.5)',
|
|
614
|
+
borderRadius: '8px',
|
|
615
|
+
padding: '16px',
|
|
616
|
+
boxShadow: '0 12px 48px rgba(0,0,0,.55)',
|
|
617
|
+
display: 'flex', flexDirection: 'column', gap: '8px',
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
h('div', { style: { fontSize: '15px', fontWeight: 600 } },
|
|
621
|
+
'下载前请先看条款'),
|
|
622
|
+
h('div', { style: { fontSize: '13px', opacity: 0.85 } },
|
|
623
|
+
(tp.name || tp.key) + '(' + tp.key + ')'),
|
|
624
|
+
|
|
625
|
+
// 条款区:只给署名 + 官方链接,不写我们自己转述的摘要(转述会失真)
|
|
626
|
+
h('div', {
|
|
627
|
+
style: {
|
|
628
|
+
marginTop: '4px', padding: '10px',
|
|
629
|
+
background: 'rgba(255,200,80,.10)',
|
|
630
|
+
border: '1px solid rgba(255,200,80,.28)',
|
|
631
|
+
borderRadius: '5px',
|
|
632
|
+
display: 'flex', flexDirection: 'column', gap: '6px',
|
|
633
|
+
fontSize: '12.5px',
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
h('div', null,
|
|
637
|
+
tp.credit
|
|
638
|
+
? ('署名要求:' + tp.credit)
|
|
639
|
+
: h('span', { style: { color: '#e0a030' } }, '该音色未标注署名要求')),
|
|
640
|
+
tp.termsUrl
|
|
641
|
+
? h('div', null,
|
|
642
|
+
'官方条款:',
|
|
643
|
+
h('a', {
|
|
644
|
+
href: tp.termsUrl,
|
|
645
|
+
target: '_blank',
|
|
646
|
+
rel: 'noreferrer noopener',
|
|
647
|
+
style: { color: '#6cf', wordBreak: 'break-all' },
|
|
648
|
+
}, tp.termsUrl),
|
|
649
|
+
)
|
|
650
|
+
: h('div', { style: { color: '#e0a030' } },
|
|
651
|
+
'该音色没有登记官方条款链接 —— 使用前请自行查证作者条款。'),
|
|
652
|
+
h('div', { style: { opacity: 0.7 } },
|
|
653
|
+
'下载后 zip 内也带 TERMS.md。你用它做的内容(视频、直播等)仍需遵守上述条款。'),
|
|
654
|
+
),
|
|
655
|
+
|
|
656
|
+
h('div', { style: { opacity: 0.6, fontSize: '11.5px' } },
|
|
657
|
+
'插件已按官方原文审核过该音色可用于本插件;'
|
|
658
|
+
+ '这里确认的是「你自己使用这些语音时也要守上述条款」。'),
|
|
659
|
+
|
|
660
|
+
h('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: '8px', marginTop: '6px' } },
|
|
661
|
+
h('button', {
|
|
662
|
+
type: 'button',
|
|
663
|
+
style: S.btn,
|
|
664
|
+
onClick: function () { cancelTerms() },
|
|
665
|
+
}, '取消'),
|
|
666
|
+
h('button', {
|
|
667
|
+
type: 'button',
|
|
668
|
+
style: Object.assign({}, S.btn, {
|
|
669
|
+
background: '#3a6', color: '#fff', border: '1px solid #3a6',
|
|
670
|
+
}),
|
|
671
|
+
onClick: function () { ackTerms() },
|
|
672
|
+
}, '我已阅读,开始下载'),
|
|
673
|
+
),
|
|
674
|
+
),
|
|
675
|
+
)
|
|
676
|
+
}
|
|
677
|
+
|
|
567
678
|
function askTerms(pack) {
|
|
568
679
|
set(function (p) {
|
|
569
680
|
return {
|
|
@@ -876,7 +987,13 @@ window.__ModuleLoader__.load({
|
|
|
876
987
|
p.installed ? h('span', { style: { color: '#2a7' } }, '已安装') : null,
|
|
877
988
|
h('button', {
|
|
878
989
|
type: 'button',
|
|
879
|
-
|
|
990
|
+
// ⚠️ 2026-10-18 第三轮审阅指出:原来的条件是
|
|
991
|
+
// `s.busy || !p.downloadable`,而离线时远程索引拿不到,
|
|
992
|
+
// 本地已装的包会是 installed=true / downloadable=false
|
|
993
|
+
// → **连卸载按钮都被禁用**。
|
|
994
|
+
//
|
|
995
|
+
// 卸载动的是本地文件,不该依赖 GitHub 在线状态。
|
|
996
|
+
disabled: s.busy || (!p.installed && !p.downloadable),
|
|
880
997
|
style: S.btn,
|
|
881
998
|
onClick: function () {
|
|
882
999
|
if (p.installed) { removePack(p.key, p.name || p.key); return }
|
|
@@ -904,44 +1021,6 @@ window.__ModuleLoader__.load({
|
|
|
904
1021
|
))
|
|
905
1022
|
rows.push(h('div', { key: 'vp-hint', style: S.subHint },
|
|
906
1023
|
'这些语音由 VOICEVOX 生成,各有各的署名与用途限制;下载后会附 TERMS.md。'))
|
|
907
|
-
// ── 下载前条款确认面板(v0.4.40)─────────────────────────────
|
|
908
|
-
//
|
|
909
|
-
// 只在用户点了某个未确认音色的「下载」时出现。
|
|
910
|
-
// 内容刻意只放:署名 + 官方条款链接 + 明确的确认动作。
|
|
911
|
-
// 不放我们自己转述的条款摘要 —— 转述会失真,用户该看原文。
|
|
912
|
-
if (s.termsPending) {
|
|
913
|
-
var tp = s.termsPending
|
|
914
|
-
rows.push(h('div', {
|
|
915
|
-
key: 'vp-terms-box',
|
|
916
|
-
style: {
|
|
917
|
-
marginTop: '6px', padding: '8px', borderRadius: '4px',
|
|
918
|
-
background: 'rgba(255,200,80,.10)',
|
|
919
|
-
border: '1px solid rgba(255,200,80,.35)',
|
|
920
|
-
display: 'flex', flexDirection: 'column', gap: '4px',
|
|
921
|
-
},
|
|
922
|
-
},
|
|
923
|
-
h('div', { style: { fontWeight: 600 } }, '下载前请先看条款:' + (tp.name || tp.key)),
|
|
924
|
-
h('div', { style: S.subHint },
|
|
925
|
-
tp.credit ? ('署名要求:' + tp.credit) : '该音色未标注署名要求'),
|
|
926
|
-
tp.termsUrl
|
|
927
|
-
? h('div', { style: S.subHint },
|
|
928
|
-
'官方条款:',
|
|
929
|
-
h('a', {
|
|
930
|
-
href: tp.termsUrl,
|
|
931
|
-
target: '_blank',
|
|
932
|
-
rel: 'noreferrer noopener',
|
|
933
|
-
style: { color: '#4a9' },
|
|
934
|
-
}, tp.termsUrl),
|
|
935
|
-
)
|
|
936
|
-
: h('div', { style: S.subHint }, '该音色没有登记官方条款链接 —— 请谨慎使用。'),
|
|
937
|
-
h('div', { style: S.subHint },
|
|
938
|
-
'下载后 zip 内也带 TERMS.md。你用它做的内容(视频、直播等)仍需遵守上述条款。'),
|
|
939
|
-
h('div', { style: S.row },
|
|
940
|
-
h('button', { type: 'button', style: S.btn, onClick: function () { ackTerms() } }, '我已阅读,下载'),
|
|
941
|
-
h('button', { type: 'button', style: S.btn, onClick: function () { cancelTerms() } }, '取消'),
|
|
942
|
-
),
|
|
943
|
-
))
|
|
944
|
-
}
|
|
945
1024
|
}
|
|
946
1025
|
}
|
|
947
1026
|
// ── 语音包专属设置(仅 bundled 时显示)──────────────────────────────
|
|
@@ -1642,7 +1721,14 @@ window.__ModuleLoader__.load({
|
|
|
1642
1721
|
rows.push(h('div', { key: 'foot', style: S.foot },
|
|
1643
1722
|
'改动立即生效,无需重启。以上为运行时覆盖,优先级高于 cordis.patch.yml。'))
|
|
1644
1723
|
|
|
1645
|
-
|
|
1724
|
+
// ── 根渲染:设置本体 + 可能出现的确认弹窗(v0.4.43)──────────────
|
|
1725
|
+
//
|
|
1726
|
+
// 弹窗作为**兄弟节点**挂在这里,而不是塞进 rows:
|
|
1727
|
+
// · 塞进 rows 会跟着设置卡片滚动,位置不固定(这正是 v0.4.40 的问题)
|
|
1728
|
+
// · 用 position:fixed 才能稳定居中覆盖
|
|
1729
|
+
var rootKids = [h('div', { key: 'root-box', style: S.box }, rows)]
|
|
1730
|
+
if (s.termsPending) rootKids.push(renderTermsModal(s.termsPending))
|
|
1731
|
+
return h('div', { key: 'root-wrap' }, rootKids)
|
|
1646
1732
|
}
|
|
1647
1733
|
|
|
1648
1734
|
/**
|