From 151f05caadd9b50deb9315701804168e64d48a2d Mon Sep 17 00:00:00 2001 From: qikongjian Date: Thu, 4 Sep 2025 17:27:17 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=B7=A6=E4=BE=A7=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=8F=B3=E4=BE=A7=E6=97=B6=E9=97=B4=E7=BA=BF=E9=AB=98?= =?UTF-8?q?=E4=BA=AE=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/dashboard/network-timeline.tsx | 58 +++++++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/components/dashboard/network-timeline.tsx b/components/dashboard/network-timeline.tsx index 3a2b768..52da35d 100644 --- a/components/dashboard/network-timeline.tsx +++ b/components/dashboard/network-timeline.tsx @@ -852,6 +852,10 @@ export function NetworkTimeline({ // 智能时间格式化 - 提升用户体验 function formatTime(ms: number): string { + // 统一兜底:避免负值/NaN 导致显示 "-Xs" + if (!Number.isFinite(ms) || ms <= 0) { + return '0s'; + } if (ms < 1000) { return `${Math.round(ms)}ms`; } @@ -983,8 +987,51 @@ export function NetworkTimeline({ }); }, []); - // 计算时间线位置 + // 计算时间线位置(用于绘制可视化相对宽度) const maxTime = Math.max(...(filteredTaskExecutions.length > 0 ? filteredTaskExecutions.map((task: TaskExecution) => task.endTime) : [0])); + + // 计算“项目总耗时”应独立于过滤条件,直接基于原始 tasks + // 规则: + // 1) 全局开始时间 = 所有任务 start_time/created_at 的最小值 + // 2) 全局结束时间 = + // - 若存在已结束任务:取已结束任务 end_time 的最大值 + // - 否则:取所有任务 updated_at 的最大值(表示仍在进行中的最近更新时间) + const projectDurationMs = React.useMemo(() => { + if (!tasks || tasks.length === 0) return 0; + + const toMs = (v: any) => { + const n = new Date(v as string).getTime(); + return Number.isNaN(n) ? NaN : n; + }; + + // 1) 全局开始 + const allStarts = tasks + .map((t: any) => toMs(t.start_time || t.created_at)) + .filter((n: number) => !Number.isNaN(n)); + const globalStart = allStarts.length > 0 ? Math.min(...allStarts) : Date.now(); + + // 2) 终止态集合 + const terminal = new Set(['COMPLETED','SUCCESS','FINISHED','FAILED','FAILURE','ERROR','CANCELLED','TIMEOUT']); + + // 3) 已结束任务的结束时间 + const endedEnds = tasks + .map((t: any) => terminal.has(t.task_status) ? toMs(t.end_time) : NaN) + .filter((n: number) => !Number.isNaN(n)); + + let globalEnd: number | null = null; + if (endedEnds.length > 0) { + globalEnd = Math.max(...endedEnds); + } else { + // 4) 无已结束任务,则取最近一次 updated_at 代表“当前进度” + const latestUpdated = tasks + .map((t: any) => toMs(t.updated_at || t.created_at)) + .filter((n: number) => !Number.isNaN(n)); + if (latestUpdated.length > 0) globalEnd = Math.max(...latestUpdated); + } + + if (!globalEnd || Number.isNaN(globalEnd)) return 0; + return Math.max(0, globalEnd - globalStart); + }, [tasks]); return (
@@ -1382,7 +1429,7 @@ export function NetworkTimeline({
- 时间线视图 (总耗时: {formatTime(maxTime)}) + 时间线视图 (总耗时: {formatTime(projectDurationMs)})
@@ -1430,12 +1477,15 @@ export function NetworkTimeline({ {/* 任务条 */}
= 400 ? "bg-rose-500" : "bg-amber-500", - selectedTask === task.id ? "opacity-100" : "opacity-80 hover:opacity-95", + // 选中时明显高亮:提高不透明度、描边、阴影与z-index + selectedTask === task.id + ? "opacity-100 ring-2 ring-cyan-300/90 shadow-[0_0_10px_rgba(34,211,238,0.6)] z-10" + : "opacity-80 hover:opacity-95", task.level === 1 && "opacity-70" )} style={{