import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import Layout from './components/layout/Layout'; import Dashboard from './pages/Dashboard'; import Accounts from './pages/Accounts'; import Settings from './pages/Settings'; import ApiProxy from './pages/ApiProxy'; import Monitor from './pages/Monitor'; import TokenStats from './pages/TokenStats'; import Security from './pages/Security'; import ThemeManager from './components/common/ThemeManager'; import UserToken from './pages/UserToken'; import { UpdateNotification } from './components/UpdateNotification'; import DebugConsole from './components/debug/DebugConsole'; import { useEffect, useState } from 'react'; import { useConfigStore } from './stores/useConfigStore'; import { useAccountStore } from './stores/useAccountStore'; import { useTranslation } from 'react-i18next'; import { listen } from '@tauri-apps/api/event'; import { isTauri } from './utils/env'; import { request as invoke } from './utils/request'; import { AdminAuthGuard } from './components/common/AdminAuthGuard'; const router = createBrowserRouter([ { path: '/', element: , children: [ { index: true, element: , }, { path: 'accounts', element: , }, { path: 'api-proxy', element: , }, { path: 'monitor', element: , }, { path: 'token-stats', element: , }, { path: 'user-token', element: , }, { path: 'security', element: , }, { path: 'settings', element: , }, ], }, ]); function App() { const { config, loadConfig } = useConfigStore(); const { fetchCurrentAccount, fetchAccounts } = useAccountStore(); const { i18n } = useTranslation(); useEffect(() => { loadConfig(); }, [loadConfig]); // Sync language from config useEffect(() => { if (config?.language) { i18n.changeLanguage(config.language); // Support RTL if (config.language === 'ar') { document.documentElement.dir = 'rtl'; } else { document.documentElement.dir = 'ltr'; } } }, [config?.language, i18n]); // Listen for tray events useEffect(() => { if (!isTauri()) return; const unlistenPromises: Promise<() => void>[] = []; // 监听托盘切换账号事件 unlistenPromises.push( listen('tray://account-switched', () => { console.log('[App] Tray account switched, refreshing...'); fetchCurrentAccount(); fetchAccounts(); }) ); // 监听托盘刷新事件 unlistenPromises.push( listen('tray://refresh-current', () => { console.log('[App] Tray refresh triggered, refreshing...'); fetchCurrentAccount(); fetchAccounts(); }) ); // 监听后端全量刷新事件 (Command / Scheduler) unlistenPromises.push( listen('accounts://refreshed', () => { console.log('[App] Backend triggered quota refresh, syncing UI...'); fetchCurrentAccount(); fetchAccounts(); }) ); // Cleanup return () => { Promise.all(unlistenPromises).then(unlisteners => { unlisteners.forEach(unlisten => unlisten()); }); }; }, [fetchCurrentAccount, fetchAccounts]); // Update notification state const [showUpdateNotification, setShowUpdateNotification] = useState(false); // Check for updates on startup useEffect(() => { const checkUpdates = async () => { try { console.log('[App] Checking if we should check for updates...'); const shouldCheck = await invoke('should_check_updates'); console.log('[App] Should check updates:', shouldCheck); if (shouldCheck) { setShowUpdateNotification(true); // 我们这里只负责显示通知组件,通知组件内部会去调用 check_for_updates // 我们在显示组件后,标记已经检查过了(即便失败或无更新,组件内部也会处理) await invoke('update_last_check_time'); console.log('[App] Update check cycle initiated and last check time updated.'); } } catch (error) { console.error('Failed to check update settings:', error); } }; // Delay check to avoid blocking initial render const timer = setTimeout(checkUpdates, 2000); return () => clearTimeout(timer); }, []); return ( {showUpdateNotification && ( setShowUpdateNotification(false)} /> )} ); } export default App;