feat: DAG画布嵌入项目详情页,任务节点点击弹详情Modal

This commit is contained in:
2026-08-13 23:13:07 +08:00
parent 2512ef72b7
commit a99f049589
+85 -32
View File
@@ -12,15 +12,20 @@ import {
Tag,
Empty,
List,
Tabs,
} from 'antd';
import {
ArrowLeftOutlined,
ReloadOutlined,
ApartmentOutlined,
ProfileOutlined,
} from '@ant-design/icons';
import { useNavigate, useParams } from 'react-router-dom';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { projectApi, taskApi, artifactApi } from '@/api';
import type { Project, ProjectStats, Task, Artifact } from '@/types';
import { ProjectStatusTag, TaskStatusTag } from '@/components/constants';
import DagCanvas from '@/pages/DagCanvas';
import TaskDetailModal from '@/components/TaskDetailModal';
import dayjs from 'dayjs';
const { Title, Text } = Typography;
@@ -28,11 +33,20 @@ const { Title, Text } = Typography;
export default function ProjectDetail() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
const activeTab = searchParams.get('tab') || 'overview';
const [loading, setLoading] = useState(true);
const [project, setProject] = useState<Project | null>(null);
const [stats, setStats] = useState<ProjectStats | null>(null);
const [tasks, setTasks] = useState<Task[]>([]);
const [artifacts, setArtifacts] = useState<Artifact[]>([]);
const [detailTaskId, setDetailTaskId] = useState<number | null>(null);
const [detailOpen, setDetailOpen] = useState(false);
const openTaskDetail = (taskId: number) => {
setDetailTaskId(taskId);
setDetailOpen(true);
};
useEffect(() => {
if (!id) return;
@@ -75,36 +89,8 @@ export default function ProjectDetail() {
].filter((item) => item.count > 0)
: [];
return (
<div>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
}}
>
<Space>
<Button
icon={<ArrowLeftOutlined />}
onClick={() => navigate('/projects')}
>
</Button>
<Title level={4} style={{ margin: 0 }}>
{project.name}
</Title>
<ProjectStatusTag status={project.status} />
</Space>
<Button
icon={<ReloadOutlined />}
onClick={() => window.location.reload()}
>
</Button>
</div>
const overviewTab = (
<>
<Card style={{ marginBottom: 16 }}>
<Descriptions column={2} bordered size="small">
<Descriptions.Item label="项目名称">{project.name}</Descriptions.Item>
@@ -198,7 +184,7 @@ export default function ProjectDetail() {
>
<List.Item.Meta
title={
<a onClick={() => navigate('/tasks')}>{task.title}</a>
<a onClick={() => openTaskDetail(task.id)}>{task.title}</a>
}
description={dayjs(task.created_at).format('MM-DD HH:mm')}
/>
@@ -231,6 +217,73 @@ export default function ProjectDetail() {
</Card>
</Col>
</Row>
</>
);
return (
<div>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
}}
>
<Space>
<Button
icon={<ArrowLeftOutlined />}
onClick={() => navigate('/projects')}
>
</Button>
<Title level={4} style={{ margin: 0 }}>
{project.name}
</Title>
<ProjectStatusTag status={project.status} />
</Space>
<Button
icon={<ReloadOutlined />}
onClick={() => window.location.reload()}
>
</Button>
</div>
<Tabs
activeKey={activeTab}
onChange={(key) => setSearchParams({ tab: key })}
items={[
{
key: 'overview',
label: (
<span>
<ProfileOutlined />
</span>
),
children: overviewTab,
},
{
key: 'dag',
label: (
<span>
<ApartmentOutlined /> DAG
</span>
),
children: (
<Card size="small" title="DAG 编排画布">
<DagCanvas projectId={project.id} />
</Card>
),
},
]}
/>
<TaskDetailModal
taskId={detailTaskId}
open={detailOpen}
onClose={() => setDetailOpen(false)}
/>
</div>
);
}