import { useEffect, useRef, useState } from 'react'; import { invoke } from '@tauri-apps/api/core'; import { listen } from '@tauri-apps/api/event'; import { Bot, ExternalLink, FileKey, Gauge, GitFork, History, LogIn, MessageCircle, Network, ServerCog, Settings, } from 'lucide-react'; import appLogo from './assets/logo.jpg'; import { CoreRuntimeProvider, useCoreRuntime } from './coreRuntime'; import { ConfigPanelPage } from './pages/ConfigPanel'; import { ApiAccessPage } from './pages/ApiAccessPage'; import { AuthFileManagementPage } from './pages/AuthFileManagementPage'; import { KernelPage } from './pages/Kernel'; import { OAuthLoginPage } from './pages/ManagementPages'; import { QuotaPage } from './pages/QuotaPage'; import { AgentsPage } from './pages/AgentsPage'; import { ThinkingAliasesPage } from './pages/ThinkingAliasesPage'; import { UsageRecordsPage } from './pages/UsageRecordsPage'; const CONTACT_URL = 'https://qm.qq.com/q/3queDaIG'; const pages = [ { id: 'kernel', label: '内核', icon: ServerCog, component: KernelPage, }, { id: 'config', label: '配置', icon: Settings, component: ConfigPanelPage, }, { id: 'thinking-aliases', label: '模型别名', icon: GitFork, component: ThinkingAliasesPage, }, { id: 'oauth', label: 'OAuth', icon: LogIn, component: OAuthLoginPage, }, { id: 'api', label: 'API 接入', icon: Network, component: ApiAccessPage, }, { id: 'auth-files', label: '认证文件', icon: FileKey, component: AuthFileManagementPage, }, { id: 'quota', label: '配额', icon: Gauge, component: QuotaPage, }, { id: 'usage-records', label: '使用记录', icon: History, component: UsageRecordsPage, }, { id: 'agents', label: '智能体', icon: Bot, component: AgentsPage, }, ] as const; type PageId = (typeof pages)[number]['id']; type WindowsCloseAction = 'exit' | 'minimize-to-tray'; type WindowsClosePrompt = { resolvingAction: WindowsCloseAction | null; error: string | null; }; function App() { return ( ); } function AppContent() { const [active, setActive] = useState('kernel'); const [windowsClosePrompt, setWindowsClosePrompt] = useState(null); const closeDialogRef = useRef(null); const { status } = useCoreRuntime(); const coreRunning = Boolean(status?.running); const activePage = pages.find((page) => page.id === active) ?? pages[0]; const ActivePage = activePage.component; useEffect(() => { if (!coreRunning && active !== 'kernel') { setActive('kernel'); } }, [active, coreRunning]); useEffect(() => { let disposed = false; let stopListening: (() => void) | undefined; void listen('windows-close-requested', () => { setWindowsClosePrompt((current) => current ?? { resolvingAction: null, error: null, }, ); }) .then((stop) => { if (disposed) { stop(); } else { stopListening = stop; } }) .catch((error) => { console.error('监听 Windows 关闭确认事件失败', error); }); return () => { disposed = true; stopListening?.(); }; }, []); useEffect(() => { if (!windowsClosePrompt || windowsClosePrompt.resolvingAction) { return; } const frame = window.requestAnimationFrame(() => { closeDialogRef.current?.focus(); }); return () => window.cancelAnimationFrame(frame); }, [windowsClosePrompt]); const select = (pageId: PageId) => { if (pageId !== 'kernel' && !coreRunning) { return; } setActive(pageId); }; const openContact = async () => { try { await invoke('open_external_url', { url: CONTACT_URL }); } catch (error) { console.error('打开联系我们链接失败', error); } }; const resolveWindowsCloseRequest = async (action: WindowsCloseAction) => { setWindowsClosePrompt((current) => current ? { ...current, resolvingAction: action, error: null, } : current, ); try { await invoke('resolve_windows_close_request', { action }); setWindowsClosePrompt(null); } catch (error) { setWindowsClosePrompt((current) => current ? { ...current, resolvingAction: null, error: error instanceof Error ? error.message : String(error), } : current, ); } }; return ( <>
{activePage.id === 'kernel' || coreRunning ? ( ) : ( )}
{windowsClosePrompt ? (
{ if (event.key === 'Escape') { event.preventDefault(); } }} >
关闭窗口

请选择后续操作

你可以退出程序,或让 EasyCLIProxyAPI 继续在系统托盘中运行。

{windowsClosePrompt.error ? (
{windowsClosePrompt.error}
) : null}
) : null} ); } function CoreLockedPage() { return (
); } export default App;