diff --git a/src/api.js b/src/api.js index d0859e7..51d379c 100644 --- a/src/api.js +++ b/src/api.js @@ -34,8 +34,8 @@ export function recommend(params) { return apiGet(`/api/lotto/recommend?${qs.toString()}`); } -export function getHistory(limit = 30) { - return apiGet(`/api/history?limit=${limit}`); +export function getHistory(limit = 30, offset = 0) { + return apiGet(`/api/history?limit=${limit}&offset=${offset}`); } export function deleteHistory(id) { diff --git a/src/pages/lotto/Functions.jsx b/src/pages/lotto/Functions.jsx index a385a03..84bbb86 100644 --- a/src/pages/lotto/Functions.jsx +++ b/src/pages/lotto/Functions.jsx @@ -63,6 +63,55 @@ const buildFrequencySeries = (frequency) => { return { series, max }; }; +const buildMetricsFromCounts = (counts) => { + if (!counts?.length) return null; + const total = counts.reduce((acc, value) => acc + value, 0); + if (!total) return null; + const min = Math.min(...counts); + const max = Math.max(...counts); + const range = max - min; + const odd = counts.reduce( + (acc, value, idx) => (idx % 2 === 0 ? acc + value : acc), + 0 + ); + const even = total - odd; + const buckets = { + '1-10': counts.slice(0, 10).reduce((a, b) => a + b, 0), + '11-20': counts.slice(10, 20).reduce((a, b) => a + b, 0), + '21-30': counts.slice(20, 30).reduce((a, b) => a + b, 0), + '31-40': counts.slice(30, 40).reduce((a, b) => a + b, 0), + '41-45': counts.slice(40, 45).reduce((a, b) => a + b, 0), + }; + return { sum: total, min, max, range, odd, even, buckets }; +}; + +const buildMetricsFromFrequency = (frequency) => { + if (!frequency?.length) return null; + const counts = Array.from({ length: 45 }, () => 0); + frequency.forEach((item) => { + const number = Number(item?.number); + const count = Number(item?.count) || 0; + if (number >= 1 && number <= 45) { + counts[number - 1] = count; + } + }); + return buildMetricsFromCounts(counts); +}; + +const buildMetricsFromHistory = (items) => { + if (!items?.length) return null; + const counts = Array.from({ length: 45 }, () => 0); + items.forEach((item) => { + (item?.numbers ?? []).forEach((value) => { + const number = Number(value); + if (number >= 1 && number <= 45) { + counts[number - 1] += 1; + } + }); + }); + return buildMetricsFromCounts(counts); +}; + const toBucketEntries = (metrics) => { if (!metrics?.buckets) return []; const entries = Object.entries(metrics.buckets); @@ -95,19 +144,21 @@ const MetricBlock = ({ title, metrics }) => {

{title}

- 합계 {metrics.sum ?? '-'} + + 총 출현 횟수 {metrics.sum ?? '-'} +
-

최솟값

+

최소 출현

{metrics.min ?? '-'}

-

최댓값

+

최대 출현

{metrics.max ?? '-'}

-

범위

+

출현 편차

{metrics.range ?? '-'}

@@ -222,6 +273,14 @@ export default function Functions() { history: false, }); const [error, setError] = useState(''); + const overallMetrics = useMemo( + () => buildMetricsFromFrequency(stats?.frequency), + [stats] + ); + const historyMetrics = useMemo( + () => buildMetricsFromHistory(history), + [history] + ); const refreshLatest = async () => { setLoading((s) => ({ ...s, latest: true })); @@ -240,8 +299,17 @@ export default function Functions() { setLoading((s) => ({ ...s, history: true })); setError(''); try { - const data = await getHistory(30); - setHistory(data.items ?? []); + const limit = 100; + let offset = 0; + const allItems = []; + while (true) { + const data = await getHistory(limit, offset); + const items = data.items ?? []; + allItems.push(...items); + if (items.length < limit) break; + offset += limit; + } + setHistory(allItems); } catch (e) { setError(e?.message ?? String(e)); } finally { @@ -382,8 +450,11 @@ export default function Functions() {

보너스 {latest.bonus}

- {latest.metrics ? ( - + {overallMetrics ? ( + ) : null} ) : ( @@ -502,17 +573,12 @@ export default function Functions() {
{result.numbers ? : null} - {result.metrics || latest?.metrics ? ( + {historyMetrics ? (
- {result.metrics ? ( - - ) : null} - {latest?.metrics ? ( - - ) : null} +
) : null} {Array.isArray(result.items) && result.items.length ? (