dsh-done-sound 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +90 -10
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -28,6 +28,7 @@ window.__ModuleLoader__.load({
|
|
|
28
28
|
'.dtc-row{justify-content:space-between;align-items:center;gap:12px;display:flex}',
|
|
29
29
|
'.dtc-muted{color:var(--dsw-alias-label-secondary);font-size:12px}',
|
|
30
30
|
'.dtc-err{color:var(--dsw-alias-state-error-primary);white-space:pre-wrap;font-size:12px}',
|
|
31
|
+
'.dtc-ok{color:var(--dsw-alias-state-success-primary);white-space:pre-wrap;font-size:12px;word-break:break-all}',
|
|
31
32
|
'.dtc-btn{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:6px;padding:3px 12px;font-size:12px;white-space:nowrap}',
|
|
32
33
|
'.dtc-btn:disabled{opacity:.5;cursor:default}',
|
|
33
34
|
'.dtc-file{display:inline-flex;align-items:center}',
|
|
@@ -86,6 +87,11 @@ window.__ModuleLoader__.load({
|
|
|
86
87
|
retryFailed: '自动发送「继续」失败',
|
|
87
88
|
logPath: '日志文件',
|
|
88
89
|
exportLog: '导出日志',
|
|
90
|
+
exportSaved: '日志已导出',
|
|
91
|
+
exportSavedFile: '保存文件名:{name}',
|
|
92
|
+
exportSavedFallbackHint: '未弹出保存窗口,文件已存到浏览器默认下载文件夹(通常 C:\\Users\\你的用户名\\Downloads)',
|
|
93
|
+
exportLogPath: '原始日志路径:{path}(复制到资源管理器地址栏可打开)',
|
|
94
|
+
exportLogPathUnknown: '原始日志路径未知(可在插件目录 logs 文件夹查看)',
|
|
89
95
|
version: '当前版本',
|
|
90
96
|
updateAvailable: '有新版本',
|
|
91
97
|
upToDate: '已是最新',
|
|
@@ -134,6 +140,11 @@ window.__ModuleLoader__.load({
|
|
|
134
140
|
retryFailed: 'failed to auto-send "continue"',
|
|
135
141
|
logPath: 'Log file',
|
|
136
142
|
exportLog: 'Export log',
|
|
143
|
+
exportSaved: 'Log exported',
|
|
144
|
+
exportSavedFile: 'Saved file name: {name}',
|
|
145
|
+
exportSavedFallbackHint: 'No save dialog shown; saved to the browser default Downloads folder (usually C:\\Users\\YourName\\Downloads)',
|
|
146
|
+
exportLogPath: 'Original log path: {path} (copy into File Explorer address bar to open)',
|
|
147
|
+
exportLogPathUnknown: 'Original log path unknown (check the plugin logs folder)',
|
|
137
148
|
version: 'Version',
|
|
138
149
|
updateAvailable: 'Update available',
|
|
139
150
|
upToDate: 'Up to date',
|
|
@@ -418,11 +429,21 @@ window.__ModuleLoader__.load({
|
|
|
418
429
|
loaded: true,
|
|
419
430
|
});
|
|
420
431
|
};
|
|
432
|
+
// 预热:模块一激活就拉取 Host 持久化配置(如自动重连秒数),
|
|
433
|
+
// 避免页面刷新后倒计时/自动重连先用初始默认值(60s),
|
|
434
|
+
// 而设置卡却显示已保存值(20s)——两者必须一致。
|
|
435
|
+
// 失败静默,卡片挂载和 detector 挂载时还会再次同步兜底。
|
|
436
|
+
api('/dsh-done-sound/api/status')
|
|
437
|
+
.then((payload) => {
|
|
438
|
+
if (payload && typeof payload === 'object') syncConfig(payload);
|
|
439
|
+
})
|
|
440
|
+
.catch(() => {});
|
|
421
441
|
|
|
422
442
|
// ---- Settings card (global slot) ----
|
|
423
443
|
const TurnChimeCard = (props) => {
|
|
424
444
|
const cfg = useConfig();
|
|
425
445
|
const [error, setError] = react.useState(null);
|
|
446
|
+
const [exportInfo, setExportInfo] = react.useState(null);
|
|
426
447
|
const [busy, setBusy] = react.useState(false);
|
|
427
448
|
const [lang] = react.useState(resolveLang());
|
|
428
449
|
const L = (key) => t(lang, key);
|
|
@@ -471,8 +492,20 @@ window.__ModuleLoader__.load({
|
|
|
471
492
|
);
|
|
472
493
|
// Export today's log file: fetch it from the host, then hand the
|
|
473
494
|
// browser a Blob download — the native save dialog lets the user pick
|
|
474
|
-
// where to store it (filename is today's dated log name).
|
|
495
|
+
// where to store it (filename is today's dated log name). After a
|
|
496
|
+
// successful export, show a green banner with the saved file name and
|
|
497
|
+
// the original log path so the user can find the file on Windows even
|
|
498
|
+
// when the browser cannot show a save dialog.
|
|
475
499
|
const exportLog = () => {
|
|
500
|
+
setExportInfo(null);
|
|
501
|
+
const showSaved = (savedName, fallbackHint) => {
|
|
502
|
+
const lines = [L('exportSaved') + ' ✓', L('exportSavedFile').replace('{name}', savedName)];
|
|
503
|
+
if (fallbackHint) lines.push(L('exportSavedFallbackHint'));
|
|
504
|
+
// 原始日志路径来自 Host,复制到资源管理器地址栏即可直接打开,
|
|
505
|
+
// 最方便排查「有概率无音效」类问题。
|
|
506
|
+
lines.push(cfg.logPath ? L('exportLogPath').replace('{path}', cfg.logPath) : L('exportLogPathUnknown'));
|
|
507
|
+
setExportInfo(lines.join('\n'));
|
|
508
|
+
};
|
|
476
509
|
fetch('/dsh-done-sound/api/log/export')
|
|
477
510
|
.then((res) => {
|
|
478
511
|
if (!res.ok) {
|
|
@@ -483,15 +516,50 @@ window.__ModuleLoader__.load({
|
|
|
483
516
|
return res.text();
|
|
484
517
|
})
|
|
485
518
|
.then((text) => {
|
|
486
|
-
const
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
519
|
+
const fileName = cfg.logFileName || 'dsh-done-sound.log';
|
|
520
|
+
const fallbackDownload = () => {
|
|
521
|
+
const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
|
|
522
|
+
const url = URL.createObjectURL(blob);
|
|
523
|
+
const a = document.createElement('a');
|
|
524
|
+
a.href = url;
|
|
525
|
+
a.download = fileName;
|
|
526
|
+
document.body.appendChild(a);
|
|
527
|
+
a.click();
|
|
528
|
+
a.remove();
|
|
529
|
+
setTimeout(() => URL.revokeObjectURL(url), 2000);
|
|
530
|
+
showSaved(fileName, true);
|
|
531
|
+
};
|
|
532
|
+
// 优先用浏览器原生「另存为」对话框(File System Access API,
|
|
533
|
+
// Chrome/Edge 支持),让用户自己选择保存位置;
|
|
534
|
+
// 不支持或用户取消时回退为普通下载。
|
|
535
|
+
if (typeof window.showSaveFilePicker === 'function') {
|
|
536
|
+
window
|
|
537
|
+
.showSaveFilePicker({
|
|
538
|
+
suggestedName: fileName,
|
|
539
|
+
types: [{ description: '日志文件', accept: { 'text/plain': ['.log', '.txt'] } }],
|
|
540
|
+
})
|
|
541
|
+
.then((handle) => {
|
|
542
|
+
const savedName = handle && typeof handle.name === 'string' && handle.name ? handle.name : fileName;
|
|
543
|
+
return handle.createWritable().then(async (writable) => {
|
|
544
|
+
await writable.write(text);
|
|
545
|
+
await writable.close();
|
|
546
|
+
showSaved(savedName, false);
|
|
547
|
+
});
|
|
548
|
+
})
|
|
549
|
+
.catch((err) => {
|
|
550
|
+
// 用户点了「取消」关闭对话框 → 不算错误,直接结束。
|
|
551
|
+
if (err && err.name === 'AbortError') return;
|
|
552
|
+
// 其他失败(如手势过期、浏览器限制)→ 回退为普通下载。
|
|
553
|
+
try {
|
|
554
|
+
if (typeof console !== 'undefined') console.warn('[dsh-done-sound] save picker failed, falling back to download:', err);
|
|
555
|
+
} catch {
|
|
556
|
+
// ignore
|
|
557
|
+
}
|
|
558
|
+
fallbackDownload();
|
|
559
|
+
});
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
fallbackDownload();
|
|
495
563
|
})
|
|
496
564
|
.catch((err) => {
|
|
497
565
|
try {
|
|
@@ -658,6 +726,7 @@ window.__ModuleLoader__.load({
|
|
|
658
726
|
L('exportLog'),
|
|
659
727
|
),
|
|
660
728
|
),
|
|
729
|
+
exportInfo !== null && react.createElement('div', { className: 'dtc-ok' }, exportInfo),
|
|
661
730
|
|
|
662
731
|
react.createElement(
|
|
663
732
|
'div',
|
|
@@ -874,6 +943,17 @@ window.__ModuleLoader__.load({
|
|
|
874
943
|
const prevPendingKeysRef = react.useRef('');
|
|
875
944
|
const seededRef = react.useRef(false);
|
|
876
945
|
|
|
946
|
+
// 兜底:挂载时若配置尚未从 Host 同步(如页面刚刷新、apply 预热未完成),
|
|
947
|
+
// 主动拉取一次,确保自动重连倒计时使用用户保存的秒数而非初始默认值。
|
|
948
|
+
react.useEffect(() => {
|
|
949
|
+
if (configStore.value.loaded) return;
|
|
950
|
+
api('/dsh-done-sound/api/status')
|
|
951
|
+
.then((payload) => {
|
|
952
|
+
if (payload && typeof payload === 'object') syncConfig(payload);
|
|
953
|
+
})
|
|
954
|
+
.catch(() => {});
|
|
955
|
+
}, []);
|
|
956
|
+
|
|
877
957
|
const snap =
|
|
878
958
|
typeof useSession === 'function'
|
|
879
959
|
? useSession((s) => {
|