From 8daf185e60ea265935cfafe1cf5e27e7de9b9c41 Mon Sep 17 00:00:00 2001 From: "Tommy\\2Fi-Staff" Date: Tue, 3 Mar 2026 18:03:58 +0800 Subject: [PATCH 1/2] trucklane dashboard --- .../truckSchedule/TruckScheduleDashboard.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/DashboardPage/truckSchedule/TruckScheduleDashboard.tsx b/src/components/DashboardPage/truckSchedule/TruckScheduleDashboard.tsx index 1588085..b89aa44 100644 --- a/src/components/DashboardPage/truckSchedule/TruckScheduleDashboard.tsx +++ b/src/components/DashboardPage/truckSchedule/TruckScheduleDashboard.tsx @@ -499,9 +499,9 @@ const TruckScheduleDashboard: React.FC = () => { {t("Truck Schedule")} {t("Time Remaining")} {t("No. of Shops")} - {t("Total Items")} {t("Tickets Released")} {t("Tickets Completed")} + {t("Total Items")} {t("First Ticket Start")} {t("Last Ticket End")} {t("Pick Time (min)")} @@ -561,11 +561,6 @@ const TruckScheduleDashboard: React.FC = () => { {row.numberOfShopsToServe} [{row.numberOfPickTickets}] - - - {row.totalItemsToPick} - - { color={row.numberOfTicketsCompleted > 0 ? 'success' : 'default'} /> + + + {row.totalItemsToPick} + + {formatDateTime(row.firstTicketStartTime)} From 5e5fa63ce818e424da771b08d5016e5549664208 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Tue, 3 Mar 2026 18:05:56 +0800 Subject: [PATCH 2/2] update --- .../GoodPickExecutiondetail.tsx | 360 +++++++++--------- 1 file changed, 188 insertions(+), 172 deletions(-) diff --git a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx index 3c773a1..2b04d3b 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx @@ -768,180 +768,196 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO // 设置 FG info 到 fgPickOrders(用于显示 FG 信息卡片) // 修改第 478-509 行的 fgOrder 构建逻辑: -const fgOrder: FGPickOrderResponse = { - doPickOrderId: hierarchicalData.fgInfo.doPickOrderId, - ticketNo: hierarchicalData.fgInfo.ticketNo, - storeId: hierarchicalData.fgInfo.storeId, - shopCode: hierarchicalData.fgInfo.shopCode, - shopName: hierarchicalData.fgInfo.shopName, - truckLanceCode: hierarchicalData.fgInfo.truckLanceCode, - DepartureTime: hierarchicalData.fgInfo.departureTime, - shopAddress: "", - pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "", - // 兼容字段 - pickOrderId: mergedPickOrder.pickOrderIds?.[0] || 0, - pickOrderConsoCode: mergedPickOrder.consoCode || "", - pickOrderTargetDate: mergedPickOrder.targetDate || "", - pickOrderStatus: mergedPickOrder.status || "", - deliveryOrderId: mergedPickOrder.doOrderIds?.[0] || 0, - deliveryNo: mergedPickOrder.deliveryOrderCodes?.[0] || "", - deliveryDate: "", - shopId: 0, - shopPoNo: "", - numberOfCartons: mergedPickOrder.pickOrderLines?.length || 0, - qrCodeData: hierarchicalData.fgInfo.doPickOrderId, - - // 新增:多个 pick orders 信息 - 保持数组格式,不要 join - numberOfPickOrders: mergedPickOrder.pickOrderIds?.length || 0, - pickOrderIds: mergedPickOrder.pickOrderIds || [], - pickOrderCodes: Array.isArray(mergedPickOrder.pickOrderCodes) - ? mergedPickOrder.pickOrderCodes - : [], // 改:保持数组 - deliveryOrderIds: mergedPickOrder.doOrderIds || [], - deliveryNos: Array.isArray(mergedPickOrder.deliveryOrderCodes) - ? mergedPickOrder.deliveryOrderCodes - : [], // 改:保持数组 - lineCountsPerPickOrder: Array.isArray(mergedPickOrder.lineCountsPerPickOrder) - ? mergedPickOrder.lineCountsPerPickOrder - : [] -}; - - setFgPickOrders([fgOrder]); - console.log(" DEBUG fgOrder.lineCountsPerPickOrder:", fgOrder.lineCountsPerPickOrder); -console.log(" DEBUG fgOrder.pickOrderCodes:", fgOrder.pickOrderCodes); -console.log(" DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); - // 移除:不需要 doPickOrderDetail 和 switcher 逻辑 - // if (hierarchicalData.pickOrders.length > 1) { ... } - - // 直接使用合并后的 pickOrderLines - console.log("🎯 Displaying merged pick order lines"); - - // 将层级数据转换为平铺格式(用于表格显示) - const flatLotData: any[] = []; - - mergedPickOrder.pickOrderLines.forEach((line: any) => { - // ✅ FIXED: 处理 lots(如果有) - if (line.lots && line.lots.length > 0) { - // 修复:先对 lots 按 lotId 去重并合并 requiredQty - const lotMap = new Map(); - - line.lots.forEach((lot: any) => { - const lotId = lot.id; - if (lotMap.has(lotId)) { - // 如果已存在,合并 requiredQty - const existingLot = lotMap.get(lotId); - existingLot.requiredQty = (existingLot.requiredQty || 0) + (lot.requiredQty || 0); - // 保留其他字段(使用第一个遇到的 lot 的字段) - } else { - // 首次遇到,添加到 map - lotMap.set(lotId, { ...lot }); - } - }); - - // 遍历去重后的 lots - lotMap.forEach((lot: any) => { - flatLotData.push({ - // 使用合并后的数据 - pickOrderConsoCode: mergedPickOrder.consoCode, - pickOrderTargetDate: mergedPickOrder.targetDate, - pickOrderStatus: mergedPickOrder.status, - pickOrderId: line.pickOrderId || mergedPickOrder.pickOrderIds?.[0] || 0, // 使用第一个 pickOrderId - pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "", - pickOrderLineId: line.id, - pickOrderLineRequiredQty: line.requiredQty, - pickOrderLineStatus: line.status, - - itemId: line.item.id, - itemCode: line.item.code, - itemName: line.item.name, - uomDesc: line.item.uomDesc, - uomShortDesc: line.item.uomShortDesc, - - lotId: lot.id, - lotNo: lot.lotNo, - expiryDate: lot.expiryDate, - location: lot.location, - stockUnit: lot.stockUnit, - availableQty: lot.availableQty, - requiredQty: lot.requiredQty, // 使用合并后的 requiredQty - actualPickQty: lot.actualPickQty, - inQty: lot.inQty, - outQty: lot.outQty, - holdQty: lot.holdQty, - lotStatus: lot.lotStatus, - lotAvailability: lot.lotAvailability, - processingStatus: lot.processingStatus, - suggestedPickLotId: lot.suggestedPickLotId, - stockOutLineId: lot.stockOutLineId, - stockOutLineStatus: lot.stockOutLineStatus, - stockOutLineQty: lot.stockOutLineQty, - stockInLineId: lot.stockInLineId, - routerId: lot.router?.id, - routerIndex: lot.router?.index, - routerRoute: lot.router?.route, - routerArea: lot.router?.area, - noLot: false, - }); + const fgOrder: FGPickOrderResponse = { + doPickOrderId: hierarchicalData.fgInfo.doPickOrderId, + ticketNo: hierarchicalData.fgInfo.ticketNo, + storeId: hierarchicalData.fgInfo.storeId, + shopCode: hierarchicalData.fgInfo.shopCode, + shopName: hierarchicalData.fgInfo.shopName, + truckLanceCode: hierarchicalData.fgInfo.truckLanceCode, + DepartureTime: hierarchicalData.fgInfo.departureTime, + shopAddress: "", + pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "", + + // 兼容字段(注意 consoCodes 是数组) + pickOrderId: mergedPickOrder.pickOrderIds?.[0] || 0, + pickOrderConsoCode: Array.isArray(mergedPickOrder.consoCodes) + ? mergedPickOrder.consoCodes[0] || "" + : "", + pickOrderTargetDate: mergedPickOrder.targetDate || "", + pickOrderStatus: mergedPickOrder.status || "", + deliveryOrderId: mergedPickOrder.doOrderIds?.[0] || 0, + deliveryNo: mergedPickOrder.deliveryOrderCodes?.[0] || "", + deliveryDate: "", + shopId: 0, + shopPoNo: "", + numberOfCartons: mergedPickOrder.pickOrderLines?.length || 0, + qrCodeData: hierarchicalData.fgInfo.doPickOrderId, + + // 多个 pick orders 信息:全部保留为数组 + numberOfPickOrders: mergedPickOrder.pickOrderIds?.length || 0, + pickOrderIds: mergedPickOrder.pickOrderIds || [], + pickOrderCodes: Array.isArray(mergedPickOrder.pickOrderCodes) + ? mergedPickOrder.pickOrderCodes + : [], + deliveryOrderIds: mergedPickOrder.doOrderIds || [], + deliveryNos: Array.isArray(mergedPickOrder.deliveryOrderCodes) + ? mergedPickOrder.deliveryOrderCodes + : [], + lineCountsPerPickOrder: Array.isArray(mergedPickOrder.lineCountsPerPickOrder) + ? mergedPickOrder.lineCountsPerPickOrder + : [], + }; + + setFgPickOrders([fgOrder]); + console.log(" DEBUG fgOrder.lineCountsPerPickOrder:", fgOrder.lineCountsPerPickOrder); + console.log(" DEBUG fgOrder.pickOrderCodes:", fgOrder.pickOrderCodes); + console.log(" DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); + + // 直接使用合并后的 pickOrderLines + console.log("🎯 Displaying merged pick order lines"); + + // 将层级数据转换为平铺格式(用于表格显示) + const flatLotData: any[] = []; + + mergedPickOrder.pickOrderLines.forEach((line: any) => { + // 用来记录这一行已经通过 lots 出现过的 lotId + const lotIdSet = new Set(); + + // ✅ lots:按 lotId 去重并合并 requiredQty + if (line.lots && line.lots.length > 0) { + const lotMap = new Map(); + + line.lots.forEach((lot: any) => { + const lotId = lot.id; + if (lotMap.has(lotId)) { + const existingLot = lotMap.get(lotId); + existingLot.requiredQty = + (existingLot.requiredQty || 0) + (lot.requiredQty || 0); + } else { + lotMap.set(lotId, { ...lot }); + } + }); + + lotMap.forEach((lot: any) => { + if (lot.id != null) { + lotIdSet.add(lot.id); + } + + flatLotData.push({ + pickOrderConsoCode: Array.isArray(mergedPickOrder.consoCodes) + ? mergedPickOrder.consoCodes[0] || "" + : "", + pickOrderTargetDate: mergedPickOrder.targetDate, + pickOrderStatus: mergedPickOrder.status, + pickOrderId: line.pickOrderId || mergedPickOrder.pickOrderIds?.[0] || 0, + pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "", + pickOrderLineId: line.id, + pickOrderLineRequiredQty: line.requiredQty, + pickOrderLineStatus: line.status, + + itemId: line.item.id, + itemCode: line.item.code, + itemName: line.item.name, + uomDesc: line.item.uomDesc, + uomShortDesc: line.item.uomShortDesc, + + lotId: lot.id, + lotNo: lot.lotNo, + expiryDate: lot.expiryDate, + location: lot.location, + stockUnit: lot.stockUnit, + availableQty: lot.availableQty, + requiredQty: lot.requiredQty, + actualPickQty: lot.actualPickQty, + inQty: lot.inQty, + outQty: lot.outQty, + holdQty: lot.holdQty, + lotStatus: lot.lotStatus, + lotAvailability: lot.lotAvailability, + processingStatus: lot.processingStatus, + suggestedPickLotId: lot.suggestedPickLotId, + stockOutLineId: lot.stockOutLineId, + stockOutLineStatus: lot.stockOutLineStatus, + stockOutLineQty: lot.stockOutLineQty, + stockInLineId: lot.stockInLineId, + routerId: lot.router?.id, + routerIndex: lot.router?.index, + routerRoute: lot.router?.route, + routerArea: lot.router?.area, + noLot: false, }); - } - - // ✅ FIXED: 同时处理 stockouts(无论是否有 lots) - if (line.stockouts && line.stockouts.length > 0) { - // ✅ FIXED: 处理所有 stockouts,而不仅仅是第一个 - line.stockouts.forEach((stockout: any) => { - flatLotData.push({ - pickOrderConsoCode: mergedPickOrder.consoCodes?.[0] || "", - pickOrderTargetDate: mergedPickOrder.targetDate, - pickOrderStatus: mergedPickOrder.status, - pickOrderId: line.pickOrderId || mergedPickOrder.pickOrderIds?.[0] || 0, - pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "", - pickOrderLineId: line.id, - pickOrderLineRequiredQty: line.requiredQty, - pickOrderLineStatus: line.status, - - itemId: line.item.id, - itemCode: line.item.code, - itemName: line.item.name, - uomDesc: line.item.uomDesc, - uomShortDesc: line.item.uomShortDesc, - - // Null stock 字段 - 从 stockouts 数组中获取 - lotId: stockout.lotId || null, - lotNo: stockout.lotNo || null, - expiryDate: null, - location: stockout.location || null, - stockUnit: line.item.uomDesc, - availableQty: stockout.availableQty || 0, - requiredQty: line.requiredQty, - actualPickQty: stockout.qty || 0, - inQty: 0, - outQty: 0, - holdQty: 0, - lotStatus: 'unavailable', - lotAvailability: 'insufficient_stock', - processingStatus: stockout.status || 'pending', - suggestedPickLotId: null, - stockOutLineId: stockout.id || null, // 使用 stockouts 数组中的 id - stockOutLineStatus: stockout.status || null, - stockOutLineQty: stockout.qty || 0, - - routerId: null, - routerIndex: 999999, - routerRoute: null, - routerArea: null, - noLot: true, - }); + }); + } + + // ✅ stockouts:只保留“真正无批次 / 未在 lots 出现过”的行 + if (line.stockouts && line.stockouts.length > 0) { + line.stockouts.forEach((stockout: any) => { + const hasLot = stockout.lotId != null; + const lotAlreadyInLots = + hasLot && lotIdSet.has(stockout.lotId as number); + + // 有批次 & 已经通过 lots 渲染过 → 跳过,避免一条变两行 + if (!stockout.noLot && lotAlreadyInLots) { + return; + } + + // 只渲染: + // - noLot === true 的 Null stock 行 + // - 或者 lotId 在 lots 中不存在的特殊情况 + flatLotData.push({ + pickOrderConsoCode: Array.isArray(mergedPickOrder.consoCodes) + ? mergedPickOrder.consoCodes[0] || "" + : "", + pickOrderTargetDate: mergedPickOrder.targetDate, + pickOrderStatus: mergedPickOrder.status, + pickOrderId: line.pickOrderId || mergedPickOrder.pickOrderIds?.[0] || 0, + pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "", + pickOrderLineId: line.id, + pickOrderLineRequiredQty: line.requiredQty, + pickOrderLineStatus: line.status, + + itemId: line.item.id, + itemCode: line.item.code, + itemName: line.item.name, + uomDesc: line.item.uomDesc, + uomShortDesc: line.item.uomShortDesc, + + lotId: stockout.lotId || null, + lotNo: stockout.lotNo || null, + expiryDate: null, + location: stockout.location || null, + stockUnit: line.item.uomDesc, + availableQty: stockout.availableQty || 0, + requiredQty: line.requiredQty, + actualPickQty: stockout.qty || 0, + inQty: 0, + outQty: 0, + holdQty: 0, + lotStatus: stockout.noLot ? "unavailable" : "available", + lotAvailability: stockout.noLot ? "insufficient_stock" : "available", + processingStatus: stockout.status || "pending", + suggestedPickLotId: null, + stockOutLineId: stockout.id || null, + stockOutLineStatus: stockout.status || null, + stockOutLineQty: stockout.qty || 0, + + routerId: null, + routerIndex: stockout.noLot ? 999999 : null, + routerRoute: null, + routerArea: null, + noLot: !!stockout.noLot, }); - } - }); - - console.log(" Transformed flat lot data:", flatLotData); - console.log(" Total items (including null stock):", flatLotData.length); - - setCombinedLotData(flatLotData); - setOriginalCombinedData(flatLotData); - checkAllLotsCompleted(flatLotData); - + }); + } + }); + + console.log(" Transformed flat lot data:", flatLotData); + console.log(" Total items (including null stock):", flatLotData.length); + + setCombinedLotData(flatLotData); + setOriginalCombinedData(flatLotData); + checkAllLotsCompleted(flatLotData); } catch (error) { console.error(" Error fetching combined lot data:", error); setCombinedLotData([]);