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)} /> ))}