forked from 77media/video-flow
dashboard数据面板样式修改
This commit is contained in:
parent
8fa3b16ecd
commit
f8a2ac1e34
@ -923,6 +923,45 @@ export function NetworkTimeline({
|
||||
return formatTime(remainingTime);
|
||||
}
|
||||
|
||||
// 获取任务日志内容(右侧面板展示)
|
||||
function getTaskLogContent(viewTask: TaskExecution): string {
|
||||
// 优先从原始任务中提取完整字段
|
||||
let origin: any | null = null;
|
||||
if (viewTask.level === 0) {
|
||||
origin = tasks.find((t: any) => t.task_id === viewTask.id) || null;
|
||||
} else if (viewTask.level === 1 && viewTask.parentId) {
|
||||
const parent = tasks.find((t: any) => t.task_id === viewTask.parentId);
|
||||
origin = parent?.sub_tasks?.find((st: any) => st.task_id === viewTask.id) || null;
|
||||
}
|
||||
|
||||
if (!origin) return '无可用日志';
|
||||
|
||||
const resultObj = parseTaskResult(origin.task_result);
|
||||
const payload: Record<string, any> = {
|
||||
task_id: origin.task_id,
|
||||
task_name: origin.task_name,
|
||||
task_status: origin.task_status,
|
||||
task_message: origin.task_message || null,
|
||||
error_message: origin.error_message || resultObj?.error_message || null,
|
||||
error_traceback: origin.error_traceback || resultObj?.error_traceback || null,
|
||||
progress_percentage: resultObj?.progress_percentage ?? origin.progress ?? null,
|
||||
params: origin.task_params || null,
|
||||
result: resultObj || origin.task_result || null,
|
||||
timestamps: {
|
||||
created_at: origin.created_at || null,
|
||||
updated_at: origin.updated_at || null,
|
||||
start_time: origin.start_time || null,
|
||||
end_time: origin.end_time || null,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
return JSON.stringify(payload, null, 2);
|
||||
} catch {
|
||||
return typeof origin.task_result === 'string' ? origin.task_result : '无可用日志';
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态颜色
|
||||
function getStatusColor(status: number): string {
|
||||
if (status >= 200 && status < 300) return 'text-green-400';
|
||||
@ -950,13 +989,13 @@ export function NetworkTimeline({
|
||||
return (
|
||||
<div className={cn("h-full flex flex-col bg-gray-950 overflow-hidden", className)}>
|
||||
{/* 工具栏 */}
|
||||
<div className="flex items-center justify-between px-6 py-4 bg-gray-900 border-b border-gray-800 flex-shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center justify-between px-6 py-3 bg-gray-900 border-b border-gray-800 flex-shrink-0">
|
||||
<div className="flex items-center gap-3">
|
||||
<Network className="w-5 h-5 text-cyan-400" />
|
||||
<h3 className="text-lg font-semibold text-white">任务执行时间线</h3>
|
||||
|
||||
{/* 任务统计 */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="flex items-center gap-1 px-3 py-1.5 bg-gray-800 rounded-md">
|
||||
<span className="text-sm text-gray-400">总任务:</span>
|
||||
<span className="text-sm font-bold text-white">{taskStats.total}</span>
|
||||
@ -1083,7 +1122,7 @@ export function NetworkTimeline({
|
||||
{/* 左侧任务列表 */}
|
||||
<div className="w-1/2 border-r border-gray-800 flex flex-col min-h-0">
|
||||
{/* 列表头部 */}
|
||||
<div className="flex items-center px-4 py-2 bg-gray-800/50 text-xs font-medium text-gray-400 border-b border-gray-800 flex-shrink-0">
|
||||
<div className="flex items-center px-4 py-1.5 bg-gray-800/50 text-xs font-medium text-gray-400 border-b border-gray-800 flex-shrink-0">
|
||||
<div className="w-8">状态</div>
|
||||
<div className="w-6"></div> {/* 展开/折叠按钮列 */}
|
||||
<div className="flex-1">任务名称</div>
|
||||
@ -1094,7 +1133,7 @@ export function NetworkTimeline({
|
||||
</div>
|
||||
|
||||
{/* 任务列表 */}
|
||||
<div className="flex-1 overflow-y-auto min-h-0" style={{ maxHeight: 'calc(100vh - 200px)' }}>
|
||||
<div className="flex-1 overflow-y-auto min-h-0">
|
||||
{filteredTaskExecutions.length === 0 ? (
|
||||
<div className="flex items-center justify-center py-8 text-gray-400">
|
||||
<div className="text-center">
|
||||
@ -1110,7 +1149,7 @@ export function NetworkTimeline({
|
||||
<div
|
||||
key={task.id}
|
||||
className={cn(
|
||||
"flex items-center px-4 py-2 text-sm border-b border-gray-800/30 cursor-pointer hover:bg-gray-800/50 transition-all duration-200 ease-out",
|
||||
"flex items-center px-4 py-1.5 text-sm border-b border-gray-800/30 cursor-pointer hover:bg-gray-800/50 transition-all duration-200 ease-out",
|
||||
selectedTask === task.id && "bg-blue-600/20",
|
||||
task.level === 1 && "ml-4 bg-gray-900/30" // 子任务缩进和背景区分
|
||||
)}
|
||||
@ -1118,10 +1157,10 @@ export function NetworkTimeline({
|
||||
>
|
||||
{/* 状态图标 */}
|
||||
<div className="w-8 flex justify-center">
|
||||
{task.statusCode === 200 && <CheckCircle className="w-5 h-5 text-emerald-400" />}
|
||||
{task.statusCode === 202 && <Clock className="w-5 h-5 text-cyan-400 animate-pulse" />}
|
||||
{task.statusCode === 100 && <Pause className="w-5 h-5 text-amber-400" />}
|
||||
{task.statusCode >= 400 && <XCircle className="w-5 h-5 text-rose-400" />}
|
||||
{task.statusCode === 200 && <CheckCircle className="w-4 h-4 text-emerald-400" />}
|
||||
{task.statusCode === 202 && <Clock className="w-4 h-4 text-cyan-400 animate-pulse" />}
|
||||
{task.statusCode === 100 && <Pause className="w-4 h-4 text-amber-400" />}
|
||||
{task.statusCode >= 400 && <XCircle className="w-4 h-4 text-rose-400" />}
|
||||
</div>
|
||||
|
||||
{/* 展开/折叠按钮 */}
|
||||
@ -1341,12 +1380,12 @@ export function NetworkTimeline({
|
||||
|
||||
{/* 右侧时间线 */}
|
||||
<div className="w-1/2 flex flex-col min-h-0">
|
||||
<div className="px-4 py-3 bg-gray-900/50 border-b border-gray-800 flex-shrink-0">
|
||||
<div className="px-4 py-2.5 bg-gray-900/50 border-b border-gray-800 flex-shrink-0">
|
||||
<div className="text-sm font-medium text-gray-300 text-center">
|
||||
时间线视图 (总耗时: {formatTime(maxTime)})
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 p-4 overflow-y-auto min-h-0" style={{ maxHeight: 'calc(100vh - 200px)' }}>
|
||||
<div className="flex-1 p-3.5 overflow-y-auto min-h-0">
|
||||
|
||||
{/* 时间刻度 */}
|
||||
<div className="relative mb-6">
|
||||
@ -1386,13 +1425,13 @@ export function NetworkTimeline({
|
||||
filteredTaskExecutions.map((task) => (
|
||||
<div key={task.id} className={cn(
|
||||
"relative",
|
||||
task.level === 0 ? "h-6" : "h-4"
|
||||
task.level === 0 ? "h-5" : "h-3.5"
|
||||
)}>
|
||||
{/* 任务条 */}
|
||||
<div
|
||||
className={cn(
|
||||
"absolute rounded-sm cursor-pointer transition-opacity",
|
||||
task.level === 0 ? "top-1 h-4" : "top-0.5 h-3",
|
||||
task.level === 0 ? "top-0.5 h-3.5" : "top-0.5 h-2.5",
|
||||
task.statusCode === 200 ? "bg-emerald-500" :
|
||||
task.statusCode === 202 ? "bg-cyan-500" :
|
||||
task.statusCode >= 400 ? "bg-rose-500" : "bg-amber-500",
|
||||
@ -1575,23 +1614,48 @@ ${task.status === 'IN_PROGRESS' ? `进度: ${task.progress}%` : ''}
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
className="border-t border-gray-800 p-4"
|
||||
className="border-t border-gray-800 p-3"
|
||||
>
|
||||
{(() => {
|
||||
const task = taskExecutions.find((t: TaskExecution) => t.id === selectedTask);
|
||||
if (!task) return null;
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<h4 className="text-base font-medium text-white mb-3">
|
||||
{task.level === 0 ? '主任务详情' : '子任务详情'}
|
||||
</h4>
|
||||
{/* 顶部一行:任务关键信息 + 时间信息 */}
|
||||
{(() => {
|
||||
const t = getTaskTimes(task);
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs sm:text-sm mb-2">
|
||||
<span className="px-2 py-1 bg-gray-800/60 border border-gray-700 rounded text-white">
|
||||
{task.displayName}
|
||||
</span>
|
||||
<span className={cn("px-2 py-1 rounded border", getTaskStatusColor(task.status), "border-gray-700/60 bg-gray-800/40 ")}>{getTaskStatusText(task.status)}</span>
|
||||
<span className="px-2 py-1 bg-gray-800/40 border border-gray-700 rounded text-gray-300">{task.type}</span>
|
||||
{t.startTime && (
|
||||
<span className="px-2 py-1 bg-gray-900/40 border border-gray-800 rounded text-green-400" title={`开始时间: ${formatDateTime(t.startTime)}`}>
|
||||
开始 {new Date(t.startTime).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
|
||||
</span>
|
||||
)}
|
||||
{t.endTime && (
|
||||
<span className="px-2 py-1 bg-gray-900/40 border border-gray-800 rounded text-blue-400" title={`结束时间: ${formatDateTime(t.endTime)}`}>
|
||||
结束 {new Date(t.endTime).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
|
||||
</span>
|
||||
)}
|
||||
{t.startTime && t.endTime && (
|
||||
<span className="px-2 py-1 bg-gray-900/40 border border-gray-800 rounded text-yellow-400">
|
||||
时长 {formatTime(task.executionTime)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
<div className="space-y-2 text-sm">
|
||||
<div><span className="text-gray-400">任务名称:</span> <span className="text-white">{task.displayName}</span></div>
|
||||
<div><span className="text-gray-400">任务ID:</span> <span className="text-white font-mono text-sm">{task.name}</span></div>
|
||||
<div><span className="text-gray-400">状态:</span> <span className={getTaskStatusColor(task.status)}>{getTaskStatusText(task.status)}</span></div>
|
||||
<div><span className="text-gray-400">类型:</span> <span className="text-white">{task.type}</span></div>
|
||||
<div><span className="text-gray-400">层级:</span> <span className="text-white">{task.level === 0 ? '主任务' : '子任务'}</span></div>
|
||||
|
||||
{/* 子任务完成状况 */}
|
||||
@ -1603,28 +1667,7 @@ ${task.status === 'IN_PROGRESS' ? `进度: ${task.progress}%` : ''}
|
||||
) : null;
|
||||
})()}
|
||||
|
||||
{/* 时间信息显示 */}
|
||||
{(() => {
|
||||
const taskTimes = getTaskTimes(task);
|
||||
return (
|
||||
<>
|
||||
<div className="border-t border-gray-700 pt-3 mt-3">
|
||||
<div className="text-gray-300 font-medium text-sm mb-2">⏰ 时间信息</div>
|
||||
<div><span className="text-gray-400">开始时间:</span> <span className="text-green-400 text-sm">{formatDateTime(taskTimes.startTime)}</span></div>
|
||||
<div><span className="text-gray-400">结束时间:</span> <span className="text-blue-400 text-sm">{formatDateTime(taskTimes.endTime)}</span></div>
|
||||
{taskTimes.createdAt && taskTimes.createdAt !== taskTimes.startTime && (
|
||||
<div><span className="text-gray-400">创建时间:</span> <span className="text-gray-300 text-sm">{formatDateTime(taskTimes.createdAt)}</span></div>
|
||||
)}
|
||||
{taskTimes.updatedAt && taskTimes.updatedAt !== taskTimes.endTime && (
|
||||
<div><span className="text-gray-400">更新时间:</span> <span className="text-gray-300 text-sm">{formatDateTime(taskTimes.updatedAt)}</span></div>
|
||||
)}
|
||||
{taskTimes.startTime && taskTimes.endTime && (
|
||||
<div><span className="text-gray-400">执行时长:</span> <span className="text-yellow-400 text-sm">{formatTime(task.executionTime)}</span></div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
{/* 时间信息已并入顶部一行,此处不再重复 */}
|
||||
{task.status === 'IN_PROGRESS' && (
|
||||
<>
|
||||
<div><span className="text-gray-400">进度:</span> <span className="text-white">{task.progress}%</span></div>
|
||||
@ -1658,21 +1701,21 @@ ${task.status === 'IN_PROGRESS' ? `进度: ${task.progress}%` : ''}
|
||||
if (!errorInfo.hasError) return null;
|
||||
|
||||
return (
|
||||
<div className="mt-2 p-2 bg-red-600/10 border border-red-600/20 rounded">
|
||||
<div className="flex items-center gap-1 mb-1">
|
||||
<div className="mt-2 p-2 bg-red-600/10 border border-red-600/20 rounded flex items-center gap-2 flex-wrap">
|
||||
<div className="flex items-center gap-1">
|
||||
<XCircle className="w-3 h-3 text-red-400" />
|
||||
<span className="text-red-400 font-medium">错误信息</span>
|
||||
<span className="text-red-400 font-medium text-[11px]">错误</span>
|
||||
</div>
|
||||
<div className="text-red-300 text-[10px] break-words">{errorInfo.errorMessage}</div>
|
||||
<span className="text-red-300 text-[10px] truncate max-w-[40%]" title={errorInfo.errorMessage}>{errorInfo.errorMessage}</span>
|
||||
{errorInfo.errorCode && (
|
||||
<div className="text-red-400 text-[10px] font-mono mt-1">代码: {errorInfo.errorCode}</div>
|
||||
<span className="text-red-400 text-[10px] font-mono">代码: {errorInfo.errorCode}</span>
|
||||
)}
|
||||
{onRetryTask && (
|
||||
<button
|
||||
onClick={() => handleRetryTask(task.id)}
|
||||
disabled={retryingTasks.has(task.id) || task.status === 'RETRYING'}
|
||||
className={cn(
|
||||
"mt-2 flex items-center gap-1 px-2 py-1 text-white text-[10px] rounded transition-colors",
|
||||
"ml-auto flex items-center gap-1 px-2 py-1 text-white text-[10px] rounded transition-colors",
|
||||
(retryingTasks.has(task.id) || task.status === 'RETRYING')
|
||||
? "bg-yellow-600 cursor-not-allowed"
|
||||
: "bg-blue-600 hover:bg-blue-700"
|
||||
@ -1691,21 +1734,15 @@ ${task.status === 'IN_PROGRESS' ? `进度: ${task.progress}%` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-base font-medium text-white mb-3">执行分析</h4>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div><span className="text-gray-400">总时间:</span> <span className="text-white">{formatTime(task.executionTime)}</span></div>
|
||||
<div><span className="text-gray-400">AI处理:</span> <span className="text-white">{formatTime(task.phases.aiProcessing || 0)}</span></div>
|
||||
{/* <div><span className="text-gray-400">数据大小:</span> <span className="text-white">{formatSize(task.dataSize)}</span></div> */}
|
||||
{task.level === 0 && task.taskResult?.total_count && (
|
||||
<div><span className="text-gray-400">子任务数:</span> <span className="text-white">{task.taskResult.total_count}</span></div>
|
||||
)}
|
||||
{task.level === 0 && task.taskResult?.completed_count !== undefined && (
|
||||
<div><span className="text-gray-400">已完成:</span> <span className="text-white">{task.taskResult.completed_count}/{task.taskResult.total_count}</span></div>
|
||||
)}
|
||||
{task.level === 1 && task.taskResult?.urls && (
|
||||
<div><span className="text-gray-400">输出文件:</span> <span className="text-white">{task.taskResult.urls.length} 个</span></div>
|
||||
)}
|
||||
</div>
|
||||
<h4 className="text-base font-medium text-white mb-3">执行日志</h4>
|
||||
{/* <div className="space-y-2 text-sm">
|
||||
<div className="bg-gray-900/50 border border-gray-800 rounded p-3 min-h-40 max-h-64 overflow-y-auto">
|
||||
<pre className="text-xs text-gray-300 font-mono whitespace-pre-wrap break-words">
|
||||
{getTaskLogContent(task)}
|
||||
</pre>
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">仅展示与该任务相关的最新字段(状态、消息、错误、参数与结果)。</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user