import { useState, useEffect, lazy, Suspense } from 'react' import { Routes, Route, NavLink, useLocation, useNavigate } from 'react-router-dom' import { FundOutlined, MonitorOutlined, FileTextOutlined, ClusterOutlined, MenuFoldOutlined, MenuUnfoldOutlined, WalletOutlined, } from '@ant-design/icons' const ScreeningPanel = lazy(() => import('./pages/ScreeningPanel')) const AnalysisMonitor = lazy(() => import('./pages/AnalysisMonitor')) const ReportsViewer = lazy(() => import('./pages/ReportsViewer')) const BatchManager = lazy(() => import('./pages/BatchManager')) const PortfolioPanel = lazy(() => import('./pages/PortfolioPanel')) const SetupWizard = lazy(() => import('./pages/SetupWizard')) const navItems = [ { path: '/', icon: , label: '筛选', key: '1' }, { path: '/monitor', icon: , label: '监控', key: '2' }, { path: '/reports', icon: , label: '报告', key: '3' }, { path: '/batch', icon: , label: '批量', key: '4' }, { path: '/portfolio', icon: , label: '组合', key: '5' }, ] function Layout({ children }) { const [collapsed, setCollapsed] = useState(false) const [isMobile, setIsMobile] = useState(false) const location = useLocation() useEffect(() => { const checkMobile = () => setIsMobile(window.innerWidth < 768) checkMobile() window.addEventListener('resize', checkMobile) return () => window.removeEventListener('resize', checkMobile) }, []) const currentPage = navItems.find(item => item.path === '/' ? location.pathname === '/' : location.pathname.startsWith(item.path) )?.label || 'TradingAgents' return (
{/* Sidebar - Apple Glass Navigation */} {!isMobile && ( )} {/* Main Content */}
{!isMobile && (
{currentPage}
{new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', })}
)}
{children}
{/* Mobile TabBar */} {isMobile && ( )}
) } export default function App() { const navigate = useNavigate() const [configured, setConfigured] = useState(null) // null = checking, true/false // Check if API key is configured on mount useEffect(() => { const checkConfig = async () => { try { // Check via Tauri command first (desktop app) if (window.__TAURI__) { const { invoke } = window.__TAURI__.core const isConfigured = await invoke('is_configured') setConfigured(isConfigured) } else { // Fallback: call backend API const res = await fetch('/api/config/check') const data = await res.json() setConfigured(data.configured) } } catch (e) { // Backend might not be ready yet, assume not configured setConfigured(false) } } checkConfig() }, []) useEffect(() => { const handleKeyDown = (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return // Close modals on Escape if (e.key === 'Escape') { document.querySelector('.ant-modal-wrap')?.click() return } // Navigation shortcuts switch (e.key) { case '1': navigate('/'); break case '2': navigate('/monitor'); break case '3': navigate('/reports'); break case '4': navigate('/batch'); break case '5': navigate('/portfolio'); break default: break } } window.addEventListener('keydown', handleKeyDown) return () => window.removeEventListener('keydown', handleKeyDown) }, [navigate]) // Still checking config if (configured === null) { return (
加载中...
) } // Not configured - show setup wizard if (!configured) { return (
加载中...
}> setConfigured(true)} />
) } return (
加载中...
}> } /> } /> } /> } /> } />
) }