import { useEffect, lazy, Suspense } from 'react'; import { HashRouter, Routes, Route, Navigate } from 'react-router-dom'; import { ConfigProvider, theme as antdTheme, Spin } from 'antd'; import zhCN from 'antd/locale/zh_CN'; import MainLayout from './layouts/MainLayout'; import Login from './pages/Login'; import { ErrorBoundary } from './components/ErrorBoundary'; import { useAuthStore } from './stores/auth'; import { useAppStore } from './stores/app'; const Home = lazy(() => import('./pages/Home')); const Users = lazy(() => import('./pages/Users')); const Roles = lazy(() => import('./pages/Roles')); const Organizations = lazy(() => import('./pages/Organizations')); const Workflow = lazy(() => import('./pages/Workflow')); const Messages = lazy(() => import('./pages/Messages')); const Settings = lazy(() => import('./pages/Settings')); const PluginAdmin = lazy(() => import('./pages/PluginAdmin')); const PluginMarket = lazy(() => import('./pages/PluginMarket')); const PluginCRUDPage = lazy(() => import('./pages/PluginCRUDPage')); const PluginTabsPage = lazy(() => import('./pages/PluginTabsPage').then((m) => ({ default: m.PluginTabsPage }))); const PluginTreePage = lazy(() => import('./pages/PluginTreePage').then((m) => ({ default: m.PluginTreePage }))); const PluginGraphPage = lazy(() => import('./pages/PluginGraphPage').then((m) => ({ default: m.PluginGraphPage }))); const PluginDashboardPage = lazy(() => import('./pages/PluginDashboardPage').then((m) => ({ default: m.PluginDashboardPage }))); const PluginKanbanPage = lazy(() => import('./pages/PluginKanbanPage')); function PrivateRoute({ children }: { children: React.ReactNode }) { const isAuthenticated = useAuthStore((s) => s.isAuthenticated); return isAuthenticated ? <>{children} : ; } const themeConfig = { token: { colorPrimary: '#2563eb', colorSuccess: '#059669', colorWarning: '#d97706', colorError: '#dc2626', colorInfo: '#0284c7', colorBgLayout: '#f8fafc', colorBgContainer: '#ffffff', colorBgElevated: '#ffffff', colorBorder: '#e2e8f0', colorBorderSecondary: '#f1f5f9', borderRadius: 10, borderRadiusLG: 12, borderRadiusSM: 6, fontFamily: "'Noto Sans SC', -apple-system, system-ui, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', Helvetica, Arial, sans-serif", fontSize: 14, fontSizeHeading4: 20, controlHeight: 40, controlHeightLG: 44, controlHeightSM: 32, boxShadow: 'none', boxShadowSecondary: '0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)', }, components: { Button: { primaryShadow: 'none', fontWeight: 500, }, Card: { paddingLG: 20, }, Table: { headerBg: '#f1f5f9', headerColor: '#475569', rowHoverBg: '#f1f5f9', fontSize: 14, }, Menu: { itemBorderRadius: 10, itemMarginInline: 8, itemHeight: 40, }, Modal: { borderRadiusLG: 16, }, Tag: { borderRadiusSM: 6, }, }, }; const darkThemeConfig = { ...themeConfig, token: { ...themeConfig.token, colorBgLayout: '#0f172a', colorBgContainer: '#1e293b', colorBgElevated: '#334155', colorBorder: '#334155', colorBorderSecondary: 'rgba(255, 255, 255, 0.06)', boxShadow: 'none', boxShadowSecondary: '0 2px 8px rgba(0,0,0,0.3), 0 1px 3px rgba(0,0,0,0.2)', }, components: { ...themeConfig.components, Table: { headerBg: '#1e293b', headerColor: '#94a3b8', rowHoverBg: '#1e293b', }, }, }; export default function App() { const loadFromStorage = useAuthStore((s) => s.loadFromStorage); const themeMode = useAppStore((s) => s.theme); useEffect(() => { loadFromStorage(); }, [loadFromStorage]); useEffect(() => { document.documentElement.setAttribute('data-theme', themeMode); }, [themeMode]); const isDark = themeMode === 'dark'; return ( <> 跳转到主要内容 } /> }> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> ); }