import React, { useState, useEffect, useRef } from 'react'; import { Task, TaskPriority } from '../types'; interface AddTaskModalProps { mode: 'child' | 'sibling'; parentTask?: Task; siblingTask: Task; allTasks: Task[]; planId: number; onSave: (data: { task_id: string; title: string; description: string; parent_id?: number | null; dependencies: string[]; durationInHours: number; priority?: string; dueDate?: string | null; sortOrder?: number; }) => void; onCancel: () => void; } const AddTaskModal: React.FC = ({ mode, parentTask, siblingTask, allTasks, planId, onSave, onCancel }) => { const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); const [taskId, setTaskId] = useState(''); const [selectedDeps, setSelectedDeps] = useState([]); const [duration, setDuration] = useState('0'); const [priority, setPriority] = useState('medium'); const [dueDate, setDueDate] = useState(''); const [dropdownOpen, setDropdownOpen] = useState(false); const dropdownRef = useRef(null); const flattenTasksWithDepth = (items: Task[], depth: number = 0): { task: Task; depth: number }[] => { const result: { task: Task; depth: number }[] = []; for (const t of items) { result.push({ task: t, depth }); if (t.children?.length) { result.push(...flattenTasksWithDepth(t.children, depth + 1)); } } return result; }; const availableTasks = flattenTasksWithDepth(allTasks); const toggleDep = (depTaskId: string) => { setSelectedDeps(prev => prev.includes(depTaskId) ? prev.filter(id => id !== depTaskId) : [...prev, depTaskId] ); }; const handleSave = (e: React.FormEvent) => { e.preventDefault(); const parentId = mode === 'child' ? siblingTask.id : siblingTask.parent_id; onSave({ task_id: taskId || `task-${Date.now()}`, title, description, parent_id: parentId, dependencies: selectedDeps, durationInHours: parseFloat(duration) || 0, priority, dueDate: dueDate || null, }); }; useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape') onCancel(); }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [onCancel]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setDropdownOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); const modeLabel = mode === 'child' ? '子任务' : '同级任务'; const parentLabel = mode === 'child' ? siblingTask.title : (parentTask?.title || '根级'); return (
e.stopPropagation()} >

添加{modeLabel}

{mode === 'child' ? `在 "${siblingTask.title}" 下添加子任务` : `与 "${siblingTask.title}" 同级添加任务`} · 归属于 {parentLabel}

setTaskId(e.target.value)} className="w-full p-2 bg-white dark:bg-slate-700 text-slate-900 dark:text-slate-100 border border-slate-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-shadow" placeholder="如: phase-2-design(留空自动生成)" />
setTitle(e.target.value)} className="w-full p-2 bg-white dark:bg-slate-700 text-slate-900 dark:text-slate-100 border border-slate-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-shadow" required placeholder="任务标题" />