diff --git a/frontend/src/components/TaskDetailModal.tsx b/frontend/src/components/TaskDetailModal.tsx new file mode 100644 index 0000000..765b41f --- /dev/null +++ b/frontend/src/components/TaskDetailModal.tsx @@ -0,0 +1,140 @@ +import { useEffect, useState } from 'react'; +import { Modal, Descriptions, Spin, Tag, Typography, Empty } from 'antd'; +import { taskApi } from '@/api'; +import type { Task } from '@/types'; +import { TaskStatusTag, PriorityTag } from '@/components/constants'; +import dayjs from 'dayjs'; + +const { Paragraph, Text } = Typography; + +interface Props { + taskId: number | null; + open: boolean; + onClose: () => void; +} + +/** 任务详情弹窗:在 DAG 画布/项目页内点击任务卡片时弹出,不跳转页面 */ +export default function TaskDetailModal({ taskId, open, onClose }: Props) { + const [task, setTask] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!open || taskId == null) return; + setLoading(true); + setTask(null); + taskApi + .get(taskId) + .then(setTask) + .catch(() => setTask(null)) + .finally(() => setLoading(false)); + }, [open, taskId]); + + const renderJsonBlock = (raw?: string) => { + if (!raw) return ; + let pretty = raw; + try { + pretty = JSON.stringify(JSON.parse(raw), null, 2); + } catch { + /* keep raw */ + } + return ( +
+        {pretty}
+      
+ ); + }; + + return ( + + {loading ? ( +
+ +
+ ) : !task ? ( + + ) : ( +
+ + + + + + + + {task.task_type} + + {task.requires_review ? ( + + ) : ( + + )} + + {task.review_status && ( + {task.review_status} + )} + {task.worker_id && ( + #{task.worker_id} + )} + {task.due_date && ( + + {dayjs(task.due_date).format('YYYY-MM-DD HH:mm')} + + )} + {task.started_at && ( + + {dayjs(task.started_at).format('YYYY-MM-DD HH:mm')} + + )} + {task.completed_at && ( + + {dayjs(task.completed_at).format('YYYY-MM-DD HH:mm')} + + )} + + {dayjs(task.created_at).format('YYYY-MM-DD HH:mm')} + + {task.description && ( + + {task.description} + + )} + + +
+ + 输入(Prompt / 参数) + + {renderJsonBlock(task.input_data)} +
+ +
+ + 输出结果 + + {renderJsonBlock(task.output_data)} +
+
+ )} +
+ ); +}