feat(网卡管理): 新增批量导入网卡功能及关联组件

refactor(端口管理): 优化端口批量导入逻辑,增加服务器端口网卡关联验证

feat(前端组件): 新增批量导入模态框、网卡导入模态框和端口导出模态框

style(设备管理): 优化设备表格加载性能,添加无限滚动功能

docs(.gitignore): 添加数据文件忽略规则
This commit is contained in:
zhang1106
2026-03-27 17:52:35 +08:00
parent e640377609
commit ae315e2775
14 changed files with 3068 additions and 843 deletions
+235
View File
@@ -0,0 +1,235 @@
import React from 'react';
import { Card, Tag, Badge, Tooltip } from 'antd';
import {
CloudServerOutlined,
GatewayOutlined,
DatabaseOutlined,
AudioOutlined,
QuestionOutlined,
} from '@ant-design/icons';
import { designTokens } from '../config/theme';
const DEVICE_TYPE_CONFIG = {
server: {
icon: <CloudServerOutlined />,
color: designTokens.colors.device.server,
label: '服务器',
},
switch: {
icon: <GatewayOutlined />,
color: designTokens.colors.device.switch,
label: '交换机',
},
router: {
icon: <GatewayOutlined />,
color: designTokens.colors.device.router,
label: '路由器',
},
storage: {
icon: <DatabaseOutlined />,
color: designTokens.colors.device.storage,
label: '存储设备',
},
other: {
icon: <QuestionOutlined />,
color: designTokens.colors.device.other,
label: '其他设备',
},
};
const STATUS_CONFIG = {
running: { color: '#10b981', text: '运行中', bg: '#ecfdf5' },
maintenance: { color: '#3b82f6', text: '维护中', bg: '#eff6ff' },
offline: { color: '#6b7280', text: '离线', bg: '#f3f4f6' },
fault: { color: '#ef4444', text: '故障', bg: '#fef2f2' },
idle: { color: '#36cfc9', text: '空闲', bg: '#e6fffb' },
};
function ServerNicCard({ server, onManage }) {
const typeConfig = DEVICE_TYPE_CONFIG[server.type] || DEVICE_TYPE_CONFIG.other;
const statusConfig = STATUS_CONFIG[server.status] || STATUS_CONFIG.offline;
const nicCount = server.nicCount || (server.nics?.length || 0);
const totalPortCount = server.nics?.reduce((sum, nic) => sum + (nic.portCount || 0), 0) || 0;
return (
<Card
hoverable
onClick={onManage}
style={{
borderRadius: designTokens.borderRadius.md,
border: `1px solid ${designTokens.colors.border.light}`,
transition: 'all 0.2s ease',
cursor: 'pointer',
overflow: 'hidden',
}}
styles={{
body: { padding: '16px' },
}}
className="server-nic-card"
>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '12px',
height: '100%',
}}
>
<div style={{ display: 'flex', alignItems: 'flex-start', gap: '12px' }}>
<div
style={{
width: '44px',
height: '44px',
borderRadius: '10px',
background: `linear-gradient(135deg, ${typeConfig.color} 0%, ${typeConfig.color}cc 100%)`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#fff',
fontSize: '20px',
flexShrink: 0,
boxShadow: `0 4px 12px ${typeConfig.color}40`,
}}
>
{typeConfig.icon}
</div>
<div style={{ flex: 1, minWidth: 0 }}>
<Tooltip title={server.name}>
<div
style={{
fontWeight: 600,
fontSize: '14px',
color: designTokens.colors.text.primary,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
marginBottom: '4px',
}}
>
{server.name}
</div>
</Tooltip>
<Tooltip title={server.deviceId}>
<div
style={{
fontSize: '12px',
color: designTokens.colors.text.tertiary,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
ID: {server.deviceId}
</div>
</Tooltip>
</div>
</div>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<Tag
style={{
background: `${typeConfig.color}15`,
color: typeConfig.color,
border: `1px solid ${typeConfig.color}30`,
borderRadius: '6px',
fontSize: '11px',
padding: '2px 8px',
}}
>
{typeConfig.icon} {typeConfig.label}
</Tag>
<Tag
style={{
background: statusConfig.bg,
color: statusConfig.color,
border: 'none',
borderRadius: '6px',
fontSize: '11px',
padding: '2px 8px',
}}
>
{statusConfig.text}
</Tag>
</div>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '8px',
padding: '12px',
background: designTokens.colors.background.secondary,
borderRadius: '8px',
}}
>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: '18px', fontWeight: 700, color: designTokens.colors.primary.main }}>
{nicCount}
</div>
<div style={{ fontSize: '11px', color: designTokens.colors.text.secondary }}>
网卡
</div>
</div>
<div style={{ textAlign: 'center', borderLeft: `1px solid ${designTokens.colors.border.light}`, borderRight: `1px solid ${designTokens.colors.border.light}` }}>
<div style={{ fontSize: '18px', fontWeight: 700, color: designTokens.colors.info.main }}>
{totalPortCount}
</div>
<div style={{ fontSize: '11px', color: designTokens.colors.text.secondary }}>
端口
</div>
</div>
<div style={{ textAlign: 'center' }}>
<Badge
status={server.nicCount > 0 ? 'success' : 'default'}
text={
<span style={{ fontSize: '12px', color: designTokens.colors.text.secondary }}>
{server.nicCount > 0 ? '已配置' : '未配置'}
</span>
}
/>
</div>
</div>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
}}
>
<div
style={{
fontSize: '12px',
fontWeight: 500,
color: designTokens.colors.primary.main,
cursor: 'pointer',
}}
onClick={(e) => {
e.stopPropagation();
onManage();
}}
>
管理
</div>
</div>
</div>
<style>{`
.server-nic-card:hover {
box-shadow: 0 8px 24px rgba(99, 102, 241, 0.15) !important;
border-color: ${designTokens.colors.primary.light} !important;
transform: translateY(-2px);
}
`}</style>
</Card>
);
}
export default React.memo(ServerNicCard);