diff --git a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx
index 0d407fb..6ad335c 100644
--- a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx
+++ b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx
@@ -19,6 +19,7 @@ import {
TablePagination,
Modal,
} from "@mui/material";
+import TestQrCodeProvider from '../QrCodeScannerProvider/TestQrCodeProvider';
import { fetchLotDetail } from "@/app/api/inventory/actions";
import { useCallback, useEffect, useState, useRef, useMemo } from "react";
import { useTranslation } from "react-i18next";
@@ -1481,6 +1482,15 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe
}
}, [t]);
return (
+ (
+ lot.lotAvailability !== 'rejected' &&
+ lot.stockOutLineStatus !== 'rejected' &&
+ lot.stockOutLineStatus !== 'completed'
+ )}
+ >
@@ -1837,6 +1847,7 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe
/>
)}
+
);
};
diff --git a/src/components/Jodetail/JobPickExecution.tsx b/src/components/Jodetail/JobPickExecution.tsx
index a1917c3..f79fb32 100644
--- a/src/components/Jodetail/JobPickExecution.tsx
+++ b/src/components/Jodetail/JobPickExecution.tsx
@@ -19,6 +19,7 @@ import {
TablePagination,
Modal,
} from "@mui/material";
+import TestQrCodeProvider from '../QrCodeScannerProvider/TestQrCodeProvider';
import { useCallback, useEffect, useState, useRef, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/navigation";
@@ -1543,6 +1544,15 @@ const JobPickExecution: React.FC = ({ filterArgs }) => {
}, [t]);
return (
+ (
+ lot.lotAvailability !== 'rejected' &&
+ lot.stockOutLineStatus !== 'rejected' &&
+ lot.stockOutLineStatus !== 'completed'
+ )}
+ >
{/* Job Order Header */}
@@ -1858,6 +1868,7 @@ const JobPickExecution: React.FC = ({ filterArgs }) => {
/>
)}
+
);
};
diff --git a/src/components/Jodetail/JobPickExecutionsecondscan.tsx b/src/components/Jodetail/JobPickExecutionsecondscan.tsx
index 6c288ff..5f3e916 100644
--- a/src/components/Jodetail/JobPickExecutionsecondscan.tsx
+++ b/src/components/Jodetail/JobPickExecutionsecondscan.tsx
@@ -19,6 +19,7 @@ import {
TablePagination,
Modal,
} from "@mui/material";
+import TestQrCodeProvider from '../QrCodeScannerProvider/TestQrCodeProvider';
import { useCallback, useEffect, useState, useRef, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/navigation";
@@ -1088,6 +1089,15 @@ const paginatedData = useMemo(() => {
}, [t]);
return (
+
+ (
+ lot.matchStatus !== 'completed' &&
+ lot.lotAvailability !== 'rejected'
+ )}
+ >
{/* Job Order Header */}
@@ -1391,6 +1401,7 @@ const paginatedData = useMemo(() => {
/>
)}
+
);
};
diff --git a/src/components/QrCodeScannerProvider/TestQrCodeProvider.tsx b/src/components/QrCodeScannerProvider/TestQrCodeProvider.tsx
new file mode 100644
index 0000000..bab1787
--- /dev/null
+++ b/src/components/QrCodeScannerProvider/TestQrCodeProvider.tsx
@@ -0,0 +1,187 @@
+"use client";
+import {
+ ReactNode,
+ createContext,
+ useCallback,
+ useContext,
+ useEffect,
+ useState,
+} from "react";
+import { useQrCodeScannerContext } from "./QrCodeScannerProvider";
+
+export interface TestQrCodeContext {
+ enableTestMode: boolean;
+ setEnableTestMode: (enabled: boolean) => void;
+ testScanLotByIndex: (index: number) => void;
+ testScanAllLots: () => void;
+ getActiveLots: () => any[];
+ onTestScan?: (data: TestScanData) => Promise;
+}
+
+export interface TestScanData {
+ type: "single" | "all";
+ lotIndex?: number;
+ lots: any[];
+}
+
+interface TestQrCodeProviderProps {
+ children: ReactNode;
+ lotData: any[]; // 当前页面的批次数据
+ onScanLot?: (lotNo: string) => Promise; // 扫描单个批次的回调
+ filterActive?: (lot: any) => boolean; // 过滤活跃批次的函数
+}
+
+export const TestQrCodeContext = createContext(
+ undefined
+);
+
+const TestQrCodeProvider: React.FC = ({
+ children,
+ lotData,
+ onScanLot,
+ filterActive,
+}) => {
+ const [enableTestMode, setEnableTestMode] = useState(true);
+ const { values: qrValues, resetScan } = useQrCodeScannerContext();
+
+ // 默认的活跃批次过滤器
+ const defaultFilterActive = useCallback((lot: any) => {
+ return (
+ lot.lotAvailability !== 'rejected' &&
+ lot.stockOutLineStatus !== 'rejected' &&
+ lot.stockOutLineStatus !== 'completed' &&
+ lot.processingStatus !== 'completed' &&
+ lot.matchStatus !== 'completed'
+ );
+ }, []);
+
+ // 获取活跃批次
+ const getActiveLots = useCallback(() => {
+ const filter = filterActive || defaultFilterActive;
+ return lotData.filter(filter);
+ }, [lotData, filterActive, defaultFilterActive]);
+
+ // 测试扫描单个批次
+ const testScanLotByIndex = useCallback(async (index: number) => {
+ const activeLots = getActiveLots();
+
+ if (index < 1 || index > activeLots.length) {
+ console.error(
+ `❌ TEST: Invalid lot index ${index}. Valid range: 1-${activeLots.length}`
+ );
+ return;
+ }
+
+ const targetLot = activeLots[index - 1]; // 转换为0-based索引
+ console.log(
+ `%c TEST: Scanning lot #${index}/${activeLots.length}: ${targetLot.lotNo}`,
+ "color: blue; font-weight: bold"
+ );
+
+ if (onScanLot) {
+ await onScanLot(targetLot.lotNo);
+ }
+ }, [getActiveLots, onScanLot]);
+
+ // 测试扫描所有批次
+ const testScanAllLots = useCallback(async () => {
+ const activeLots = getActiveLots();
+
+ if (activeLots.length === 0) {
+ console.error("❌ TEST: No active lots to scan");
+ return;
+ }
+
+ console.log(
+ `%c TEST: Scanning ALL ${activeLots.length} lots...`,
+ "color: orange; font-weight: bold"
+ );
+
+ for (let i = 0; i < activeLots.length; i++) {
+ const lot = activeLots[i];
+ console.log(
+ `%c TEST: Scanning lot ${i + 1}/${activeLots.length}: ${lot.lotNo}`,
+ "color: blue"
+ );
+
+ if (onScanLot) {
+ await onScanLot(lot.lotNo);
+ // 添加延迟避免并发冲突
+ await new Promise(resolve => setTimeout(resolve, 300));
+ }
+ }
+
+ console.log(
+ `%c TEST: Completed scanning all ${activeLots.length} lots`,
+ "color: green; font-weight: bold"
+ );
+ }, [getActiveLots, onScanLot]);
+
+ // 监听 QR 扫描值,处理测试格式
+ useEffect(() => {
+ if (!enableTestMode || qrValues.length === 0) {
+ return;
+ }
+
+ const latestQr = qrValues[qrValues.length - 1];
+ let processed = false;
+
+ // 处理 {2fitestall}
+ if (latestQr === "{2fitestall}") {
+ console.log(
+ "%c TEST QR: Detected {2fitestall}",
+ "color: purple; font-weight: bold"
+ );
+ testScanAllLots();
+ processed = true;
+ }
+
+ // 处理 {2fitest[number]}
+ else if (latestQr.startsWith("{2fitest") && latestQr.endsWith("}")) {
+ const content = latestQr.substring(8, latestQr.length - 1);
+
+ if (/^\d+$/.test(content)) {
+ const lotIndex = parseInt(content, 10);
+ console.log(
+ `%c TEST QR: Detected {2fitest${lotIndex}}`,
+ "color: purple; font-weight: bold"
+ );
+ testScanLotByIndex(lotIndex);
+ processed = true;
+ }
+ }
+
+ // 如果处理了测试格式,重置扫描器
+ if (processed) {
+ setTimeout(() => {
+ resetScan();
+ }, 100);
+ }
+ }, [qrValues, enableTestMode, testScanAllLots, testScanLotByIndex, resetScan]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useTestQrCode = (): TestQrCodeContext => {
+ const context = useContext(TestQrCodeContext);
+ if (!context) {
+ throw new Error(
+ "useTestQrCode must be used within a TestQrCodeProvider"
+ );
+ }
+ return context;
+};
+
+export default TestQrCodeProvider;
\ No newline at end of file