import type { DevTask, DevTaskStatus } from './dev-task'; export type ReqDevStatus = 'unscheduled' | 'todo' | 'developing' | 'completed'; export const REQ_DEV_STATUS_LABEL: Record = { unscheduled: '未排期', todo: '待开发', developing: '开发中', completed: '已完成', }; export const REQ_DEV_STATUS_COLOR: Record = { unscheduled: 'bg-zinc-100 text-zinc-500', todo: 'bg-amber-50 text-amber-600', developing: 'bg-blue-50 text-blue-600', completed: 'bg-emerald-50 text-emerald-600', }; /** * 推导需求的开发状态 * 规则:根据关联的 devTasks 状态聚合推导 */ export function deriveReqDevStatus(reqId: string, devTasks: DevTask[]): ReqDevStatus { const tasks = devTasks.filter((t) => t.requirementId === reqId); if (tasks.length === 0) return 'unscheduled'; if (tasks.every((t) => t.status === 'submitted')) return 'completed'; if (tasks.some((t) => t.status === 'in_progress' || t.status === 'testing')) return 'developing'; return 'todo'; } export function buildRequirementDevStatusMap(devTasks: DevTask[]): Map { const stats = new Map(); for (const task of devTasks) { if (!task.requirementId) continue; const row = stats.get(task.requirementId) ?? { total: 0, submitted: 0, active: false }; row.total += 1; if (task.status === 'submitted') row.submitted += 1; if (task.status === 'in_progress' || task.status === 'testing') row.active = true; stats.set(task.requirementId, row); } const statusMap = new Map(); for (const [requirementId, row] of stats) { if (row.total > 0 && row.submitted === row.total) { statusMap.set(requirementId, 'completed'); } else if (row.active) { statusMap.set(requirementId, 'developing'); } else { statusMap.set(requirementId, 'todo'); } } return statusMap; } /** * 需求是否可编辑 * 规则:开发中(有 in_progress 或 testing 的任务)不可编辑 */ export function canEditRequirement(reqId: string, devTasks: DevTask[]): boolean { const status = deriveReqDevStatus(reqId, devTasks); return !isRequirementExecutionLocked(status); } export function canCloseRequirement(reqId: string, devTasks: DevTask[]): boolean { const status = deriveReqDevStatus(reqId, devTasks); return !isRequirementExecutionLocked(status); } function isRequirementExecutionLocked(status: ReqDevStatus): boolean { return status === 'developing' || status === 'completed'; } /** * 需求设置 versionId 的副作用检查 * 当需求已有关联的开发任务时,换版本是高风险操作 */ export function checkVersionChangeRisk(reqId: string, devTasks: DevTask[]): { safe: boolean; reason?: string } { const tasks = devTasks.filter((t) => t.requirementId === reqId); if (tasks.length === 0) return { safe: true }; const activeTasks = tasks.filter((t) => t.status !== 'submitted'); if (activeTasks.length > 0) { return { safe: false, reason: `该需求有 ${activeTasks.length} 个未完成的开发任务,变更版本可能导致数据不一致` }; } return { safe: true }; }