import React, { useState, useEffect } from 'react'; import { Modal, Form, Select, Button, message, Steps, Transfer, Card, Alert, Divider, Typography } from 'antd'; import { useStore } from '../store'; import { DBGetDatabases, DBGetTables, DataSync } from '../../wailsjs/go/app/App'; import { SavedConnection } from '../types'; import { connection } from '../../wailsjs/go/models'; const { Title, Text } = Typography; const { Step } = Steps; const { Option } = Select; const DataSyncModal: React.FC<{ open: boolean; onClose: () => void }> = ({ open, onClose }) => { const connections = useStore((state) => state.connections); const [currentStep, setCurrentStep] = useState(0); const [loading, setLoading] = useState(false); // Step 1: Config const [sourceConnId, setSourceConnId] = useState(''); const [targetConnId, setTargetConnId] = useState(''); const [sourceDb, setSourceDb] = useState(''); const [targetDb, setTargetDb] = useState(''); const [sourceDbs, setSourceDbs] = useState([]); const [targetDbs, setTargetDbs] = useState([]); // Step 2: Tables const [allTables, setAllTables] = useState([]); const [selectedTables, setSelectedTables] = useState([]); // Step 3: Result const [syncResult, setSyncResult] = useState(null); useEffect(() => { if (open) { setCurrentStep(0); setSourceConnId(''); setTargetConnId(''); setSourceDb(''); setTargetDb(''); setSelectedTables([]); setSyncResult(null); } }, [open]); const handleSourceConnChange = async (connId: string) => { setSourceConnId(connId); setSourceDb(''); const conn = connections.find(c => c.id === connId); if (conn) { setLoading(true); try { const res = await DBGetDatabases(conn.config as any); if (res.success) { setSourceDbs((res.data as any[]).map((r: any) => r.Database || r.database || r.username)); } } catch(e) { message.error("Failed to fetch source databases"); } setLoading(false); } }; const handleTargetConnChange = async (connId: string) => { setTargetConnId(connId); setTargetDb(''); const conn = connections.find(c => c.id === connId); if (conn) { setLoading(true); try { const res = await DBGetDatabases(conn.config as any); if (res.success) { setTargetDbs((res.data as any[]).map((r: any) => r.Database || r.database || r.username)); } } catch(e) { message.error("Failed to fetch target databases"); } setLoading(false); } }; const nextToTables = async () => { if (!sourceConnId || !targetConnId) return message.error("Select connections first"); if (!sourceDb) return message.error("Select source database"); if (!targetDb) return message.error("Select target database"); setLoading(true); try { const conn = connections.find(c => c.id === sourceConnId); if (conn) { const config = { ...conn.config, database: sourceDb }; const res = await DBGetTables(config as any, sourceDb); if (res.success) { // DBGetTables returns [{Table: "name"}, ...] const tables = (res.data as any[]).map((row: any) => row.Table || row.table || row.TABLE_NAME || Object.values(row)[0]); setAllTables(tables as string[]); setCurrentStep(1); } else { message.error(res.message); } } } catch (e) { message.error("Failed to fetch tables"); } setLoading(false); }; const runSync = async () => { setLoading(true); const sConn = connections.find(c => c.id === sourceConnId)!; const tConn = connections.find(c => c.id === targetConnId)!; const config = { sourceConfig: { ...sConn.config, database: sourceDb }, targetConfig: { ...tConn.config, database: targetDb }, tables: selectedTables, mode: "insert_update" }; try { const res = await DataSync(config as any); setSyncResult(res); setCurrentStep(2); } catch (e) { message.error("Sync execution failed"); } setLoading(false); }; return ( {/* STEP 1: CONFIG */} {currentStep === 0 && (
)} {/* STEP 2: TABLES */} {currentStep === 1 && (
请选择需要同步的表: ({ key: t, title: t }))} titles={['源表', '已选表']} targetKeys={selectedTables} onChange={(keys) => setSelectedTables(keys as string[])} render={item => item.title} listStyle={{ width: 350, height: 350, marginTop: 12 }} locale={{ itemUnit: '项', itemsUnit: '项', searchPlaceholder: '搜索表', notFoundContent: '暂无数据' }} />
)} {/* STEP 3: RESULT */} {currentStep === 2 && syncResult && (
日志
{syncResult.logs.map((log: string, i: number) =>
{log}
)}
)}
{currentStep === 0 && ( )} {currentStep === 1 && ( <> )} {currentStep === 2 && ( <> )}
); }; export default DataSyncModal;