import React, { useState, useEffect, useCallback } from 'react';
import { Badge, Space, Typography, Spin, Empty, Button, Tooltip, Tag, Modal } from 'antd';
import {
CloudServerOutlined,
PlusOutlined,
ReloadOutlined,
ApiOutlined,
ThunderboltOutlined,
DesktopOutlined,
UsbOutlined,
MonitorOutlined,
SettingOutlined
} from '@ant-design/icons';
import PortPanel from './PortPanel';
import axios from 'axios';
const { Text } = Typography;
const designTokens = {
colors: {
primary: { main: '#667eea', gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
success: '#10b981',
error: '#ef4444',
warning: '#f59e0b',
metal: { light: '#9ca3af', DEFAULT: '#6b7280', dark: '#4b5563' },
slot: { empty: '#d1d5db', occupied: '#3b82f6' }
}
};
/**
* 服务器背板可视化组件
* 按照真实服务器背板布局展示网卡和端口
*
* @param {string} deviceId - 设备ID
* @param {string} deviceName - 设备名称
* @param {Object[]} cables - 接线列表
* @param {Object[]} allDevices - 所有设备列表
* @param {Function} onPortClick - 端口点击回调
* @param {Function} onManageNetworkCards - 网卡管理回调
*/
const ServerBackplanePanel = ({
deviceId,
deviceName,
cables,
allDevices,
onPortClick,
onManageNetworkCards
}) => {
const [cards, setCards] = useState([]);
const [loading, setLoading] = useState(false);
const [selectedSlot, setSelectedSlot] = useState(null);
// 获取网卡及端口数据
const fetchData = useCallback(async () => {
if (!deviceId) return;
try {
setLoading(true);
const response = await axios.get(`/api/network-cards/device/${deviceId}/with-ports`);
const cardsData = response.data || [];
setCards(cardsData);
} catch (error) {
console.error('获取网卡数据失败:', error);
setCards([]);
} finally {
setLoading(false);
}
}, [deviceId]);
useEffect(() => {
fetchData();
}, [fetchData]);
// 按类型和槽位号对网卡进行分类
const categorizeCards = () => {
const onboard = []; // 板载网卡
const management = []; // 管理口
const expansionSlots = []; // 扩展插槽
cards.forEach(card => {
const slotNum = card.slotNumber;
const name = (card.name || '').toLowerCase();
// 判断网卡类型
if (name.includes('idrac') || name.includes('ilo') || name.includes('bmc') || name.includes('mgmt') || name.includes('管理')) {
management.push({ ...card, type: 'management' });
} else if (slotNum === 0 || name.includes('onboard') || name.includes('板载') || name.includes('内置')) {
onboard.push({ ...card, type: 'onboard' });
} else {
expansionSlots.push({ ...card, type: 'expansion', slotIndex: slotNum });
}
});
// 按槽位号排序扩展插槽
expansionSlots.sort((a, b) => (a.slotNumber || 0) - (b.slotNumber || 0));
return { onboard, management, expansionSlots };
};
const { onboard, management, expansionSlots } = categorizeCards();
// 渲染管理口区域(左侧)
const renderManagementArea = () => {
const mgmtCard = management[0];
return (
MGMT
{mgmtCard ? (
setSelectedSlot(mgmtCard)}
style={{
width: '48px',
height: '48px',
background: 'linear-gradient(145deg, #1f2937 0%, #111827 100%)',
borderRadius: '4px',
border: `2px solid ${mgmtCard.ports?.length > 0 ? designTokens.colors.success : '#6b7280'}`,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
transition: 'all 0.2s',
boxShadow: '0 2px 4px rgba(0,0,0,0.3)'
}}
>
{mgmtCard.ports?.length || 0}口
) : (
)}
{/* 其他接口占位 */}
VGA
USB
);
};
// 渲染板载网卡区域
const renderOnboardArea = () => {
const onboardCard = onboard[0];
return (
板载网卡 (Onboard)
{onboardCard && (
)}
{onboardCard ? (
setSelectedSlot(onboardCard)}
style={{
background: 'linear-gradient(145deg, #1f2937 0%, #111827 100%)',
borderRadius: '6px',
padding: '12px',
border: `2px solid ${onboardCard.ports?.length > 0 ? designTokens.colors.primary.main : '#6b7280'}`,
cursor: 'pointer',
transition: 'all 0.2s'
}}
>
{/* 4个RJ45端口布局 */}
{[0, 1, 2, 3].map((idx) => {
const port = onboardCard.ports?.[idx];
const hasPort = !!port;
const isOccupied = hasPort && port.status === 'occupied';
return (
{/* LED指示灯 */}
⬡
{hasPort ? idx + 1 : '-'}
);
})}
) : (
)}
);
};
// 渲染扩展插槽区域
const renderExpansionSlots = () => {
// 标准2U服务器通常有4-8个PCIe插槽
const totalSlots = 6;
const slots = [];
for (let i = 1; i <= totalSlots; i++) {
const card = expansionSlots.find(c => c.slotNumber === i);
slots.push({ slotNumber: i, card });
}
return (
PCIe 扩展插槽
/{totalSlots}
{slots.map(({ slotNumber, card }) => (
card && setSelectedSlot(card)}
style={{
width: '70px',
height: '90px',
background: card
? 'linear-gradient(145deg, #1f2937 0%, #111827 100%)'
: '#374151',
borderRadius: '4px',
border: `2px solid ${card ? designTokens.colors.slot.occupied : designTokens.colors.slot.empty}`,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-between',
padding: '6px',
cursor: card ? 'pointer' : 'default',
transition: 'all 0.2s',
boxShadow: card ? '0 2px 8px rgba(59, 130, 246, 0.3)' : 'none'
}}
>
Slot {slotNumber}
{card ? (
<>
{card.ports?.slice(0, 4).map((port, idx) => (
))}
{card.ports?.length > 4 && (
+{card.ports.length - 4}
)}
{card.ports?.length || 0}口
>
) : (
<>
空闲
>
)}
))}
);
};
// 渲染电源区域(右侧)
const renderPowerArea = () => {
return (
电源
{[1, 2].map((psu) => (
))}
);
};
if (loading) {
return (
);
}
return (
{/* 工具栏 */}
!c.isUngrouped).length} style={{ backgroundColor: designTokens.colors.primary.main }} />
个网卡
acc + (card.ports?.length || 0), 0)}
style={{ backgroundColor: '#667eea' }}
/>
个端口
} onClick={fetchData}>
刷新
}
onClick={onManageNetworkCards}
style={{ background: designTokens.colors.primary.gradient, border: 'none' }}
>
网卡管理
{/* 服务器背板主体 */}
{/* 服务器标识 */}
{deviceName || '服务器'} - 背板视图
{/* 背板布局 */}
{/* 左侧:管理口区域 */}
{renderManagementArea()}
{/* 中间左:板载网卡 */}
{renderOnboardArea()}
{/* 中间:扩展插槽 */}
{renderExpansionSlots()}
{/* 右侧:电源 */}
{renderPowerArea()}
{/* 选中插槽的端口详情模态框 */}
{selectedSlot?.name}
{selectedSlot?.slotNumber > 0 && ` (Slot ${selectedSlot.slotNumber})`}
}
open={!!selectedSlot}
onCancel={() => setSelectedSlot(null)}
footer={null}
width={700}
destroyOnClose
>
{selectedSlot && (
类型: {selectedSlot.type === 'onboard' ? '板载网卡' : selectedSlot.type === 'management' ? '管理口' : '扩展网卡'}
{selectedSlot.description && 描述: {selectedSlot.description}}
端口统计:
空闲: {selectedSlot.stats?.free || 0}
占用: {selectedSlot.stats?.occupied || 0}
{selectedSlot.stats?.fault > 0 && 故障: {selectedSlot.stats.fault}}
总计: {selectedSlot.ports?.length || 0}
{selectedSlot.ports && selectedSlot.ports.length > 0 ? (
) : (
该网卡暂无端口
}
onClick={onManageNetworkCards}
style={{ padding: 0, marginTop: 8 }}
>
前往网卡管理添加端口
}
/>
)}
)}
);
};
export default ServerBackplanePanel;