From 7326aa2d7e0aa432531bd747f5337bf2243af1e9 Mon Sep 17 00:00:00 2001 From: baiqing Date: Wed, 29 Apr 2026 17:05:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(vocab):=20=E5=85=BC=E5=AE=B9=20Swift=20dict?= =?UTF-8?q?ionary.json=20=E8=80=81=20schema=20(notes/hitCount)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 老 Swift 版 DictionaryEntry 写到 ~/Library/Application Support/OpenLess/dictionary.json 的 字段名是 `notes`(复数)和 `hitCount`,Rust 这边期待 `note`/`hits` → serde decode 失败 → list_vocab 命令永远返回 Err → 前端 spinner 永久卡死。 修法: - types.rs DictionaryEntry 加 #[serde(alias = "notes")] / #[serde(alias = "hitCount")] + default,兼容老文件 + 新写入。 - Vocab.tsx refresh() 加 try/catch + finally,即使后端报错也清掉加载状态,显示错误提示。 --- openless -all/app/src-tauri/src/types.rs | 10 ++++++++++ openless -all/app/src/pages/Vocab.tsx | 24 +++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/openless -all/app/src-tauri/src/types.rs b/openless -all/app/src-tauri/src/types.rs index 88feccad..7fdaa8c8 100644 --- a/openless -all/app/src-tauri/src/types.rs +++ b/openless -all/app/src-tauri/src/types.rs @@ -57,12 +57,22 @@ pub struct DictationSession { pub struct DictionaryEntry { pub id: String, pub phrase: String, + /// Swift `DictionaryEntry.swift` 用的是 `notes`(复数);Rust 用 `note`(单数)。 + /// alias 接受老文件 + 自身字段名。 + #[serde(default, alias = "notes")] pub note: Option, + #[serde(default = "default_true")] pub enabled: bool, + /// Swift 用 `hitCount`,Rust 用 `hits`。alias + default 让老文件不缺字段。 + #[serde(default, alias = "hitCount")] pub hits: u64, + /// Swift 写 ISO8601;Rust 也用 String,直接通过。 + #[serde(default)] pub created_at: String, } +fn default_true() -> bool { true } + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct UserPreferences { diff --git a/openless -all/app/src/pages/Vocab.tsx b/openless -all/app/src/pages/Vocab.tsx index 8267439b..b3d9e6ed 100644 --- a/openless -all/app/src/pages/Vocab.tsx +++ b/openless -all/app/src/pages/Vocab.tsx @@ -11,10 +11,19 @@ export function Vocab() { const [loading, setLoading] = useState(true); const inputRef = useRef(null); + const [error, setError] = useState(null); + const refresh = async () => { - const data = await listVocab(); - setEntries(data); - setLoading(false); + try { + setError(null); + const data = await listVocab(); + setEntries(data); + } catch (e) { + // 之前没 try/catch,后端 decode 失败时 spinner 永久卡死。 + setError(e instanceof Error ? e.message : String(e)); + } finally { + setLoading(false); + } }; useEffect(() => { @@ -82,12 +91,17 @@ export function Vocab() {
{loading &&
加载中…
} - {!loading && entries.length === 0 && ( + {!loading && error && ( +
+ 加载失败:{error} +
+ )} + {!loading && !error && entries.length === 0 && (
还没有词条。在上面输入一个生词或专业术语,让模型在听写时优先匹配。
)} - {entries.map(e => ( + {!error && entries.map(e => ( onRemove(e.id)} onToggle={() => onToggle(e)} /> ))}