'use client'; import { useState, useEffect, useMemo } from 'react'; import { Search, X } from 'lucide-react'; import type { Requirement, DictItem, SourceType, SourceTarget } from '@/lib/requirement'; import type { Priority } from '@/lib/derive'; import { filterRequirementProjectOptions, filterRequirementVersionOptions, filterSourceTargetsByKeyword, formatSourceTargetSelection, parseSourceTargetSelection, SOURCE_TYPE_LABEL, SOURCE_TARGET_LABEL } from '@/lib/requirement'; interface RequirementModalProps { open: boolean; initial?: Requirement | null; products: { id: string; name: string }[]; projects: { id: string; name: string; productId: string }[]; versions: { id: string; name: string; projectId: string }[]; sourceTargets: SourceTarget[]; types: DictItem[]; platforms: DictItem[]; requirements: Requirement[]; currentUserName: string; onClose: () => void; onSubmit: (data: any) => void; onOpenDrawer: (type: 'source' | 'type' | 'platform') => void; } const PRIORITIES: Priority[] = ['P0', 'P1', 'P2', 'P3', 'P4']; const SOURCE_TYPES: SourceType[] = ['customer', 'internal', 'operation', 'aftersale', 'market', 'competitor', 'management']; const PRIORITY_COLORS: Record = { P0: 'bg-red-500 text-white', P1: 'bg-orange-500 text-white', P2: 'bg-blue-500 text-white', P3: 'bg-zinc-500 text-white', P4: 'bg-zinc-400 text-white', }; export function RequirementModal({ open, initial, products, projects, versions, sourceTargets, types, platforms, requirements, currentUserName, onClose, onSubmit, onOpenDrawer, }: RequirementModalProps) { const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); const [sourceType, setSourceType] = useState('customer'); const [selectedSourceTargets, setSelectedSourceTargets] = useState([]); const [productId, setProductId] = useState(''); const [projectId, setProjectId] = useState(''); const [selectedPlatforms, setSelectedPlatforms] = useState([]); const [typeId, setTypeId] = useState(''); const [priority, setPriority] = useState('P2'); const [productOwner, setProductOwner] = useState(''); const [parentId, setParentId] = useState(''); const [versionId, setVersionId] = useState(''); const [sourceTypeDropOpen, setSourceTypeDropOpen] = useState(false); const [sourceTargetDropOpen, setSourceTargetDropOpen] = useState(false); const [sourceTargetSearch, setSourceTargetSearch] = useState(''); const [productDropOpen, setProductDropOpen] = useState(false); const [projectDropOpen, setProjectDropOpen] = useState(false); const [projectSearch, setProjectSearch] = useState(''); const [versionDropOpen, setVersionDropOpen] = useState(false); const [versionSearch, setVersionSearch] = useState(''); const [typeDropOpen, setTypeDropOpen] = useState(false); const [platformDropOpen, setPlatformDropOpen] = useState(false); const filteredProjects = useMemo( () => filterRequirementProjectOptions(projects, productId, projectSearch), [projects, productId, projectSearch], ); const filteredVersions = useMemo( () => filterRequirementVersionOptions(versions, projectId, versionSearch), [versions, projectId, versionSearch], ); useEffect(() => { if (initial) { setTitle(initial.title); setDescription(initial.description || ''); setSourceType(initial.sourceType || 'customer'); setSelectedSourceTargets(parseSourceTargetSelection(initial.sourceTarget)); setSourceTypeDropOpen(false); setSourceTargetSearch(''); setSourceTargetDropOpen(false); setProductDropOpen(false); setProjectSearch(''); setProjectDropOpen(false); setVersionSearch(''); setVersionDropOpen(false); setTypeDropOpen(false); setProductId(initial.productId || ''); setProjectId(initial.projectId || ''); setVersionId(initial.versionId || ''); setSelectedPlatforms(initial.platforms || []); setTypeId(initial.typeId || ''); setPriority(initial.priority || 'P2'); setProductOwner(initial.productOwner || ''); setParentId(initial.parentId || ''); } else { setTitle(''); setDescription(''); setSourceType('customer'); setSelectedSourceTargets([]); setSourceTypeDropOpen(false); setSourceTargetSearch(''); setSourceTargetDropOpen(false); setProductDropOpen(false); setProjectSearch(''); setProjectDropOpen(false); setVersionSearch(''); setVersionDropOpen(false); setTypeDropOpen(false); setProductId(''); setProjectId(''); setVersionId(''); setSelectedPlatforms([]); setTypeId(''); setPriority('P2'); setProductOwner(''); setParentId(''); } }, [initial, open]); if (!open) return null; const filteredTargets = filterSourceTargetsByKeyword(sourceTargets, sourceType, sourceTargetSearch); const toggleSourceTarget = (name: string) => { setSelectedSourceTargets((prev) => prev.includes(name) ? prev.filter((item) => item !== name) : [...prev, name] ); }; const togglePlatform = (id: string) => { setSelectedPlatforms((prev) => prev.includes(id) ? prev.filter((p) => p !== id) : [...prev, id] ); }; const handleSubmit = () => { if (!title.trim() || !productId || !projectId) return; onSubmit({ title: title.trim(), description: description.trim(), sourceType, sourceTarget: formatSourceTargetSelection(selectedSourceTargets) || undefined, productId, projectId, versionId: versionId || undefined, platforms: selectedPlatforms, typeId: typeId || undefined, priority, effort: initial?.effort ?? 'M', status: initial?.status ?? 'pending_review', creator: initial?.creator || currentUserName || '系统', parentId: parentId || undefined, }); }; const sourceTargetDisplay = selectedSourceTargets.length > 0 ? formatSourceTargetSelection(selectedSourceTargets) : '请选择'; const productDisplay = productId ? products.find((product) => product.id === productId)?.name ?? '请选择产品' : '请选择产品'; const projectDisplay = projectId ? projects.find((project) => project.id === projectId)?.name ?? '请选择项目' : productId ? '请选择项目' : '先选择产品'; const versionDisplay = versionId ? versions.find((version) => version.id === versionId)?.name ?? '请选择版本' : projectId ? '请选择版本' : '先选择项目'; const typeDisplay = typeId ? types.find((type) => type.id === typeId)?.name ?? '请选择类型' : '请选择类型'; const platformDisplay = selectedPlatforms.length > 0 ? platforms .filter((p) => selectedPlatforms.includes(p.id)) .map((p) => p.name) .join(', ') : '请选择'; return (
e.stopPropagation()} > {/* Header */}

{initial ? '编辑需求' : '新建需求'}

{/* 1. 需求概述 */}
setTitle(e.target.value)} placeholder="请输入需求标题" className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] text-[var(--ink)] placeholder:text-[var(--ink-muted)] outline-none focus:border-[var(--accent)]" />
{/* 2. 需求描述 */}