UI/UX 全面改进:22项优化落地(报纸风前端 + 管理后台)

P0 严重问题:
- 采集任务进度反馈:Collection 页新增任务状态跟踪(运行中/完成/失败) + 轮询 ingest 状态
- 积分榜加载态:切换联赛显示 spinner + 禁用 tab 防重复点击
- 数据完整性可操作:问题列表每项加「去修复」按钮,跳转采集页并预填参数
- 面包屑导航:顶部显示 仪表盘 > 当前页

P1 重要问题:
- 侧边栏当前页指示器:1.5px 圆点 → 4px 左侧彩色竖条 + 背景高亮
- Key Ring 重置确认:点击「重置冷却」前弹窗确认
- 预测比赛选择器:只显示未开赛 + 联赛筛选 + 显示可预测数量
- 表格移动端溢出:评估页表格加 overflow-x-auto
- 设置页合并:数据源 + LLM + 系统配置 → 统一「设置」页
- 预测按钮去重:移动端/桌面端合并为一个响应式按钮

P2 体验优化:
- 日志滚动保持:自动滚动仅当用户未向上滚动时
- 评估结果预览:显示「共 N 组」
- ⌘K 命令面板:键盘导航跳转所有管理页面
- 专家意见折叠:默认折叠,可展开(已存在)
- 版本信息:侧边栏底部显示 v1.0
- 积分榜表格:min-w 防止挤压

Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
This commit is contained in:
shangfangjian
2026-09-20 21:24:21 +08:00
co-authored by new-provider/LongCat-2.0 <
parent dd538d66d7
commit fb27f6e2d2
13 changed files with 854 additions and 107 deletions
+36 -9
View File
@@ -31,6 +31,25 @@ function pctColor(pct: number): string {
return 'bg-rose-500'
}
/** 根据问题描述生成可操作的修复链接 */
function getIssueAction(issue: string): { href: string; label: 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: '去采集' }
}
if (issue.includes('无统计回填') || issue.includes('统计覆盖率')) {
return { href: `/admin/collection?task=stats&league=${code}`, label: '去回填' }
}
if (issue.includes('无积分榜')) {
return { href: `/admin/collection?task=standings&league=${code}`, label: '去采集' }
}
return null
}
export default function DataCompletenessPage() {
const [data, setData] = useState<DataCompletenessResponse | null>(null)
const [loading, setLoading] = useState(true)
@@ -95,19 +114,27 @@ export default function DataCompletenessPage() {
</Card>
</div>
{/* 健康问题 */}
{/* 健康问题(可操作) */}
<Card>
<CardHeader title="健康摘要" />
<CardBody>
<div className="space-y-2">
{data.issues.map((issue, i) => (
<Alert
key={i}
kind={issue.includes('良好') ? 'ok' : issue.includes('建议') || issue.includes('仅') ? 'warning' : 'error'}
title={issue.includes('良好') ? '数据良好' : '需要关注'}
message={issue}
/>
))}
{data.issues.map((issue, i) => {
const action = getIssueAction(issue)
return (
<Alert
key={i}
kind={issue.includes('良好') ? 'ok' : issue.includes('建议') || issue.includes('仅') ? 'warning' : 'error'}
title={issue.includes('良好') ? '数据良好' : '需要关注'}
message={issue}
action={action ? (
<a href={action.href} className="btn btn-sm whitespace-nowrap">
{action.label}
</a>
) : undefined}
/>
)
})}
</div>
</CardBody>
</Card>