From 83cc24e54b6596c77cf9628a862a602de764cbcd Mon Sep 17 00:00:00 2001 From: shangfangjian Date: Mon, 21 Sep 2026 00:44:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=81=A5=E5=BA=B7=E6=91=98=E8=A6=81=E4=B8=8E?= =?UTF-8?q?=E8=81=94=E8=B5=9B=E5=8D=A1=E7=89=87=E8=81=94=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 问题项新增「定位」按钮,点击滚动到对应联赛卡片 - 被定位的联赛卡片高亮显示(ring + scale),3秒后自动消失 - 健康摘要 → 联赛详情形成闭环操作 Co-Authored-By: new-provider/LongCat-2.0 <> ) --- frontend/src/admin/pages/DataCompleteness.tsx | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) 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]' : ''}`} + > + +
) })}