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}`;
+}