110 lines
4.0 KiB
TypeScript
110 lines
4.0 KiB
TypeScript
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<ProductionWorkOrderItem, 'workOrderStatus'>): boolean {
|
||
return ACTIVE_WORK_ORDER_STATUSES.has((row.workOrderStatus || '').trim())
|
||
}
|
||
|
||
function isActiveTask(task: Record<string, any>): boolean {
|
||
return ACTIVE_TASK_STATUSES.has((task.taskStatus || '').trim())
|
||
}
|
||
|
||
function isActiveStep(step: Record<string, any>): boolean {
|
||
return (step.stepStatus || '').trim() !== 'ywc'
|
||
}
|
||
|
||
function stepAssigneeUserIds(step: Record<string, any>): 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<string, any>): boolean {
|
||
const planned = (step.plannedStartTime || '').trim().slice(0, 10)
|
||
if (!planned) return false
|
||
return planned > todayYmd()
|
||
}
|
||
|
||
/** 与后端 mine-tab-step-counts 任务过滤一致 */
|
||
function isMineQualifyingTask(task: Record<string, any>, 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<string, any>): boolean {
|
||
const planned = (step.plannedStartTime || '').trim().slice(0, 10)
|
||
if (!planned) return false
|
||
return planned <= todayYmd()
|
||
}
|
||
|
||
/** 单张生产工单卡片:工艺步骤到期未完成 / 计划开始在今日之后未完成(与 Tab 角标语义一致) */
|
||
export function sumProductionWorkOrderStepBadgeCount(
|
||
workOrder: ProductionWorkOrderItem,
|
||
tasks: Record<string, any>[] | 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(',')
|
||
}
|