'use client'; import { useState, useMemo } from 'react'; import { X, AlertTriangle } from 'lucide-react'; import { useDevTaskStore } from '@/stores/useDevTaskStore'; import { useTaskCategoryStore } from '@/stores/useTaskCategoryStore'; import { useRequirementStore } from '@/stores/useRequirementStore'; import { useMemberStore } from '@/stores/useMemberStore'; import { useAuthStore } from '@/stores/useAuthStore'; import type { Priority } from '@/lib/derive'; interface Props { versionId: string; requirementIds: string[]; versionDeadline?: string; onClose: () => void; onCreated?: () => void; } export function DevTaskCreateModal({ versionId, requirementIds, versionDeadline, onClose, onCreated }: Props) { const { createTask, tasks } = useDevTaskStore(); const { categories } = useTaskCategoryStore(); const { requirements } = useRequirementStore(); const { members } = useMemberStore(); const user = useAuthStore((s) => s.user); const versionReqs = useMemo( () => requirements.filter((r) => requirementIds.includes(r.id)), [requirements, requirementIds], ); const versionTasks = useMemo( () => tasks.filter((t) => requirementIds.includes(t.requirementId)), [tasks, requirementIds], ); const [title, setTitle] = useState(''); const [requirementId, setRequirementId] = useState(versionReqs[0]?.id || ''); const [categoryId, setCategoryId] = useState(categories[0]?.id || ''); const [assigneeId, setAssigneeId] = useState(user?.name || ''); const [priority, setPriority] = useState(versionReqs[0]?.priority || 'P2'); const [priorityManuallySet, setPriorityManuallySet] = useState(false); const [estimateHours, setEstimateHours] = useState(8); const [dueDate, setDueDate] = useState(''); const [predecessorIds, setPredecessorIds] = useState([]); const [description, setDescription] = useState(''); const [overdueReason, setOverdueReason] = useState(''); const selectedReq = versionReqs.find((r) => r.id === requirementId); const effectivePriority = priorityManuallySet ? priority : (selectedReq?.priority || priority); const isOverdue = !!(dueDate && versionDeadline && dueDate > versionDeadline); const canSubmit = title.trim() && requirementId && categoryId && assigneeId && estimateHours > 0 && (!isOverdue || overdueReason.trim()); const handleSubmit = () => { if (!canSubmit) return; createTask({ requirementId, title: title.trim(), description: description.trim() || undefined, categoryId, assigneeId, reviewerId: undefined, priority: effectivePriority, estimateHours, startDate: undefined, dueDate: dueDate || undefined, completedAt: undefined, status: 'todo', blockReason: undefined, blockedById: undefined, predecessorIds: predecessorIds.length > 0 ? predecessorIds : undefined, riskLevel: undefined, overdueReason: isOverdue ? overdueReason.trim() : undefined, createdBy: user?.name || '系统', }); onCreated?.(); onClose(); }; return (
e.stopPropagation()}>

新建开发任务

setTitle(e.target.value)} className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" placeholder="例如:排班界面开发" />
setEstimateHours(parseFloat(e.target.value) || 0)} className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" />
setDueDate(e.target.value)} className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" /> {versionDeadline && (

版本截止:{versionDeadline}

)}
{isOverdue && (
任务截止日期超出版本截止日期({versionDeadline}),请说明原因
setOverdueReason(e.target.value)} placeholder="超期原因(必填)" className="h-8 w-full rounded-md border border-orange-200 bg-white px-2 text-[12px] focus:border-orange-400 focus:outline-none" />
)} {versionTasks.length > 0 && (
{versionTasks.map((t) => ( ))}
)}