import { useState, useEffect, useMemo, useCallback } from 'react'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, LineChart, Line, Cell, } from 'recharts'; import type { ServiceStatsResponse } from '../../types/statistics'; import { getServiceStats } from '../../services/statisticsService'; import DateRangeFilter from '../../components/DateRangeFilter'; import { CHART_COLORS_HEX } from '../../constants/chart'; import { useTheme } from '../../hooks/useTheme'; const getToday = () => new Date().toISOString().slice(0, 10); const ServiceStatsPage = () => { const { theme } = useTheme(); const chartColors = CHART_COLORS_HEX[theme]; const [startDate, setStartDate] = useState(getToday()); const [endDate, setEndDate] = useState(getToday()); const [data, setData] = useState(null); const [isLoading, setIsLoading] = useState(true); const fetchData = useCallback(async () => { setIsLoading(true); try { const res = await getServiceStats(startDate, endDate); if (res.success && res.data) { setData(res.data); } } finally { setIsLoading(false); } }, [startDate, endDate]); useEffect(() => { fetchData(); }, [fetchData]); const handlePreset = (days: number) => { const today = getToday(); if (days === 0) { setStartDate(today); } else { const d = new Date(); d.setDate(d.getDate() - days); setStartDate(d.toISOString().slice(0, 10)); } setEndDate(today); }; const hourlyTrendPivoted = useMemo(() => { if (!data) return { data: [], serviceNames: [] }; const serviceNames = [...new Set(data.hourlyTrend.map((e) => e.serviceName))]; const byHour: Record> = {}; for (const item of data.hourlyTrend) { if (!byHour[item.hour]) { byHour[item.hour] = { hour: item.hour }; } byHour[item.hour][item.serviceName] = item.count; } return { data: Object.values(byHour), serviceNames }; }, [data]); const barChartData = useMemo(() => { if (!data) return []; return data.serviceStats.map((s) => ({ serviceName: s.serviceName, totalRequests: s.totalRequests, })); }, [data]); if (isLoading) { return (
로딩 중...
); } return (

서비스 통계

{!data || data.serviceStats.length === 0 ? (

데이터가 없습니다

) : ( <> {/* Summary Cards */}
{data.serviceStats.map((svc) => (

{svc.serviceName}

{svc.totalRequests.toLocaleString()}

성공 {svc.successRate.toFixed(1)}% {svc.avgResponseTime.toFixed(0)}ms
))}
{/* Charts */}
{/* Chart 1: Service Request Count Bar */}

서비스별 요청 수

{/* Chart 2: Hourly Service Trend */}

시간별 서비스 요청 추이

{hourlyTrendPivoted.data.length > 0 ? ( `${h}시`} /> `${h}시`} /> {hourlyTrendPivoted.serviceNames.map((name, idx) => ( ))} ) : (

데이터가 없습니다

)}
{/* Charts Row 2: Error Rate + Response Time */}
{/* Chart: Error Rate Comparison */}

서비스별 에러율 비교

({ serviceName: s.serviceName, successRate: Number(s.successRate.toFixed(1)), errorRate: Number((100 - s.successRate).toFixed(1)), }))} layout="vertical" >
{/* Chart: Avg Response Time Comparison */}

서비스별 평균 응답시간 비교

({ serviceName: s.serviceName, avgResponseTime: Number(s.avgResponseTime.toFixed(0)), }))} layout="vertical" > {data.serviceStats.map((s, idx) => { const rt = s.avgResponseTime; const color = rt < 100 ? '#10b981' : rt < 300 ? '#f59e0b' : '#ef4444'; return ; })}
)}
); }; export default ServiceStatsPage;