export type SupportTicketStatus = | 'PENDING_REVIEW' | 'REJECTED' | 'DEVELOPING' | 'TESTING' | 'PASSED' | 'PUBLISHED'; export type SupportTicketStatusTransitionContext = { linkedTaskCount: number; isSuperAdmin: boolean; rejectReason?: string; }; const FORWARD_TRANSITIONS: Record = { PENDING_REVIEW: ['DEVELOPING', 'REJECTED'], DEVELOPING: ['TESTING', 'REJECTED'], TESTING: ['PASSED', 'REJECTED'], REJECTED: [], PASSED: ['PUBLISHED'], PUBLISHED: [], }; /** 技术支持工单批量/人工改状态校验(禁止回退) */ export function validateSupportTicketStatusTransition( from: SupportTicketStatus, to: SupportTicketStatus, ctx: SupportTicketStatusTransitionContext, ): { ok: boolean; message?: string } { if (from === to) return { ok: true }; const allowed = FORWARD_TRANSITIONS[from] ?? []; if (!allowed.includes(to)) { return { ok: false, message: `不允许从「${from}」变更为「${to}」` }; } if (to === 'REJECTED') { if (!ctx.isSuperAdmin) return { ok: false, message: '仅最高管理员可驳回工单' }; if (!ctx.rejectReason?.trim()) return { ok: false, message: '请填写驳回理由' }; } if (from === 'PENDING_REVIEW' && to === 'DEVELOPING' && ctx.linkedTaskCount < 1) { return { ok: false, message: '待评审工单转入开发须至少 1 条关联开发任务' }; } return { ok: true }; }