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 (
加载中...
}>
} />
} />
} />
} />
} />
)
}