"use client"; import React, { useState, useEffect } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Progress } from "@/components/ui/progress"; import { RefreshCw, Play, Pause, AlertCircle, CheckCircle, Clock } from "lucide-react"; import { toast } from "sonner"; import { BatchAPI, BatchMonitoring, BatchExecution } from "@/lib/api/batch"; export default function MonitoringDashboard() { const [monitoring, setMonitoring] = useState(null); const [isLoading, setIsLoading] = useState(false); const [autoRefresh, setAutoRefresh] = useState(false); useEffect(() => { loadMonitoringData(); let interval: NodeJS.Timeout; if (autoRefresh) { interval = setInterval(loadMonitoringData, 30000); // 30초마다 자동 새로고침 } return () => { if (interval) clearInterval(interval); }; }, [autoRefresh]); const loadMonitoringData = async () => { setIsLoading(true); try { const data = await BatchAPI.getBatchMonitoring(); setMonitoring(data); } catch (error) { console.error("모니터링 데이터 조회 오류:", error); toast.error("모니터링 데이터를 불러오는데 실패했습니다."); } finally { setIsLoading(false); } }; const handleRefresh = () => { loadMonitoringData(); }; const toggleAutoRefresh = () => { setAutoRefresh(!autoRefresh); }; const getStatusIcon = (status: string) => { switch (status) { case 'completed': return ; case 'failed': return ; case 'running': return ; case 'pending': return ; default: return ; } }; const getStatusBadge = (status: string) => { const variants = { completed: "bg-green-100 text-green-800", failed: "bg-red-100 text-red-800", running: "bg-blue-100 text-blue-800", pending: "bg-yellow-100 text-yellow-800", cancelled: "bg-gray-100 text-gray-800", }; const labels = { completed: "완료", failed: "실패", running: "실행 중", pending: "대기 중", cancelled: "취소됨", }; return ( {labels[status as keyof typeof labels] || status} ); }; const formatDuration = (ms: number) => { if (ms < 1000) return `${ms}ms`; if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`; return `${(ms / 60000).toFixed(1)}m`; }; const getSuccessRate = () => { if (!monitoring) return 0; const total = monitoring.successful_jobs_today + monitoring.failed_jobs_today; if (total === 0) return 100; return Math.round((monitoring.successful_jobs_today / total) * 100); }; if (!monitoring) { return (

모니터링 데이터를 불러오는 중...

); } return (
{/* 헤더 */}

배치 모니터링

{/* 통계 카드 */}
총 작업 수
📋
{monitoring.total_jobs}

활성: {monitoring.active_jobs}개

실행 중
🔄
{monitoring.running_jobs}

현재 실행 중인 작업

오늘 성공
{monitoring.successful_jobs_today}

성공률: {getSuccessRate()}%

오늘 실패
{monitoring.failed_jobs_today}

주의가 필요한 작업

{/* 성공률 진행바 */} 오늘 실행 성공률
성공: {monitoring.successful_jobs_today}건 실패: {monitoring.failed_jobs_today}건
{getSuccessRate()}% 성공률
{/* 최근 실행 이력 */} 최근 실행 이력 {monitoring.recent_executions.length === 0 ? (
최근 실행 이력이 없습니다.
) : ( 상태 작업 ID 시작 시간 완료 시간 실행 시간 오류 메시지 {monitoring.recent_executions.map((execution) => (
{getStatusIcon(execution.execution_status)} {getStatusBadge(execution.execution_status)}
#{execution.job_id} {execution.started_at ? new Date(execution.started_at).toLocaleString() : "-"} {execution.completed_at ? new Date(execution.completed_at).toLocaleString() : "-"} {execution.execution_time_ms ? formatDuration(execution.execution_time_ms) : "-"} {execution.error_message ? ( {execution.error_message} ) : ( "-" )}
))}
)}
); }