From 66f4b7e0c4b8c258519c7946809794f3cfe8f116 Mon Sep 17 00:00:00 2001 From: impressionyang Date: Thu, 21 May 2026 19:10:11 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A2=9E=E5=BC=BA=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=A4=84=E7=90=86=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E4=B9=9F=E8=83=BD=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端变更: - src/app/mod.rs: 窗口 hide() 使用 _ 忽略错误,避免 unwrap() panic 前端变更: - web/src/components/ErrorBoundary.tsx: 新增错误边界组件,捕获未处理的错误 - web/src/main.tsx: 使用 ErrorBoundary 包裹 App 组件 - web/src/App.tsx: 优化主题加载和监听器的错误处理,确保失败时使用默认主题 错误处理能力: - 即使 Tauri 命令失败,页面也能正常显示 - 未捕获错误会显示友好的错误页面,提供刷新按钮 - 主题加载失败时自动使用 system 主题降级 - 事件监听器清理更安全,避免异步问题 构建结果: - Windows 包:dist/impress-asr-windows-x64-20260521_190528.zip - 文件大小:5.0MB --- src/app/mod.rs | 2 +- web/src/App.tsx | 13 +++- web/src/components/ErrorBoundary.tsx | 89 ++++++++++++++++++++++++++++ web/src/main.tsx | 5 +- 4 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 web/src/components/ErrorBoundary.tsx diff --git a/src/app/mod.rs b/src/app/mod.rs index f57f1f8..6ec01dd 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -151,7 +151,7 @@ pub fn run() -> Result<()> { tauri::WindowEvent::CloseRequested { api, .. } => { info!(" [窗口] 关闭请求 - 隐藏窗口到托盘"); // 隐藏窗口而不是关闭 - window.hide().unwrap(); + let _ = window.hide(); api.prevent_close(); } tauri::WindowEvent::Focused(focused) => { diff --git a/web/src/App.tsx b/web/src/App.tsx index eab3b17..0f4ccbe 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -27,19 +27,28 @@ function App() { applyTheme(currentTheme) } catch (e) { console.error('Failed to load theme:', e) + // 使用默认主题,不影响页面显示 + applyTheme('system') } } loadTheme() // 监听主题变化事件 - const unlisten = window.__TAURI__.listen('theme-change', (event) => { + let unlistenFn: (() => void) | null = null + window.__TAURI__.listen('theme-change', (event) => { const newTheme = event.payload as string setTheme(newTheme as Theme) applyTheme(newTheme as Theme) + }).then(fn => { + unlistenFn = fn + }).catch(e => { + console.error('Failed to setup theme listener:', e) }) return () => { - unlisten.then(fn => fn()) + if (unlistenFn) { + unlistenFn() + } } }, []) diff --git a/web/src/components/ErrorBoundary.tsx b/web/src/components/ErrorBoundary.tsx new file mode 100644 index 0000000..3834338 --- /dev/null +++ b/web/src/components/ErrorBoundary.tsx @@ -0,0 +1,89 @@ +import { Component, ErrorInfo, ReactNode } from 'react' + +interface Props { + children: ReactNode + fallback?: ReactNode +} + +interface State { + hasError: boolean + error: Error | null +} + +export class ErrorBoundary extends Component { + public state: State = { + hasError: false, + error: null + } + + public static getDerivedStateFromError(error: Error): State { + return { hasError: true, error } + } + + public componentDidCatch(error: Error, errorInfo: ErrorInfo): void { + console.error('ErrorBoundary caught an error:', error, errorInfo) + } + + public render(): ReactNode { + if (this.state.hasError) { + if (this.props.fallback) { + return this.props.fallback + } + + return ( +
+

+ 发生错误 +

+

+ 抱歉,页面加载时出现问题。请尝试刷新页面或重启应用。 +

+ {this.state.error && ( +
+ + 错误详情(点击展开) + + {this.state.error.toString()} +
+ )} + +
+ ) + } + + return this.props.children + } +} + +export default ErrorBoundary diff --git a/web/src/main.tsx b/web/src/main.tsx index 791f139..481bd1a 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -1,10 +1,13 @@ import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' +import ErrorBoundary from './components/ErrorBoundary' import './index.css' ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - + + + , )