import React, { useState, useEffect } from 'react'; import { Modal, Table, Alert, Progress, Button, Space } from 'antd'; import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'; import { PreviewImportFile, ImportDataWithProgress } from '../../wailsjs/go/app/App'; import { EventsOn, EventsOff } from '../../wailsjs/runtime/runtime'; import { useStore } from '../store'; interface ImportPreviewModalProps { visible: boolean; filePath: string; connectionId: string; dbName: string; tableName: string; onClose: () => void; onSuccess: () => void; } interface PreviewData { columns: string[]; totalRows: number; previewRows: any[]; } interface ImportProgress { current: number; total: number; success: number; errors: number; } const ImportPreviewModal: React.FC = ({ visible, filePath, connectionId, dbName, tableName, onClose, onSuccess }) => { const connections = useStore(state => state.connections); const [loading, setLoading] = useState(true); const [previewData, setPreviewData] = useState(null); const [error, setError] = useState(null); const [importing, setImporting] = useState(false); const [progress, setProgress] = useState(null); const [importResult, setImportResult] = useState(null); useEffect(() => { if (visible && filePath) { loadPreview(); } }, [visible, filePath]); useEffect(() => { if (importing) { const unsubscribe = EventsOn('import:progress', (data: ImportProgress) => { setProgress(data); }); return () => { EventsOff('import:progress'); }; } }, [importing]); const loadPreview = async () => { setLoading(true); setError(null); try { const res = await PreviewImportFile(filePath); if (res.success && res.data) { setPreviewData({ columns: res.data.columns || [], totalRows: res.data.totalRows || 0, previewRows: res.data.previewRows || [] }); } else { setError(res.message || '预览失败'); } } catch (e: any) { setError('预览失败: ' + e.message); } finally { setLoading(false); } }; const handleImport = async () => { if (!previewData) return; setImporting(true); setProgress({ current: 0, total: previewData.totalRows, success: 0, errors: 0 }); setImportResult(null); try { const conn = connections.find(c => c.id === connectionId); if (!conn) { setError('连接配置未找到'); setImporting(false); return; } const config = { ...conn.config, port: Number(conn.config.port), password: conn.config.password || '', database: conn.config.database || '', useSSH: conn.config.useSSH || false, ssh: conn.config.ssh || { host: '', port: 22, user: '', password: '', keyPath: '' } }; const res = await ImportDataWithProgress(config as any, dbName, tableName, filePath); if (res.success && res.data) { setImportResult(res.data); if (res.data.failed === 0) { onSuccess(); } } else { setError(res.message || '导入失败'); } } catch (e: any) { setError('导入失败: ' + e.message); } finally { setImporting(false); } }; const columns = previewData?.columns.map(col => ({ title: col, dataIndex: col, key: col, ellipsis: true, width: 150 })) || []; const progressPercent = progress ? Math.round((progress.current / progress.total) * 100) : 0; return ( ) : importing ? null : ( ) } > {error && } {loading &&
加载预览数据...
} {!loading && previewData && !importing && !importResult && ( <>
字段列表:
{previewData.columns.join(', ')}
数据预览(前 5 行):
)} {importing && progress && (
正在导入数据...
已处理 {progress.current} / {progress.total} 行 成功 {progress.success} {progress.errors > 0 && ( 失败 {progress.errors} )}
)} {importResult && (
成功导入 {importResult.success} 行
{importResult.failed > 0 &&
失败 {importResult.failed} 行
}
} showIcon style={{ marginBottom: 16 }} /> {importResult.errorLogs && importResult.errorLogs.length > 0 && ( <>
错误日志:
{importResult.errorLogs.map((log: string, idx: number) => (
{log}
))}
)} )} ); }; export default ImportPreviewModal;