Bläddra i källkod

update qr code scan

MergeProblem1
CANCERYS\kw093 1 vecka sedan
förälder
incheckning
55d9e24f83
1 ändrade filer med 170 tillägg och 44 borttagningar
  1. +170
    -44
      src/components/QrCodeScannerProvider/QrCodeScannerProvider.tsx

+ 170
- 44
src/components/QrCodeScannerProvider/QrCodeScannerProvider.tsx Visa fil

@@ -1,5 +1,6 @@
"use client";
import { QrCodeInfo } from "@/app/api/qrcode";
import { useRef } from "react";
import {
ReactNode,
createContext,
@@ -7,6 +8,7 @@ import {
useContext,
useEffect,
useState,
startTransition,
} from "react";

export interface QrCodeScanner {
@@ -39,6 +41,10 @@ const QrCodeScannerProvider: React.FC<QrCodeScannerProviderProps> = ({
const [scanResult, setScanResult] = useState<QrCodeInfo | undefined>()
const [scanState, setScanState] = useState<"scanning" | "pending" | "retry">("pending");
const [scanError, setScanError] = useState<string | undefined>() // TODO return scan error message
const keysRef = useRef<string[]>([]);
const leftBraceCountRef = useRef<number>(0);
const rightBraceCountRef = useRef<number>(0);
const isFirstKeyRef = useRef<boolean>(true);

const resetScannerInput = useCallback(() => {
setKeys(() => []);
@@ -61,10 +67,22 @@ const QrCodeScannerProvider: React.FC<QrCodeScannerProviderProps> = ({
}, []);

const startQrCodeScanner = useCallback(() => {
const startTime = performance.now();
console.log(`⏱️ [SCANNER START] Called at: ${new Date().toISOString()}`);
resetQrCodeScanner();
const resetTime = performance.now() - startTime;
console.log(`⏱️ [SCANNER START] Reset time: ${resetTime.toFixed(2)}ms`);
setIsScanning(() => true);
console.log("%c Scanning started ", "color:cyan");
}, []);
const setScanningTime = performance.now() - startTime;
console.log(`⏱️ [SCANNER START] setScanning time: ${setScanningTime.toFixed(2)}ms`);
const totalTime = performance.now() - startTime;
console.log(`%c Scanning started `, "color:cyan");
console.log(`⏱️ [SCANNER START] Total start time: ${totalTime.toFixed(2)}ms`);
console.log(`⏰ [SCANNER START] Scanner started at: ${new Date().toISOString()}`);
}, [resetQrCodeScanner]);

const endQrCodeScanner = useCallback(() => {
setIsScanning(() => false);
@@ -107,65 +125,154 @@ const QrCodeScannerProvider: React.FC<QrCodeScannerProviderProps> = ({
return result;
};

// Check the KeyDown
useEffect(() => {
const effectStartTime = performance.now();
console.log(`⏱️ [KEYBOARD LISTENER EFFECT] Triggered at: ${new Date().toISOString()}`);
console.log(`⏱️ [KEYBOARD LISTENER EFFECT] isScanning: ${isScanning}`);
if (isScanning) {
const listenerRegisterStartTime = performance.now();
console.log(`⏱️ [KEYBOARD LISTENER] Registering keyboard listener at: ${new Date().toISOString()}`);
// Reset refs when starting scan
keysRef.current = [];
leftBraceCountRef.current = 0;
rightBraceCountRef.current = 0;
isFirstKeyRef.current = true;
const handleKeyDown = (event: KeyboardEvent) => {
const keyPressTime = performance.now();
const keyPressTimestamp = new Date().toISOString();
// ✅ OPTIMIZED: Use refs to accumulate keys immediately (no state update delay)
if (event.key.length === 1) {
setKeys((key) => [...key, event.key]);
if (isFirstKeyRef.current) {
console.log(`⏱️ [KEYBOARD] First key press detected: "${event.key}"`);
console.log(`⏰ [KEYBOARD] First key press at: ${keyPressTimestamp}`);
console.log(`⏱️ [KEYBOARD] Time since listener registered: ${(keyPressTime - listenerRegisterStartTime).toFixed(2)}ms`);
isFirstKeyRef.current = false;
}
keysRef.current.push(event.key);
}

if (event.key === "{") {
setLeftCurlyBraceCount((count) => count + 1);
const braceTime = performance.now();
console.log(`⏱️ [KEYBOARD] Left brace "{" detected at: ${new Date().toISOString()}`);
console.log(`⏱️ [KEYBOARD] Time since listener registered: ${(braceTime - listenerRegisterStartTime).toFixed(2)}ms`);
leftBraceCountRef.current += 1;
} else if (event.key === "}") {
setRightCurlyBraceCount((count) => count + 1);
const braceTime = performance.now();
console.log(`⏱️ [KEYBOARD] Right brace "}" detected at: ${new Date().toISOString()}`);
console.log(`⏱️ [KEYBOARD] Time since listener registered: ${(braceTime - listenerRegisterStartTime).toFixed(2)}ms`);
rightBraceCountRef.current += 1;
// ✅ OPTIMIZED: Check for complete QR immediately and update state only once
if (leftBraceCountRef.current === rightBraceCountRef.current && leftBraceCountRef.current > 0) {
const completeTime = performance.now();
console.log(`⏱️ [KEYBOARD] Complete QR detected immediately! Time: ${completeTime.toFixed(2)}ms`);
console.log(`⏰ [KEYBOARD] Complete QR at: ${new Date().toISOString()}`);
const qrValue = keysRef.current.join("").substring(
keysRef.current.indexOf("{"),
keysRef.current.lastIndexOf("}") + 1
);
console.log(`⏱️ [KEYBOARD] QR value: ${qrValue}`);
// ✅ TABLET OPTIMIZATION: Directly set qrCodeScannerValues without any state chain
// Use flushSync for immediate update on tablets (if available, otherwise use regular setState)
setQrCodeScannerValues((value) => {
console.log(`⏱️ [KEYBOARD] Setting qrCodeScannerValues directly: ${qrValue}`);
return [...value, qrValue];
});
// Reset scanner input immediately (using refs, no state update)
keysRef.current = [];
leftBraceCountRef.current = 0;
rightBraceCountRef.current = 0;
isFirstKeyRef.current = true;
// ✅ TABLET OPTIMIZATION: Defer all cleanup state updates to avoid blocking
// Use setTimeout to ensure QR processing happens first
setTimeout(() => {
startTransition(() => {
setKeys([]);
setLeftCurlyBraceCount(0);
setRightCurlyBraceCount(0);
setScanState("pending");
resetScannerInput();
});
}, 0);
return;
}
}
// ✅ TABLET OPTIMIZATION: Completely skip state updates during scanning
// Only update state for the first brace detection (for UI feedback)
// All other updates are deferred to avoid blocking on tablets
if (leftBraceCountRef.current === 1 && keysRef.current.length === 1 && event.key === "{") {
// Only update state once when first brace is detected
startTransition(() => {
setKeys([...keysRef.current]);
setLeftCurlyBraceCount(leftBraceCountRef.current);
setRightCurlyBraceCount(rightBraceCountRef.current);
});
}
// Skip all other state updates during scanning to maximize performance on tablets
};

document.addEventListener("keydown", handleKeyDown);

const listenerRegisterTime = performance.now() - listenerRegisterStartTime;
console.log(`⏱️ [KEYBOARD LISTENER] Listener registered in: ${listenerRegisterTime.toFixed(2)}ms`);
console.log(`⏰ [KEYBOARD LISTENER] Listener ready at: ${new Date().toISOString()}`);
return () => {
console.log(`⏱️ [KEYBOARD LISTENER] Removing keyboard listener at: ${new Date().toISOString()}`);
document.removeEventListener("keydown", handleKeyDown);
};
} else {
console.log(`⏱️ [KEYBOARD LISTENER EFFECT] Scanner not active, skipping listener registration`);
}
const effectTime = performance.now() - effectStartTime;
console.log(`⏱️ [KEYBOARD LISTENER EFFECT] Total effect time: ${effectTime.toFixed(2)}ms`);
}, [isScanning]);

// Update Qr Code Scanner Values
useEffect(() => {
if (rightCurlyBraceCount > leftCurlyBraceCount || leftCurlyBraceCount > 1) { // Prevent multiple scan
setScanState("retry");
setScanError("Too many scans at once");
resetQrCodeScanner("Too many scans at once");
} else {
if (leftCurlyBraceCount == 1 && keys.length == 1)
{
setScanState("scanning");
console.log("%c Scan detected, waiting for inputs...", "color:cyan");
}
if (
leftCurlyBraceCount !== 0 &&
rightCurlyBraceCount !== 0 &&
leftCurlyBraceCount === rightCurlyBraceCount
) {
const startBrace = keys.indexOf("{");
const endBrace = keys.lastIndexOf("}");
setScanState("pending");
setQrCodeScannerValues((value) => [
...value,
keys.join("").substring(startBrace, endBrace + 1),
]);
// console.log(keys);
// console.log("%c QR Scanner Values:", "color:cyan", qrCodeScannerValues);
// ✅ OPTIMIZED: Simplify the QR scanner effect - it's now mainly for initial detection
useEffect(() => {
const effectStartTime = performance.now();
console.log(`⏱️ [QR SCANNER EFFECT] Triggered at: ${new Date().toISOString()}`);
console.log(`⏱️ [QR SCANNER EFFECT] Keys count: ${keys.length}, leftBrace: ${leftCurlyBraceCount}, rightBrace: ${rightCurlyBraceCount}`);
resetScannerInput();
if (rightCurlyBraceCount > leftCurlyBraceCount || leftCurlyBraceCount > 1) { // Prevent multiple scan
setScanState("retry");
setScanError("Too many scans at once");
resetQrCodeScanner("Too many scans at once");
} else {
// Only show "scanning" state when first brace is detected
if (leftCurlyBraceCount == 1 && keys.length == 1)
{
const scanDetectedTime = performance.now();
setScanState("scanning");
console.log(`%c Scan detected, waiting for inputs...`, "color:cyan");
console.log(`⏱️ [QR SCANNER] Scan detected time: ${scanDetectedTime.toFixed(2)}ms`);
console.log(`⏰ [QR SCANNER] Scan detected at: ${new Date().toISOString()}`);
}
}
}, [keys, leftCurlyBraceCount, rightCurlyBraceCount]);

// Note: Complete QR detection is now handled directly in handleKeyDown
// This effect is mainly for UI feedback and error handling
}
}, [keys, leftCurlyBraceCount, rightCurlyBraceCount]);
useEffect(() => {
if (qrCodeScannerValues.length > 0) {
const processStartTime = performance.now();
console.log(`⏱️ [QR SCANNER PROCESS] Processing qrCodeScannerValues at: ${new Date().toISOString()}`);
console.log(`⏱️ [QR SCANNER PROCESS] Values count: ${qrCodeScannerValues.length}`);
const scannedValues = qrCodeScannerValues[0];
console.log("%c Scanned Result: ", "color:cyan", scannedValues);
console.log(`%c Scanned Result: `, "color:cyan", scannedValues);
console.log(`⏱️ [QR SCANNER PROCESS] Scanned value: ${scannedValues}`);
console.log(`⏰ [QR SCANNER PROCESS] Processing at: ${new Date().toISOString()}`);
if (scannedValues.substring(0, 8) == "{2fitest") { // DEBUGGING
// 先检查是否是 {2fiteste...} 或 {2fitestu...} 格式
@@ -174,11 +281,13 @@ const QrCodeScannerProvider: React.FC<QrCodeScannerProviderProps> = ({
const ninthChar = scannedValues.substring(8, 9);
if (ninthChar === "e" || ninthChar === "u") {
// {2fiteste数字} 或 {2fitestu任何内容} 格式
console.log("%c DEBUG: detected shortcut format: ", "color:pink", scannedValues);
console.log(`%c DEBUG: detected shortcut format: `, "color:pink", scannedValues);
const debugValue = {
value: scannedValues // 传递完整值,让 processQrCode 处理
}
setScanResult(debugValue);
const processTime = performance.now() - processStartTime;
console.log(`⏱️ [QR SCANNER PROCESS] Shortcut processing time: ${processTime.toFixed(2)}ms`);
return;
}
}
@@ -186,30 +295,47 @@ const QrCodeScannerProvider: React.FC<QrCodeScannerProviderProps> = ({
// 原有的 {2fitest数字} 格式(纯数字,向后兼容)
const number = scannedValues.substring(8, scannedValues.length - 1);
if (/^\d+$/.test(number)) { // Check if number contains only digits
console.log("%c DEBUG: detected ID: ", "color:pink", number);
console.log(`%c DEBUG: detected ID: `, "color:pink", number);
const debugValue = {
value: number
}
setScanResult(debugValue);
const processTime = performance.now() - processStartTime;
console.log(`⏱️ [QR SCANNER PROCESS] ID processing time: ${processTime.toFixed(2)}ms`);
return;
} else {
// 如果不是纯数字,传递完整值让 processQrCode 处理
const debugValue = {
value: scannedValues
}
setScanResult(debugValue);
const processTime = performance.now() - processStartTime;
console.log(`⏱️ [QR SCANNER PROCESS] Non-numeric processing time: ${processTime.toFixed(2)}ms`);
return;
}
return;
}
try {
const parseStartTime = performance.now();
const data: QrCodeInfo = JSON.parse(scannedValues);
console.log("%c Parsed scan data", "color:green", data);
const parseTime = performance.now() - parseStartTime;
console.log(`%c Parsed scan data`, "color:green", data);
console.log(`⏱️ [QR SCANNER PROCESS] JSON parse time: ${parseTime.toFixed(2)}ms`);
const content = scannedValues.substring(1, scannedValues.length - 1);
data.value = content;
const setResultStartTime = performance.now();
setScanResult(data);
const setResultTime = performance.now() - setResultStartTime;
console.log(`⏱️ [QR SCANNER PROCESS] setScanResult time: ${setResultTime.toFixed(2)}ms`);
console.log(`⏰ [QR SCANNER PROCESS] setScanResult at: ${new Date().toISOString()}`);
const processTime = performance.now() - processStartTime;
console.log(`⏱️ [QR SCANNER PROCESS] Total processing time: ${processTime.toFixed(2)}ms`);
} catch (error) { // Rough match for other scanner input -- Pending Review
console.log(`⏱️ [QR SCANNER PROCESS] JSON parse failed, trying rough match`);
const silId = findIdByRoughMatch(scannedValues, "StockInLine").number ?? 0;
if (silId == 0) {


Laddar…
Avbryt
Spara