From 02e2cb03f37c2402d51a9d46f0eeb787963e80c8 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Fri, 5 Dec 2025 10:32:18 +0800 Subject: [PATCH] update --- src/app/api/do/actions.tsx | 43 ++- src/app/api/do/index.tsx | 15 + src/app/api/pickOrder/actions.ts | 55 +++- .../FinishedGoodSearch/GoodPickExecution.tsx | 97 +++++++ .../GoodPickExecutiondetail.tsx | 257 +++++++++++++++--- 5 files changed, 421 insertions(+), 46 deletions(-) diff --git a/src/app/api/do/actions.tsx b/src/app/api/do/actions.tsx index 3c368d9..1aa4ded 100644 --- a/src/app/api/do/actions.tsx +++ b/src/app/api/do/actions.tsx @@ -10,7 +10,7 @@ import { DoResult } from "."; import { GridRowId, GridRowSelectionModel } from "@mui/x-data-grid"; import { GET } from "../auth/[...nextauth]/route"; import { stringify } from "querystring"; - +import { convertObjToURLSearchParams } from "@/app/utils/commonUtil"; export interface CreateConsoDoInput { ids: GridRowSelectionModel; } @@ -131,7 +131,48 @@ export interface getTicketReleaseTable { handlerName: string | null; numberOfFGItems: number; } +export interface SearchDeliveryOrderInfoRequest { + code: string; + shopName: string; + status: string; + orderStartDate: string; + orderEndDate: string; + estArrStartDate: string; + estArrEndDate: string; + pageSize: number; + pageNum: number; +} +export interface SearchDeliveryOrderInfoResponse { + records: DeliveryOrderInfo[]; + total: number; +} +export interface DeliveryOrderInfo { + id: number; + code: string; + shopName: string; + supplierName: string; // 改为必需字段 + status: string; + orderDate: string; + + estimatedArrivalDate: string; + deliveryOrderLines: DoDetailLine[]; +} +export const fetchDoRecordByPage = cache(async (data?: SearchDeliveryOrderInfoRequest) => { + const queryStr = convertObjToURLSearchParams(data) + console.log("queryStr", queryStr) + const response = serverFetchJson( + `${BASE_API_URL}/jo/getRecordByPage?${queryStr}`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + next: { + tags: ["jos"] + } + } + ) + return response +}) export const fetchTicketReleaseTable = cache(async ()=> { return await serverFetchJson( `${BASE_API_URL}/doPickOrder/ticket-release-table`, diff --git a/src/app/api/do/index.tsx b/src/app/api/do/index.tsx index ecdaeaa..80b5569 100644 --- a/src/app/api/do/index.tsx +++ b/src/app/api/do/index.tsx @@ -13,6 +13,21 @@ export interface DoResult { shopName: string; } +export interface DoOrder { + id: number; + code: string; + supplierName: string; + shopName: string; + currencyCode: string; + orderDate: string; + estimatedArrivalDate: string; + estArrStartDate: string; + estArrEndDate: string; + completeDate: string; + status: string; + // deliveryOrderLines: DoDetailLine[]; + +} export interface DoDetailLine { id: number; itemNo: string; diff --git a/src/app/api/pickOrder/actions.ts b/src/app/api/pickOrder/actions.ts index ce5fc0d..7c96290 100644 --- a/src/app/api/pickOrder/actions.ts +++ b/src/app/api/pickOrder/actions.ts @@ -453,8 +453,59 @@ export interface LaneBtn { total: number; } - - +export interface QrPickBatchSubmitRequest { + userId: number; + lines: QrPickSubmitLineRequest[]; +} +export interface QrPickSubmitLineRequest { + stockOutLineId: number; + pickOrderLineId: number; + inventoryLotLineId: number | null; // ✅ 修复:应该是 nullable + requiredQty: number | null; // ✅ 修复:添加 requiredQty + actualPickQty: number | null; // ✅ 修复:添加 actualPickQty + stockOutLineStatus: string | null; // ✅ 修复:添加 stockOutLineStatus + pickOrderConsoCode: string | null; // ✅ 修复:添加 pickOrderConsoCode + noLot: boolean; // ✅ 修复:添加 noLot +} +export interface UpdateStockOutLineStatusByQRCodeAndLotNoRequest { + pickOrderLineId: number, + inventoryLotNo: string, + stockOutLineId: number, + itemId: number, + status: string +} +export const updateStockOutLineStatusByQRCodeAndLotNo = async (data: UpdateStockOutLineStatusByQRCodeAndLotNoRequest) => { + console.log("🚀 Frontend: Calling updateStockOutLineStatusByQRCodeAndLotNo with data:", data); + + try { + const response = await serverFetchJson>( + `${BASE_API_URL}/stockOutLine/updateStatusByQRCodeAndLotNo`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }, + ); + + console.log("✅ Frontend: API call successful, response:", response); + return response; + } catch (error) { + console.error("❌ Frontend: API call failed:", error); + throw error; + } +}; +export const batchQrSubmit = async (data: QrPickBatchSubmitRequest) => { + const response = await serverFetchJson>( + `${BASE_API_URL}/stockOutLine/batchQrSubmit`, + { + method: "POST", + body: JSON.stringify(data), + }, + ); + return response; +}; export const fetchDoPickOrderDetail = async ( doPickOrderId: number, diff --git a/src/components/FinishedGoodSearch/GoodPickExecution.tsx b/src/components/FinishedGoodSearch/GoodPickExecution.tsx index 6c58f2e..73ebd76 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecution.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecution.tsx @@ -35,6 +35,7 @@ import { checkAndCompletePickOrderByConsoCode, fetchDoPickOrderDetail, DoPickOrderDetail, + batchQrSubmit, } from "@/app/api/pickOrder/actions"; import { fetchNameList, NameList } from "@/app/api/user/actions"; import { @@ -488,6 +489,7 @@ const fetchFgPickOrdersData = useCallback(async () => { // Handle QR code submission for matched lot (external scanning) // Handle QR code submission for matched lot (external scanning) + /* const handleQrCodeSubmit = useCallback(async (lotNo: string) => { console.log(` Processing QR Code for lot: ${lotNo}`); @@ -583,6 +585,101 @@ const fetchFgPickOrdersData = useCallback(async () => { }, 3000); } }, [combinedLotData, fetchAllCombinedLotData]); + */ const handleQrCodeSubmit = useCallback(async (lotNo: string) => { + console.log(` Processing QR Code for lot: ${lotNo}`); + + // Use current data without refreshing to avoid infinite loop + const currentLotData = combinedLotData; + console.log(`🔍 Available lots:`, currentLotData.map(lot => lot.lotNo)); + + const matchingLots = currentLotData.filter(lot => + lot.lotNo === lotNo || + lot.lotNo?.toLowerCase() === lotNo.toLowerCase() + ); + + if (matchingLots.length === 0) { + console.error(`❌ Lot not found: ${lotNo}`); + setQrScanError(true); + setQrScanSuccess(false); + return; + } + + console.log(` Found ${matchingLots.length} matching lots:`, matchingLots); + setQrScanError(false); + + try { + let successCount = 0; + let existsCount = 0; + let errorCount = 0; + + for (const matchingLot of matchingLots) { + console.log(`🔄 Processing pick order line ${matchingLot.pickOrderLineId} for lot ${lotNo}`); + + if (matchingLot.stockOutLineId) { + console.log(` Stock out line already exists for line ${matchingLot.pickOrderLineId}`); + existsCount++; + } else { + const stockOutLineData: CreateStockOutLine = { + consoCode: matchingLot.pickOrderConsoCode, + pickOrderLineId: matchingLot.pickOrderLineId, + inventoryLotLineId: matchingLot.lotId, + qty: 0.0 + }; + + console.log(`Creating stock out line for pick order line ${matchingLot.pickOrderLineId}:`, stockOutLineData); + const result = await createStockOutLine(stockOutLineData); + console.log(`Create stock out line result for line ${matchingLot.pickOrderLineId}:`, result); + + if (result && result.code === "EXISTS") { + console.log(` Stock out line already exists for line ${matchingLot.pickOrderLineId}`); + existsCount++; + } else if (result && result.code === "SUCCESS") { + console.log(` Stock out line created successfully for line ${matchingLot.pickOrderLineId}`); + successCount++; + } else { + console.error(`❌ Failed to create stock out line for line ${matchingLot.pickOrderLineId}:`, result); + errorCount++; + } + } + } + + // Always refresh data after processing (success or failure) + console.log("🔄 Refreshing data after QR code processing..."); + await fetchAllCombinedLotData(); + + if (successCount > 0 || existsCount > 0) { + console.log(` QR Code processing completed: ${successCount} created, ${existsCount} already existed`); + setQrScanSuccess(true); + setQrScanInput(''); // Clear input after successful processing + + // Clear success state after a delay + setTimeout(() => { + setQrScanSuccess(false); + }, 2000); + } else { + console.error(`❌ QR Code processing failed: ${errorCount} errors`); + setQrScanError(true); + setQrScanSuccess(false); + + // Clear error state after a delay + setTimeout(() => { + setQrScanError(false); + }, 3000); + } + } catch (error) { + console.error("❌ Error processing QR code:", error); + setQrScanError(true); + setQrScanSuccess(false); + + // Still refresh data even on error + await fetchAllCombinedLotData(); + + // Clear error state after a delay + setTimeout(() => { + setQrScanError(false); + }, 3000); + } + }, [combinedLotData, fetchAllCombinedLotData]); const handleManualInputSubmit = useCallback(() => { if (qrScanInput.trim() !== '') { diff --git a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx index b2f43bb..433832e 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx @@ -41,10 +41,12 @@ import { PickOrderCompletionResponse, checkAndCompletePickOrderByConsoCode, updateSuggestedLotLineId, + updateStockOutLineStatusByQRCodeAndLotNo, confirmLotSubstitution, fetchDoPickOrderDetail, // 必须添加 DoPickOrderDetail, // 必须添加 - fetchFGPickOrdersByUserId + fetchFGPickOrdersByUserId , + batchQrSubmit } from "@/app/api/pickOrder/actions"; import FGPickOrderInfoCard from "./FGPickOrderInfoCard"; @@ -124,7 +126,7 @@ const QrCodeModal: React.FC<{ onClose(); resetScan(); } else { - console.log(`❌ QR Code mismatch. Expected: ${lot.lotNo}, Got: ${stockInLineInfo.lotNo}`); + console.log(` QR Code mismatch. Expected: ${lot.lotNo}, Got: ${stockInLineInfo.lotNo}`); setQrScanFailed(true); setManualInputError(true); setManualInputSubmitted(true); @@ -498,7 +500,7 @@ const fgOrder: FGPickOrderResponse = { console.log("🔍 DEBUG fgOrder.lineCountsPerPickOrder:", fgOrder.lineCountsPerPickOrder); console.log("🔍 DEBUG fgOrder.pickOrderCodes:", fgOrder.pickOrderCodes); console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); - // ❌ 移除:不需要 doPickOrderDetail 和 switcher 逻辑 + // 移除:不需要 doPickOrderDetail 和 switcher 逻辑 // if (hierarchicalData.pickOrders.length > 1) { ... } // 直接使用合并后的 pickOrderLines @@ -629,14 +631,14 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); checkAllLotsCompleted(flatLotData); } catch (error) { - console.error("❌ Error fetching combined lot data:", error); + console.error(" Error fetching combined lot data:", error); setCombinedLotData([]); setOriginalCombinedData([]); setAllLotsCompleted(false); } finally { setCombinedDataLoading(false); } -}, [currentUserId, checkAllLotsCompleted]); // ❌ 移除 selectedPickOrderId 依赖 +}, [currentUserId, checkAllLotsCompleted]); // 移除 selectedPickOrderId 依赖 // Add effect to check completion when lot data changes useEffect(() => { if (combinedLotData.length > 0) { @@ -714,7 +716,7 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); // 检查 lotNo 是否为 null 或 undefined(包括字符串 "null") if (!lotNo || lotNo === 'null' || lotNo.trim() === '') { - console.error("❌ Invalid lotNo: null, undefined, or empty"); + console.error(" Invalid lotNo: null, undefined, or empty"); return; } @@ -730,11 +732,11 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); }); if (matchingLots.length === 0) { - console.error(`❌ Lot not found: ${lotNo}`); + console.error(` Lot not found: ${lotNo}`); setQrScanError(true); setQrScanSuccess(false); const availableLotNos = currentLotData.map(lot => lot.lotNo).join(', '); - console.log(`❌ QR Code "${lotNo}" does not match any expected lots. Available lots: ${availableLotNos}`); + console.log(` QR Code "${lotNo}" does not match any expected lots. Available lots: ${availableLotNos}`); return; } @@ -832,7 +834,7 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); //setQrScanSuccess(false); //}, 2000); } else { - console.error(`❌ QR Code processing failed: ${errorCount} errors`); + console.error(` QR Code processing failed: ${errorCount} errors`); setQrScanError(true); setQrScanSuccess(false); @@ -842,14 +844,11 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); //}, 3000); } } catch (error) { - console.error("❌ Error processing QR code:", error); + console.error(" Error processing QR code:", error); setQrScanError(true); setQrScanSuccess(false); - // Still refresh data even on error - setIsRefreshingData(true); - await fetchAllCombinedLotData(); - + // Clear error state after a delay setTimeout(() => { setQrScanError(false); @@ -860,7 +859,88 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); setIsRefreshingData(false); }, 1000); } - }, [combinedLotData, fetchAllCombinedLotData]); + }, [combinedLotData]); + const handleFastQrScan = useCallback(async (lotNo: string) => { + const startTime = performance.now(); + console.log(`⏱️ [FAST SCAN START] Lot: ${lotNo}`); + console.log(`⏰ Start time: ${new Date().toISOString()}`); + + // 从 combinedLotData 中找到对应的 lot + const findStartTime = performance.now(); + const matchingLot = combinedLotData.find(lot => + lot.lotNo && lot.lotNo === lotNo + ); + const findTime = performance.now() - findStartTime; + console.log(`⏱️ Find lot time: ${findTime.toFixed(2)}ms`); + + if (!matchingLot || !matchingLot.stockOutLineId) { + const totalTime = performance.now() - startTime; + console.warn(`⚠️ Fast scan: Lot ${lotNo} not found or no stockOutLineId`); + console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms`); + return; + } + + try { + // ✅ 使用快速 API + const apiStartTime = performance.now(); + const res = await updateStockOutLineStatusByQRCodeAndLotNo({ + pickOrderLineId: matchingLot.pickOrderLineId, + inventoryLotNo: lotNo, + stockOutLineId: matchingLot.stockOutLineId, + itemId: matchingLot.itemId, + status: "checked", + }); + const apiTime = performance.now() - apiStartTime; + console.log(`⏱️ API call time: ${apiTime.toFixed(2)}ms`); + + if (res.code === "checked" || res.code === "SUCCESS") { + // ✅ 只更新本地状态,不调用 fetchAllCombinedLotData + const updateStartTime = performance.now(); + const entity = res.entity as any; + + setCombinedLotData(prev => prev.map(lot => { + if (lot.stockOutLineId === matchingLot.stockOutLineId && + lot.pickOrderLineId === matchingLot.pickOrderLineId) { + return { + ...lot, + stockOutLineStatus: 'checked', + stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty, + }; + } + return lot; + })); + + setOriginalCombinedData(prev => prev.map(lot => { + if (lot.stockOutLineId === matchingLot.stockOutLineId && + lot.pickOrderLineId === matchingLot.pickOrderLineId) { + return { + ...lot, + stockOutLineStatus: 'checked', + stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty, + }; + } + return lot; + })); + const updateTime = performance.now() - updateStartTime; + console.log(`⏱️ State update time: ${updateTime.toFixed(2)}ms`); + + const totalTime = performance.now() - startTime; + console.log(`✅ [FAST SCAN END] Lot: ${lotNo}`); + console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`); + console.log(`⏰ End time: ${new Date().toISOString()}`); + } else { + const totalTime = performance.now() - startTime; + console.warn(`⚠️ Fast scan failed for ${lotNo}:`, res.code); + console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms`); + } + } catch (error) { + const totalTime = performance.now() - startTime; + console.error(` Fast scan error for ${lotNo}:`, error); + console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms`); + } + }, [combinedLotData, updateStockOutLineStatusByQRCodeAndLotNo]); + + const processOutsideQrCode = useCallback(async (latestQr: string) => { // 1) Parse JSON safely let qrData: any = null; @@ -916,7 +996,7 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); return; } - // FIXED: Find the ACTIVE suggested lot (not rejected lots) + // FIXED: Find the ACTIVE suggested lot (not rejected lots) const activeSuggestedLots = sameItemLotsInExpected.filter(lot => lot.lotAvailability !== 'rejected' && lot.stockOutLineStatus !== 'rejected' && @@ -937,14 +1017,85 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); ); if (exactLotMatch && scanned?.lotNo) { - // Case 1: Normal case - item matches AND lot matches -> proceed - console.log(`Exact lot match found for ${scanned.lotNo}, submitting QR`); - handleQrCodeSubmit(scanned.lotNo); - return; + // ✅ Case 1: 使用 updateStockOutLineStatusByQRCodeAndLotNo API(更快) + console.log(`✅ Exact lot match found for ${scanned.lotNo}, using fast API`); + + if (!exactLotMatch.stockOutLineId) { + console.warn("No stockOutLineId on exactLotMatch, cannot update status by QR."); + setQrScanError(true); + setQrScanSuccess(false); + return; + } + + try { + // ✅ 直接调用后端 API,后端会处理所有匹配逻辑 + const res = await updateStockOutLineStatusByQRCodeAndLotNo({ + pickOrderLineId: exactLotMatch.pickOrderLineId, + inventoryLotNo: scanned.lotNo, + stockOutLineId: exactLotMatch.stockOutLineId, + itemId: exactLotMatch.itemId, + status: "checked", + }); + + console.log("updateStockOutLineStatusByQRCodeAndLotNo result:", res); + + // 后端返回三种 code:checked / LOT_NUMBER_MISMATCH / ITEM_MISMATCH + if (res.code === "checked" || res.code === "SUCCESS") { + // ✅ 完全匹配 - 只更新本地状态,不调用 fetchAllCombinedLotData + setQrScanError(false); + setQrScanSuccess(true); + + // ✅ 更新本地状态 + const entity = res.entity as any; + + setCombinedLotData(prev => prev.map(lot => { + if (lot.stockOutLineId === exactLotMatch.stockOutLineId && + lot.pickOrderLineId === exactLotMatch.pickOrderLineId) { + return { + ...lot, + stockOutLineStatus: 'checked', + stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty, + }; + } + return lot; + })); + + setOriginalCombinedData(prev => prev.map(lot => { + if (lot.stockOutLineId === exactLotMatch.stockOutLineId && + lot.pickOrderLineId === exactLotMatch.pickOrderLineId) { + return { + ...lot, + stockOutLineStatus: 'checked', + stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty, + }; + } + return lot; + })); + + console.log("✅ Status updated locally, no full data refresh needed"); + } else if (res.code === "LOT_NUMBER_MISMATCH") { + console.warn("Backend reported LOT_NUMBER_MISMATCH:", res.message); + setQrScanError(true); + setQrScanSuccess(false); + } else if (res.code === "ITEM_MISMATCH") { + console.warn("Backend reported ITEM_MISMATCH:", res.message); + setQrScanError(true); + setQrScanSuccess(false); + } else { + console.warn("Unexpected response code from backend:", res.code); + setQrScanError(true); + setQrScanSuccess(false); + } + } catch (e) { + console.error("Error calling updateStockOutLineStatusByQRCodeAndLotNo:", e); + setQrScanError(true); + setQrScanSuccess(false); + } + + return; // ✅ 直接返回,不再调用 handleQrCodeSubmit } // Case 2: Item matches but lot number differs -> open confirmation modal - // FIXED: Use the first ACTIVE suggested lot, not just any lot const expectedLot = activeSuggestedLots[0]; if (!expectedLot) { console.error("Could not determine expected lot for confirmation"); @@ -953,7 +1104,7 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); return; } - // Check if the expected lot is already the scanned lot (after substitution) + // Check if the expected lot is already the scanned lot (after substitution) if (expectedLot.lotNo === scanned?.lotNo) { console.log(`Lot already substituted, proceeding with ${scanned.lotNo}`); handleQrCodeSubmit(scanned.lotNo); @@ -982,7 +1133,7 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); setQrScanSuccess(false); return; } - }, [combinedLotData, handleQrCodeSubmit, handleLotMismatch]); + }, [combinedLotData, handleQrCodeSubmit, handleLotMismatch]); // Update the outside QR scanning effect to use enhanced processing // Update the outside QR scanning effect to use enhanced processing useEffect(() => { @@ -1073,13 +1224,12 @@ useEffect(() => { console.log(` Auto-set pick quantity to ${requiredQty} for lot ${lotNo}`); }, 500); - // Refresh data - await fetchAllCombinedLotData(); + } catch (error) { console.error("Error creating stock out line:", error); } } - }, [selectedLotForQr, fetchAllCombinedLotData]); + }, [selectedLotForQr]); const handlePickQtyChange = useCallback((lotKey: string, value: number | string) => { @@ -1190,7 +1340,7 @@ useEffect(() => { } else if (completionResponse.message === "not completed") { console.log(`⏳ Pick order not completed yet, more lines remaining`); } else { - console.error(`❌ Error checking completion: ${completionResponse.message}`); + console.error(` Error checking completion: ${completionResponse.message}`); } } catch (error) { console.error("Error checking pick order completion:", error); @@ -1268,7 +1418,7 @@ useEffect(() => { if (result && result.code === "SUCCESS") { console.log(" Pick execution issue recorded successfully"); } else { - console.error("❌ Failed to record pick execution issue:", result); + console.error(" Failed to record pick execution issue:", result); } setPickExecutionFormOpen(false); @@ -1452,7 +1602,7 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe } else if (completionResponse.message === "not completed") { console.log(`⏳ Pick order not completed yet, more lines remaining`); } else { - console.error(`❌ Error checking completion: ${completionResponse.message}`); + console.error(` Error checking completion: ${completionResponse.message}`); } } catch (error) { console.error("Error checking pick order completion:", error); @@ -1513,7 +1663,7 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe const stockOutLineId = lot.stockOutLineId; if (!stockOutLineId) { - console.error("❌ No stockOutLineId found for lot:", lot); + console.error(" No stockOutLineId found for lot:", lot); return; } @@ -1558,17 +1708,20 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe if (result && result.code === "SUCCESS") { console.log(" No-lot item handled and issue recorded successfully"); } else { - console.error("❌ Failed to record pick execution issue:", result); + console.error(" Failed to record pick execution issue:", result); } // Step 3: Refresh data await fetchAllCombinedLotData(); } catch (error) { - console.error("❌ Error in handlelotnull:", error); + console.error(" Error in handlelotnull:", error); } }, [fetchAllCombinedLotData, session, currentUserId, fgPickOrders]); // ... existing code ... const handleSubmitAllScanned = useCallback(async () => { + const startTime = performance.now(); + console.log(`⏱️ [BATCH SUBMIT START]`); + console.log(`⏰ Start time: ${new Date().toISOString()}`); const scannedLots = combinedLotData.filter(lot => { // 如果是 noLot 情况,检查状态是否为 pending 或 partially_complete if (lot.noLot === true) { @@ -1667,14 +1820,31 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe }); // Wait for all submissions to complete - const results = await Promise.all(submitPromises); - const successCount = results.filter(r => r.success).length; + const submitStartTime = performance.now(); + const submitResults = await Promise.all(submitPromises); + const submitSuccessCount = submitResults.filter(r => r.success).length; - console.log(` Batch submit completed: ${successCount}/${scannedLots.length} items submitted`); - - // Refresh data once after all submissions - await fetchAllCombinedLotData(); + console.log(` Batch submit completed: ${submitSuccessCount}/${scannedLots.length} items submitted`); + // Wait for all submissions to complete + const results = await Promise.all(submitPromises); + const submitTime = performance.now() - submitStartTime; + const successCount = results.filter(r => r.success).length; + + console.log(`⏱️ All submissions completed in ${submitTime.toFixed(2)}ms (${(submitTime / 1000).toFixed(3)}s)`); + console.log(`⏱️ Average time per item: ${(submitTime / scannedLots.length).toFixed(2)}ms`); + console.log(` Batch submit completed: ${successCount}/${scannedLots.length} items submitted`); + + // Refresh data once after all submissions + const refreshStartTime = performance.now(); + await fetchAllCombinedLotData(); + const refreshTime = performance.now() - refreshStartTime; + console.log(`⏱️ Data refresh time: ${refreshTime.toFixed(2)}ms (${(refreshTime / 1000).toFixed(3)}s)`); + + const totalTime = performance.now() - startTime; + console.log(`⏱️ [BATCH SUBMIT END]`); + console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`); + console.log(`⏰ End time: ${new Date().toISOString()}`); if (successCount > 0) { setQrScanSuccess(true); setTimeout(() => { @@ -1961,10 +2131,10 @@ paginatedData.map((lot, index) => { }} > - - {index + 1} - - + + {paginationController.pageNum * paginationController.pageSize + index + 1} + + {lot.routerRoute || '-'} @@ -2218,7 +2388,8 @@ paginatedData.map((lot, index) => { uomDesc: selectedLotForExecutionForm.uomDesc || '', pickedQty: selectedLotForExecutionForm.actualPickQty || 0, uomShortDesc: selectedLotForExecutionForm.uomShortDesc || '', - suggestedList: [] + suggestedList: [], + noLotLines: [], }} pickOrderId={selectedLotForExecutionForm.pickOrderId} pickOrderCreateDate={new Date()}