-
- {getLanguageIcon(script.language)}
-
-
-
{script.name}
-
{script.description}
-
-
- {script.language.toUpperCase()}
-
-
{script.createdAt}
+ {savedScripts.length === 0 ? (
+
+ ) : (
+
+ {savedScripts.map((script) => (
+
+
+
+
+ {getLanguageIcon(script.language)}
+
+
+
{script.name}
+
{script.description}
+
+
+ {script.language.toUpperCase()}
+
+ {script.createdAt}
+
-
-
- {script.tags.map((tag) => (
-
- {tag}
-
- ))}
+
+ {script.tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
-
- ))}
-
+ ))}
+
+ )}
diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx
index 7c7ba79..b7dad1e 100644
--- a/frontend/src/components/layout/Sidebar.tsx
+++ b/frontend/src/components/layout/Sidebar.tsx
@@ -28,12 +28,10 @@ import {
Key,
Compass,
Brain,
- ScrollText,
FileTerminal,
Activity,
BarChart3,
GitBranch,
- Monitor,
Bot,
AlertTriangle,
} from 'lucide-react';
@@ -92,8 +90,6 @@ const menuItems: MenuItem[] = [
{ id: 'metrics', name: '指标监控', icon: Cpu, path: '/metrics' },
{ id: 'alert-center', name: '告警中心', icon: Bell, path: '/alert-center' },
{ id: 'logs-monitor', name: '日志能力', icon: FileCode, path: '/logs-monitor' },
- { id: 'trace', name: '链路追踪', icon: GitBranch, path: '/trace' },
- { id: 'grafana', name: '监控大屏', icon: Monitor, path: '/grafana' },
{ id: 'agent-alerts', name: 'Agent告警', icon: AlertTriangle, path: '/agent-alerts' },
],
},
@@ -120,7 +116,6 @@ const menuItems: MenuItem[] = [
{ id: 'ai-script-generator', name: 'AI脚本生成', icon: FileCode, path: '/ai-script-generator' },
{ id: 'ai-fault-diagnosis', name: '故障智能诊断', icon: Activity, path: '/ai-fault-diagnosis' },
{ id: 'ai-predictive', name: 'AI预测分析', icon: BarChart3, path: '/ai-predictive' },
- { id: 'sql-audit', name: 'SQL审计', icon: ScrollText, path: '/sql-audit' },
],
},
{
diff --git a/frontend/src/components/monitor/alert-center/AlertCenter.tsx b/frontend/src/components/monitor/alert-center/AlertCenter.tsx
index 4d80155..31ce844 100644
--- a/frontend/src/components/monitor/alert-center/AlertCenter.tsx
+++ b/frontend/src/components/monitor/alert-center/AlertCenter.tsx
@@ -121,7 +121,7 @@ const AlertCenter: React.FC = () => {
const fetchRules = async () => {
try {
const res = await alertCenterApi.getRules();
- setRules(res.data || []);
+ setRules(res.list || []);
} catch (error) {
toast.error('获取告警规则失败');
}
diff --git a/frontend/src/components/server/BatchImport.tsx b/frontend/src/components/server/BatchImport.tsx
index 2f0c530..a7499f1 100644
--- a/frontend/src/components/server/BatchImport.tsx
+++ b/frontend/src/components/server/BatchImport.tsx
@@ -1,4 +1,5 @@
import { useState, useCallback } from 'react';
+import { toast } from 'sonner';
import { cn } from '@/lib/utils';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
@@ -62,82 +63,13 @@ export function BatchImport() {
const handleDrop = useCallback((e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
- // 模拟文件解析
- generateMockRecords();
+ toast.info('文件解析功能开发中');
}, []);
- const generateMockRecords = () => {
- const mockRecords: ImportRecord[] = [
- {
- id: '1',
- hostname: 'web-server-03',
- ip: '192.168.1.111',
- os: 'CentOS 7.9',
- cpu: '16',
- memory: '64',
- disk: '500',
- region: '华北-北京',
- tags: 'web,production',
- status: 'valid',
- },
- {
- id: '2',
- hostname: 'app-server-03',
- ip: '192.168.1.112',
- os: 'Ubuntu 22.04 LTS',
- cpu: '32',
- memory: '128',
- disk: '1000',
- region: '华东-上海',
- tags: 'app,production',
- status: 'valid',
- },
- {
- id: '3',
- hostname: 'cache-server-02',
- ip: '192.168.1.113',
- os: 'Ubuntu 20.04 LTS',
- cpu: '16',
- memory: '64',
- disk: '200',
- region: '华南-广州',
- tags: 'cache,redis',
- status: 'valid',
- },
- {
- id: '4',
- hostname: '',
- ip: '192.168.1.114',
- os: 'CentOS 8.5',
- cpu: '8',
- memory: '32',
- disk: '500',
- region: '华北-北京',
- tags: 'test',
- status: 'invalid',
- message: '主机名不能为空',
- },
- {
- id: '5',
- hostname: 'invalid-server',
- ip: 'invalid-ip',
- os: 'Ubuntu 22.04 LTS',
- cpu: '16',
- memory: '64',
- disk: '500',
- region: '华东-上海',
- tags: 'dev',
- status: 'invalid',
- message: 'IP地址格式不正确',
- },
- ];
- setRecords(mockRecords);
- };
-
const handleFileUpload = (e: React.ChangeEvent
) => {
const file = e.target.files?.[0];
if (file) {
- generateMockRecords();
+ toast.info('文件解析功能开发中');
}
};
@@ -238,6 +170,15 @@ export function BatchImport() {
+ {/* Empty State */}
+ {records.length === 0 && (
+
+
+
暂无导入记录
+
上传文件后将在此预览数据
+
+ )}
+
{/* Import Stats */}
{records.length > 0 && (
diff --git a/frontend/src/components/server/CabinetView.tsx b/frontend/src/components/server/CabinetView.tsx
index 93d9f3f..5ff8d1a 100644
--- a/frontend/src/components/server/CabinetView.tsx
+++ b/frontend/src/components/server/CabinetView.tsx
@@ -1,9 +1,8 @@
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Badge } from '@/components/ui/badge';
-import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import {
Select,
SelectContent,
@@ -23,135 +22,73 @@ import {
Server,
Plus,
Search,
- MapPin,
- Zap,
Grid3X3,
List,
+ MapPin,
+ Cpu,
+ MemoryStick,
HardDrive,
- Network,
- Router,
- Shield,
- Database,
- Monitor,
- Edit,
- Trash2,
Eye,
- ArrowUp,
- ArrowDown,
+ Edit,
} from 'lucide-react';
-import { cabinets, devices } from '@/mocks/data';
-import type { Cabinet, Device } from '@/types';
+import { serverApi } from '@/services/api';
+import type { Server as ServerType } from '@/types';
export function CabinetView() {
- const [viewMode, setViewMode] = useState<'room' | 'cabinet' | 'list'>('room');
- const [selectedRoom, setSelectedRoom] = useState
('all');
- const [selectedCabinet, setSelectedCabinet] = useState(null);
- const [selectedDevice, setSelectedDevice] = useState(null);
+ const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
+ const [statusFilter, setStatusFilter] = useState('all');
const [searchQuery, setSearchQuery] = useState('');
+ const [servers, setServers] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [selectedServer, setSelectedServer] = useState(null);
- const rooms = Array.from(new Set(cabinets.map((c) => c.room)));
-
- const filteredCabinets = cabinets.filter((cabinet) => {
- const matchesRoom = selectedRoom === 'all' || cabinet.room === selectedRoom;
- const matchesSearch = cabinet.name.toLowerCase().includes(searchQuery.toLowerCase());
- return matchesRoom && matchesSearch;
+ // 拉取服务器列表 // Logan.Li
+ const fetchServers = async () => {
+ setLoading(true);
+ try {
+ const resp = await serverApi.getServers({ page: 1, page_size: 200 });
+ setServers((resp?.list ?? []) as ServerType[]);
+ } catch {
+ setServers([]);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ fetchServers();
+ }, []);
+
+ const filteredServers = servers.filter((srv) => {
+ const matchesStatus = statusFilter === 'all' || srv.status === statusFilter;
+ const matchesSearch =
+ srv.hostname?.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ srv.ip?.toLowerCase().includes(searchQuery.toLowerCase());
+ return matchesStatus && matchesSearch;
});
- const getCabinetDevices = (cabinetId: string) => {
- return devices.filter((d) => d.cabinetId === cabinetId).sort((a, b) => b.startU - a.startU);
- };
-
- const getDeviceIcon = (type: Device['type']) => {
- const icons = {
- server: ,
- switch: ,
- router: ,
- firewall: ,
- storage: ,
- other: ,
+ const getStatusColor = (status: string) => {
+ const colors: Record = {
+ running: 'border-emerald-500/30 text-emerald-400 bg-emerald-500/10',
+ stopped: 'border-red-500/30 text-red-400 bg-red-500/10',
+ maintenance: 'border-amber-500/30 text-amber-400 bg-amber-500/10',
+ offline: 'border-slate-500/30 text-slate-400 bg-slate-500/10',
};
- return icons[type];
+ return colors[status] ?? colors.offline;
};
- const getDeviceColor = (type: Device['type']) => {
- const colors = {
- server: 'bg-blue-500/20 text-blue-400 border-blue-500/30',
- switch: 'bg-purple-500/20 text-purple-400 border-purple-500/30',
- router: 'bg-cyan-500/20 text-cyan-400 border-cyan-500/30',
- firewall: 'bg-red-500/20 text-red-400 border-red-500/30',
- storage: 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30',
- other: 'bg-slate-500/20 text-slate-400 border-slate-500/30',
+ const getStatusText = (status: string) => {
+ const map: Record = {
+ running: '运行中',
+ stopped: '已停止',
+ maintenance: '维护中',
+ offline: '离线',
};
- return colors[type];
+ return map[status] ?? status;
};
- const getStatusColor = (status: Cabinet['status']) => {
- const colors = {
- active: 'border-emerald-500/50 bg-emerald-500/5',
- empty: 'border-slate-600 bg-slate-800/30',
- disabled: 'border-slate-700 bg-slate-800/50 opacity-50',
- };
- return colors[status];
- };
-
- // 渲染机柜正面视图
- const renderCabinetFront = (cabinet: Cabinet) => {
- const cabinetDevices = getCabinetDevices(cabinet.id);
- const uSlots: (Device | null)[] = new Array(cabinet.totalU).fill(null);
-
- cabinetDevices.forEach((device) => {
- for (let i = 0; i < device.sizeU; i++) {
- const uIndex = cabinet.totalU - device.startU - i;
- if (uIndex >= 0 && uIndex < cabinet.totalU) {
- uSlots[uIndex] = device;
- }
- }
- });
-
- return (
-
- {/* U位编号 */}
-
- {Array.from({ length: cabinet.totalU }, (_, i) => (
-
- {cabinet.totalU - i}U
-
- ))}
-
-
- {/* 机柜 */}
-
- {uSlots.map((device, index) => {
- const uNumber = cabinet.totalU - index;
- if (device) {
- const isFirstU = uNumber === device.startU + device.sizeU - 1;
- if (!isFirstU) return null;
-
- return (
-
setSelectedDevice(device)}
- >
- {getDeviceIcon(device.type)}
- {device.name}
- {device.ip}
-
- );
- }
-
- return (
-
- );
- })}
-
-
- );
- };
+ const getUsageColor = (usage: number) =>
+ usage > 80 ? 'bg-red-400' : usage > 60 ? 'bg-amber-400' : 'bg-emerald-400';
return (
@@ -159,18 +96,12 @@ export function CabinetView() {
-
-
-
+
数据中心服务器资产概览
+
{/* Stats Cards */}
@@ -179,36 +110,10 @@ export function CabinetView() {
-
机房数
-
{rooms.length}
+
服务器总数
+
{servers.length}
-
-
-
-
-
-
-
-
-
-
机柜数
-
{cabinets.length}
-
-
-
-
-
-
-
-
-
-
-
-
设备数
-
{devices.length}
-
-
@@ -218,13 +123,43 @@ export function CabinetView() {
-
总功率
+
运行中
+
+ {servers.filter((s) => s.status === 'running').length}
+
+
+
+
+
+
+
+
+
+
+
+
+
维护中
- {cabinets.reduce((acc, c) => acc + c.powerUsed, 0).toFixed(1)}kW
+ {servers.filter((s) => s.status === 'maintenance').length}
-
+
+
+
+
+
+
+
+
+
+
离线
+
+ {servers.filter((s) => s.status === 'offline' || s.status === 'stopped').length}
+
+
+
+
@@ -237,44 +172,34 @@ export function CabinetView() {
setSearchQuery(e.target.value)}
className="pl-9 h-9 bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-500"
/>
-
-