import { useState } from 'react'; import { Alert, Button, Card, Col, DatePicker, message, Row, Select, Space, Statistic, Steps, Table, Tag, Typography, } from 'antd'; import { CheckCircleOutlined, CloseCircleOutlined, PlayCircleOutlined, ReloadOutlined, } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import dayjs, { Dayjs } from 'dayjs'; import { useNavigate } from 'react-router-dom'; import PageContainer from '@/components/common/PageContainer'; import PermissionButton from '@/components/common/PermissionButton'; import { batchRunApi, BatchHistoryResp, BatchJobLogResp } from '@/api/batch'; const { Text } = Typography; const STEP_NAMES = [ { key: 'receive', label: '데이터 수신' }, { key: 'transform', label: '데이터 변환' }, { key: 'reconcile', label: '대사 검증' }, { key: 'calcRecruit', label: '모집수수료' }, { key: 'calcMaintain', label: '유지수수료' }, { key: 'chargebackException', label: '환수/예외' }, { key: 'calcOverride', label: '오버라이드' }, { key: 'aggregate', label: '집계' }, ] as const; function currentStepIndex(stepName?: string): number { if (!stepName) return -1; return STEP_NAMES.findIndex((s) => s.key === stepName); } function formatMs(ms?: number): string { if (ms == null) return '-'; if (ms < 1000) return `${ms}ms`; return `${(ms / 1000).toFixed(1)}s`; } function stepStatus( idx: number, currentIdx: number, jobStatus: BatchJobLogResp['status'], ): 'finish' | 'process' | 'wait' | 'error' { if (jobStatus === 'FAILED' && idx === currentIdx) return 'error'; if (idx < currentIdx) return 'finish'; if (idx === currentIdx) return 'process'; return 'wait'; } export default function BatchRun() { const navigate = useNavigate(); const [settleMonth, setSettleMonth] = useState(dayjs()); const [companyCode, setCompanyCode] = useState(undefined); const [jobLogId, setJobLogId] = useState(null); const [running, setRunning] = useState(false); const { data: jobStatus } = useQuery({ queryKey: ['batch', 'status', jobLogId], queryFn: () => batchRunApi.status(jobLogId!), enabled: jobLogId != null, refetchInterval: (query) => { const s = query.state.data?.status; return s === 'COMPLETED' || s === 'FAILED' ? false : 5000; }, }); const { data: history = [] } = useQuery({ queryKey: ['batch', 'history'], queryFn: () => batchRunApi.history(10), }); const isFinished = jobStatus?.status === 'COMPLETED' || jobStatus?.status === 'FAILED'; const onRun = async () => { if (!settleMonth) { message.warning('정산월을 선택하세요'); return; } setRunning(true); try { const id = await batchRunApi.run( settleMonth.format('YYYYMM'), companyCode, ); setJobLogId(id); message.success('정산 배치를 실행했습니다'); } catch (err: unknown) { const e = err as { code?: string; message?: string }; if (e?.code === 'BATCH_RUNNING') { message.error('이미 실행 중인 배치가 있습니다'); } } finally { setRunning(false); } }; const currentIdx = currentStepIndex(jobStatus?.stepName); return ( {/* 컨트롤 영역 */} v && setSettleMonth(v)} format="YYYY-MM" />