import { useState, useEffect, useCallback } from 'react' import { fetchPredictionAnalyses } from '../services/predictionApi' import type { PredictionAnalysis } from '../services/predictionApi' export type Analysis = PredictionAnalysis interface AnalysisListTableProps { onTabChange: (tab: string) => void onSelectAnalysis?: (analysis: Analysis) => void } export function AnalysisListTable({ onTabChange, onSelectAnalysis }: AnalysisListTableProps) { const [analyses, setAnalyses] = useState([]) const [loading, setLoading] = useState(true) const [searchTerm, setSearchTerm] = useState('') const [currentPage, setCurrentPage] = useState(1) const itemsPerPage = 10 const loadData = useCallback(async () => { setLoading(true) try { const items = await fetchPredictionAnalyses({ search: searchTerm || undefined }) setAnalyses(items) } catch (err) { console.error('[prediction] 분석 목록 조회 실패:', err) } finally { setLoading(false) } }, [searchTerm]) useEffect(() => { loadData() }, [loadData]) const getStatusBadge = (status: string) => { switch (status) { case 'completed': return ( 완료 ) case 'running': return ( 실행중 ) case 'pending': return ( 대기 ) case 'error': return ( 오류 ) default: return null } } const totalPages = Math.ceil(analyses.length / itemsPerPage) const startIndex = (currentPage - 1) * itemsPerPage const endIndex = startIndex + itemsPerPage const currentAnalyses = analyses.slice(startIndex, endIndex) const renderPageNumbers = () => { const pages = [] const maxVisible = 5 if (totalPages <= maxVisible) { for (let i = 1; i <= totalPages; i++) { pages.push(i) } } else { if (currentPage <= 3) { for (let i = 1; i <= 5; i++) pages.push(i) pages.push('...') pages.push(totalPages) } else if (currentPage >= totalPages - 2) { pages.push(1) pages.push('...') for (let i = totalPages - 4; i <= totalPages; i++) pages.push(i) } else { pages.push(1) pages.push('...') for (let i = currentPage - 1; i <= currentPage + 1; i++) pages.push(i) pages.push('...') pages.push(totalPages) } } return pages.map((page, index) => { if (page === '...') { return ( ... ) } return ( ) }) } return (
{/* 헤더 */}

유출유 확산 예측 목록

총 {analyses.length}건

setSearchTerm(e.target.value)} className="w-64 px-4 py-2 text-sm bg-bg-2 border border-border rounded-md text-text-1 placeholder-text-3 focus:border-primary-cyan focus:outline-none" />
{/* 테이블 */}
{loading ? (
로딩 중...
) : ( {currentAnalyses.map((analysis) => ( ))}
번호 사고명 사고일시 예측시간 유종 유출량 KOSPS POSEIDON OpenDrift 역추적 담당자 소속
{analysis.acdntSn}
{ e.stopPropagation() if (onSelectAnalysis) { onSelectAnalysis(analysis) } }} > {analysis.acdntNm}
{analysis.occurredAt ? new Date(analysis.occurredAt).toLocaleString('ko-KR', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }) : '—'} {analysis.duration} {analysis.oilType} {analysis.volume != null ? analysis.volume.toFixed(2) : '—'} {getStatusBadge(analysis.kospsStatus)} {getStatusBadge(analysis.poseidonStatus)} {getStatusBadge(analysis.opendriftStatus)} {getStatusBadge(analysis.backtrackStatus)} {analysis.analyst} {analysis.officeName}
)} {!loading && analyses.length === 0 && (
분석 데이터가 없습니다.
)}
{/* 페이지네이션 */}
{renderPageNumbers()}
) }