From dcd2910ceabed2350d9d29c6963427e2e2d60b84 Mon Sep 17 00:00:00 2001 From: gahusb Date: Sun, 25 Jan 2026 22:10:24 +0900 Subject: [PATCH] =?UTF-8?q?lotto=20=EA=B8=B0=EB=8A=A5=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EA=B2=B0=EA=B3=BC=20=ED=86=B5=EA=B3=84=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=81=ED=99=94=20(=EB=B6=84=ED=8F=AC,=20=ED=95=A9=EA=B3=84,?= =?UTF-8?q?=20=ED=99=80=EC=A7=9D)=EB=A5=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/lotto/Functions.jsx | 147 ++++++++++++++++++++++++++++-- src/pages/lotto/Lotto.css | 163 ++++++++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+), 5 deletions(-) diff --git a/src/pages/lotto/Functions.jsx b/src/pages/lotto/Functions.jsx index 41ac9a6..acaa5aa 100644 --- a/src/pages/lotto/Functions.jsx +++ b/src/pages/lotto/Functions.jsx @@ -21,6 +21,88 @@ const NumberRow = ({ nums }) => ( ); +const bucketOrder = ['1-10', '11-20', '21-30', '31-40', '41-45']; + +const toBucketEntries = (metrics) => { + if (!metrics?.buckets) return []; + const entries = Object.entries(metrics.buckets); + const ordered = bucketOrder + .filter((key) => Object.prototype.hasOwnProperty.call(metrics.buckets, key)) + .map((key) => [key, metrics.buckets[key]]); + const rest = entries + .filter(([key]) => !bucketOrder.includes(key)) + .sort((a, b) => { + const aStart = Number(a[0].split('-')[0]); + const bStart = Number(b[0].split('-')[0]); + if (Number.isNaN(aStart) || Number.isNaN(bStart)) return 0; + return aStart - bStart; + }); + return [...ordered, ...rest]; +}; + +const MetricBlock = ({ title, metrics }) => { + if (!metrics) return null; + const buckets = toBucketEntries(metrics); + const maxBucket = buckets.length + ? Math.max(...buckets.map(([, value]) => Number(value) || 0), 1) + : 1; + const odd = Number(metrics.odd) || 0; + const even = Number(metrics.even) || 0; + const totalOE = odd + even || 1; + const oddPct = (odd / totalOE) * 100; + + return ( +
+
+

{title}

+ 합계 {metrics.sum ?? '-'} +
+
+
+

최솟값

+

{metrics.min ?? '-'}

+
+
+

최댓값

+

{metrics.max ?? '-'}

+
+
+

범위

+

{metrics.range ?? '-'}

+
+
+
+
+ 홀 {odd} + 짝 {even} +
+
+ + +
+
+ {buckets.length ? ( +
+ {buckets.map(([label, value]) => ( +
+ {label} +
+ +
+ {value} +
+ ))} +
+ ) : null} +
+ ); +}; + export default function Functions() { const [latest, setLatest] = useState(null); const [params, setParams] = useState({ @@ -169,6 +251,9 @@ export default function Functions() {

보너스 {latest.bonus}

+ {latest.metrics ? ( + + ) : null} ) : (

최신 회차 데이터가 없습니다.

@@ -285,11 +370,63 @@ export default function Functions() { 번호 복사 - -
- 설명 보기 -
{JSON.stringify(result.explain, null, 2)}
-
+ {result.numbers ? : null} + {result.metrics || latest?.metrics ? ( +
+ {result.metrics ? ( + + ) : null} + {latest?.metrics ? ( + + ) : null} +
+ ) : null} + {Array.isArray(result.items) && result.items.length ? ( +
+ 추천 후보 보기 +
+ {result.items.map((item, idx) => ( +
+
+
+

+ 후보 #{item.id ?? idx + 1} +

+

+ 기준 회차 {item.based_on_draw ?? '-'} +

+
+ +
+ + {item.metrics ? ( + + ) : null} +
+ ))} +
+
+ ) : null} + {result.explain ? ( +
+ 설명 보기 +
{JSON.stringify(result.explain, null, 2)}
+
+ ) : null} ) : (

아직 추천 결과가 없습니다.

diff --git a/src/pages/lotto/Lotto.css b/src/pages/lotto/Lotto.css index c80e3fe..ec43130 100644 --- a/src/pages/lotto/Lotto.css +++ b/src/pages/lotto/Lotto.css @@ -244,6 +244,169 @@ border: 1px solid var(--line); } +.lotto-compare { + display: grid; + gap: 12px; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); +} + +.lotto-metrics { + border: 1px solid var(--line); + border-radius: 16px; + padding: 14px; + background: rgba(255, 255, 255, 0.02); + display: grid; + gap: 12px; +} + +.lotto-metrics__head { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; +} + +.lotto-metrics__title { + margin: 0; + font-weight: 600; + font-size: 14px; +} + +.lotto-metrics__sum { + font-size: 12px; + color: var(--muted); +} + +.lotto-metric-cards { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 8px; +} + +.lotto-metric-card { + border: 1px solid var(--line); + border-radius: 12px; + padding: 10px; + background: rgba(0, 0, 0, 0.2); + display: grid; + gap: 6px; +} + +.lotto-metric-card__label { + margin: 0; + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--muted); +} + +.lotto-metric-card__value { + margin: 0; + font-weight: 600; + font-size: 16px; +} + +.lotto-odd-even { + display: grid; + gap: 8px; +} + +.lotto-odd-even__labels { + display: flex; + justify-content: space-between; + font-size: 12px; + color: var(--muted); +} + +.lotto-odd-even__bar { + height: 10px; + border-radius: 999px; + overflow: hidden; + display: grid; + grid-template-columns: 1fr 1fr; + border: 1px solid var(--line); + background: rgba(0, 0, 0, 0.2); +} + +.lotto-odd-even__odd { + background: rgba(247, 168, 165, 0.6); +} + +.lotto-odd-even__even { + background: rgba(151, 201, 170, 0.6); +} + +.lotto-buckets { + display: grid; + gap: 8px; +} + +.lotto-bucket { + display: grid; + grid-template-columns: 54px minmax(0, 1fr) 28px; + align-items: center; + gap: 8px; + font-size: 12px; + color: var(--muted); +} + +.lotto-bucket__label { + font-weight: 600; +} + +.lotto-bucket__bar { + height: 8px; + border-radius: 999px; + background: rgba(0, 0, 0, 0.25); + overflow: hidden; + border: 1px solid var(--line); +} + +.lotto-bucket__bar span { + display: block; + height: 100%; + background: rgba(133, 165, 216, 0.7); +} + +.lotto-bucket__value { + text-align: right; + font-weight: 600; +} + +.lotto-batch { + display: grid; + gap: 12px; + margin-top: 12px; +} + +.lotto-batch__item { + border: 1px solid var(--line); + border-radius: 16px; + padding: 14px; + display: grid; + gap: 10px; + background: rgba(0, 0, 0, 0.2); +} + +.lotto-batch__meta { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.lotto-batch__title { + margin: 0; + font-weight: 600; +} + +.lotto-batch__sub { + margin: 4px 0 0; + color: var(--muted); + font-size: 12px; +} + .lotto-empty { margin: 0; color: var(--muted);