diff --git a/frontend/src/pages/Matches.tsx b/frontend/src/pages/Matches.tsx index 25a1bea..324fe40 100644 --- a/frontend/src/pages/Matches.tsx +++ b/frontend/src/pages/Matches.tsx @@ -189,12 +189,12 @@ function OutcomeLine({ export default function Matches() { const [league, setLeague] = useState('E0') const [status, setStatus] = useState('scheduled') - const [date, setDate] = useState('') // 日期筛选(空=全部),"today"=今日 const [matches, setMatches] = useState([]) const [nextCursor, setNextCursor] = useState(null) const [loadingMore, setLoadingMore] = useState(false) const [loading, setLoading] = useState(false) const [showAllUpcoming, setShowAllUpcoming] = useState(false) // 默认仅展示未来 3 天;true 展开全部 + const [liveMatches, setLiveMatches] = useState([]) // 进行中比赛(顶部独立区块) const [predictingId, setPredictingId] = useState(null) const [prediction, setPrediction] = useState(null) const [predictionFor, setPredictionFor] = useState(null) @@ -228,8 +228,6 @@ export default function Matches() { setError(null) try { const params = new URLSearchParams({ league, status, limit: '50' }) - if (date === 'today') params.set('date', todayStr()) - else if (date) params.set('date', date) const res = await fetch(`/api/v1/matches?${params}`) if (seq !== loadSeq.current) return // 已有更新的请求,丢弃本次结果 if (!res.ok) throw new Error(`HTTP ${res.status}`) @@ -243,7 +241,7 @@ export default function Matches() { } finally { if (seq === loadSeq.current) setLoading(false) } - }, [league, status, date]) + }, [league, status]) // 加载下一页(游标分页) const loadMore = async () => { @@ -252,8 +250,6 @@ export default function Matches() { setLoadingMore(true) try { const params = new URLSearchParams({ league, status, limit: '50', cursor: nextCursor }) - if (date === 'today') params.set('date', todayStr()) - else if (date) params.set('date', date) const res = await fetch(`/api/v1/matches?${params}`) if (seq !== loadSeq.current) return if (!res.ok) throw new Error(`HTTP ${res.status}`) @@ -269,21 +265,32 @@ export default function Matches() { } } - useEffect(() => { load() }, [load]) + // 加载进行中比赛(顶部独立区块) + const loadLive = useCallback(async () => { + try { + const params = new URLSearchParams({ league, status: 'in_play', limit: '20' }) + const res = await fetch(`/api/v1/matches?${params}`) + if (!res.ok) return + const data = await res.json() + setLiveMatches(data.items ?? []) + } catch { + /* ignore:进行中非核心功能 */ + } + }, [league]) - /** 今日日期 YYYY-MM-DD(本地时区,非 UTC) */ - function todayStr(): string { - const d = new Date() + useEffect(() => { load(); loadLive() }, [load, loadLive]) + + /** 日期 key 辅助:YYYY-MM-DD(本地时区) */ + function dateKey(d: Date): string { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` } - /** 未来 3 天窗口:今天 00:00 → 第 3 天 00:00(即今天/明天/后天) */ function addDays(d: Date, n: number): string { const x = new Date(d) x.setFullYear(x.getFullYear(), x.getMonth(), x.getDate() + n) - return `${x.getFullYear()}-${String(x.getMonth() + 1).padStart(2, '0')}-${String(x.getDate()).padStart(2, '0')}` + return dateKey(x) } - const todayKey = todayStr() + const todayKey = dateKey(new Date()) const windowEnd = addDays(new Date(), 3) // 不含 /** 比赛是否在未来 3 天内(用于默认视图过滤) */ @@ -423,27 +430,6 @@ export default function Matches() { /> - - 日期 - - - setDate(e.target.value)} - className="field px-1.5 py-1 text-xs" - aria-label="按日期筛选" - /> - {date && ( - - )} - - - {isScheduledView && !showAllUpcoming && hasHiddenUpcoming @@ -478,6 +464,40 @@ export default function Matches() { /> )} + {/* ── 进行中比赛(顶部独立区块,仅未开赛视图展示) ── */} + {isScheduledView && liveMatches.length > 0 && ( +
+
+ + 进行中 · 实时比分 + {liveMatches.length} 场 +
+
+ {liveMatches.map(m => { + const homeName = m.home_team_zh || m.home_team + const awayName = m.away_team_zh || m.away_team + return ( +
+
+ + {m.home_goals ?? '-'} + + {homeName} +
+ vs +
+ {awayName} + + {m.away_goals ?? '-'} + +
+
+ ) + })} +
+
+ )} + {/* ── 赛程栏:表格化,行间细线,按日期分组 ── */}
{loading && }