import type { ProductionWorkOrderItem } from '@/api/production-work-order' import type { ProductionWorkOrderTabStepCount } from '@/api/production-work-order' import { isProductionWorkOrderTabStepBadgeZero } from '@/api/production-work-order' export type ProductionWorkOrderStepBadgeScope = 'manage' | 'mine' const ACTIVE_WORK_ORDER_STATUSES = new Set(['dpz', 'jxz']) const ACTIVE_TASK_STATUSES = new Set(['dpz', 'jxz']) function todayYmd(): string { const d = new Date() const y = d.getFullYear() const m = String(d.getMonth() + 1).padStart(2, '0') const day = String(d.getDate()).padStart(2, '0') return `${y}-${m}-${day}` } function isActiveWorkOrder(row: Pick): boolean { return ACTIVE_WORK_ORDER_STATUSES.has((row.workOrderStatus || '').trim()) } function isActiveTask(task: Record): boolean { return ACTIVE_TASK_STATUSES.has((task.taskStatus || '').trim()) } function isActiveStep(step: Record): boolean { return (step.stepStatus || '').trim() !== 'ywc' } function stepAssigneeUserIds(step: Record): string[] { const ids = step.assigneeUserIds if (Array.isArray(ids) && ids.length) { return ids.map((id) => String(id || '').trim()).filter(Boolean) } const assignees = step.assignees if (!Array.isArray(assignees)) return [] return assignees .map((a) => String(a?.userId || a?.id || '').trim()) .filter(Boolean) } function isStepFutureIncomplete(step: Record): boolean { const planned = (step.plannedStartTime || '').trim().slice(0, 10) if (!planned) return false return planned > todayYmd() } /** 与后端 mine-tab-step-counts 任务过滤一致 */ function isMineQualifyingTask(task: Record, userId: string): boolean { const uid = userId.trim() if (!uid) return false if (String(task.currentAssigneeUserId || '').trim() === uid) return true const steps = Array.isArray(task.steps) ? task.steps : [] for (const step of steps) { if (stepAssigneeUserIds(step).includes(uid)) return true } return false } /** 与后端 tab-step-counts 一致:计划开始日期已到期且步骤未完成 */ function isStepOverdueIncomplete(step: Record): boolean { const planned = (step.plannedStartTime || '').trim().slice(0, 10) if (!planned) return false return planned <= todayYmd() } /** 单张生产工单卡片:工艺步骤到期未完成 / 计划开始在今日之后未完成(与 Tab 角标语义一致) */ export function sumProductionWorkOrderStepBadgeCount( workOrder: ProductionWorkOrderItem, tasks: Record[] | undefined, scope: ProductionWorkOrderStepBadgeScope, currentUserId?: string ): ProductionWorkOrderTabStepCount { const result: ProductionWorkOrderTabStepCount = { overdueIncomplete: 0, futureIncomplete: 0 } if (!isActiveWorkOrder(workOrder)) return result const uid = String(currentUserId || '').trim() for (const task of tasks || []) { if (!isActiveTask(task)) continue if (scope === 'mine' && uid && !isMineQualifyingTask(task, uid)) continue for (const step of Array.isArray(task.steps) ? task.steps : []) { if (!isActiveStep(step)) continue if (isStepOverdueIncomplete(step)) result.overdueIncomplete += 1 if (isStepFutureIncomplete(step)) result.futureIncomplete += 1 } } return result } export function isProductionWorkOrderStepBadgeVisible( count: ProductionWorkOrderTabStepCount ): boolean { return !isProductionWorkOrderTabStepBadgeZero(count) } export function productionWorkOrderStepBadgeTitle(count: ProductionWorkOrderTabStepCount): string { if (isProductionWorkOrderTabStepBadgeZero(count)) return '' const overdue = count.overdueIncomplete || 0 const future = count.futureIncomplete || 0 const parts: string[] = [] if (overdue > 0) { parts.push(`${overdue} 个工艺步骤已到期未完成`) } if (future > 0) { parts.push(`${future} 个工艺步骤计划开始在今日之后`) } return parts.join(',') }