From d013407aa10c6503fb5b398c9281de12c97d8925 Mon Sep 17 00:00:00 2001 From: WorkBuddy Date: Tue, 22 Sep 2026 12:44:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E9=87=87=E9=9B=86=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=8E=86=E5=8F=B2=E5=88=97=E8=A1=A8=20+=20=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E8=AF=AD=E8=A8=80=E7=BB=9F=E4=B8=80=20+=20=E5=AD=98?= =?UTF-8?q?=E9=87=8F=E6=A0=B7=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dal 新增 fetchIngestJobs(接已有 GET /admin/ingest/jobs,此前前端未用) - Collection 新增「最近任务」卡:最新 10 条,状态点/任务类型/结果摘要, 任务终态后自动刷新 —— 补齐采集失败后的回看入口 - 任务选择按钮修复:brand-* 色在 tailwind 中不存在(选中态样式失效), 改用全站 press/press-wash;去掉与报刊风方角语言不符的 rounded-lg - 任务图标 ⚽🏆📊 → ◈◇▤⇉,与全站几何字符一致,不混用 emoji - Logs 页描述补充 LOG_FILE 持久化边界说明 --- frontend/src/admin/dal.ts | 11 +++++ frontend/src/admin/pages/Collection.tsx | 63 +++++++++++++++++++++---- frontend/src/admin/pages/Logs.tsx | 2 +- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/frontend/src/admin/dal.ts b/frontend/src/admin/dal.ts index 90cc311..d4cf05c 100644 --- a/frontend/src/admin/dal.ts +++ b/frontend/src/admin/dal.ts @@ -370,6 +370,17 @@ export function fetchIngestJob(jobId: string): Promise { return api.get(`${API_BASE}/admin/ingest/jobs/${jobId}`) } +/** + * 采集任务历史列表(GET /admin/ingest/jobs,最新在前) + */ +export function fetchIngestJobs(params: { limit?: number; status?: string } = {}): Promise { + const q = new URLSearchParams() + if (params.limit != null) q.set('limit', String(params.limit)) + if (params.status) q.set('status', params.status) + const qs = q.toString() + return api.get(`${API_BASE}/admin/ingest/jobs${qs ? `?${qs}` : ''}`) +} + /** * 比赛详情(含最近预测摘要) */ diff --git a/frontend/src/admin/pages/Collection.tsx b/frontend/src/admin/pages/Collection.tsx index 6eafd29..0f1cadf 100644 --- a/frontend/src/admin/pages/Collection.tsx +++ b/frontend/src/admin/pages/Collection.tsx @@ -11,16 +11,17 @@ */ import { useEffect, useState, useCallback, useRef } from 'react' -import { triggerCollection, fetchLeagues, fetchIngestJob } from '../dal' +import { triggerCollection, fetchLeagues, fetchIngestJob, fetchIngestJobs } from '../dal' import type { IngestJob, League } from '../types' import type { CollectionRequest } from '../types' import { Card, CardBody, CardHeader, Badge, SectionHeader, Alert, Spinner } from '../components' +// 图标用与全站一致的几何字符(Dashboard 工作流卡同款),不混用 emoji const TASKS = [ - { value: 'events', label: '比赛数据', desc: '赛程 / 比分 / 未开赛安排', icon: '⚽' }, - { value: 'standings', label: '积分榜', desc: '联赛排名 / 积分 / xG差 / 近期走势', icon: '🏆' }, - { value: 'stats', label: '统计回填', desc: '已完赛比赛的 xG / 射门 / 控球等详细统计', icon: '📊' }, - { value: 'all', label: '全量采集', desc: '依次采集比赛 + 积分榜 + 统计回填', icon: '⏵⏵' }, + { value: 'events', label: '比赛数据', desc: '赛程 / 比分 / 未开赛安排', icon: '◈' }, + { value: 'standings', label: '积分榜', desc: '联赛排名 / 积分 / xG差 / 近期走势', icon: '◇' }, + { value: 'stats', label: '统计回填', desc: '已完赛比赛的 xG / 射门 / 控球等详细统计', icon: '▤' }, + { value: 'all', label: '全量采集', desc: '依次采集比赛 + 积分榜 + 统计回填', icon: '⇉' }, ] as const type TaskUIStatus = 'idle' | 'running' | 'done' | 'error' @@ -73,6 +74,16 @@ export default function CollectionPage() { useEffect(() => () => stopPolling(), [stopPolling]) + // ── 最近任务历史(GET /admin/ingest/jobs,最新在前) ── + // 声明须在 startJobPolling 之前(其终态回调会刷新历史) + const [recentJobs, setRecentJobs] = useState(null) + const loadRecentJobs = useCallback(async () => { + try { + setRecentJobs(await fetchIngestJobs({ limit: 10 })) + } catch { /* 历史列表失败不影响主流程 */ } + }, []) + useEffect(() => { loadRecentJobs() }, [loadRecentJobs]) + const startJobPolling = useCallback((id: string) => { stopPolling() const tick = async () => { @@ -82,12 +93,13 @@ export default function CollectionPage() { if (TERMINAL_STATUSES.has(job.status)) { setTaskStatus(job.status === 'success' ? 'done' : 'error') stopPolling() + loadRecentJobs() // 终态后刷新历史列表 } } catch { /* 单次轮询失败不影响后续 */ } } tick() pollRef.current = setInterval(tick, 3_000) - }, [stopPolling]) + }, [stopPolling, loadRecentJobs]) const isEventsTask = task === 'events' || task === 'all' @@ -183,9 +195,9 @@ export default function CollectionPage() { key={t.value} type="button" onClick={() => setTask(t.value)} - className={`rounded-lg border px-3 py-2 text-left text-xs transition-colors ${ + className={`border px-3 py-2 text-left text-xs transition-colors ${ task === t.value - ? 'border-brand-500 bg-brand-50 text-brand-700' + ? 'border-press bg-press-wash text-press' : 'border-ink-200 text-ink-600 hover:border-ink-300' }`} > @@ -345,6 +357,41 @@ export default function CollectionPage() { + {/* 最近任务历史 */} + + 刷新} + /> + + {recentJobs === null ? ( +

加载中…

+ ) : recentJobs.length === 0 ? ( +

还没有任务记录,触发一次采集后这里会出现历史。

+ ) : ( +
+ {recentJobs.map(j => { + const st = j.status + const dot = st === 'success' ? 'bg-ink-900' : st === 'failed' ? 'bg-press' : 'bg-amber-500 animate-pulse' + const label = st === 'success' ? '完成' : st === 'failed' ? '失败' : st === 'running' ? '执行中' : '排队中' + return ( +
+
+ ) + })} +
+ )} +
+
+ {/* 数据源说明 */} diff --git a/frontend/src/admin/pages/Logs.tsx b/frontend/src/admin/pages/Logs.tsx index d8d2328..513ac30 100644 --- a/frontend/src/admin/pages/Logs.tsx +++ b/frontend/src/admin/pages/Logs.tsx @@ -85,7 +85,7 @@ export default function LogsPage() {
{error && }