import React, { useState } from 'react'; import { Box, Typography, Card, CardContent, Grid, Button, Chip, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, LinearProgress, IconButton, Menu, MenuItem, Tabs, Tab, TextField, InputAdornment, } from '@mui/material'; import { Memory as MemoryIcon, Storage as StorageIcon, Speed as SpeedIcon, CloudDownload as CloudDownloadIcon, Settings as SettingsIcon, MoreVert as MoreVertIcon, Search as SearchIcon, Add as AddIcon, } from '@mui/icons-material'; import { styled } from '@mui/material/styles'; const PageContainer = styled(Box)(({ theme }) => ({ padding: '1.5rem', backgroundColor: '#F8F9FA', minHeight: 'calc(100vh - 60px)', })); const PageHeader = styled(Box)(({ theme }) => ({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1.5rem', })); const ResourceCard = styled(Card)(({ theme }) => ({ height: '100%', border: '1px solid #E5E5E5', transition: 'all 0.2s ease-in-out', '&:hover': { boxShadow: '0 4px 12px rgba(0,0,0,0.1)', }, })); const StatusChip = styled(Chip)<{ status: string }>(({ status, theme }) => ({ fontSize: '0.75rem', height: '24px', backgroundColor: status === 'active' ? '#E8F5E8' : status === 'loading' ? '#FFF3CD' : status === 'error' ? '#F8D7DA' : '#F8F9FA', color: status === 'active' ? '#155724' : status === 'loading' ? '#856404' : status === 'error' ? '#721C24' : '#666', })); const UsageBar = styled(Box)(({ theme }) => ({ display: 'flex', alignItems: 'center', gap: '0.5rem', marginTop: '0.5rem', })); const mockModels = [ { id: 1, name: 'GPT-4', type: 'LLM', provider: 'OpenAI', status: 'active', usage: 75, cost: '$234.56', requests: '12.3K', latency: '1.2s', }, { id: 2, name: 'text-embedding-ada-002', type: 'Embedding', provider: 'OpenAI', status: 'active', usage: 45, cost: '$89.12', requests: '45.6K', latency: '0.3s', }, { id: 3, name: 'Claude-3-Sonnet', type: 'LLM', provider: 'Anthropic', status: 'loading', usage: 0, cost: '$0.00', requests: '0', latency: 'N/A', }, { id: 4, name: 'BGE-Large-ZH', type: 'Embedding', provider: 'BAAI', status: 'error', usage: 0, cost: '$0.00', requests: '0', latency: 'N/A', }, ]; const mockResources = [ { id: 1, name: 'GPU-Server-01', type: 'GPU', specs: 'NVIDIA A100 80GB', usage: 85, status: 'active', location: '北京机房', }, { id: 2, name: 'CPU-Cluster-01', type: 'CPU', specs: '64 Core Intel Xeon', usage: 45, status: 'active', location: '上海机房', }, { id: 3, name: 'Storage-Pool-01', type: 'Storage', specs: '10TB NVMe SSD', usage: 67, status: 'active', location: '深圳机房', }, ]; const ModelsResources: React.FC = () => { const [tabValue, setTabValue] = useState(0); const [searchTerm, setSearchTerm] = useState(''); const [anchorEl, setAnchorEl] = useState(null); const [selectedItem, setSelectedItem] = useState(null); const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { setTabValue(newValue); }; const handleMenuClick = (event: React.MouseEvent, itemId: number) => { setAnchorEl(event.currentTarget); setSelectedItem(itemId); }; const handleMenuClose = () => { setAnchorEl(null); setSelectedItem(null); }; const filteredModels = mockModels.filter(model => model.name.toLowerCase().includes(searchTerm.toLowerCase()) || model.provider.toLowerCase().includes(searchTerm.toLowerCase()) ); const filteredResources = mockResources.filter(resource => resource.name.toLowerCase().includes(searchTerm.toLowerCase()) || resource.type.toLowerCase().includes(searchTerm.toLowerCase()) ); return ( 模型与资源 setSearchTerm(e.target.value)} InputProps={{ startAdornment: ( ), }} sx={{ width: '400px' }} /> {tabValue === 0 && ( <> {/* 模型概览卡片 */} 活跃模型 {mockModels.filter(m => m.status === 'active').length} 总请求数 57.9K 总成本 $323.68 平均延迟 0.8s {/* 模型列表 */} 模型列表 模型名称 类型 提供商 状态 使用率 请求数 成本 延迟 操作 {filteredModels.map((model) => ( {model.name} {model.provider} 80 ? 'error' : model.usage > 60 ? 'warning' : 'primary'} /> {model.usage}% {model.requests} {model.cost} {model.latency} handleMenuClick(e, model.id)} > ))}
)} {tabValue === 1 && ( <> {/* 资源概览卡片 */} GPU 使用率 85% CPU 使用率 45% 存储使用率 67% {/* 资源列表 */} 计算资源 资源名称 类型 规格 使用率 状态 位置 操作 {filteredResources.map((resource) => ( {resource.name} {resource.specs} 80 ? 'error' : resource.usage > 60 ? 'warning' : 'primary'} /> {resource.usage}% {resource.location} handleMenuClick(e, resource.id)} > ))}
)} 配置 查看详情 监控 停用
); }; export default ModelsResources;