feat: 重构项目页面架构并实现流水线步骤拖拽排序功能

主要更新:
- 重构项目页面结构:将原有项目页面拆分为 list 和 detail 两个子模块
- 新增项目详情页面,支持多标签页展示(流水线、部署记录)
- 实现流水线管理功能:支持新建、编辑、复制、删除、启用/禁用
- 实现流水线步骤管理:支持添加、编辑、删除、启用/禁用步骤
- 新增流水线步骤拖拽排序功能:集成 @dnd-kit 实现拖拽重排
- 优化左右两栏布局:左侧流水线列表,右侧步骤详情
- 新增部署记录展示功能:左右两栏布局,支持选中切换
- 提取可复用组件:DeployRecordItem、PipelineStepItem
- 添加表单验证和用户交互反馈
- 更新路由配置支持项目详情页面

技术改进:
- 安装 @dnd-kit 相关依赖实现拖拽功能
- 优化 TypeScript 类型定义
- 改进组件化设计,提高代码复用性
- 增强用户体验和交互反馈
This commit is contained in:
2025-09-07 22:35:33 +08:00
parent f0e1a649ee
commit ef4fce6d42
14 changed files with 1272 additions and 122 deletions

View File

@@ -0,0 +1,110 @@
import { Grid, Typography, Button, Message } from '@arco-design/web-react';
import { IconPlus } from '@arco-design/web-react/icon';
import { useState } from 'react';
import type { Project } from '../types';
import { useAsyncEffect } from '../../../hooks/useAsyncEffect';
import { projectService } from './service';
import ProjectCard from './components/ProjectCard';
import EditProjectModal from './components/EditProjectModal';
import CreateProjectModal from './components/CreateProjectModal';
const { Text } = Typography;
function ProjectPage() {
const [projects, setProjects] = useState<Project[]>([]);
const [editModalVisible, setEditModalVisible] = useState(false);
const [editingProject, setEditingProject] = useState<Project | null>(null);
const [createModalVisible, setCreateModalVisible] = useState(false);
useAsyncEffect(async () => {
const response = await projectService.list();
setProjects(response.data);
}, []);
const handleEditProject = (project: Project) => {
setEditingProject(project);
setEditModalVisible(true);
};
const handleEditSuccess = (updatedProject: Project) => {
setProjects(prev =>
prev.map(p => p.id === updatedProject.id ? updatedProject : p)
);
};
const handleEditCancel = () => {
setEditModalVisible(false);
setEditingProject(null);
};
const handleCreateProject = () => {
setCreateModalVisible(true);
};
const handleCreateSuccess = (newProject: Project) => {
setProjects(prev => [newProject, ...prev]);
};
const handleCreateCancel = () => {
setCreateModalVisible(false);
};
const handleDeleteProject = async (project: Project) => {
try {
await projectService.delete(project.id);
setProjects(prev => prev.filter(p => p.id !== project.id));
Message.success('项目删除成功');
} catch (error) {
console.error('删除项目失败:', error);
Message.error('删除项目失败,请稍后重试');
}
};
return (
<div className="p-6">
<div className="mb-6 flex items-center justify-between">
<div>
<Typography.Title heading={2} className="!m-0 !text-gray-900">
</Typography.Title>
<Text type="secondary"></Text>
</div>
<Button
type="primary"
icon={<IconPlus />}
onClick={handleCreateProject}
className="!rounded-lg"
>
</Button>
</div>
<Grid.Row gutter={[16, 16]}>
{projects.map((project) => (
<Grid.Col key={project.id} span={8}>
<ProjectCard
project={project}
onEdit={handleEditProject}
onDelete={handleDeleteProject}
/>
</Grid.Col>
))}
</Grid.Row>
<EditProjectModal
visible={editModalVisible}
project={editingProject}
onCancel={handleEditCancel}
onSuccess={handleEditSuccess}
/>
<CreateProjectModal
visible={createModalVisible}
onCancel={handleCreateCancel}
onSuccess={handleCreateSuccess}
/>
</div>
);
}
export default ProjectPage;