feat: DAG画布嵌入项目详情页,任务节点点击弹详情Modal
This commit is contained in:
@@ -12,15 +12,20 @@ import {
|
|||||||
Tag,
|
Tag,
|
||||||
Empty,
|
Empty,
|
||||||
List,
|
List,
|
||||||
|
Tabs,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
ArrowLeftOutlined,
|
ArrowLeftOutlined,
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
|
ApartmentOutlined,
|
||||||
|
ProfileOutlined,
|
||||||
} from '@ant-design/icons';
|
} 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 { projectApi, taskApi, artifactApi } from '@/api';
|
||||||
import type { Project, ProjectStats, Task, Artifact } from '@/types';
|
import type { Project, ProjectStats, Task, Artifact } from '@/types';
|
||||||
import { ProjectStatusTag, TaskStatusTag } from '@/components/constants';
|
import { ProjectStatusTag, TaskStatusTag } from '@/components/constants';
|
||||||
|
import DagCanvas from '@/pages/DagCanvas';
|
||||||
|
import TaskDetailModal from '@/components/TaskDetailModal';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
@@ -28,11 +33,20 @@ const { Title, Text } = Typography;
|
|||||||
export default function ProjectDetail() {
|
export default function ProjectDetail() {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
const activeTab = searchParams.get('tab') || 'overview';
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [project, setProject] = useState<Project | null>(null);
|
const [project, setProject] = useState<Project | null>(null);
|
||||||
const [stats, setStats] = useState<ProjectStats | null>(null);
|
const [stats, setStats] = useState<ProjectStats | null>(null);
|
||||||
const [tasks, setTasks] = useState<Task[]>([]);
|
const [tasks, setTasks] = useState<Task[]>([]);
|
||||||
const [artifacts, setArtifacts] = useState<Artifact[]>([]);
|
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(() => {
|
useEffect(() => {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
@@ -75,36 +89,8 @@ export default function ProjectDetail() {
|
|||||||
].filter((item) => item.count > 0)
|
].filter((item) => item.count > 0)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return (
|
const overviewTab = (
|
||||||
<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>
|
|
||||||
|
|
||||||
<Card style={{ marginBottom: 16 }}>
|
<Card style={{ marginBottom: 16 }}>
|
||||||
<Descriptions column={2} bordered size="small">
|
<Descriptions column={2} bordered size="small">
|
||||||
<Descriptions.Item label="项目名称">{project.name}</Descriptions.Item>
|
<Descriptions.Item label="项目名称">{project.name}</Descriptions.Item>
|
||||||
@@ -198,7 +184,7 @@ export default function ProjectDetail() {
|
|||||||
>
|
>
|
||||||
<List.Item.Meta
|
<List.Item.Meta
|
||||||
title={
|
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')}
|
description={dayjs(task.created_at).format('MM-DD HH:mm')}
|
||||||
/>
|
/>
|
||||||
@@ -231,6 +217,73 @@ export default function ProjectDetail() {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user