diff --git a/src/views/erp/product/product/ProductForm.vue b/src/views/erp/product/product/ProductForm.vue index d8c4fd79..8196fed3 100644 --- a/src/views/erp/product/product/ProductForm.vue +++ b/src/views/erp/product/product/ProductForm.vue @@ -87,7 +87,7 @@ /> --> - + diff --git a/src/views/mes/tasksummary/components/ScheduleGanttPanelEditable.vue b/src/views/mes/tasksummary/components/ScheduleGanttPanelEditable.vue index 54d20bfd..c45f4467 100644 --- a/src/views/mes/tasksummary/components/ScheduleGanttPanelEditable.vue +++ b/src/views/mes/tasksummary/components/ScheduleGanttPanelEditable.vue @@ -110,6 +110,12 @@ const previewDeviceOptions = computed(() => })) ) +const hasCurrentPlan = (device: any) => + (device?.plans ?? []).some((plan: any) => String(plan.sourceType ?? '').toUpperCase() === 'CURRENT') + +const getGanttScheduleList = () => + previewScheduleList.value.filter((device: any) => hasCurrentPlan(device)) + const getGlobalDateRange = (scheduleList: any[]) => { const allPlans = scheduleList.flatMap((item: any) => item?.plans ?? []) const starts = allPlans.map((item: any) => dayjs(item?.planStartTimeStr).valueOf()).filter((item: number) => Number.isFinite(item)) @@ -240,10 +246,20 @@ const cleanupTaskTooltips = () => { } const destroyGantt = () => { - cleanupTaskTooltips() - ganttEventIds.value.forEach((eventId) => gantt.detachEvent(eventId)) + try { + cleanupTaskTooltips() + } catch {} + try { + ganttEventIds.value.forEach((eventId) => { + try { + gantt.detachEvent(eventId) + } catch {} + }) + } catch {} ganttEventIds.value = [] - gantt.clearAll() + try { + gantt.clearAll() + } catch {} } const formatGridDateText = (value: unknown) => { @@ -534,18 +550,122 @@ const getDeviceInsertIndex = (deviceTaskId: string | number, startDate: dayjs.Da return childTaskIds.length } +const addDeviceToGantt = (device: any, excludePlanIdentity?: string) => { + const deviceId = `device-${device.deviceId}` + try { + gantt.getTask(deviceId) + return + } catch {} + const plans = (device?.plans ?? []).map((plan: any) => ({ + ...plan, + _start: dayjs(plan?.planStartTimeStr), + _end: dayjs(plan?.planEndTimeStr) + })) + const validPlans = plans + .filter((plan: any) => plan._start.isValid() && plan._end.isValid()) + .sort((a: any, b: any) => a._start.valueOf() - b._start.valueOf()) + const firstPlan = validPlans[0] + const deviceRange = getDeviceTaskRangeByChildren( + validPlans.map((item: any) => ({ start_date: item?._start, end_date: item?._end })) + ) + gantt.addTask({ + id: deviceId, + text: `${device.deviceName ?? '-'}`, + start_date: formatGanttDate(deviceRange?.start_date ?? firstPlan?._start), + end_date: formatGanttDate(deviceRange?.end_date ?? firstPlan?._end), + duration: deviceRange?.duration ?? 1, + parent: 0, + progress: 0, + open: true, + readonly: true, + deviceName: device.deviceName ?? '-', + _deviceData: device + }) + validPlans.forEach((plan: any, index: number) => { + const planIdentity = `${plan?.taskId ?? ''}-${plan?.taskDetailId ?? ''}` + if (excludePlanIdentity && planIdentity === excludePlanIdentity) return + const startDate = formatGanttDate(plan.planStartTimeStr) + const endDate = formatGanttDate(plan.planEndTimeStr) + if (!startDate || !endDate) return + const duration = Number(plan.scheduleDays) > 0 ? Number(plan.scheduleDays) : Math.max(plan._end.diff(plan._start, 'day') + 1, 1) + const isHistory = String(plan.sourceType ?? '').toUpperCase() === 'HISTORY' + const planTaskId = `plan-${device.deviceId}-${plan.taskDetailId ?? index}-${index}` + gantt.addTask({ + id: planTaskId, + text: `${plan.productCode ?? '-'} / ${plan.productName ?? '-'} / ${plan.taskCode ?? '-'}`, + start_date: startDate, + end_date: endDate, + duration, + parent: deviceId, + progress: 0, + readonly: isHistory, + _planData: plan, + _deviceData: device + }) + }) +} + +const removeDeviceFromGanttIfNoCurrent = (deviceTaskId: string | number) => { + try { + const deviceTask = gantt.getTask(deviceTaskId) + if (!deviceTask || deviceTask?._planData) return + const childTaskIds = gantt.getChildren(deviceTaskId) + const hasCurrent = (Array.isArray(childTaskIds) ? childTaskIds : []).some((childId: string | number) => { + const childTask = gantt.getTask(childId) + return childTask?._planData && String(childTask._planData.sourceType ?? '').toUpperCase() === 'CURRENT' + }) + if (!hasCurrent) { + gantt.deleteTask(String(deviceTaskId)) + } + } catch {} +} + const applyTaskAdjust = (task: any, targetDeviceTaskId: string | number, startDate: string, endDate: string) => { - const targetDeviceTask = gantt.getTask(targetDeviceTaskId) - if (!targetDeviceTask || targetDeviceTask?._planData) return const sourceDeviceTaskId = task.parent const nextStart = dayjs(startDate) const nextEnd = dayjs(endDate) const duration = Math.max(nextEnd.diff(nextStart, 'day') + 1, 1) + const planIdentity = `${task?._planData?.taskId ?? ''}-${task?._planData?.taskDetailId ?? ''}` + + const targetDeviceData = previewScheduleList.value.find((d: any) => `device-${d.deviceId}` === targetDeviceTaskId) + if (!targetDeviceData) return + + const sourceDeviceData = task._deviceData + if (sourceDeviceData?.plans && Array.isArray(sourceDeviceData.plans)) { + sourceDeviceData.plans = sourceDeviceData.plans.filter((item: any) => { + const itemId = `${item?.taskId ?? ''}-${item?.taskDetailId ?? ''}` + return itemId !== planIdentity + }) + } + if (!Array.isArray(targetDeviceData.plans)) { + targetDeviceData.plans = [] + } + const targetExists = targetDeviceData.plans.some((item: any) => { + const itemId = `${item?.taskId ?? ''}-${item?.taskDetailId ?? ''}` + return itemId === planIdentity + }) + if (!targetExists) { + targetDeviceData.plans.push(task._planData) + } + task._planData.deviceId = targetDeviceData.deviceId + task._planData.feedingPipeline = targetDeviceData.deviceId + task._deviceData = targetDeviceData + + let targetDeviceInGantt = true + try { + gantt.getTask(targetDeviceTaskId) + } catch { + targetDeviceInGantt = false + } + + if (!targetDeviceInGantt) { + addDeviceToGantt(targetDeviceData, planIdentity) + } + task.parent = targetDeviceTaskId task.start_date = nextStart.toDate() task.end_date = nextEnd.toDate() task.duration = duration - movePlanDataToDevice(task, targetDeviceTaskId, sourceDeviceTaskId) const targetIndex = getDeviceInsertIndex(targetDeviceTaskId, nextStart) gantt.moveTask(task.id, targetIndex, targetDeviceTaskId) gantt.updateTask(task.id) @@ -553,9 +673,11 @@ const applyTaskAdjust = (task: any, targetDeviceTaskId: string | number, startDa normalizeDeviceChildren(targetDeviceTaskId, task.id) if (sourceDeviceTaskId && sourceDeviceTaskId !== targetDeviceTaskId) { normalizeDeviceChildren(sourceDeviceTaskId) + removeDeviceFromGanttIfNoCurrent(sourceDeviceTaskId) } refreshPlanLinksByRowOrder() refreshTimelineRangeByTasks() + gantt.render() } const openTaskAdjustDialog = (task: any) => { @@ -666,13 +788,14 @@ const initGanttPreview = () => { return sourceType === 'HISTORY' ? 'schedule-plan-task-history' : 'schedule-plan-task' } - const globalRange = getGlobalDateRange(previewScheduleList.value) + const ganttScheduleData = getGanttScheduleList() + const globalRange = getGlobalDateRange(ganttScheduleData) gantt.config.start_date = dayjs(globalRange.start).startOf('day').toDate() gantt.config.end_date = dayjs(globalRange.end).endOf('day').toDate() gantt.init(ganttContainerRef.value) - const ganttData = buildPreviewGanttData(previewScheduleList.value) + const ganttData = buildPreviewGanttData(ganttScheduleData) gantt.parse(ganttData) // 强制刷新所有任务的样式,确保颜色正确应用 @@ -775,6 +898,7 @@ const initGanttPreview = () => { syncPlanTimeFromTask(task) normalizeDeviceChildren(parent) normalizeDeviceChildren(sourceParent) + removeDeviceFromGanttIfNoCurrent(sourceParent) refreshPlanLinksByRowOrder() refreshTimelineRangeByTasks() } finally { @@ -838,7 +962,9 @@ onMounted(async () => { watch( () => props.scheduleList, async () => { + if (ganttSyncing.value) return await nextTick() + if (ganttSyncing.value) return initGanttPreview() }, { deep: true }