'use client'; import { useState } from 'react'; import { Plus, X, Search } from 'lucide-react'; import { FilterSelect } from '@/components/FilterSelect'; import type { Requirement, ChangeReason } from '@/lib/requirement'; import type { DevTask } from '@/lib/dev-task'; import { REQ_STATUS_LABEL, REQ_STATUS_COLOR, CHANGE_REASON_LABEL } from '@/lib/requirement'; import { deriveReqDevStatus, canEditRequirement, REQ_DEV_STATUS_LABEL, REQ_DEV_STATUS_COLOR } from '@/lib/linkage-engine'; import { getProjectAdoptedRequirementCandidates } from '@/lib/requirement-selector'; interface Props { versionId: string; projectId: string; requirements: Requirement[]; devTasks: DevTask[]; versionMembers: { role: string; name: string }[]; onLink: (reqIds: string[], addedBy: string) => void; onUnlink: (reqId: string) => void; onCreateChange: (data: Partial) => void; currentUserName: string; readOnly?: boolean; } export function VersionRequirementsTab({ versionId, projectId, requirements, devTasks, versionMembers, onLink, onUnlink, onCreateChange, currentUserName, readOnly = false }: Props) { const [showAddModal, setShowAddModal] = useState(false); const [showChangeModal, setShowChangeModal] = useState(false); const linkedReqs = requirements.filter((r) => r.versionId === versionId); const availableReqs = getProjectAdoptedRequirementCandidates(requirements, projectId).filter((r) => !r.versionId); return (
{linkedReqs.length} 条关联需求 {!readOnly && (
)}
{linkedReqs.length === 0 ? (
暂无关联需求,从当前项目已采纳需求中添加
) : (
{!readOnly && } {linkedReqs.map((req) => { const devStatus = deriveReqDevStatus(req.id, devTasks); const isDeveloping = !canEditRequirement(req.id, devTasks); return ( {!readOnly && ( )} ); })}
编号 需求概述 描述 需求类型 变更原因 状态 开发状态 添加人 添加日期操作
{req.code} {req.title} {req.description || '-'} {req.reqType === 'change' ? '变更需求' : '原始需求'} {req.changeReason ? CHANGE_REASON_LABEL[req.changeReason] : '-'} {REQ_STATUS_LABEL[req.status]} {REQ_DEV_STATUS_LABEL[devStatus]} {req.addedToVersionBy || '系统添加'} {req.createdAt?.slice(0, 10) || '-'} {isDeveloping ? ( 开发中 ) : ( )}
)} {showAddModal && !readOnly && ( setShowAddModal(false)} onConfirm={(ids) => { onLink(ids, currentUserName); setShowAddModal(false); }} /> )} {showChangeModal && !readOnly && ( setShowChangeModal(false)} onSubmit={(data) => { onCreateChange(data); setShowChangeModal(false); }} /> )}
); } function ChangeRequirementModal({ versionMembers, currentUserName, onClose, onSubmit }: { versionMembers: { role: string; name: string }[]; currentUserName: string; onClose: () => void; onSubmit: (data: Partial) => void; }) { const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); const [changeBy, setChangeBy] = useState(currentUserName); const [changeReason, setChangeReason] = useState(''); const handleSubmit = () => { if (!title.trim() || !changeReason || !changeBy) return; onSubmit({ title: title.trim(), description: description.trim(), changeBy, changeReason: changeReason as ChangeReason, reqType: 'change', }); }; return (
e.stopPropagation()}>

需求变更

setChangeBy(value === 'all' ? '' : value)} options={versionMembers.map((member) => ({ value: member.name, label: member.name }))} allLabel="选择变更人员" className="w-full" />
setChangeReason(value === 'all' ? '' : value as ChangeReason)} options={Object.entries(CHANGE_REASON_LABEL).map(([key, label]) => ({ value: key, label }))} allLabel="请选择变更原因" className="w-full" />
setTitle(e.target.value)} placeholder="变更需求标题" className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" />