feat(平台): 补齐服务端持久化和AI拆解契约
This commit is contained in:
42
apps/web/lib/requirement-selector.ts
Normal file
42
apps/web/lib/requirement-selector.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { Requirement } from './requirement';
|
||||
|
||||
export interface RequirementOption {
|
||||
id: string;
|
||||
code: string;
|
||||
title: string;
|
||||
productOwner?: string;
|
||||
status: Requirement['status'];
|
||||
isHistorical?: boolean;
|
||||
}
|
||||
|
||||
export function toRequirementOption(requirement: Requirement, isHistorical = false): RequirementOption {
|
||||
return {
|
||||
id: requirement.id,
|
||||
code: requirement.code,
|
||||
title: requirement.title,
|
||||
productOwner: requirement.productOwner,
|
||||
status: requirement.status,
|
||||
isHistorical,
|
||||
};
|
||||
}
|
||||
|
||||
export function getProjectAdoptedRequirementCandidates(requirements: Requirement[], projectId: string): Requirement[] {
|
||||
return requirements
|
||||
.filter((r) => r.projectId === projectId && r.status === 'adopted')
|
||||
.sort((a, b) => a.code.localeCompare(b.code, 'zh-CN'));
|
||||
}
|
||||
|
||||
export function mergeSelectedRequirementOptions(
|
||||
candidates: Requirement[],
|
||||
allRequirements: Requirement[],
|
||||
selectedIds: string[] = [],
|
||||
): RequirementOption[] {
|
||||
const candidateOptions = candidates.map((r) => toRequirementOption(r));
|
||||
const candidateIds = new Set(candidateOptions.map((r) => r.id));
|
||||
const historical = selectedIds
|
||||
.filter((id) => !candidateIds.has(id))
|
||||
.map((id) => allRequirements.find((r) => r.id === id))
|
||||
.filter((r): r is Requirement => Boolean(r))
|
||||
.map((r) => toRequirementOption(r, true));
|
||||
return [...candidateOptions, ...historical];
|
||||
}
|
||||
Reference in New Issue
Block a user