import { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Input } from '@/components/ui/input'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog'; import { Download, Upload, FileSpreadsheet, Check, X, AlertCircle, ChevronRight, ChevronLeft, } from 'lucide-react'; import { regionApi } from '@/services/api'; interface RegionOption { id: string; name: string; code: string; } interface ExcelServerImportProps { open: boolean; onClose: () => void; } const connectionMethods = [ { id: 'password', name: '密码认证', description: '使用用户名密码连接' }, { id: 'key', name: '密钥认证', description: '使用SSH密钥连接' }, ]; type PreviewRow = { row: number; hostname: string; ip: string; port: number; username: string; status: string; message: string; }; export function ExcelServerImport({ open, onClose }: ExcelServerImportProps) { const [step, setStep] = useState(1); const [selectedRegion, setSelectedRegion] = useState(''); const [connectionMethod, setConnectionMethod] = useState('password'); const [selectedFile, setSelectedFile] = useState(null); const [isUploading, setIsUploading] = useState(false); const [previewData, setPreviewData] = useState([]); const [regions, setRegions] = useState([]); // 对话框打开时拉取区域列表 // Logan.Li useEffect(() => { if (!open) return; let cancelled = false; (async () => { try { const resp = await regionApi.list(); if (cancelled) return; const list = resp?.list ?? []; setRegions( list.map((r: any) => ({ id: String(r.id ?? ''), name: r.name ?? '', code: r.code ?? '', })) ); } catch { if (!cancelled) setRegions([]); } })(); return () => { cancelled = true; }; }, [open]); const handleNext = () => { if (step === 2 && selectedFile) { setIsUploading(true); setTimeout(() => { setIsUploading(false); setPreviewData([]); // 真实解析由后端处理 setStep(step + 1); }, 1500); } else { setStep(step + 1); } }; const handleBack = () => { if (step > 1) { setStep(step - 1); } }; const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { setSelectedFile(e.target.files[0]); } }; const handleImport = () => { setTimeout(() => { onClose(); setStep(1); setSelectedRegion(''); setConnectionMethod('password'); setSelectedFile(null); setPreviewData([]); }, 1500); }; const handleClose = () => { onClose(); setStep(1); setSelectedRegion(''); setConnectionMethod('password'); setSelectedFile(null); setPreviewData([]); }; const validCount = previewData.filter(d => d.status === 'valid').length; const warningCount = previewData.filter(d => d.status === 'warning').length; const errorCount = previewData.filter(d => d.status === 'error').length; const steps = [ { id: 1, title: '配置' }, { id: 2, title: '上传' }, { id: 3, title: '确认' }, ]; return ( Excel导入服务器 {/* Step Indicator */}
{steps.map((s, index) => (
s.id ? 'bg-emerald-600 text-white' : 'bg-slate-800 text-slate-500' }`}> {step > s.id ? : s.id}
{s.title} {index < steps.length - 1 && (
)}
))}
{/* Step 1: Configuration */} {step === 1 && (
{/* Download Template */}

主机导入模板

下载Excel模板,填写服务器信息后上传

{/* Region Selection */}
{/* Connection Method */}
{connectionMethods.map((method) => ( setConnectionMethod(method.id)} >

{method.name}

{method.description}

))}
)} {/* Step 2: Upload */} {step === 2 && (

点击或拖拽文件到此处上传

支持 .xlsx, .xls 格式文件

{selectedFile && (

{selectedFile.name}

{(selectedFile.size / 1024).toFixed(2)} KB

)} {isUploading && (

正在解析文件...

)}
)} {/* Step 3: Preview & Confirm */} {step === 3 && (

数据预览

{validCount} 有效 {warningCount > 0 && ( {warningCount} 警告 )} {errorCount > 0 && ( {errorCount} 错误 )}
{previewData.map((row) => ( ))}
行号 主机名 IP地址 端口 用户名 状态
{row.row} {row.hostname || '-'} {row.ip} {row.port} {row.username}
{row.status === 'valid' && ( {row.message} )} {row.status === 'warning' && ( {row.message} )} {row.status === 'error' && ( {row.message} )}
{errorCount > 0 && (
存在 {errorCount} 条错误数据,请修正后重新上传
)}
)} {/* Footer */}
{step > 1 && ( )}
{step < 3 ? ( ) : ( )}
); }