diff --git a/edict/frontend/src/components/TaskModal.tsx b/edict/frontend/src/components/TaskModal.tsx index a5fdb84..c4f92f6 100644 --- a/edict/frontend/src/components/TaskModal.tsx +++ b/edict/frontend/src/components/TaskModal.tsx @@ -1,6 +1,7 @@ import { useEffect, useState, useRef, useCallback } from 'react'; import { useStore, getPipeStatus, deptColor, stateLabel, STATE_LABEL } from '../store'; import { api } from '../api'; +import { formatDashboardDateTime, formatDashboardTime } from '../time'; import type { Task, TaskActivityData, @@ -43,13 +44,7 @@ function fmtStalled(sec: number): string { } function fmtActivityTime(ts: number | string | undefined): string { - if (!ts) return ''; - if (typeof ts === 'number') { - const d = new Date(ts); - return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`; - } - if (typeof ts === 'string' && ts.length >= 19) return ts.substring(11, 19); - return String(ts).substring(0, 8); + return formatDashboardTime(ts, { showSeconds: true }); } export default function TaskModal() { @@ -302,8 +297,8 @@ export default function TaskModal() { {sched && (
- {sched.lastProgressAt && 最近进展 {(sched.lastProgressAt || '').replace('T', ' ').substring(0, 19)}} - {sched.lastDispatchAt && 最近派发 {(sched.lastDispatchAt || '').replace('T', ' ').substring(0, 19)}} + {sched.lastProgressAt && 最近进展 {formatDashboardDateTime(sched.lastProgressAt)}} + {sched.lastDispatchAt && 最近派发 {formatDashboardDateTime(sched.lastDispatchAt)}} 自动回滚 {sched.autoRollback === false ? '关闭' : '开启'} {sched.lastDispatchAgent && 目标 {sched.lastDispatchAgent}}
@@ -365,7 +360,7 @@ export default function TaskModal() { const col = deptColor(fl.from || ''); return (
-
{fl.at ? fl.at.substring(11, 16) : ''}
+
{formatDashboardTime(fl.at, { showSeconds: false })}
@@ -458,7 +453,7 @@ function LiveActivitySection({ const agentParts: string[] = []; if (data.agentLabel) agentParts.push(data.agentLabel); if (data.relatedAgents && data.relatedAgents.length > 1) agentParts.push(`${data.relatedAgents.length}个 Agent`); - if (data.lastActive) agentParts.push(`最后活跃: ${data.lastActive}`); + if (data.lastActive) agentParts.push(`最后活跃: ${formatDashboardDateTime(data.lastActive)}`); // Phase durations const phaseDurations = data.phaseDurations || []; diff --git a/edict/frontend/src/time.ts b/edict/frontend/src/time.ts new file mode 100644 index 0000000..bc36793 --- /dev/null +++ b/edict/frontend/src/time.ts @@ -0,0 +1,57 @@ +function pad2(value: number): string { + return String(value).padStart(2, '0'); +} + +export function parseDashboardTimestamp(value: number | string | undefined | null): Date | null { + if (value === undefined || value === null || value === '') return null; + + if (typeof value === 'number') { + const ms = Math.abs(value) < 1e12 ? value * 1000 : value; + const d = new Date(ms); + return Number.isNaN(d.getTime()) ? null : d; + } + + const raw = String(value).trim(); + if (!raw) return null; + + if (/^\d+(\.\d+)?$/.test(raw)) { + return parseDashboardTimestamp(Number(raw)); + } + + let normalized = raw; + if (normalized.includes(' ') && !normalized.includes('T')) { + normalized = normalized.replace(' ', 'T'); + } + + const looksIso = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(normalized); + const hasTimezone = /(?:Z|[+\-]\d{2}:\d{2})$/i.test(normalized); + if (looksIso && !hasTimezone) { + normalized += 'Z'; + } + + const d = new Date(normalized); + return Number.isNaN(d.getTime()) ? null : d; +} + +export function formatDashboardTime( + value: number | string | undefined | null, + { showSeconds = true }: { showSeconds?: boolean } = {} +): string { + const d = parseDashboardTimestamp(value); + if (!d) return ''; + const hh = pad2(d.getHours()); + const mm = pad2(d.getMinutes()); + if (!showSeconds) return `${hh}:${mm}`; + return `${hh}:${mm}:${pad2(d.getSeconds())}`; +} + +export function formatDashboardDateTime( + value: number | string | undefined | null, + { showSeconds = true }: { showSeconds?: boolean } = {} +): string { + const d = parseDashboardTimestamp(value); + if (!d) return ''; + const date = `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`; + const time = formatDashboardTime(d.getTime(), { showSeconds }); + return `${date} ${time}`; +}