{/* 过滤器区域 */}
设备
端口类型
端口速率
状态
搜索
setFilters(prev => ({ ...prev, searchText: e.target.value }))}
onPressEnter={handleSearch}
prefix={}
allowClear
/>
操作
}
onClick={handleSearch}
style={{
background: designTokens.colors.primary.gradient,
border: 'none',
borderRadius: designTokens.borderRadius.sm,
}}
>
筛选
}
onClick={handleReset}
style={{ borderRadius: designTokens.borderRadius.sm }}
/>
{/* 操作按钮区域 */}
}
onClick={handleAdd}
size="large"
style={{
background: designTokens.colors.primary.gradient,
border: 'none',
borderRadius: designTokens.borderRadius.sm,
boxShadow: designTokens.shadows.md,
}}
>
新增端口
}
onClick={handleImport}
size="large"
style={{ borderRadius: designTokens.borderRadius.sm }}
>
批量导入
}
size="large"
style={{ borderRadius: designTokens.borderRadius.sm }}
>
导出
}
onClick={() => setViewMode('list')}
style={viewMode === 'list' ? {
background: designTokens.colors.primary.gradient,
border: 'none',
} : {}}
>
列表
}
onClick={() => setViewMode('panel')}
style={viewMode === 'panel' ? {
background: designTokens.colors.primary.gradient,
border: 'none',
} : {}}
>
面板
}
onClick={fetchPorts}
loading={loading}
style={{ borderRadius: designTokens.borderRadius.sm }}
/>
{/* 数据展示区域 */}
{loading ? (
) : Object.keys(groupedPorts).length === 0 ? (
暂无端口数据
点击"新增端口"按钮创建第一个端口
}
>
}
onClick={handleAdd}
style={{
background: designTokens.colors.primary.gradient,
border: 'none',
borderRadius: designTokens.borderRadius.sm,
}}
>
新增端口
) : viewMode === 'panel' ? (
g.device)
.filter(Boolean)}
groupedPorts={groupedPorts}
cables={cables}
allDevices={devices}
onPortClick={port => handleEdit(port)}
onAddPort={device => handleAddPortForDevice(device)}
onManageNetworkCards={device => handleManageNetworkCards(device)}
initialVisibleCount={5}
loadMoreCount={5}
/>
) : (
{Object.entries(groupedPorts).map(([deviceId, data], index) => {
const device = data.device;
const devicePorts = data.ports || [];
const freeCount = devicePorts.filter(p => p.status === 'free').length;
const occupiedCount = devicePorts.filter(p => p.status === 'occupied').length;
const faultCount = devicePorts.filter(p => p.status === 'fault').length;
return (
{getDeviceIcon(device)}
{device?.name || '未知设备'}
{device?.deviceId || '-'} · {device?.model || device?.type || '设备'}
}
>
{freeCount}
}
>
{occupiedCount}
{faultCount > 0 && (
}
>
{faultCount}
)}
总计: {devicePorts.length}
}
extra={
e.stopPropagation()}>
}
onClick={() => handleAddPortForDevice(device)}
style={{ color: designTokens.colors.primary.main }}
/>
{device?.type?.toLowerCase()?.includes('server') && (
}
onClick={() => handleManageNetworkCards(device)}
style={{ color: designTokens.colors.primary.main }}
/>
)}
}
style={{
background: '#fff',
borderRadius: designTokens.borderRadius.lg,
marginBottom: '12px',
border: `1px solid ${designTokens.colors.neutral[200]}`,
overflow: 'hidden',
}}
>
`共 ${total} 个端口`,
pageSizeOptions: ['10', '20', '50', '100'],
}}
size="middle"
scroll={{ x: 1000 }}
style={{
borderRadius: designTokens.borderRadius.md,
overflow: 'hidden',
}}
/>
);
})}
)}
{/* 新增/编辑端口弹窗 */}
{editingPort ? '编辑端口' : '新增端口'}
}
open={modalVisible}
onOk={handleSubmit}
onCancel={() => {
setModalVisible(false);
form.resetFields();
}}
width={600}
okText="确定"
cancelText="取消"
okButtonProps={{
style: {
background: designTokens.colors.primary.gradient,
border: 'none',
borderRadius: designTokens.borderRadius.sm,
},
}}
>
{/* 批量导入弹窗 */}
批量导入端口
}
open={importModalVisible}
onCancel={() => {
setImportModalVisible(false);
setImportPreview([]);
setImportProgress({ current: 0, total: 0 });
}}
width={900}
footer={[
,
}
onClick={handleDownloadTemplate}
style={{ borderRadius: designTokens.borderRadius.sm }}
>
下载模板
,
}
onClick={handleBatchImport}
loading={importing}
disabled={importPreview.length === 0}
style={{
background: designTokens.colors.primary.gradient,
border: 'none',
borderRadius: designTokens.borderRadius.sm,
}}
>
开始导入
,
]}
>
false}
customRequest={({ file, onSuccess }) => {
handleFileUpload({ file, onSuccess });
}}
style={{
borderRadius: designTokens.borderRadius.lg,
border: `2px dashed ${designTokens.colors.primary.light}`,
background: designTokens.colors.primary.bg,
}}
>
点击或拖拽文件到此处上传
支持 .xlsx, .xls, .csv 格式文件
setSkipExisting(e.target.checked)}>
跳过已存在的端口
setUpdateExisting(e.target.checked)}>
更新已存在的端口
{importPreview.length > 0 && (
数据预览(前10条)
getPortTypeTag(type) },
{ title: '端口速率', dataIndex: '端口速率', key: 'portSpeed', width: 100 },
{ title: '状态', dataIndex: '状态', key: 'status', width: 100, render: status => getStatusTag(status) },
{ title: 'VLAN ID', dataIndex: 'VLAN ID', key: 'vlanId', width: 100, render: vlanId => vlanId || '-' },
{ title: '描述', dataIndex: '描述', key: 'description', ellipsis: true },
]}
dataSource={importPreview.slice(0, 10)}
rowKey={(record, index) => index}
pagination={false}
size="small"
scroll={{ x: 800 }}
style={{ borderRadius: designTokens.borderRadius.md }}
/>
{importPreview.length > 10 && (
仅显示前10条数据,共 {importPreview.length} 条
)}
)}
{importing && (
正在导入 {importProgress.current} / {importProgress.total} 条数据...
)}
{/* 网卡管理模态框 */}
网卡管理 - {selectedDeviceForNic?.name}
}
open={networkCardModalVisible}
onCancel={() => {
setNetworkCardModalVisible(false);
setSelectedDeviceForNic(null);
}}
footer={null}
width={800}
destroyOnClose
>
{selectedDeviceForNic && (
)}
{/* 创建网卡模态框 */}
{
setPortCreateModalVisible(false);
setSelectedDeviceForNic(null);
}}
onSuccess={handleNicSuccess}
/>
);
}
export default PortManagement;