export type VersionStatus = 'developing' | 'planned' | 'released' | 'paused' | 'closed'; const READONLY_VERSION_STATUSES = new Set(['released', 'closed', 'paused']); export function isVersionReadonly(status: VersionStatus): boolean { return READONLY_VERSION_STATUSES.has(status); } export const VERSION_STATUS_LABEL: Record = { developing: '进行中', planned: '规划中', released: '已发布', paused: '已暂停', closed: '已关闭', }; export function getVersionReadonlyNotice(status: VersionStatus): string | null { if (!isVersionReadonly(status)) return null; return `${VERSION_STATUS_LABEL[status]}版本不可编辑或删除任务`; } export const VERSION_STATUS_DOT: Record = { developing: 'bg-blue-500', planned: 'bg-orange-500', released: 'bg-zinc-300', paused: 'bg-purple-400', closed: 'bg-zinc-400', }; export const VERSION_STATUS_BG: Record = { developing: 'bg-blue-500/10 text-blue-600', planned: 'bg-orange-500/10 text-orange-600', released: 'bg-zinc-100 text-zinc-600', paused: 'bg-purple-100 text-purple-600', closed: 'bg-zinc-100 text-zinc-500', }; export const STAGE_LABEL: Record = { requirement: '调研中', product_design: '产品设计中', ui_design: 'UI设计中', dev: '开发中', testing: '测试中', bug: 'BUG跟进中', released: '已发布', }; export function getVersionDisplayStatus(status: VersionStatus, _currentStage?: string): string { return VERSION_STATUS_LABEL[status]; } // === 版本执行态推导 === export type VersionExecutionStatus = 'planning' | 'developing' | 'submitted' | 'testing' | 'ready' | 'released'; export const EXECUTION_STATUS_LABEL: Record = { planning: '规划中', developing: '开发中', submitted: '已提测', testing: '测试中', ready: '可发布', released: '已发布', }; export const EXECUTION_STATUS_COLOR: Record = { planning: 'bg-zinc-100 text-zinc-600', developing: 'bg-blue-50 text-blue-600', submitted: 'bg-orange-50 text-orange-600', testing: 'bg-purple-50 text-purple-600', ready: 'bg-emerald-50 text-emerald-600', released: 'bg-zinc-100 text-zinc-500', }; export interface ExecutionInput { manualStatus?: VersionStatus; devTasks: { status: string }[]; testCases: { status: string }[]; bugs: { status: string }[]; } export function calcVersionExecutionStatus(input: ExecutionInput): VersionExecutionStatus { const { manualStatus, devTasks, testCases, bugs } = input; if (manualStatus === 'released') return 'released'; if (manualStatus === 'planned' || manualStatus === 'paused' || manualStatus === 'closed') return 'planning'; // fallback: 没有 DevTask 则停留 planning if (devTasks.length === 0) return 'planning'; const allDevSubmitted = devTasks.every((t) => t.status === 'submitted'); // 判断是否可发布 if (testCases.length > 0) { const allPassed = testCases.every((c) => c.status === 'passed'); const allBugsClosed = bugs.every((b) => b.status === 'closed' || b.status === 'rejected'); if (allPassed && allBugsClosed) return 'ready'; } // 测试中(有用例在执行) if (allDevSubmitted && testCases.length > 0) { const hasRunning = testCases.some((c) => c.status === 'running' || c.status === 'passed' || c.status === 'failed' || c.status === 'blocked'); if (hasRunning) return 'testing'; } // 已提测 if (allDevSubmitted) return 'submitted'; return 'developing'; }