/** * Admin 后台 - 仪表盘(报刊风) * * 展示: * - 数据流水线状态(采集 → 预测 → 评估,每步的实际数据量) * - 近期预测活动(24h / 7d / 总计) * - 快捷操作入口(带工作流引导) */ import { useEffect, useState, useCallback } from 'react' import { fetchAdminStats, fetchIngestStatus, fetchDashboard } from '../dal' import type { AdminStats, IngestSourceStatus, DashboardStats } from '../types' import { Card, CardBody, CardHeader, Alert, SkeletonBlock } from '../components' /** 工作流步骤卡片 */ const STEPS = [ { to: '/admin/collection', step: '1', title: '采集数据', desc: 'bzzoiro: 赛程 / 积分榜 / 比赛统计(xG、射门、控球等)', icon: '◈' }, { to: '/admin/predictions', step: '2', title: '运行预测', desc: '调 LLM 多专家生成比分预测', icon: '◆' }, { to: '/admin/eval', step: '3', title: '评估准确率', desc: '结算后查看 1X2 命中率与校准度', icon: '◈' }, ] export default function Dashboard() { const [stats, setStats] = useState(null) const [ingest, setIngest] = useState([]) const [dash, setDash] = useState(null) const [loading, setLoading] = useState(true) const load = useCallback(async () => { setLoading(true) const [s, i, d] = await Promise.allSettled([ fetchAdminStats(), fetchIngestStatus(), fetchDashboard(), ]) if (s.status === 'fulfilled') setStats(s.value) if (i.status === 'fulfilled') setIngest(i.value.sources) if (d.status === 'fulfilled') setDash(d.value) setLoading(false) }, []) useEffect(() => { load() }, [load]) const sourceByName = Object.fromEntries(ingest.map(s => [s.name, s])) const bzzoiro = sourceByName['bzzoiro'] return (
{/* ── 工作流引导(采集 → 预测 → 评估) ── */}
{STEPS.map((s, i) => (
{s.step} {s.title}

{s.desc}

{i < STEPS.length - 1 && 下一步}
))}
{/* ── 数据源健康一览 ── */} {loading ? (
{[1, 2, 3].map(i => )}
) : (
{[ { name: 'bzzoiro', label: 'Bzzoiro', st: bzzoiro }, ].map(({ name, label, st }) => { const hasData = st && st.recent_count > 0 const keyOk = st?.key_configured !== false return (
{label} {hasData ? ( <> {st.recent_count.toLocaleString()} 条 {st.last_success_at ? new Date(st.last_success_at).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false }) : ''} ) : keyOk ? ( 无数据 ) : ( 未配置 Key )}
) })}
)}
{/* ── 近期预测活动 ── */} {stats ? (
{stats.predictions.last_24h}
近 24 小时
{stats.predictions.last_7d}
近 7 天
{stats.predictions.total}
累计
{/* F3 修复: 真实比赛计数(非 limit=100 近似) */}
{stats.matches?.total ?? 0}
比赛总数
{stats.matches?.finished ?? 0}
已完赛
{stats.stats?.total ?? 0}
统计行
{stats.standings?.total ?? 0}
积分榜
) : (
)}
{/* ── 已入库联赛 ── */} {dash && dash.leagues.length > 0 && (
{dash.leagues.map(l => ( {l.name_zh || l.name} {l.code} ))}
)}
) }