健康摘要与联赛卡片联动
- 问题项新增「定位」按钮,点击滚动到对应联赛卡片 - 被定位的联赛卡片高亮显示(ring + scale),3秒后自动消失 - 健康摘要 → 联赛详情形成闭环操作 Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>> )
This commit is contained in:
@@ -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<DataCompletenessResponse | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [highlightedLeague, setHighlightedLeague] = useState<string | null>(null)
|
||||
const leagueRefs = useRef<Record<string, HTMLDivElement | null>>({})
|
||||
|
||||
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 (
|
||||
<div className="space-y-6">
|
||||
<SectionHeader
|
||||
@@ -128,9 +138,17 @@ export default function DataCompletenessPage() {
|
||||
title={issue.includes('良好') ? '数据良好' : '需要关注'}
|
||||
message={issue}
|
||||
action={action ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => scrollToLeague(action.code)}
|
||||
className="btn btn-sm whitespace-nowrap"
|
||||
>
|
||||
定位
|
||||
</button>
|
||||
<a href={action.href} className="btn btn-sm whitespace-nowrap">
|
||||
{action.label}
|
||||
</a>
|
||||
</div>
|
||||
) : 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 (
|
||||
<Card key={league.code}>
|
||||
<div
|
||||
key={league.code}
|
||||
ref={el => { leagueRefs.current[league.code] = el }}
|
||||
className={`transition-all duration-500 ${isHighlighted ? 'ring-2 ring-press scale-[1.01]' : ''}`}
|
||||
>
|
||||
<Card>
|
||||
<CardHeader
|
||||
title={league.name}
|
||||
description={[
|
||||
@@ -196,6 +220,7 @@ export default function DataCompletenessPage() {
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user