首页:去掉日期选择器,顶部增加「进行中」比赛区块
- 移除日期选择器(今日按钮 + date input + 清除按钮)及相关 date 状态 - 顶部新增「进行中 · 实时比分」独立区块:红色脉冲圆点 + 主客比分 - 进行中区块仅在默认「未开赛」视图显示,切换已完赛/全部时隐藏 - 进行中数据独立请求(status=in_play,limit 20),不影响主列表逻辑 - 清理 todayStr(),改用 dateKey()统一日期格式化 Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
This commit is contained in:
co-authored by
new-provider/LongCat-2.0 <
parent
9d7f8dfeee
commit
dd538d66d7
@@ -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<Match[]>([])
|
||||
const [nextCursor, setNextCursor] = useState<string | null>(null)
|
||||
const [loadingMore, setLoadingMore] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [showAllUpcoming, setShowAllUpcoming] = useState(false) // 默认仅展示未来 3 天;true 展开全部
|
||||
const [liveMatches, setLiveMatches] = useState<Match[]>([]) // 进行中比赛(顶部独立区块)
|
||||
const [predictingId, setPredictingId] = useState<number | null>(null)
|
||||
const [prediction, setPrediction] = useState<Prediction | null>(null)
|
||||
const [predictionFor, setPredictionFor] = useState<Match | null>(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() {
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<span className="text-2xs text-ink-400">日期</span>
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<button
|
||||
onClick={() => setDate(date === 'today' ? '' : 'today')}
|
||||
className={`btn btn-sm px-2 ${date === 'today' ? 'btn-solid' : ''}`}
|
||||
title="只看今日"
|
||||
>今日</button>
|
||||
<input
|
||||
type="date"
|
||||
value={date === 'today' ? todayStr() : date}
|
||||
onChange={e => setDate(e.target.value)}
|
||||
className="field px-1.5 py-1 text-xs"
|
||||
aria-label="按日期筛选"
|
||||
/>
|
||||
{date && (
|
||||
<button onClick={() => setDate('')} className="text-ink-400 hover:text-ink-900 text-sm px-0.5" aria-label="清除日期" title="清除">×</button>
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="ml-auto inline-flex items-center gap-3">
|
||||
<span className="tabular-nums">
|
||||
{isScheduledView && !showAllUpcoming && hasHiddenUpcoming
|
||||
@@ -478,6 +464,40 @@ export default function Matches() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* ── 进行中比赛(顶部独立区块,仅未开赛视图展示) ── */}
|
||||
{isScheduledView && liveMatches.length > 0 && (
|
||||
<section aria-label="进行中" className="border border-ink-900 bg-paper-100">
|
||||
<div className="flex items-center gap-2 border-b border-ink-900 px-3 py-2">
|
||||
<span className="inline-block h-2 w-2 animate-pulse rounded-full bg-press" />
|
||||
<span className="text-xs font-medium tracking-wide text-ink-700">进行中 · 实时比分</span>
|
||||
<span className="text-2xs text-ink-400">{liveMatches.length} 场</span>
|
||||
</div>
|
||||
<div className="divide-y divide-ink-200">
|
||||
{liveMatches.map(m => {
|
||||
const homeName = m.home_team_zh || m.home_team
|
||||
const awayName = m.away_team_zh || m.away_team
|
||||
return (
|
||||
<div key={m.id} className="flex items-center justify-between gap-3 px-3 py-2.5">
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="w-12 shrink-0 text-center font-serif text-lg font-bold tabular-nums text-ink-900">
|
||||
{m.home_goals ?? '-'}
|
||||
</span>
|
||||
<span className="min-w-0 truncate text-xs text-ink-700">{homeName}</span>
|
||||
</div>
|
||||
<span className="shrink-0 text-2xs text-ink-400">vs</span>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="min-w-0 truncate text-right text-xs text-ink-700">{awayName}</span>
|
||||
<span className="w-12 shrink-0 text-center font-serif text-lg font-bold tabular-nums text-ink-900">
|
||||
{m.away_goals ?? '-'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* ── 赛程栏:表格化,行间细线,按日期分组 ── */}
|
||||
<section aria-label="赛程">
|
||||
{loading && <SkeletonRows n={4} />}
|
||||
|
||||
Reference in New Issue
Block a user