Files
tick-stock-panel/frontend
shy3130 cce38f2ce7 fix(settings): 系统设置改后端持久化, 修复换端口后配置丢失
用户反馈系统设置里部分配置保存后重新打开又变回之前的状态。

根因不是保存逻辑坏了, 而是存储位置错。系统设置页有 9 项只写浏览器
localStorage: 通知弹窗开关/最大弹窗个数/声效开关/声效选择/语音播报
开关/音色/语速/个股外链模板/界面缩放。而浏览器按 origin (协议+主机+
端口) 隔离 localStorage, 桌面版启动时用 _find_free_port(3018) 从 3018
起取第一个空闲端口再以 http://127.0.0.1:{port} 打开窗口 —— 端口一变,
对这个应用就是另一个站点, 此前存的设置全部读不到。走 preferences.json
的那些设置一直正常, 所以现象是「有些配置会丢」。

修复: 后端权威副本 + localStorage 本地缓存的双写方案。
- preferences.py 新增 ui_prefs: 9 个键的白名单、只接受 JSON 标量、
  null 表示删除、16KB 上限;
- 新增 PUT /api/settings/preferences/ui-prefs, GET /preferences 带上
  ui_prefs;
- 新增 lib/uiPrefs.ts: setUiPref 写本地后 300ms 合并上推后端,
  hydrateUiPrefs 启动时从后端回填;
- 系统设置页 7 处 localStorage 直写、外链模板、界面缩放改走 setUiPref;
- main.tsx 启动触发回填并重放一次缩放。

保留 localStorage 而非全部搬到后端, 是因为通知/语音/缩放等模块在非
React 路径 (SSE 回调、index.html 首帧脚本) 同步取值, 不能等网络。
回填规则为本地优先: 本地已有值上推后端, 不被启动时的旧副本覆盖; 只有
本地缺失的键才用后端值补 —— 升级用户首次启动即完成迁移。

验证: 端到端模拟「清空 localStorage 换端口」后重载, 三项设置在 ~330ms
内全部恢复且稳定, UI 正确反映 (弹窗数 5 / 语音开启 / 缩放 110%);
后端 test_ui_prefs 8 passed (stash 实现后 8 个全失败, 确认用例有效);
tsc --noEmit 与 pnpm build 通过; ruff 告警数与基线持平。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-24 22:52:41 +08:00
..
2026-06-18 17:18:23 +08:00
2026-10-23 11:37:41 +08:00
2026-06-18 17:18:23 +08:00
2026-06-18 17:18:23 +08:00
2026-06-18 17:18:23 +08:00