feat(平台): 补齐服务端持久化和AI拆解契约

This commit is contained in:
Script Generator
2026-06-25 15:21:32 +08:00
parent 5723356d08
commit 5adc7759ad
73 changed files with 5599 additions and 368 deletions

View File

@@ -6,6 +6,7 @@ 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;
@@ -23,7 +24,7 @@ export function VersionRequirementsTab({ versionId, projectId, requirements, dev
const [showAddModal, setShowAddModal] = useState(false);
const [showChangeModal, setShowChangeModal] = useState(false);
const linkedReqs = requirements.filter((r) => r.versionId === versionId);
const availableReqs = requirements.filter((r) => r.projectId === projectId && !r.versionId && r.status === 'adopted');
const availableReqs = getProjectAdoptedRequirementCandidates(requirements, projectId).filter((r) => !r.versionId);
return (
<div className="space-y-4">
@@ -43,7 +44,7 @@ export function VersionRequirementsTab({ versionId, projectId, requirements, dev
{linkedReqs.length === 0 ? (
<div className="rounded-xl border border-[var(--line)] bg-[var(--bg-card)] p-12 text-center text-[13px] text-[var(--ink-muted)]">
</div>
) : (
<div className="rounded-xl border border-[var(--line)] bg-[var(--bg-card)] overflow-hidden">
@@ -213,7 +214,7 @@ function AddRequirementModal({ available, onClose, onConfirm }: {
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={onClose}>
<div className="w-full max-w-lg rounded-2xl bg-[var(--bg-card)] border border-[var(--line)] shadow-[var(--shadow-md)] flex flex-col max-h-[70vh]" onClick={(e) => e.stopPropagation()}>
<div className="flex items-center justify-between px-5 py-4 border-b border-[var(--line)]">
<h3 className="text-[13px] font-semibold text-[var(--ink)]"></h3>
<h3 className="text-[13px] font-semibold text-[var(--ink)]"></h3>
<button onClick={onClose} className="p-1 rounded hover:bg-[var(--bg-subtle)] text-[var(--ink-muted)]"><X className="h-4 w-4" /></button>
</div>
<div className="px-5 py-3 border-b border-[var(--line)]">
@@ -221,6 +222,15 @@ function AddRequirementModal({ available, onClose, onConfirm }: {
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[var(--ink-muted)]" />
<input value={search} onChange={(e) => setSearch(e.target.value)} placeholder="搜索需求编号或标题" className="h-8 w-full rounded-lg border border-[var(--line)] bg-[var(--bg)] pl-9 pr-3 text-[12px] focus:border-[var(--accent)] focus:outline-none" />
</div>
{filtered.length > 0 && (
<div className="mt-2 flex items-center justify-between">
<span className="text-[11px] text-[var(--ink-muted)]"> {filtered.length} {selected.size} </span>
<div className="flex gap-2">
<button type="button" onClick={() => setSelected(new Set(filtered.map((r) => r.id)))} className="text-[11px] text-[var(--accent)] hover:underline"></button>
<button type="button" onClick={() => setSelected(new Set())} className="text-[11px] text-[var(--ink-muted)] hover:underline"></button>
</div>
</div>
)}
</div>
<div className="flex-1 overflow-y-auto px-5 py-3">
{filtered.length === 0 ? (