/** * ProjectDetailView Component * * Displays project details and associated tasks. * Requirements: 1.5, 1.6 */ import React, { useEffect, useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useAtom } from 'jotai'; import { Button, IconArrowLeft, IconEdit, IconPlus, DataTable, type ExtendedDataTableColumnDef, Badge, Dialog, DialogContent, DialogHeader, DialogTitle, } from '@humansignal/ui'; import { getProject, getProjectTasks, createTask } from '../services/api'; import { currentProjectAtom, projectLoadingAtom, projectErrorAtom } from '../atoms/project-atoms'; import { tasksAtom, type Task } from '../atoms/task-atoms'; import { TaskForm, type TaskFormData } from '../components'; export const ProjectDetailView: React.FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [currentProject, setCurrentProject] = useAtom(currentProjectAtom); const [loading, setLoading] = useAtom(projectLoadingAtom); const [error, setError] = useAtom(projectErrorAtom); const [tasks, setTasks] = useAtom(tasksAtom); const [tasksLoading, setTasksLoading] = useState(false); const [isCreateTaskDialogOpen, setIsCreateTaskDialogOpen] = useState(false); const [isCreatingTask, setIsCreatingTask] = useState(false); // Load project details and tasks useEffect(() => { if (!id) return; const loadProjectData = async () => { try { setLoading(true); setError(null); // Load project details const projectData = await getProject(id); setCurrentProject(projectData); // Load project tasks setTasksLoading(true); const tasksData = await getProjectTasks(id); setTasks(tasksData); } catch (err: any) { setError(err.message || '加载项目详情失败'); } finally { setLoading(false); setTasksLoading(false); } }; loadProjectData(); }, [id]); const handleEditProject = () => { navigate(`/projects/${id}/edit`); }; const handleCreateTask = () => { setIsCreateTaskDialogOpen(true); }; const handleTaskFormSubmit = async (data: TaskFormData) => { try { setIsCreatingTask(true); // Create task via API const newTask = await createTask({ project_id: data.project_id, name: data.name, data: data.data, assigned_to: data.assigned_to || null, }); // Add new task to tasks list setTasks((prevTasks) => [...prevTasks, newTask]); // Update project task count if (currentProject) { setCurrentProject({ ...currentProject, task_count: currentProject.task_count + 1, }); } // Close dialog setIsCreateTaskDialogOpen(false); } catch (err: any) { throw new Error(err.message || '创建任务失败'); } finally { setIsCreatingTask(false); } }; const handleTaskFormCancel = () => { setIsCreateTaskDialogOpen(false); }; // Define task table columns const taskColumns: ExtendedDataTableColumnDef[] = [ { accessorKey: 'name', header: '任务名称', enableSorting: true, cell: ({ row }) => ( {row.original.name} ), size: 300, minSize: 200, }, { accessorKey: 'status', header: '状态', enableSorting: true, cell: ({ row }) => { const statusMap = { pending: { label: '待处理', variant: 'secondary' as const }, in_progress: { label: '进行中', variant: 'info' as const }, completed: { label: '已完成', variant: 'success' as const }, }; const status = statusMap[row.original.status]; return {status.label}; }, size: 120, minSize: 100, maxSize: 150, }, { accessorKey: 'progress', header: '进度', enableSorting: true, cell: ({ row }) => ( {row.original.progress}% ), size: 100, minSize: 80, maxSize: 120, }, { accessorKey: 'assigned_to', header: '分配给', enableSorting: true, cell: ({ row }) => ( {row.original.assigned_to || '未分配'} ), size: 150, minSize: 120, maxSize: 180, }, { accessorKey: 'created_at', header: '创建时间', enableSorting: true, cell: ({ row }) => { const date = new Date(row.original.created_at); return ( {date.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', })} ); }, size: 150, minSize: 120, maxSize: 180, }, ]; if (loading) { return (

加载中...

); } if (error) { return (
加载失败 {error}
); } if (!currentProject) { return (

项目不存在

); } return (
{/* Header */}

{currentProject.name}

{currentProject.description}

{/* Project Info */}

项目信息

创建时间

{new Date(currentProject.created_at).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', })}

任务数量

{currentProject.task_count} 个任务

标注配置
              {currentProject.config}
            
{/* Tasks Section */}

关联任务

} > 创建任务 ), }} />
{/* Create Task Dialog */} 创建任务
); };