diff --git a/frontend/src/pages/Matches.tsx b/frontend/src/pages/Matches.tsx index 925afc4..7ac436a 100644 --- a/frontend/src/pages/Matches.tsx +++ b/frontend/src/pages/Matches.tsx @@ -194,6 +194,7 @@ export default function Matches() { const [nextCursor, setNextCursor] = useState(null) const [loadingMore, setLoadingMore] = useState(false) const [loading, setLoading] = useState(false) + const [showAllUpcoming, setShowAllUpcoming] = useState(false) // 默认仅展示未来 3 天;true 展开全部 const [predictingId, setPredictingId] = useState(null) const [prediction, setPrediction] = useState(null) const [predictionFor, setPredictionFor] = useState(null) @@ -223,6 +224,7 @@ export default function Matches() { const seq = ++loadSeq.current setLoading(true) setLoadingMore(false) + setShowAllUpcoming(false) // 切换筛选重置为「未来 3 天」视图 setError(null) try { const params = new URLSearchParams({ league, status, limit: '50' }) @@ -275,6 +277,21 @@ export default function Matches() { 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')}` + } + const todayKey = todayStr() + const windowEnd = addDays(new Date(), 3) // 不含 + + /** 比赛是否在未来 3 天内(用于默认视图过滤) */ + function withinNext3Days(matchDate: string): boolean { + const key = toLocalDateKey(matchDate) + return key >= todayKey && key < windowEnd + } + /** UTC ISO → 本地日期 YYYY-MM-DD(用于分组) */ function toLocalDateKey(iso: string): string { const d = new Date(iso) @@ -346,6 +363,14 @@ export default function Matches() { const leagueName = LEAGUES.find(l => l.code === league)?.name ?? league + /** 未开赛默认仅展示未来 3 天;其余状态展示全部。showAllUpcoming=true 时展开全部。 */ + const isScheduledView = status === 'scheduled' + const visibleMatches = (!isScheduledView || showAllUpcoming) + ? matches + : matches.filter(m => withinNext3Days(m.match_date)) + // 是否有被折叠的未开赛比赛(用于显示「展开」按钮) + const hasHiddenUpcoming = isScheduledView && !showAllUpcoming && matches.length > visibleMatches.length + /** 状态/模式一组的文字切换 */ const Switch = ({ value, onChange, items }: { value: string @@ -420,7 +445,11 @@ export default function Matches() { - 共 {matches.length} 场 + + {isScheduledView && !showAllUpcoming && hasHiddenUpcoming + ? `未来3天 ${visibleMatches.length} / 共 ${matches.length} 场` + : `共 ${visibleMatches.length} 场`} + @@ -453,17 +482,26 @@ export default function Matches() {
{loading && } - {!loading && matches.length === 0 && ( + {!loading && visibleMatches.length === 0 && (
-

本版暂无赛程

-

请先通过「数据采集」导入 {leagueName} 的比赛数据

- - 前往数据采集 - + {matches.length > 0 ? ( + <> +

未来 3 天暂无 {leagueName} 比赛

+

已导入 {matches.length} 场未开赛,点击下方按钮查看

+ + ) : ( + <> +

本版暂无赛程

+

请先通过「数据采集」导入 {leagueName} 的比赛数据

+ + 前往数据采集 + + + )}
)} - {!loading && groupByDate(matches).map(([dateKey, group]) => ( + {!loading && groupByDate(visibleMatches).map(([dateKey, group]) => (
{/* 日期分组头:sticky 但 z 低于弹窗 z-50 */}
@@ -604,8 +642,32 @@ export default function Matches() {
))} + {/* 未开赛视图:从「未来 3 天」展开全部已加载的未开赛 */} + {!loading && hasHiddenUpcoming && ( +
+ +
+ )} + + {/* 已展开全部但未开赛:提供「收起」回未来 3 天 */} + {!loading && isScheduledView && showAllUpcoming && matches.length > 0 && ( +
+ +
+ )} + {!loading && nextCursor && ( -
+