import { useState, useEffect, useCallback } from 'react'; import { getNumericalDataStatus, type NumericalDataStatus, } from '../services/monitorApi'; type TabId = 'all' | 'ocean' | 'koast'; const TABS: { id: TabId; label: string }[] = [ { id: 'all', label: '전체' }, { id: 'ocean', label: '기상·해양 모델' }, { id: 'koast', label: 'KOAST' }, ]; const OCEAN_MODELS = ['HYCOM', 'GFS', 'WW3']; const KOAST_MODELS = ['KOAST POS_WIND', 'KOAST POS_HYDR', 'KOAST POS_WAVE']; function filterByTab(rows: NumericalDataStatus[], tab: TabId): NumericalDataStatus[] { if (tab === 'ocean') return rows.filter((r) => OCEAN_MODELS.includes(r.modelName)); if (tab === 'koast') return rows.filter((r) => KOAST_MODELS.includes(r.modelName)); return rows; } function formatDuration(sec: number | null): string { if (sec == null) return '-'; const m = Math.floor(sec / 60); const s = sec % 60; return m > 0 ? `${m}분 ${s}초` : `${s}초`; } function formatDatetime(iso: string | null): string { if (!iso) return '-'; const d = new Date(iso); const mm = String(d.getMonth() + 1).padStart(2, '0'); const dd = String(d.getDate()).padStart(2, '0'); const hh = String(d.getHours()).padStart(2, '0'); const min = String(d.getMinutes()).padStart(2, '0'); return `${mm}-${dd} ${hh}:${min}`; } function formatTime(iso: string | null): string { if (!iso) return '-'; const d = new Date(iso); const hh = String(d.getHours()).padStart(2, '0'); const min = String(d.getMinutes()).padStart(2, '0'); return `${hh}:${min}`; } function StatusCell({ row }: { row: NumericalDataStatus }) { if (row.lastStatus === 'COMPLETED') { return 정상; } if (row.lastStatus === 'FAILED') { return ( 오류{row.consecutiveFailures > 0 ? ` (${row.consecutiveFailures}회 연속)` : ''} ); } if (row.lastStatus === 'STARTED') { return ( 실행 중 ); } return -; } function StatusBadge({ loading, errorCount, total, }: { loading: boolean; errorCount: number; total: number; }) { if (loading) { return ( 조회 중... ); } if (errorCount === total && total > 0) { return ( 연계 오류 ); } if (errorCount > 0) { return ( 일부 오류 ({errorCount}/{total}) ); } return ( 정상 ); } const TABLE_HEADERS = [ '모델명', '데이터 기준일', '마지막 다운로드', '상태', '소요 시간', '다음 예정', ]; function ForecastTable({ rows, loading, }: { rows: NumericalDataStatus[]; loading: boolean; }) { return (
| {h} | ))}|||||
|---|---|---|---|---|---|
| ))} | |||||
| {row.modelName} | {row.lastDataDate ?? '-'} | {formatDatetime(row.lastDownloadedAt)} |
|
{formatDuration(row.durationSec)} | {formatTime(row.nextScheduledAt)} |