|
|
|
@@ -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<void>; |
|
|
|
} |
|
|
|
|
|
|
|
export interface TestScanData { |
|
|
|
type: "single" | "all"; |
|
|
|
lotIndex?: number; |
|
|
|
lots: any[]; |
|
|
|
} |
|
|
|
|
|
|
|
interface TestQrCodeProviderProps { |
|
|
|
children: ReactNode; |
|
|
|
lotData: any[]; // 当前页面的批次数据 |
|
|
|
onScanLot?: (lotNo: string) => Promise<void>; // 扫描单个批次的回调 |
|
|
|
filterActive?: (lot: any) => boolean; // 过滤活跃批次的函数 |
|
|
|
} |
|
|
|
|
|
|
|
export const TestQrCodeContext = createContext<TestQrCodeContext | undefined>( |
|
|
|
undefined |
|
|
|
); |
|
|
|
|
|
|
|
const TestQrCodeProvider: React.FC<TestQrCodeProviderProps> = ({ |
|
|
|
children, |
|
|
|
lotData, |
|
|
|
onScanLot, |
|
|
|
filterActive, |
|
|
|
}) => { |
|
|
|
const [enableTestMode, setEnableTestMode] = useState<boolean>(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 ( |
|
|
|
<TestQrCodeContext.Provider |
|
|
|
value={{ |
|
|
|
enableTestMode, |
|
|
|
setEnableTestMode, |
|
|
|
testScanLotByIndex, |
|
|
|
testScanAllLots, |
|
|
|
getActiveLots, |
|
|
|
}} |
|
|
|
> |
|
|
|
{children} |
|
|
|
</TestQrCodeContext.Provider> |
|
|
|
); |
|
|
|
}; |
|
|
|
|
|
|
|
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; |