Explorar el Código

update

MergeProblem1
CANCERYS\kw093 hace 2 días
padre
commit
045f9a6bd5
Se han modificado 3 ficheros con 161 adiciones y 117 borrados
  1. +157
    -110
      src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx
  2. +2
    -6
      src/components/PoDetail/PoDetail.tsx
  3. +2
    -1
      src/i18n/zh/pickOrder.json

+ 157
- 110
src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx Ver fichero

@@ -147,7 +147,7 @@ const QrCodeModal: React.FC<{
if (qrData.stockInLineId && qrData.itemId) { if (qrData.stockInLineId && qrData.itemId) {
// ✅ Check if we're already fetching this stockInLineId // ✅ Check if we're already fetching this stockInLineId
if (fetchingRef.current.has(qrData.stockInLineId)) { if (fetchingRef.current.has(qrData.stockInLineId)) {
console.log(`⏱️ [QR MODAL] Already fetching stockInLineId: ${qrData.stockInLineId}, skipping duplicate call`);
console.log(` [QR MODAL] Already fetching stockInLineId: ${qrData.stockInLineId}, skipping duplicate call`);
return; return;
} }
@@ -159,7 +159,7 @@ const QrCodeModal: React.FC<{
fetchingRef.current.add(qrData.stockInLineId); fetchingRef.current.add(qrData.stockInLineId);
const fetchStartTime = performance.now(); const fetchStartTime = performance.now();
console.log(`⏱️ [QR MODAL] Starting fetchStockInLineInfo for stockInLineId: ${qrData.stockInLineId}`);
console.log(` [QR MODAL] Starting fetchStockInLineInfo for stockInLineId: ${qrData.stockInLineId}`);
fetchStockInLineInfo(qrData.stockInLineId) fetchStockInLineInfo(qrData.stockInLineId)
.then((stockInLineInfo) => { .then((stockInLineInfo) => {
@@ -173,7 +173,7 @@ const QrCodeModal: React.FC<{
} }
const fetchTime = performance.now() - fetchStartTime; const fetchTime = performance.now() - fetchStartTime;
console.log(`⏱️ [QR MODAL] fetchStockInLineInfo time: ${fetchTime.toFixed(2)}ms (${(fetchTime / 1000).toFixed(3)}s)`);
console.log(` [QR MODAL] fetchStockInLineInfo time: ${fetchTime.toFixed(2)}ms (${(fetchTime / 1000).toFixed(3)}s)`);
console.log("Stock in line info:", stockInLineInfo); console.log("Stock in line info:", stockInLineInfo);
setScannedQrResult(stockInLineInfo.lotNo || 'Unknown lot number'); setScannedQrResult(stockInLineInfo.lotNo || 'Unknown lot number');
@@ -655,7 +655,7 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false);
abortControllerRef.current = abortController; abortControllerRef.current = abortController;
try { try {
console.log(`⏱️ [CACHE MISS] Fetching stockInLineInfo for ${stockInLineId}`);
console.log(` [CACHE MISS] Fetching stockInLineInfo for ${stockInLineId}`);
const stockInLineInfo = await fetchStockInLineInfo(stockInLineId); const stockInLineInfo = await fetchStockInLineInfo(stockInLineId);
// Store in cache // Store in cache
@@ -675,7 +675,7 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false);
return { lotNo: stockInLineInfo.lotNo || null }; return { lotNo: stockInLineInfo.lotNo || null };
} catch (error: any) { } catch (error: any) {
if (error.name === 'AbortError') { if (error.name === 'AbortError') {
console.log(`⏱️ [CACHE] Request aborted for ${stockInLineId}`);
console.log(` [CACHE] Request aborted for ${stockInLineId}`);
throw error; throw error;
} }
console.error(`❌ [CACHE] Error fetching stockInLineInfo for ${stockInLineId}:`, error); console.error(`❌ [CACHE] Error fetching stockInLineInfo for ${stockInLineId}:`, error);
@@ -685,8 +685,8 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false);


const handleLotMismatch = useCallback((expectedLot: any, scannedLot: any, qrScanCountAtOpen?: number) => { const handleLotMismatch = useCallback((expectedLot: any, scannedLot: any, qrScanCountAtOpen?: number) => {
const mismatchStartTime = performance.now(); const mismatchStartTime = performance.now();
console.log(`⏱️ [HANDLE LOT MISMATCH START]`);
console.log(` Start time: ${new Date().toISOString()}`);
console.log(` [HANDLE LOT MISMATCH START]`);
console.log(` Start time: ${new Date().toISOString()}`);
console.log("Lot mismatch detected:", { expectedLot, scannedLot }); console.log("Lot mismatch detected:", { expectedLot, scannedLot });


lotConfirmOpenedQrCountRef.current = lotConfirmOpenedQrCountRef.current =
@@ -705,26 +705,26 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false);
setLotConfirmationOpen(true); setLotConfirmationOpen(true);
const setStateTime = performance.now() - setStateStartTime; const setStateTime = performance.now() - setStateStartTime;
console.timeEnd('setLotConfirmationOpen'); console.timeEnd('setLotConfirmationOpen');
console.log(`⏱️ [HANDLE LOT MISMATCH] Modal state set to open (setState time: ${setStateTime.toFixed(2)}ms)`);
console.log(` [HANDLE LOT MISMATCH] Modal state set to open (setState time: ${setStateTime.toFixed(2)}ms)`);
console.log(`✅ [HANDLE LOT MISMATCH] Modal state set to open`); console.log(`✅ [HANDLE LOT MISMATCH] Modal state set to open`);
}, 0); }, 0);
const setTimeoutTime = performance.now() - setTimeoutStartTime; const setTimeoutTime = performance.now() - setTimeoutStartTime;
console.log(`⏱️ [PERF] setTimeout scheduling time: ${setTimeoutTime.toFixed(2)}ms`);
console.log(` [PERF] setTimeout scheduling time: ${setTimeoutTime.toFixed(2)}ms`);
// ✅ Fetch lotNo in background ONLY for display purposes (using cached version) // ✅ Fetch lotNo in background ONLY for display purposes (using cached version)
if (!scannedLot.lotNo && scannedLot.stockInLineId) { if (!scannedLot.lotNo && scannedLot.stockInLineId) {
const stockInLineId = scannedLot.stockInLineId; const stockInLineId = scannedLot.stockInLineId;
if (typeof stockInLineId !== 'number') { if (typeof stockInLineId !== 'number') {
console.warn(`⏱️ [HANDLE LOT MISMATCH] Invalid stockInLineId: ${stockInLineId}`);
console.warn(` [HANDLE LOT MISMATCH] Invalid stockInLineId: ${stockInLineId}`);
return; return;
} }
console.log(`⏱️ [HANDLE LOT MISMATCH] Fetching lotNo in background (stockInLineId: ${stockInLineId})`);
console.log(` [HANDLE LOT MISMATCH] Fetching lotNo in background (stockInLineId: ${stockInLineId})`);
const fetchStartTime = performance.now(); const fetchStartTime = performance.now();
fetchStockInLineInfoCached(stockInLineId) fetchStockInLineInfoCached(stockInLineId)
.then((stockInLineInfo) => { .then((stockInLineInfo) => {
const fetchTime = performance.now() - fetchStartTime; const fetchTime = performance.now() - fetchStartTime;
console.log(`⏱️ [HANDLE LOT MISMATCH] fetchStockInLineInfoCached time: ${fetchTime.toFixed(2)}ms (${(fetchTime / 1000).toFixed(3)}s)`);
console.log(` [HANDLE LOT MISMATCH] fetchStockInLineInfoCached time: ${fetchTime.toFixed(2)}ms (${(fetchTime / 1000).toFixed(3)}s)`);
const updateStateStartTime = performance.now(); const updateStateStartTime = performance.now();
startTransition(() => { startTransition(() => {
@@ -734,10 +734,10 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false);
})); }));
}); });
const updateStateTime = performance.now() - updateStateStartTime; const updateStateTime = performance.now() - updateStateStartTime;
console.log(`⏱️ [PERF] Update scanned lot data time: ${updateStateTime.toFixed(2)}ms`);
console.log(` [PERF] Update scanned lot data time: ${updateStateTime.toFixed(2)}ms`);
const totalTime = performance.now() - mismatchStartTime; const totalTime = performance.now() - mismatchStartTime;
console.log(`⏱️ [HANDLE LOT MISMATCH] Background fetch completed: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
console.log(` [HANDLE LOT MISMATCH] Background fetch completed: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
}) })
.catch((error) => { .catch((error) => {
if (error.name !== 'AbortError') { if (error.name !== 'AbortError') {
@@ -747,7 +747,7 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false);
}); });
} else { } else {
const totalTime = performance.now() - mismatchStartTime; const totalTime = performance.now() - mismatchStartTime;
console.log(`⏱️ [HANDLE LOT MISMATCH END] Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
console.log(` [HANDLE LOT MISMATCH END] Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
} }
}, [fetchStockInLineInfoCached]); }, [fetchStockInLineInfoCached]);
const checkAllLotsCompleted = useCallback((lotData: any[]) => { const checkAllLotsCompleted = useCallback((lotData: any[]) => {
@@ -1187,7 +1187,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
setTimeout(() => { setTimeout(() => {
lastProcessedQrRef.current = ''; lastProcessedQrRef.current = '';
processedQrCodesRef.current.clear(); processedQrCodesRef.current.clear();
console.log(`⏱️ [LOT CONFIRM MODAL] Cleared refs to allow reprocessing`);
console.log(` [LOT CONFIRM MODAL] Cleared refs to allow reprocessing`);
}, 100); }, 100);
} }
}, []); }, []);
@@ -1362,6 +1362,16 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
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; return;
} }

const hasExpiredLot = matchingLots.some(
(lot: any) => String(lot.lotAvailability || '').toLowerCase() === 'expired'
);
if (hasExpiredLot) {
console.warn(`⚠️ [QR PROCESS] Scanned lot ${lotNo} is expired`);
setQrScanError(true);
setQrScanSuccess(false);
return;
}
console.log(` Found ${matchingLots.length} matching lots:`, matchingLots); console.log(` Found ${matchingLots.length} matching lots:`, matchingLots);
setQrScanError(false); setQrScanError(false);
@@ -1485,8 +1495,8 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
}, [combinedLotData]); }, [combinedLotData]);
const handleFastQrScan = useCallback(async (lotNo: string) => { const handleFastQrScan = useCallback(async (lotNo: string) => {
const startTime = performance.now(); const startTime = performance.now();
console.log(`⏱️ [FAST SCAN START] Lot: ${lotNo}`);
console.log(` Start time: ${new Date().toISOString()}`);
console.log(` [FAST SCAN START] Lot: ${lotNo}`);
console.log(` Start time: ${new Date().toISOString()}`);
// 从 combinedLotData 中找到对应的 lot // 从 combinedLotData 中找到对应的 lot
const findStartTime = performance.now(); const findStartTime = performance.now();
@@ -1494,12 +1504,12 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
lot.lotNo && lot.lotNo === lotNo lot.lotNo && lot.lotNo === lotNo
); );
const findTime = performance.now() - findStartTime; const findTime = performance.now() - findStartTime;
console.log(`⏱️ Find lot time: ${findTime.toFixed(2)}ms`);
console.log(` Find lot time: ${findTime.toFixed(2)}ms`);
if (!matchingLot || !matchingLot.stockOutLineId) { if (!matchingLot || !matchingLot.stockOutLineId) {
const totalTime = performance.now() - startTime; const totalTime = performance.now() - startTime;
console.warn(`⚠️ Fast scan: Lot ${lotNo} not found or no stockOutLineId`); console.warn(`⚠️ Fast scan: Lot ${lotNo} not found or no stockOutLineId`);
console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms`);
console.log(` Total time: ${totalTime.toFixed(2)}ms`);
return; return;
} }
@@ -1514,7 +1524,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
status: "checked", status: "checked",
}); });
const apiTime = performance.now() - apiStartTime; const apiTime = performance.now() - apiStartTime;
console.log(`⏱️ API call time: ${apiTime.toFixed(2)}ms`);
console.log(` API call time: ${apiTime.toFixed(2)}ms`);
if (res.code === "checked" || res.code === "SUCCESS") { if (res.code === "checked" || res.code === "SUCCESS") {
// ✅ 只更新本地状态,不调用 fetchAllCombinedLotData // ✅ 只更新本地状态,不调用 fetchAllCombinedLotData
@@ -1545,27 +1555,27 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
return lot; return lot;
})); }));
const updateTime = performance.now() - updateStartTime; const updateTime = performance.now() - updateStartTime;
console.log(`⏱️ State update time: ${updateTime.toFixed(2)}ms`);
console.log(` State update time: ${updateTime.toFixed(2)}ms`);
const totalTime = performance.now() - startTime; const totalTime = performance.now() - startTime;
console.log(`✅ [FAST SCAN END] Lot: ${lotNo}`); 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()}`);
console.log(` Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
console.log(` End time: ${new Date().toISOString()}`);
} else { } else {
const totalTime = performance.now() - startTime; const totalTime = performance.now() - startTime;
console.warn(`⚠️ Fast scan failed for ${lotNo}:`, res.code); console.warn(`⚠️ Fast scan failed for ${lotNo}:`, res.code);
console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms`);
console.log(` Total time: ${totalTime.toFixed(2)}ms`);
} }
} catch (error) { } catch (error) {
const totalTime = performance.now() - startTime; const totalTime = performance.now() - startTime;
console.error(` Fast scan error for ${lotNo}:`, error); console.error(` Fast scan error for ${lotNo}:`, error);
console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms`);
console.log(` Total time: ${totalTime.toFixed(2)}ms`);
} }
}, [combinedLotData, updateStockOutLineStatusByQRCodeAndLotNo]); }, [combinedLotData, updateStockOutLineStatusByQRCodeAndLotNo]);
// Enhanced lotDataIndexes with cached active lots for better performance // Enhanced lotDataIndexes with cached active lots for better performance
const lotDataIndexes = useMemo(() => { const lotDataIndexes = useMemo(() => {
const indexStartTime = performance.now(); const indexStartTime = performance.now();
console.log(`⏱️ [PERF] lotDataIndexes calculation START, data length: ${combinedLotData.length}`);
console.log(` [PERF] lotDataIndexes calculation START, data length: ${combinedLotData.length}`);
const byItemId = new Map<number, any[]>(); const byItemId = new Map<number, any[]>();
const byItemCode = new Map<string, any[]>(); const byItemCode = new Map<string, any[]>();
@@ -1622,7 +1632,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
const indexTime = performance.now() - indexStartTime; const indexTime = performance.now() - indexStartTime;
if (indexTime > 10) { if (indexTime > 10) {
console.log(`⏱️ [PERF] lotDataIndexes calculation END: ${indexTime.toFixed(2)}ms (${(indexTime / 1000).toFixed(3)}s)`);
console.log(` [PERF] lotDataIndexes calculation END: ${indexTime.toFixed(2)}ms (${(indexTime / 1000).toFixed(3)}s)`);
} }
return { byItemId, byItemCode, byLotId, byLotNo, byStockInLineId, activeLotsByItemId }; return { byItemId, byItemCode, byLotId, byLotNo, byStockInLineId, activeLotsByItemId };
@@ -1633,14 +1643,14 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
const processOutsideQrCode = useCallback(async (latestQr: string, qrScanCountAtInvoke?: number) => { const processOutsideQrCode = useCallback(async (latestQr: string, qrScanCountAtInvoke?: number) => {
const totalStartTime = performance.now(); const totalStartTime = performance.now();
console.log(`⏱️ [PROCESS OUTSIDE QR START] QR: ${latestQr.substring(0, 50)}...`);
console.log(` Start time: ${new Date().toISOString()}`);
console.log(` [PROCESS OUTSIDE QR START] QR: ${latestQr.substring(0, 50)}...`);
console.log(` Start time: ${new Date().toISOString()}`);
// ✅ Measure index access time // ✅ Measure index access time
const indexAccessStart = performance.now(); const indexAccessStart = performance.now();
const indexes = lotDataIndexes; // Access the memoized indexes const indexes = lotDataIndexes; // Access the memoized indexes
const indexAccessTime = performance.now() - indexAccessStart; const indexAccessTime = performance.now() - indexAccessStart;
console.log(`⏱️ [PERF] Index access time: ${indexAccessTime.toFixed(2)}ms`);
console.log(` [PERF] Index access time: ${indexAccessTime.toFixed(2)}ms`);
// 1) Parse JSON safely (parse once, reuse) // 1) Parse JSON safely (parse once, reuse)
const parseStartTime = performance.now(); const parseStartTime = performance.now();
@@ -1649,7 +1659,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
try { try {
qrData = JSON.parse(latestQr); qrData = JSON.parse(latestQr);
parseTime = performance.now() - parseStartTime; parseTime = performance.now() - parseStartTime;
console.log(`⏱️ [PERF] JSON parse time: ${parseTime.toFixed(2)}ms`);
console.log(` [PERF] JSON parse time: ${parseTime.toFixed(2)}ms`);
} catch { } catch {
console.log("QR content is not JSON; skipping lotNo direct submit to avoid false matches."); console.log("QR content is not JSON; skipping lotNo direct submit to avoid false matches.");
startTransition(() => { startTransition(() => {
@@ -1670,7 +1680,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
return; return;
} }
const validationTime = performance.now() - validationStartTime; const validationTime = performance.now() - validationStartTime;
console.log(`⏱️ [PERF] Validation time: ${validationTime.toFixed(2)}ms`);
console.log(` [PERF] Validation time: ${validationTime.toFixed(2)}ms`);
const scannedItemId = qrData.itemId; const scannedItemId = qrData.itemId;
const scannedStockInLineId = qrData.stockInLineId; const scannedStockInLineId = qrData.stockInLineId;
@@ -1680,11 +1690,11 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
const itemProcessedSet = processedQrCombinations.get(scannedItemId); const itemProcessedSet = processedQrCombinations.get(scannedItemId);
if (itemProcessedSet?.has(scannedStockInLineId)) { if (itemProcessedSet?.has(scannedStockInLineId)) {
const duplicateCheckTime = performance.now() - duplicateCheckStartTime; const duplicateCheckTime = performance.now() - duplicateCheckStartTime;
console.log(`⏱️ [SKIP] Already processed combination: itemId=${scannedItemId}, stockInLineId=${scannedStockInLineId} (check time: ${duplicateCheckTime.toFixed(2)}ms)`);
console.log(` [SKIP] Already processed combination: itemId=${scannedItemId}, stockInLineId=${scannedStockInLineId} (check time: ${duplicateCheckTime.toFixed(2)}ms)`);
return; return;
} }
const duplicateCheckTime = performance.now() - duplicateCheckStartTime; const duplicateCheckTime = performance.now() - duplicateCheckStartTime;
console.log(`⏱️ [PERF] Duplicate check time: ${duplicateCheckTime.toFixed(2)}ms`);
console.log(` [PERF] Duplicate check time: ${duplicateCheckTime.toFixed(2)}ms`);
// ✅ OPTIMIZATION: Use cached active lots directly (no filtering needed) // ✅ OPTIMIZATION: Use cached active lots directly (no filtering needed)
const lookupStartTime = performance.now(); const lookupStartTime = performance.now();
@@ -1692,7 +1702,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
// ✅ Also get all lots for this item (not just active ones) to allow lot switching even when all lots are rejected // ✅ Also get all lots for this item (not just active ones) to allow lot switching even when all lots are rejected
const allLotsForItem = indexes.byItemId.get(scannedItemId) || []; const allLotsForItem = indexes.byItemId.get(scannedItemId) || [];
const lookupTime = performance.now() - lookupStartTime; const lookupTime = performance.now() - lookupStartTime;
console.log(`⏱️ [PERF] Index lookup time: ${lookupTime.toFixed(2)}ms, found ${activeSuggestedLots.length} active lots, ${allLotsForItem.length} total lots`);
console.log(` [PERF] Index lookup time: ${lookupTime.toFixed(2)}ms, found ${activeSuggestedLots.length} active lots, ${allLotsForItem.length} total lots`);
// ✅ Check if scanned lot is rejected BEFORE checking activeSuggestedLots // ✅ Check if scanned lot is rejected BEFORE checking activeSuggestedLots
// This allows users to scan other lots even when all suggested lots are rejected // This allows users to scan other lots even when all suggested lots are rejected
@@ -1724,6 +1734,27 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
}); });
return; return;
} }

const isExpired =
String(scannedLot.lotAvailability || '').toLowerCase() === 'expired';
if (isExpired) {
console.warn(`⚠️ [QR PROCESS] Scanned lot (stockInLineId: ${scannedStockInLineId}, lotNo: ${scannedLot.lotNo}) is expired`);
startTransition(() => {
setQrScanError(true);
setQrScanSuccess(false);
setQrScanErrorMsg(
`此批次(${scannedLot.lotNo || scannedStockInLineId})已过期,无法使用。请扫描其他批次。`
);
});
// Mark as processed to prevent re-processing the same expired QR repeatedly
setProcessedQrCombinations(prev => {
const newMap = new Map(prev);
if (!newMap.has(scannedItemId)) newMap.set(scannedItemId, new Set());
newMap.get(scannedItemId)!.add(scannedStockInLineId);
return newMap;
});
return;
}
} }
// ✅ If no active suggested lots, but scanned lot is not rejected, allow lot switching // ✅ If no active suggested lots, but scanned lot is not rejected, allow lot switching
@@ -1793,7 +1824,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
} }
} }
const matchTime = performance.now() - matchStartTime; const matchTime = performance.now() - matchStartTime;
console.log(`⏱️ [PERF] Find exact match time: ${matchTime.toFixed(2)}ms, found: ${exactMatch ? 'yes' : 'no'}`);
console.log(` [PERF] Find exact match time: ${matchTime.toFixed(2)}ms, found: ${exactMatch ? 'yes' : 'no'}`);
// ✅ Check if scanned lot exists in allLotsForItem but not in activeSuggestedLots // ✅ Check if scanned lot exists in allLotsForItem but not in activeSuggestedLots
// This handles the case where Lot A is rejected and user scans Lot B // This handles the case where Lot A is rejected and user scans Lot B
@@ -1843,8 +1874,8 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
try { try {
const apiStartTime = performance.now(); const apiStartTime = performance.now();
console.log(`⏱️ [API CALL START] Calling updateStockOutLineStatusByQRCodeAndLotNo`);
console.log(` [API CALL] API start time: ${new Date().toISOString()}`);
console.log(` [API CALL START] Calling updateStockOutLineStatusByQRCodeAndLotNo`);
console.log(` [API CALL] API start time: ${new Date().toISOString()}`);
const res = await updateStockOutLineStatusByQRCodeAndLotNo({ const res = await updateStockOutLineStatusByQRCodeAndLotNo({
pickOrderLineId: exactMatch.pickOrderLineId, pickOrderLineId: exactMatch.pickOrderLineId,
inventoryLotNo: exactMatch.lotNo, inventoryLotNo: exactMatch.lotNo,
@@ -1853,8 +1884,8 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
status: "checked", status: "checked",
}); });
const apiTime = performance.now() - apiStartTime; const apiTime = performance.now() - apiStartTime;
console.log(`⏱️ [API CALL END] Total API time: ${apiTime.toFixed(2)}ms (${(apiTime / 1000).toFixed(3)}s)`);
console.log(` [API CALL] API end time: ${new Date().toISOString()}`);
console.log(` [API CALL END] Total API time: ${apiTime.toFixed(2)}ms (${(apiTime / 1000).toFixed(3)}s)`);
console.log(` [API CALL] API end time: ${new Date().toISOString()}`);
if (res.code === "checked" || res.code === "SUCCESS") { if (res.code === "checked" || res.code === "SUCCESS") {
const entity = res.entity as any; const entity = res.entity as any;
@@ -1890,7 +1921,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
})); }));
}); });
const stateUpdateTime = performance.now() - stateUpdateStartTime; const stateUpdateTime = performance.now() - stateUpdateStartTime;
console.log(`⏱️ [PERF] State update time: ${stateUpdateTime.toFixed(2)}ms`);
console.log(` [PERF] State update time: ${stateUpdateTime.toFixed(2)}ms`);
// Mark this combination as processed // Mark this combination as processed
const markProcessedStartTime = performance.now(); const markProcessedStartTime = performance.now();
@@ -1903,11 +1934,11 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
return newMap; return newMap;
}); });
const markProcessedTime = performance.now() - markProcessedStartTime; const markProcessedTime = performance.now() - markProcessedStartTime;
console.log(`⏱️ [PERF] Mark processed time: ${markProcessedTime.toFixed(2)}ms`);
console.log(` [PERF] Mark processed time: ${markProcessedTime.toFixed(2)}ms`);
const totalTime = performance.now() - totalStartTime; const totalTime = performance.now() - totalStartTime;
console.log(`✅ [PROCESS OUTSIDE QR END] Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`); console.log(`✅ [PROCESS OUTSIDE QR END] Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
console.log(` End time: ${new Date().toISOString()}`);
console.log(` End time: ${new Date().toISOString()}`);
console.log(`📊 Breakdown: parse=${parseTime.toFixed(2)}ms, validation=${validationTime.toFixed(2)}ms, duplicateCheck=${duplicateCheckTime.toFixed(2)}ms, lookup=${lookupTime.toFixed(2)}ms, match=${matchTime.toFixed(2)}ms, api=${apiTime.toFixed(2)}ms, stateUpdate=${stateUpdateTime.toFixed(2)}ms, markProcessed=${markProcessedTime.toFixed(2)}ms`); console.log(`📊 Breakdown: parse=${parseTime.toFixed(2)}ms, validation=${validationTime.toFixed(2)}ms, duplicateCheck=${duplicateCheckTime.toFixed(2)}ms, lookup=${lookupTime.toFixed(2)}ms, match=${matchTime.toFixed(2)}ms, api=${apiTime.toFixed(2)}ms, stateUpdate=${stateUpdateTime.toFixed(2)}ms, markProcessed=${markProcessedTime.toFixed(2)}ms`);
console.log("✅ Status updated locally, no full data refresh needed"); console.log("✅ Status updated locally, no full data refresh needed");
} else { } else {
@@ -1936,11 +1967,11 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
const itemProcessedSet2 = processedQrCombinations.get(scannedItemId); const itemProcessedSet2 = processedQrCombinations.get(scannedItemId);
if (itemProcessedSet2?.has(scannedStockInLineId)) { if (itemProcessedSet2?.has(scannedStockInLineId)) {
const mismatchCheckTime = performance.now() - mismatchCheckStartTime; const mismatchCheckTime = performance.now() - mismatchCheckStartTime;
console.log(`⏱️ [SKIP] Already processed this exact combination (check time: ${mismatchCheckTime.toFixed(2)}ms)`);
console.log(` [SKIP] Already processed this exact combination (check time: ${mismatchCheckTime.toFixed(2)}ms)`);
return; return;
} }
const mismatchCheckTime = performance.now() - mismatchCheckStartTime; const mismatchCheckTime = performance.now() - mismatchCheckStartTime;
console.log(`⏱️ [PERF] Mismatch check time: ${mismatchCheckTime.toFixed(2)}ms`);
console.log(` [PERF] Mismatch check time: ${mismatchCheckTime.toFixed(2)}ms`);
// 取应被替换的活跃行(同物料多行时优先有建议批次的行) // 取应被替换的活跃行(同物料多行时优先有建议批次的行)
const expectedLotStartTime = performance.now(); const expectedLotStartTime = performance.now();
@@ -1954,7 +1985,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
return; return;
} }
const expectedLotTime = performance.now() - expectedLotStartTime; const expectedLotTime = performance.now() - expectedLotStartTime;
console.log(`⏱️ [PERF] Get expected lot time: ${expectedLotTime.toFixed(2)}ms`);
console.log(` [PERF] Get expected lot time: ${expectedLotTime.toFixed(2)}ms`);
// ✅ 立即打开确认模态框,不等待其他操作 // ✅ 立即打开确认模态框,不等待其他操作
console.log(`⚠️ Lot mismatch: Expected stockInLineId=${expectedLot.stockInLineId}, Scanned stockInLineId=${scannedStockInLineId}`); console.log(`⚠️ Lot mismatch: Expected stockInLineId=${expectedLot.stockInLineId}, Scanned stockInLineId=${scannedStockInLineId}`);
@@ -1963,7 +1994,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
const setSelectedLotStartTime = performance.now(); const setSelectedLotStartTime = performance.now();
setSelectedLotForQr(expectedLot); setSelectedLotForQr(expectedLot);
const setSelectedLotTime = performance.now() - setSelectedLotStartTime; const setSelectedLotTime = performance.now() - setSelectedLotStartTime;
console.log(`⏱️ [PERF] Set selected lot time: ${setSelectedLotTime.toFixed(2)}ms`);
console.log(` [PERF] Set selected lot time: ${setSelectedLotTime.toFixed(2)}ms`);
// ✅ 获取扫描的 lot 信息(从 QR 数据中提取,或使用默认值) // ✅ 获取扫描的 lot 信息(从 QR 数据中提取,或使用默认值)
// Call handleLotMismatch immediately - it will open the modal // Call handleLotMismatch immediately - it will open the modal
@@ -1984,11 +2015,11 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
qrScanCountAtInvoke qrScanCountAtInvoke
); );
const handleMismatchTime = performance.now() - handleMismatchStartTime; const handleMismatchTime = performance.now() - handleMismatchStartTime;
console.log(`⏱️ [PERF] Handle mismatch call time: ${handleMismatchTime.toFixed(2)}ms`);
console.log(` [PERF] Handle mismatch call time: ${handleMismatchTime.toFixed(2)}ms`);
const totalTime = performance.now() - totalStartTime; const totalTime = performance.now() - totalStartTime;
console.log(`⚠️ [PROCESS OUTSIDE QR MISMATCH] Total time before modal: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`); console.log(`⚠️ [PROCESS OUTSIDE QR MISMATCH] Total time before modal: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
console.log(` End time: ${new Date().toISOString()}`);
console.log(` End time: ${new Date().toISOString()}`);
console.log(`📊 Breakdown: parse=${parseTime.toFixed(2)}ms, validation=${validationTime.toFixed(2)}ms, duplicateCheck=${duplicateCheckTime.toFixed(2)}ms, lookup=${lookupTime.toFixed(2)}ms, match=${matchTime.toFixed(2)}ms, mismatchCheck=${mismatchCheckTime.toFixed(2)}ms, expectedLot=${expectedLotTime.toFixed(2)}ms, setSelectedLot=${setSelectedLotTime.toFixed(2)}ms, handleMismatch=${handleMismatchTime.toFixed(2)}ms`); console.log(`📊 Breakdown: parse=${parseTime.toFixed(2)}ms, validation=${validationTime.toFixed(2)}ms, duplicateCheck=${duplicateCheckTime.toFixed(2)}ms, lookup=${lookupTime.toFixed(2)}ms, match=${matchTime.toFixed(2)}ms, mismatchCheck=${mismatchCheckTime.toFixed(2)}ms, expectedLot=${expectedLotTime.toFixed(2)}ms, setSelectedLot=${setSelectedLotTime.toFixed(2)}ms, handleMismatch=${handleMismatchTime.toFixed(2)}ms`);
} catch (error) { } catch (error) {
const totalTime = performance.now() - totalStartTime; const totalTime = performance.now() - totalStartTime;
@@ -2011,13 +2042,13 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
} }
const qrValuesChangeStartTime = performance.now(); const qrValuesChangeStartTime = performance.now();
console.log(`⏱️ [QR VALUES EFFECT] Triggered at: ${new Date().toISOString()}`);
console.log(`⏱️ [QR VALUES EFFECT] qrValues.length: ${qrValues.length}`);
console.log(`⏱️ [QR VALUES EFFECT] qrValues:`, qrValues);
console.log(` [QR VALUES EFFECT] Triggered at: ${new Date().toISOString()}`);
console.log(` [QR VALUES EFFECT] qrValues.length: ${qrValues.length}`);
console.log(` [QR VALUES EFFECT] qrValues:`, qrValues);
const latestQr = qrValues[qrValues.length - 1]; const latestQr = qrValues[qrValues.length - 1];
console.log(`⏱️ [QR VALUES EFFECT] Latest QR: ${latestQr}`);
console.log(` [QR VALUES EFFECT] Latest QR detected at: ${new Date().toISOString()}`);
console.log(` [QR VALUES EFFECT] Latest QR: ${latestQr}`);
console.log(` [QR VALUES EFFECT] Latest QR detected at: ${new Date().toISOString()}`);
// ✅ FIXED: Handle test shortcut {2fitestx,y} or {2fittestx,y} where x=itemId, y=stockInLineId // ✅ FIXED: Handle test shortcut {2fitestx,y} or {2fittestx,y} where x=itemId, y=stockInLineId
// Support both formats: {2fitest (2 t's) and {2fittest (3 t's) // Support both formats: {2fitest (2 t's) and {2fittest (3 t's)
@@ -2048,8 +2079,8 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
stockInLineId: stockInLineId stockInLineId: stockInLineId
}); });
console.log(`⏱️ [TEST QR] Simulated QR content: ${simulatedQr}`);
console.log(`⏱️ [TEST QR] Start time: ${new Date().toISOString()}`);
console.log(` [TEST QR] Simulated QR content: ${simulatedQr}`);
console.log(` [TEST QR] Start time: ${new Date().toISOString()}`);
const testStartTime = performance.now(); const testStartTime = performance.now();
// ✅ Mark as processed FIRST to avoid duplicate processing // ✅ Mark as processed FIRST to avoid duplicate processing
@@ -2068,8 +2099,8 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
if (processOutsideQrCodeRef.current) { if (processOutsideQrCodeRef.current) {
processOutsideQrCodeRef.current(simulatedQr, qrValues.length).then(() => { processOutsideQrCodeRef.current(simulatedQr, qrValues.length).then(() => {
const testTime = performance.now() - testStartTime; const testTime = performance.now() - testStartTime;
console.log(`⏱️ [TEST QR] Total processing time: ${testTime.toFixed(2)}ms (${(testTime / 1000).toFixed(3)}s)`);
console.log(`⏱️ [TEST QR] End time: ${new Date().toISOString()}`);
console.log(` [TEST QR] Total processing time: ${testTime.toFixed(2)}ms (${(testTime / 1000).toFixed(3)}s)`);
console.log(` [TEST QR] End time: ${new Date().toISOString()}`);
}).catch((error) => { }).catch((error) => {
const testTime = performance.now() - testStartTime; const testTime = performance.now() - testStartTime;
console.error(`❌ [TEST QR] Error after ${testTime.toFixed(2)}ms:`, error); console.error(`❌ [TEST QR] Error after ${testTime.toFixed(2)}ms:`, error);
@@ -2082,13 +2113,13 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
} }
const qrValuesChangeTime = performance.now() - qrValuesChangeStartTime; const qrValuesChangeTime = performance.now() - qrValuesChangeStartTime;
console.log(`⏱️ [QR VALUES EFFECT] Test QR handling time: ${qrValuesChangeTime.toFixed(2)}ms`);
console.log(` [QR VALUES EFFECT] Test QR handling time: ${qrValuesChangeTime.toFixed(2)}ms`);
return; // ✅ IMPORTANT: Return early to prevent normal processing return; // ✅ IMPORTANT: Return early to prevent normal processing
} else { } else {
console.warn(`⏱️ [TEST QR] Invalid itemId or stockInLineId: itemId=${parts[0]}, stockInLineId=${parts[1]}`);
console.warn(` [TEST QR] Invalid itemId or stockInLineId: itemId=${parts[0]}, stockInLineId=${parts[1]}`);
} }
} else { } else {
console.warn(`⏱️ [TEST QR] Invalid format. Expected {2fitestx,y} or {2fittestx,y}, got: ${latestQr}`);
console.warn(` [TEST QR] Invalid format. Expected {2fitestx,y} or {2fittestx,y}, got: ${latestQr}`);
} }
} }
@@ -2118,23 +2149,23 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
// Check if this is a different QR code than what triggered the modal // Check if this is a different QR code than what triggered the modal
const modalTriggerQr = lastProcessedQrRef.current; const modalTriggerQr = lastProcessedQrRef.current;
if (latestQr === modalTriggerQr) { if (latestQr === modalTriggerQr) {
console.log(`⏱️ [QR PROCESS] Skipping - manual modal open for same QR`);
console.log(` [QR PROCESS] Skipping - manual modal open for same QR`);
return; return;
} }
// If it's a different QR, allow processing // If it's a different QR, allow processing
console.log(`⏱️ [QR PROCESS] Different QR detected while manual modal open, allowing processing`);
console.log(` [QR PROCESS] Different QR detected while manual modal open, allowing processing`);
} }
const qrDetectionStartTime = performance.now(); const qrDetectionStartTime = performance.now();
console.log(`⏱️ [QR DETECTION] Latest QR detected: ${latestQr?.substring(0, 50)}...`);
console.log(` [QR DETECTION] Detection time: ${new Date().toISOString()}`);
console.log(`⏱️ [QR DETECTION] Time since QR scanner set value: ${(qrDetectionStartTime - qrValuesChangeStartTime).toFixed(2)}ms`);
console.log(` [QR DETECTION] Latest QR detected: ${latestQr?.substring(0, 50)}...`);
console.log(` [QR DETECTION] Detection time: ${new Date().toISOString()}`);
console.log(` [QR DETECTION] Time since QR scanner set value: ${(qrDetectionStartTime - qrValuesChangeStartTime).toFixed(2)}ms`);
// Skip if already processed (use refs to avoid dependency issues and delays) // Skip if already processed (use refs to avoid dependency issues and delays)
const checkProcessedStartTime = performance.now(); const checkProcessedStartTime = performance.now();
if (processedQrCodesRef.current.has(latestQr) || lastProcessedQrRef.current === latestQr) { if (processedQrCodesRef.current.has(latestQr) || lastProcessedQrRef.current === latestQr) {
const checkTime = performance.now() - checkProcessedStartTime; const checkTime = performance.now() - checkProcessedStartTime;
console.log(`⏱️ [QR PROCESS] Already processed check time: ${checkTime.toFixed(2)}ms`);
console.log(` [QR PROCESS] Already processed check time: ${checkTime.toFixed(2)}ms`);
return; return;
} }
const checkTime = performance.now() - checkProcessedStartTime; const checkTime = performance.now() - checkProcessedStartTime;
@@ -2174,8 +2205,8 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
// Check against refs to avoid state update delays // Check against refs to avoid state update delays
if (latestQr && latestQr !== lastProcessedQrRef.current) { if (latestQr && latestQr !== lastProcessedQrRef.current) {
const processingStartTime = performance.now(); const processingStartTime = performance.now();
console.log(`⏱️ [QR PROCESS] Starting processing at: ${new Date().toISOString()}`);
console.log(`⏱️ [QR PROCESS] Time since detection: ${(processingStartTime - qrDetectionStartTime).toFixed(2)}ms`);
console.log(` [QR PROCESS] Starting processing at: ${new Date().toISOString()}`);
console.log(` [QR PROCESS] Time since detection: ${(processingStartTime - qrDetectionStartTime).toFixed(2)}ms`);
// ✅ Process immediately for better responsiveness // ✅ Process immediately for better responsiveness
// Clear any pending debounced processing // Clear any pending debounced processing
@@ -2185,7 +2216,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
} }
// Log immediately (console.log is synchronous) // Log immediately (console.log is synchronous)
console.log(`⏱️ [QR PROCESS] Processing new QR code with enhanced validation: ${latestQr}`);
console.log(` [QR PROCESS] Processing new QR code with enhanced validation: ${latestQr}`);
// Update refs immediately (no state update delay) - do this FIRST // Update refs immediately (no state update delay) - do this FIRST
const refUpdateStartTime = performance.now(); const refUpdateStartTime = performance.now();
@@ -2198,7 +2229,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
} }
} }
const refUpdateTime = performance.now() - refUpdateStartTime; const refUpdateTime = performance.now() - refUpdateStartTime;
console.log(`⏱️ [QR PROCESS] Ref update time: ${refUpdateTime.toFixed(2)}ms`);
console.log(` [QR PROCESS] Ref update time: ${refUpdateTime.toFixed(2)}ms`);
// Process immediately in background - no modal/form needed, no delays // Process immediately in background - no modal/form needed, no delays
// Use ref to avoid dependency issues // Use ref to avoid dependency issues
@@ -2207,8 +2238,8 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
processOutsideQrCodeRef.current(latestQr, qrValues.length).then(() => { processOutsideQrCodeRef.current(latestQr, qrValues.length).then(() => {
const processCallTime = performance.now() - processCallStartTime; const processCallTime = performance.now() - processCallStartTime;
const totalProcessingTime = performance.now() - processingStartTime; const totalProcessingTime = performance.now() - processingStartTime;
console.log(`⏱️ [QR PROCESS] processOutsideQrCode call time: ${processCallTime.toFixed(2)}ms`);
console.log(`⏱️ [QR PROCESS] Total processing time: ${totalProcessingTime.toFixed(2)}ms (${(totalProcessingTime / 1000).toFixed(3)}s)`);
console.log(` [QR PROCESS] processOutsideQrCode call time: ${processCallTime.toFixed(2)}ms`);
console.log(` [QR PROCESS] Total processing time: ${totalProcessingTime.toFixed(2)}ms (${(totalProcessingTime / 1000).toFixed(3)}s)`);
}).catch((error) => { }).catch((error) => {
const processCallTime = performance.now() - processCallStartTime; const processCallTime = performance.now() - processCallStartTime;
const totalProcessingTime = performance.now() - processingStartTime; const totalProcessingTime = performance.now() - processingStartTime;
@@ -2222,12 +2253,12 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
setLastProcessedQr(latestQr); setLastProcessedQr(latestQr);
setProcessedQrCodes(new Set(processedQrCodesRef.current)); setProcessedQrCodes(new Set(processedQrCodesRef.current));
const stateUpdateTime = performance.now() - stateUpdateStartTime; const stateUpdateTime = performance.now() - stateUpdateStartTime;
console.log(`⏱️ [QR PROCESS] State update time: ${stateUpdateTime.toFixed(2)}ms`);
console.log(` [QR PROCESS] State update time: ${stateUpdateTime.toFixed(2)}ms`);
const detectionTime = performance.now() - qrDetectionStartTime; const detectionTime = performance.now() - qrDetectionStartTime;
const totalEffectTime = performance.now() - qrValuesChangeStartTime; const totalEffectTime = performance.now() - qrValuesChangeStartTime;
console.log(`⏱️ [QR DETECTION] Total detection time: ${detectionTime.toFixed(2)}ms`);
console.log(`⏱️ [QR VALUES EFFECT] Total effect time: ${totalEffectTime.toFixed(2)}ms`);
console.log(` [QR DETECTION] Total detection time: ${detectionTime.toFixed(2)}ms`);
console.log(` [QR VALUES EFFECT] Total effect time: ${totalEffectTime.toFixed(2)}ms`);
} }
return () => { return () => {
@@ -2248,7 +2279,7 @@ useEffect(() => {
if (renderStartTimeRef.current !== null) { if (renderStartTimeRef.current !== null) {
const renderTime = now - renderStartTimeRef.current; const renderTime = now - renderStartTimeRef.current;
if (renderTime > 100) { // Only log slow renders (>100ms) if (renderTime > 100) { // Only log slow renders (>100ms)
console.log(`⏱️ [PERF] Render #${renderCountRef.current} took ${renderTime.toFixed(2)}ms, combinedLotData length: ${combinedLotData.length}`);
console.log(` [PERF] Render #${renderCountRef.current} took ${renderTime.toFixed(2)}ms, combinedLotData length: ${combinedLotData.length}`);
} }
renderStartTimeRef.current = null; renderStartTimeRef.current = null;
} }
@@ -2256,7 +2287,7 @@ useEffect(() => {
// Track when lotConfirmationOpen changes // Track when lotConfirmationOpen changes
if (lotConfirmationOpen) { if (lotConfirmationOpen) {
renderStartTimeRef.current = performance.now(); renderStartTimeRef.current = performance.now();
console.log(`⏱️ [PERF] Render triggered by lotConfirmationOpen=true`);
console.log(` [PERF] Render triggered by lotConfirmationOpen=true`);
} }
}, [combinedLotData.length, lotConfirmationOpen]); }, [combinedLotData.length, lotConfirmationOpen]);
// Auto-start scanner only once on mount // Auto-start scanner only once on mount
@@ -2719,12 +2750,12 @@ useEffect(() => {
}, [hasPendingBatchSubmit]); }, [hasPendingBatchSubmit]);
const handleStartScan = useCallback(() => { const handleStartScan = useCallback(() => {
const startTime = performance.now(); const startTime = performance.now();
console.log(`⏱️ [START SCAN] Called at: ${new Date().toISOString()}`);
console.log(`⏱️ [START SCAN] Starting manual QR scan...`);
console.log(` [START SCAN] Called at: ${new Date().toISOString()}`);
console.log(` [START SCAN] Starting manual QR scan...`);
setIsManualScanning(true); setIsManualScanning(true);
const setManualScanningTime = performance.now() - startTime; const setManualScanningTime = performance.now() - startTime;
console.log(`⏱️ [START SCAN] setManualScanning time: ${setManualScanningTime.toFixed(2)}ms`);
console.log(` [START SCAN] setManualScanning time: ${setManualScanningTime.toFixed(2)}ms`);
setProcessedQrCodes(new Set()); setProcessedQrCodes(new Set());
setLastProcessedQr(''); setLastProcessedQr('');
@@ -2734,11 +2765,11 @@ const handleStartScan = useCallback(() => {
const beforeStartScanTime = performance.now(); const beforeStartScanTime = performance.now();
startScan(); startScan();
const startScanTime = performance.now() - beforeStartScanTime; const startScanTime = performance.now() - beforeStartScanTime;
console.log(`⏱️ [START SCAN] startScan() call time: ${startScanTime.toFixed(2)}ms`);
console.log(` [START SCAN] startScan() call time: ${startScanTime.toFixed(2)}ms`);
const totalTime = performance.now() - startTime; const totalTime = performance.now() - startTime;
console.log(`⏱️ [START SCAN] Total start scan time: ${totalTime.toFixed(2)}ms`);
console.log(` [START SCAN] Start scan completed at: ${new Date().toISOString()}`);
console.log(` [START SCAN] Total start scan time: ${totalTime.toFixed(2)}ms`);
console.log(` [START SCAN] Start scan completed at: ${new Date().toISOString()}`);
}, [startScan]); }, [startScan]);
const handlePickOrderSwitch = useCallback(async (pickOrderId: number) => { const handlePickOrderSwitch = useCallback(async (pickOrderId: number) => {
if (pickOrderSwitching) return; if (pickOrderSwitching) return;
@@ -2835,8 +2866,8 @@ const handleStartScan = useCallback(() => {
}, [fetchAllCombinedLotData, session, currentUserId, fgPickOrders, actionBusyBySolId]); }, [fetchAllCombinedLotData, session, currentUserId, fgPickOrders, actionBusyBySolId]);
const handleBatchScan = useCallback(async () => { const handleBatchScan = useCallback(async () => {
const startTime = performance.now(); const startTime = performance.now();
console.log(`⏱️ [BATCH SCAN START]`);
console.log(` Start time: ${new Date().toISOString()}`);
console.log(` [BATCH SCAN START]`);
console.log(` Start time: ${new Date().toISOString()}`);
// 获取所有活跃批次(未扫描的) // 获取所有活跃批次(未扫描的)
const activeLots = combinedLotData.filter(lot => { const activeLots = combinedLotData.filter(lot => {
@@ -2884,19 +2915,19 @@ const handleStartScan = useCallback(() => {
const result = await batchScan(request); const result = await batchScan(request);
const scanTime = performance.now() - scanStartTime; const scanTime = performance.now() - scanStartTime;
console.log(`⏱️ Batch scan API call completed in ${scanTime.toFixed(2)}ms (${(scanTime / 1000).toFixed(3)}s)`);
console.log(` Batch scan API call completed in ${scanTime.toFixed(2)}ms (${(scanTime / 1000).toFixed(3)}s)`);
console.log(`📥 Batch scan result:`, result); console.log(`📥 Batch scan result:`, result);
// ✅ 刷新数据以获取最新的状态 // ✅ 刷新数据以获取最新的状态
const refreshStartTime = performance.now(); const refreshStartTime = performance.now();
await fetchAllCombinedLotData(); await fetchAllCombinedLotData();
const refreshTime = performance.now() - refreshStartTime; const refreshTime = performance.now() - refreshStartTime;
console.log(`⏱️ Data refresh time: ${refreshTime.toFixed(2)}ms (${(refreshTime / 1000).toFixed(3)}s)`);
console.log(` Data refresh time: ${refreshTime.toFixed(2)}ms (${(refreshTime / 1000).toFixed(3)}s)`);
const totalTime = performance.now() - startTime; const totalTime = performance.now() - startTime;
console.log(`⏱️ [BATCH SCAN END]`);
console.log(`⏱️ Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
console.log(` End time: ${new Date().toISOString()}`);
console.log(` [BATCH SCAN END]`);
console.log(` Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
console.log(` End time: ${new Date().toISOString()}`);
if (result && result.code === "SUCCESS") { if (result && result.code === "SUCCESS") {
setQrScanSuccess(true); setQrScanSuccess(true);
@@ -2915,8 +2946,8 @@ const handleStartScan = useCallback(() => {
}, [combinedLotData, fetchAllCombinedLotData, currentUserId]); }, [combinedLotData, fetchAllCombinedLotData, currentUserId]);
const handleSubmitAllScanned = useCallback(async () => { const handleSubmitAllScanned = useCallback(async () => {
const startTime = performance.now(); const startTime = performance.now();
console.log(`⏱️ [BATCH SUBMIT START]`);
console.log(` Start time: ${new Date().toISOString()}`);
console.log(` [BATCH SUBMIT START]`);
console.log(` Start time: ${new Date().toISOString()}`);
const scannedLots = combinedLotData.filter(lot => { const scannedLots = combinedLotData.filter(lot => {
const status = lot.stockOutLineStatus; const status = lot.stockOutLineStatus;
@@ -3011,19 +3042,19 @@ const handleSubmitAllScanned = useCallback(async () => {
const result = await batchSubmitList(request); const result = await batchSubmitList(request);
const submitTime = performance.now() - submitStartTime; const submitTime = performance.now() - submitStartTime;
console.log(`⏱️ Batch submit API call completed in ${submitTime.toFixed(2)}ms (${(submitTime / 1000).toFixed(3)}s)`);
console.log(` Batch submit API call completed in ${submitTime.toFixed(2)}ms (${(submitTime / 1000).toFixed(3)}s)`);
console.log(`📥 Batch submit result:`, result); console.log(`📥 Batch submit result:`, result);
// Refresh data once after batch submission // Refresh data once after batch submission
const refreshStartTime = performance.now(); const refreshStartTime = performance.now();
await fetchAllCombinedLotData(); await fetchAllCombinedLotData();
const refreshTime = performance.now() - refreshStartTime; const refreshTime = performance.now() - refreshStartTime;
console.log(`⏱️ Data refresh time: ${refreshTime.toFixed(2)}ms (${(refreshTime / 1000).toFixed(3)}s)`);
console.log(` Data refresh time: ${refreshTime.toFixed(2)}ms (${(refreshTime / 1000).toFixed(3)}s)`);
const totalTime = performance.now() - startTime; 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()}`);
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 (result && result.code === "SUCCESS") { if (result && result.code === "SUCCESS") {
setQrScanSuccess(true); setQrScanSuccess(true);
@@ -3380,16 +3411,31 @@ paginatedData.map((lot, index) => {
<TableCell>{lot.itemCode}</TableCell> <TableCell>{lot.itemCode}</TableCell>
<TableCell>{lot.itemName + '(' + lot.stockUnit + ')'}</TableCell> <TableCell>{lot.itemName + '(' + lot.stockUnit + ')'}</TableCell>
<TableCell> <TableCell>
<Box>
<Typography
sx={{
// color: isIssueLot ? 'warning.main' : lot.lotAvailability === 'rejected' ? 'text.disabled' : 'inherit',
}}
>
{lot.lotNo ||
t('Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.')}
</Typography>
</Box>
<Box>
<Typography
sx={{
color:
lot.lotAvailability === 'expired'
? 'warning.main'
: /* isIssueLot ? 'warning.main' : lot.lotAvailability === 'rejected' ? 'text.disabled' : */ 'inherit',
}}
>
{lot.lotNo ? (
lot.lotAvailability === 'expired' ? (
<>
{lot.lotNo}{' '}
{t('is expired. Please check around have available QR code or not.')}
</>
) : (
lot.lotNo
)
) : (
t(
'Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.'
)
)}
</Typography>
</Box>
</TableCell> </TableCell>
<TableCell align="right"> <TableCell align="right">
{(() => { {(() => {
@@ -3568,6 +3614,7 @@ paginatedData.map((lot, index) => {
lot.stockOutLineStatus === 'completed' || lot.stockOutLineStatus === 'completed' ||
lot.stockOutLineStatus === 'checked' || lot.stockOutLineStatus === 'checked' ||
lot.stockOutLineStatus === 'partially_completed' || lot.stockOutLineStatus === 'partially_completed' ||
lot.lotAvailability === 'expired' ||


// 使用 issue form 後,禁用「Just Completed」(避免再次点击造成重复提交) // 使用 issue form 後,禁用「Just Completed」(避免再次点击造成重复提交)
(Number(lot.stockOutLineId) > 0 && issuePickedQtyBySolId[Number(lot.stockOutLineId)] !== undefined) || (Number(lot.stockOutLineId) > 0 && issuePickedQtyBySolId[Number(lot.stockOutLineId)] !== undefined) ||
@@ -3622,7 +3669,7 @@ paginatedData.map((lot, index) => {
<LotConfirmationModal <LotConfirmationModal
open={lotConfirmationOpen} open={lotConfirmationOpen}
onClose={() => { onClose={() => {
console.log(`⏱️ [LOT CONFIRM MODAL] Closing modal, clearing state`);
console.log(` [LOT CONFIRM MODAL] Closing modal, clearing state`);
clearLotConfirmationState(true); clearLotConfirmationState(true);
}} }}
onConfirm={handleLotConfirmation} onConfirm={handleLotConfirmation}


+ 2
- 6
src/components/PoDetail/PoDetail.tsx Ver fichero

@@ -456,11 +456,6 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => {
alert("來貨數量必須大於0!"); alert("來貨數量必須大於0!");
return; return;
} }
if (!Number.isInteger(acceptedQty)) {
alert("來貨數量必須是整數(不能有小數)!");
return;
}
const doSubmit = () => { const doSubmit = () => {
setTimeout(async () => { setTimeout(async () => {
const currentDnNo = dnFormProps.watch("dnNo"); const currentDnNo = dnFormProps.watch("dnNo");
@@ -622,7 +617,8 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => {
InputProps={{ InputProps={{
inputProps: { inputProps: {
min: 0, // Optional: set a minimum value min: 0, // Optional: set a minimum value
step: 1 // Optional: set the step for the number input
step: "any",
inputMode: "decimal",
} }
}} }}
/> />


+ 2
- 1
src/i18n/zh/pickOrder.json Ver fichero

@@ -50,7 +50,8 @@
"Delivery Order": "送貨單", "Delivery Order": "送貨單",
"items": "項目", "items": "項目",
"Select Pick Order:": "選擇提料單:", "Select Pick Order:": "選擇提料單:",
"⚠️ No Stock Available": "⚠️ 沒有庫存",
"No Stock Available": "沒有庫存",
"is expired. Please check around have available QR code or not.": "已過期。請檢查周圍是否有可用的 QR 碼。",
"Start Fail": "開始失敗", "Start Fail": "開始失敗",
"Start PO": "開始採購訂單", "Start PO": "開始採購訂單",
"Do you want to complete?": "確定完成嗎?", "Do you want to complete?": "確定完成嗎?",


Cargando…
Cancelar
Guardar