"use client"; import React, { useState, useEffect } from "react"; import { useParams, useRouter } from "next/navigation"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { RefreshCw, Save, ArrowLeft, Plus, Trash2 } from "lucide-react"; import { toast } from "sonner"; import { BatchAPI, BatchConfig, BatchMapping, ConnectionInfo } from "@/lib/api/batch"; interface BatchColumnInfo { column_name: string; data_type: string; is_nullable: string; } // 배치 타입 감지 함수 const detectBatchType = (mapping: BatchMapping): 'db-to-db' | 'restapi-to-db' | 'db-to-restapi' => { const fromType = mapping.from_connection_type; const toType = mapping.to_connection_type; if (fromType === 'restapi' && (toType === 'internal' || toType === 'external')) { return 'restapi-to-db'; } else if ((fromType === 'internal' || fromType === 'external') && toType === 'restapi') { return 'db-to-restapi'; } else { return 'db-to-db'; } }; export default function BatchEditPage() { const params = useParams(); const router = useRouter(); const batchId = parseInt(params.id as string); // 기본 상태 const [loading, setLoading] = useState(false); const [batchConfig, setBatchConfig] = useState(null); const [batchName, setBatchName] = useState(""); const [cronSchedule, setCronSchedule] = useState("0 12 * * *"); const [description, setDescription] = useState(""); const [isActive, setIsActive] = useState("Y"); // 연결 정보 const [connections, setConnections] = useState([]); const [fromConnection, setFromConnection] = useState(null); const [toConnection, setToConnection] = useState(null); // 테이블 및 컬럼 정보 const [fromTables, setFromTables] = useState([]); const [toTables, setToTables] = useState([]); const [fromTable, setFromTable] = useState(""); const [toTable, setToTable] = useState(""); const [fromColumns, setFromColumns] = useState([]); const [toColumns, setToColumns] = useState([]); // 매핑 정보 const [mappings, setMappings] = useState([]); // 배치 타입 감지 const [batchType, setBatchType] = useState<'db-to-db' | 'restapi-to-db' | 'db-to-restapi' | null>(null); // 페이지 로드 시 배치 정보 조회 useEffect(() => { if (batchId) { loadBatchConfig(); loadConnections(); } }, [batchId]); // 연결 정보가 로드된 후 배치 설정의 연결 정보 설정 useEffect(() => { if (batchConfig && connections.length > 0 && batchConfig.batch_mappings && batchConfig.batch_mappings.length > 0) { const firstMapping = batchConfig.batch_mappings[0]; console.log("🔗 연결 정보 설정 시작:", firstMapping); // FROM 연결 정보 설정 if (firstMapping.from_connection_type === 'internal') { setFromConnection({ type: 'internal', name: '내부 DB' }); // 내부 DB 테이블 목록 로드 BatchAPI.getTablesFromConnection({ type: 'internal', name: '내부 DB' }).then(tables => { console.log("📋 FROM 테이블 목록:", tables); setFromTables(tables); // 컬럼 정보도 로드 if (firstMapping.from_table_name) { BatchAPI.getTableColumns({ type: 'internal', name: '내부 DB' }, firstMapping.from_table_name).then(columns => { console.log("📊 FROM 컬럼 목록:", columns); setFromColumns(columns); }); } }); } else if (firstMapping.from_connection_id) { const fromConn = connections.find(c => c.id === firstMapping.from_connection_id); if (fromConn) { setFromConnection(fromConn); // 외부 DB 테이블 목록 로드 BatchAPI.getTablesFromConnection(fromConn).then(tables => { console.log("📋 FROM 테이블 목록:", tables); setFromTables(tables); // 컬럼 정보도 로드 if (firstMapping.from_table_name) { BatchAPI.getTableColumns(fromConn, firstMapping.from_table_name).then(columns => { console.log("📊 FROM 컬럼 목록:", columns); setFromColumns(columns); }); } }); } } // TO 연결 정보 설정 if (firstMapping.to_connection_type === 'internal') { setToConnection({ type: 'internal', name: '내부 DB' }); // 내부 DB 테이블 목록 로드 BatchAPI.getTablesFromConnection({ type: 'internal', name: '내부 DB' }).then(tables => { console.log("📋 TO 테이블 목록:", tables); setToTables(tables); // 컬럼 정보도 로드 if (firstMapping.to_table_name) { BatchAPI.getTableColumns({ type: 'internal', name: '내부 DB' }, firstMapping.to_table_name).then(columns => { console.log("📊 TO 컬럼 목록:", columns); setToColumns(columns); }); } }); } else if (firstMapping.to_connection_id) { const toConn = connections.find(c => c.id === firstMapping.to_connection_id); if (toConn) { setToConnection(toConn); // 외부 DB 테이블 목록 로드 BatchAPI.getTablesFromConnection(toConn).then(tables => { console.log("📋 TO 테이블 목록:", tables); setToTables(tables); // 컬럼 정보도 로드 if (firstMapping.to_table_name) { BatchAPI.getTableColumns(toConn, firstMapping.to_table_name).then(columns => { console.log("📊 TO 컬럼 목록:", columns); setToColumns(columns); }); } }); } } } }, [batchConfig, connections]); // 배치 설정 조회 const loadBatchConfig = async () => { try { setLoading(true); console.log("🔍 배치 설정 조회 시작:", batchId); const config = await BatchAPI.getBatchConfig(batchId); console.log("📋 조회된 배치 설정:", config); setBatchConfig(config); setBatchName(config.batch_name); setCronSchedule(config.cron_schedule); setDescription(config.description || ""); setIsActive(config.is_active || "Y"); if (config.batch_mappings && config.batch_mappings.length > 0) { console.log("📊 매핑 정보:", config.batch_mappings); console.log("📊 매핑 개수:", config.batch_mappings.length); config.batch_mappings.forEach((mapping, idx) => { console.log(`📊 매핑 #${idx + 1}:`, { from: `${mapping.from_column_name} (${mapping.from_column_type})`, to: `${mapping.to_column_name} (${mapping.to_column_type})`, type: mapping.mapping_type }); }); setMappings(config.batch_mappings); // 첫 번째 매핑에서 연결 및 테이블 정보 추출 const firstMapping = config.batch_mappings[0]; setFromTable(firstMapping.from_table_name); setToTable(firstMapping.to_table_name); // 배치 타입 감지 const detectedBatchType = detectBatchType(firstMapping); setBatchType(detectedBatchType); console.log("🎯 감지된 배치 타입:", detectedBatchType); // FROM 연결 정보 설정 if (firstMapping.from_connection_type === 'internal') { setFromConnection({ type: 'internal', name: '내부 DB' }); } else if (firstMapping.from_connection_id) { // 외부 연결은 connections 로드 후 설정 setTimeout(() => { const fromConn = connections.find(c => c.id === firstMapping.from_connection_id); if (fromConn) { setFromConnection(fromConn); } }, 100); } // TO 연결 정보 설정 if (firstMapping.to_connection_type === 'internal') { setToConnection({ type: 'internal', name: '내부 DB' }); } else if (firstMapping.to_connection_id) { // 외부 연결은 connections 로드 후 설정 setTimeout(() => { const toConn = connections.find(c => c.id === firstMapping.to_connection_id); if (toConn) { setToConnection(toConn); } }, 100); } console.log("🔗 테이블 정보 설정:", { fromTable: firstMapping.from_table_name, toTable: firstMapping.to_table_name, fromConnectionType: firstMapping.from_connection_type, toConnectionType: firstMapping.to_connection_type }); } } catch (error) { console.error("❌ 배치 설정 조회 오류:", error); toast.error("배치 설정을 불러오는데 실패했습니다."); } finally { setLoading(false); } }; // 연결 정보 조회 const loadConnections = async () => { try { const connectionList = await BatchAPI.getConnections(); setConnections(connectionList); } catch (error) { console.error("연결 정보 조회 오류:", error); toast.error("연결 정보를 불러오는데 실패했습니다."); } }; // FROM 연결 변경 시 const handleFromConnectionChange = async (connectionId: string) => { const connection = connections.find(c => c.id?.toString() === connectionId) || (connectionId === 'internal' ? { type: 'internal' as const, name: '내부 DB' } : null); if (connection) { setFromConnection(connection); try { const tables = await BatchAPI.getTablesFromConnection(connection); setFromTables(tables); setFromTable(""); setFromColumns([]); } catch (error) { console.error("테이블 목록 조회 오류:", error); toast.error("테이블 목록을 불러오는데 실패했습니다."); } } }; // TO 연결 변경 시 const handleToConnectionChange = async (connectionId: string) => { const connection = connections.find(c => c.id?.toString() === connectionId) || (connectionId === 'internal' ? { type: 'internal' as const, name: '내부 DB' } : null); if (connection) { setToConnection(connection); try { const tables = await BatchAPI.getTablesFromConnection(connection); setToTables(tables); setToTable(""); setToColumns([]); } catch (error) { console.error("테이블 목록 조회 오류:", error); toast.error("테이블 목록을 불러오는데 실패했습니다."); } } }; // FROM 테이블 변경 시 const handleFromTableChange = async (tableName: string) => { setFromTable(tableName); if (fromConnection && tableName) { try { const columns = await BatchAPI.getTableColumns(fromConnection, tableName); setFromColumns(columns); } catch (error) { console.error("컬럼 정보 조회 오류:", error); toast.error("컬럼 정보를 불러오는데 실패했습니다."); } } }; // TO 테이블 변경 시 const handleToTableChange = async (tableName: string) => { setToTable(tableName); if (toConnection && tableName) { try { const columns = await BatchAPI.getTableColumns(toConnection, tableName); setToColumns(columns); } catch (error) { console.error("컬럼 정보 조회 오류:", error); toast.error("컬럼 정보를 불러오는데 실패했습니다."); } } }; // 매핑 추가 const addMapping = () => { const newMapping: BatchMapping = { from_connection_type: fromConnection?.type === 'internal' ? 'internal' : 'external', from_connection_id: fromConnection?.type === 'internal' ? undefined : fromConnection?.id, from_table_name: fromTable, from_column_name: '', from_column_type: '', to_connection_type: toConnection?.type === 'internal' ? 'internal' : 'external', to_connection_id: toConnection?.type === 'internal' ? undefined : toConnection?.id, to_table_name: toTable, to_column_name: '', to_column_type: '', mapping_type: 'direct', mapping_order: mappings.length + 1 }; setMappings([...mappings, newMapping]); }; // 매핑 삭제 const removeMapping = (index: number) => { const updatedMappings = mappings.filter((_, i) => i !== index); setMappings(updatedMappings); }; // 매핑 업데이트 const updateMapping = (index: number, field: keyof BatchMapping, value: any) => { setMappings(prevMappings => { const updatedMappings = [...prevMappings]; updatedMappings[index] = { ...updatedMappings[index], [field]: value }; return updatedMappings; }); }; // 배치 설정 저장 const saveBatchConfig = async () => { if (!batchName || !cronSchedule || mappings.length === 0) { toast.error("필수 항목을 모두 입력해주세요."); return; } try { setLoading(true); await BatchAPI.updateBatchConfig(batchId, { batchName, description, cronSchedule, isActive, mappings }); toast.success("배치 설정이 성공적으로 수정되었습니다."); router.push("/admin/batchmng"); } catch (error) { console.error("배치 설정 수정 실패:", error); toast.error("배치 설정 수정에 실패했습니다."); } finally { setLoading(false); } }; if (loading && !batchConfig) { return (
배치 설정을 불러오는 중...
); } return (

배치 설정 수정

{/* 기본 정보 */} 기본 정보
setBatchName(e.target.value)} placeholder="배치명을 입력하세요" />
setCronSchedule(e.target.value)} placeholder="0 12 * * *" />