import React, { useState, useEffect} from 'react'; import { createRoot } from 'react-dom/client'; import { createBrowserRouter, RouterProvider, Outlet, useNavigate, useLocation, Navigate, useParams, useRouteError } from 'react-router'; import { Layout, Menu, Button, Table, Space, Form, Input, Select, message, Modal, Card, Spin, Row, Col, Breadcrumb, Avatar, Dropdown, ConfigProvider, theme, Typography, Switch, Badge, Image, Upload, Divider, Descriptions, Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer } from 'antd'; import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, DashboardOutlined, TeamOutlined, SettingOutlined, LogoutOutlined, BellOutlined, BookOutlined, FileOutlined, PieChartOutlined, VerticalAlignTopOutlined, CloseOutlined, SearchOutlined } from '@ant-design/icons'; import { QueryClient, QueryClientProvider, } from '@tanstack/react-query'; import dayjs from 'dayjs'; import weekday from 'dayjs/plugin/weekday'; import localeData from 'dayjs/plugin/localeData'; import 'dayjs/locale/zh-cn'; import type { GlobalConfig } from '../share/types.ts'; import { AuthProvider, useAuth, ThemeProvider, useTheme, } from './hooks_sys.tsx'; import { DashboardPage } from './pages_dashboard.tsx'; import { UsersPage } from './pages_users.tsx'; import { FileLibraryPage } from './pages_file_library.tsx'; import { KnowInfoPage } from './pages_know_info.tsx'; import { MessagesPage } from './pages_messages.tsx'; import {SettingsPage } from './pages_settings.tsx'; import {ThemeSettingsPage} from './pages_theme_settings.tsx' import { ChartDashboardPage } from './pages_chart.tsx'; import { LoginMapPage } from './pages_map.tsx'; import { LoginPage } from './pages_login_reg.tsx'; import { ProtectedRoute } from './components_protected_route.tsx'; // 配置 dayjs 插件 dayjs.extend(weekday); dayjs.extend(localeData); // 设置 dayjs 语言 dayjs.locale('zh-cn'); const { Header, Sider, Content } = Layout; // 创建QueryClient实例 const queryClient = new QueryClient(); // 声明全局配置对象类型 declare global { interface Window { CONFIG?: GlobalConfig; } } // 主布局组件 const MainLayout = () => { const [collapsed, setCollapsed] = useState(false); const { user, logout } = useAuth(); const { isDark, toggleTheme } = useTheme(); const navigate = useNavigate(); const location = useLocation(); const [openKeys, setOpenKeys] = useState([]); const [showBackTop, setShowBackTop] = useState(false); const [searchText, setSearchText] = useState(''); const [filteredMenuItems, setFilteredMenuItems] = useState([]); // 检测滚动位置,控制回到顶部按钮显示 useEffect(() => { const handleScroll = () => { setShowBackTop(window.pageYOffset > 300); }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); // 回到顶部 const scrollToTop = () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }; // 菜单项配置 const menuItems = [ { key: '/dashboard', icon: , label: '仪表盘', }, { key: '/analysis', icon: , label: '数据分析', children: [ { key: '/chart-dashboard', label: '图表统计', }, { key: '/map-dashboard', label: '地图概览', }, ], }, { key: '/files', icon: , label: '文件管理', children: [ { key: '/file-library', label: '文件库', }, ], }, { key: '/know-info', icon: , label: '知识库', }, { key: '/users', icon: , label: '用户管理', }, { key: '/messages', icon: , label: '消息管理', }, { key: '/settings_group', icon: , label: '系统设置', children: [ { key: '/theme-settings', label: '主题设置', }, { key: '/settings', label: '基本设置', }, ], }, ]; // 初始化filteredMenuItems useEffect(() => { setFilteredMenuItems(menuItems); }, []); // 搜索菜单项 const handleSearch = (value: string) => { setSearchText(value); if (!value.trim()) { setFilteredMenuItems(menuItems); return; } // 搜索功能 - 过滤菜单项 const filtered = menuItems.reduce((acc: any[], item) => { // 检查主菜单项是否匹配 const mainItemMatch = item.label.toString().toLowerCase().includes(value.toLowerCase()); // 如果有子菜单,检查子菜单中是否有匹配项 if (item.children) { const matchedChildren = item.children.filter(child => child.label.toString().toLowerCase().includes(value.toLowerCase()) ); if (matchedChildren.length > 0) { // 如果有匹配的子菜单,创建包含匹配子菜单的副本 acc.push({ ...item, children: matchedChildren }); return acc; } } // 如果主菜单项匹配,添加整个项 if (mainItemMatch) { acc.push(item); } return acc; }, []); setFilteredMenuItems(filtered); }; // 清除搜索 const clearSearch = () => { setSearchText(''); setFilteredMenuItems(menuItems); }; const handleMenuClick = ({ key }: { key: string }) => { navigate(`/admin${key}`); // 如果有搜索文本,清除搜索 if (searchText) { clearSearch(); } }; // 处理登出 const handleLogout = async () => { await logout(); navigate('/admin/login'); }; // 处理菜单展开/收起 const onOpenChange = (keys: string[]) => { // 当侧边栏折叠时不保存openKeys状态 if (!collapsed) { setOpenKeys(keys); } }; // 当侧边栏折叠状态改变时,控制菜单打开状态 useEffect(() => { if (collapsed) { setOpenKeys([]); } else { // 找到当前路径所属的父菜单 const currentPath = location.pathname.replace('/admin', ''); const parentKeys = menuItems .filter(item => item.children && item.children.some(child => child.key === currentPath)) .map(item => item.key); // 仅展开当前所在的菜单组 if (parentKeys.length > 0) { setOpenKeys(parentKeys); } else { // 初始时可以根据需要设置要打开的菜单组 setOpenKeys([]); } } }, [collapsed, location.pathname]); // 用户下拉菜单项 const userMenuItems = [ { key: 'profile', label: '个人信息', icon: }, { key: 'theme', label: isDark ? '切换到亮色模式' : '切换到暗色模式', icon: , onClick: toggleTheme }, { key: 'logout', label: '退出登录', icon: , onClick: handleLogout } ]; // 应用名称 - 从CONFIG中获取或使用默认值 const appName = window.CONFIG?.APP_NAME || '应用Starter'; return (
{collapsed ? '应用' : appName}
{/* 搜索框 - 仅在展开状态下显示 */} {!collapsed && (
handleSearch(e.target.value)} suffix={ searchText ?
)}
{/* 回到顶部按钮 */} {showBackTop && ( ); }; // 应用入口组件 const App = () => { // 路由配置 const router = createBrowserRouter([ { path: '/', element: }, { path: '/admin/login', element: }, { path: '/admin', element: ( ), children: [ { index: true, element: }, { path: 'dashboard', element: , errorElement: }, { path: 'users', element: , errorElement: }, { path: 'settings', element: , errorElement: }, { path: 'theme-settings', element: , errorElement: }, { path: 'chart-dashboard', element: , errorElement: }, { path: 'map-dashboard', element: , errorElement: }, { path: 'know-info', element: , errorElement: }, { path: 'file-library', element: , errorElement: }, { path: 'messages', element: , errorElement: }, ], }, ]); return }; // 渲染应用 const root = createRoot(document.getElementById('root') as HTMLElement); root.render( );