diff --git a/frontend/src/admin/pages/DataCompleteness.tsx b/frontend/src/admin/pages/DataCompleteness.tsx index bd5fa2c..a601698 100644 --- a/frontend/src/admin/pages/DataCompleteness.tsx +++ b/frontend/src/admin/pages/DataCompleteness.tsx @@ -7,7 +7,7 @@ * 3. 覆盖是否新鲜(最近一场/最近一次采集) */ -import { useEffect, useState, useCallback } from 'react' +import { useEffect, useState, useCallback, useRef } from 'react' import { fetchDataCompleteness } from '../dal' import type { DataCompletenessResponse } from '../dal' import { @@ -32,20 +32,20 @@ function pctColor(pct: number): string { } /** 根据问题描述生成可操作的修复链接 */ -function getIssueAction(issue: string): { href: string; label: string } | null { +function getIssueAction(issue: string): { href: string; label: string; code: string } | null { // 提取联赛代码(大写字母+数字,如 E0, SP1) const codeMatch = issue.match(/\b([A-Z]{1,2}\d?)\b/) const code = codeMatch ? codeMatch[1] : '' if (!code) return null if (issue.includes('无已完赛比赛')) { - return { href: `/admin/collection?task=events&league=${code}`, label: '去采集' } + return { href: `/admin/collection?task=events&league=${code}`, label: '去采集', code } } if (issue.includes('无统计回填') || issue.includes('统计覆盖率')) { - return { href: `/admin/collection?task=stats&league=${code}`, label: '去回填' } + return { href: `/admin/collection?task=stats&league=${code}`, label: '去回填', code } } if (issue.includes('无积分榜')) { - return { href: `/admin/collection?task=standings&league=${code}`, label: '去采集' } + return { href: `/admin/collection?task=standings&league=${code}`, label: '去采集', code } } return null } @@ -54,6 +54,8 @@ export default function DataCompletenessPage() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) + const [highlightedLeague, setHighlightedLeague] = useState(null) + const leagueRefs = useRef>({}) const load = useCallback(async () => { setLoading(true) @@ -70,6 +72,14 @@ export default function DataCompletenessPage() { useEffect(() => { load() }, [load]) + // 点击问题项 → 滚动到对应联赛卡片并高亮 + const scrollToLeague = useCallback((code: string) => { + setHighlightedLeague(code) + leagueRefs.current[code]?.scrollIntoView({ behavior: 'smooth', block: 'center' }) + // 3秒后移除高亮 + setTimeout(() => setHighlightedLeague(null), 3000) + }, []) + return (
- {action.label} - +
+ + + {action.label} + +
) : undefined} /> ) @@ -144,8 +162,14 @@ export default function DataCompletenessPage() { {data.leagues.map(league => { const finished = league.matches.finished const statsPct = finished > 0 ? Math.round((league.stats.rows / finished) * 100) : 0 + const isHighlighted = highlightedLeague === league.code return ( - +
{ leagueRefs.current[league.code] = el }} + className={`transition-all duration-500 ${isHighlighted ? 'ring-2 ring-press scale-[1.01]' : ''}`} + > + +
) })}