lotto lab 통계 수치 정상화

This commit is contained in:
2026-01-26 01:05:42 +09:00
parent 472a55c0a7
commit d67f925878
2 changed files with 86 additions and 20 deletions

View File

@@ -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) {

View File

@@ -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 }) => {
<div className="lotto-metrics">
<div className="lotto-metrics__head">
<p className="lotto-metrics__title">{title}</p>
<span className="lotto-metrics__sum">합계 {metrics.sum ?? '-'}</span>
<span className="lotto-metrics__sum">
출현 횟수 {metrics.sum ?? '-'}
</span>
</div>
<div className="lotto-metric-cards">
<div className="lotto-metric-card">
<p className="lotto-metric-card__label">솟값</p>
<p className="lotto-metric-card__label"> 출현</p>
<p className="lotto-metric-card__value">{metrics.min ?? '-'}</p>
</div>
<div className="lotto-metric-card">
<p className="lotto-metric-card__label">댓값</p>
<p className="lotto-metric-card__label"> 출현</p>
<p className="lotto-metric-card__value">{metrics.max ?? '-'}</p>
</div>
<div className="lotto-metric-card">
<p className="lotto-metric-card__label">범위</p>
<p className="lotto-metric-card__label">출현 편차</p>
<p className="lotto-metric-card__value">{metrics.range ?? '-'}</p>
</div>
</div>
@@ -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() {
<p className="lotto-bonus">
보너스 <strong>{latest.bonus}</strong>
</p>
{latest.metrics ? (
<MetricBlock title="당첨 통계" metrics={latest.metrics} />
{overallMetrics ? (
<MetricBlock
title="당첨 통계 (전체 회차)"
metrics={overallMetrics}
/>
) : null}
</>
) : (
@@ -502,17 +573,12 @@ export default function Functions() {
</button>
</div>
{result.numbers ? <NumberRow nums={result.numbers} /> : null}
{result.metrics || latest?.metrics ? (
{historyMetrics ? (
<div className="lotto-compare">
{result.metrics ? (
<MetricBlock title="추천 통계" metrics={result.metrics} />
) : null}
{latest?.metrics ? (
<MetricBlock
title="당첨 통계 (최신 회차)"
metrics={latest.metrics}
/>
) : null}
<MetricBlock
title="추천 통계 (히스토리)"
metrics={historyMetrics}
/>
</div>
) : null}
{Array.isArray(result.items) && result.items.length ? (