'use client'; import { useState, useMemo, useRef } from 'react'; import { X, ImagePlus, Trash2 } from 'lucide-react'; import { useBugStore } from '@/stores/useBugStore'; import { useTestCaseStore } from '@/stores/useTestCaseStore'; import { useDevTaskStore } from '@/stores/useDevTaskStore'; import { useRequirementStore } from '@/stores/useRequirementStore'; import { useMemberStore } from '@/stores/useMemberStore'; import { useAuthStore } from '@/stores/useAuthStore'; import type { Priority } from '@/lib/derive'; import type { BugSeverity } from '@/lib/bug'; interface Props { testCaseId: string; onClose: () => void; } export function BugCreateModal({ testCaseId, onClose }: Props) { const { createBug } = useBugStore(); const { testCases } = useTestCaseStore(); const { tasks: devTasks } = useDevTaskStore(); const { requirements } = useRequirementStore(); const { members } = useMemberStore(); const user = useAuthStore((s) => s.user); const tc = testCases.find((c) => c.id === testCaseId); const requirement = requirements.find((r) => r.id === tc?.requirementId); const defaultAssignee = useMemo(() => { if (!tc) return ''; const reqTasks = devTasks.filter((t) => t.requirementId === tc.requirementId); const inProgress = reqTasks.filter((t) => t.status === 'in_progress').sort((a, b) => b.createdAt.localeCompare(a.createdAt)); if (inProgress.length > 0) return inProgress[0].assigneeId; const latest = reqTasks.sort((a, b) => b.createdAt.localeCompare(a.createdAt)); return latest.length > 0 ? latest[0].assigneeId : ''; }, [tc, devTasks]); const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); const [severity, setSeverity] = useState('major'); const [priority, setPriority] = useState(tc?.priority || 'P1'); const [assigneeId, setAssigneeId] = useState(defaultAssignee); const [images, setImages] = useState([]); const fileRef = useRef(null); const canSubmit = title.trim() && description.trim() && assigneeId; const handleFiles = (files: FileList | null) => { if (!files) return; Array.from(files).forEach((file) => { if (!file.type.startsWith('image/')) return; const reader = new FileReader(); reader.onload = () => { setImages((prev) => [...prev, reader.result as string]); }; reader.readAsDataURL(file); }); }; const handleSubmit = () => { if (!canSubmit) return; createBug({ versionId: tc?.versionId || '', testCaseId, requirementId: tc?.requirementId || undefined, title: title.trim(), description: description.trim(), severity, priority, reportedBy: user?.name || '系统', assigneeId, images: images.length > 0 ? images : undefined, }, user?.name || '系统'); onClose(); }; return (
e.stopPropagation()}>

提交 Bug

关联用例:{tc?.caseNo} {tc?.title}
{requirement &&
关联需求:{requirement.code} {requirement.title}
}
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="简要描述问题" />