|
|
|
@@ -36,6 +36,7 @@ import { |
|
|
|
fetchWorkbenchPrinters, |
|
|
|
printWorkbenchLotLabel, |
|
|
|
} from "@/app/api/doworkbench/actions"; |
|
|
|
import { QRCodeSVG } from "qrcode.react"; |
|
|
|
|
|
|
|
type ScanPayload = { |
|
|
|
itemId: number; |
|
|
|
@@ -66,6 +67,7 @@ type QrCodeAnalysisResponse = { |
|
|
|
sameItemLots: Array<{ |
|
|
|
lotNo: string; |
|
|
|
inventoryLotLineId: number; |
|
|
|
stockInLineId?: number | null; |
|
|
|
availableQty: number; |
|
|
|
uom: string; |
|
|
|
warehouseCode?: string | null; |
|
|
|
@@ -175,9 +177,9 @@ const WorkbenchLotLabelPrintModal: React.FC<WorkbenchLotLabelPrintModalProps> = |
|
|
|
const [printingLotLineId, setPrintingLotLineId] = useState<number | null>( |
|
|
|
null, |
|
|
|
); |
|
|
|
const [workbenchScanPickLotLineId, setWorkbenchScanPickLotLineId] = useState< |
|
|
|
number | null |
|
|
|
>(null); |
|
|
|
const [qrVisibleLotLineId, setQrVisibleLotLineId] = useState<number | null>( |
|
|
|
null, |
|
|
|
); |
|
|
|
|
|
|
|
const [snackbar, setSnackbar] = useState<{ |
|
|
|
open: boolean; |
|
|
|
@@ -195,7 +197,7 @@ const WorkbenchLotLabelPrintModal: React.FC<WorkbenchLotLabelPrintModalProps> = |
|
|
|
setAnalysis(null); |
|
|
|
setPrintQty(1); |
|
|
|
setPrintingLotLineId(null); |
|
|
|
setWorkbenchScanPickLotLineId(null); |
|
|
|
setQrVisibleLotLineId(null); |
|
|
|
}, []); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
@@ -383,6 +385,7 @@ const WorkbenchLotLabelPrintModal: React.FC<WorkbenchLotLabelPrintModalProps> = |
|
|
|
? { |
|
|
|
lotNo: scanned?.lotNo ?? "", |
|
|
|
inventoryLotLineId: scannedLotLineId, |
|
|
|
stockInLineId: Number(scanned?.stockInLineId ?? 0) || null, |
|
|
|
availableQty: Math.max(fromApi, fromTable) as number, |
|
|
|
uom: (scannedRow?.uom ?? triggerLotUom ?? "") as string, |
|
|
|
warehouseCode: |
|
|
|
@@ -465,33 +468,6 @@ const WorkbenchLotLabelPrintModal: React.FC<WorkbenchLotLabelPrintModalProps> = |
|
|
|
[selectedPrinterId, printQty], |
|
|
|
); |
|
|
|
|
|
|
|
const handleWorkbenchScanPickOne = useCallback( |
|
|
|
async (inventoryLotLineId: number, lotNo: string) => { |
|
|
|
if (!onWorkbenchScanPick) return; |
|
|
|
setWorkbenchScanPickLotLineId(inventoryLotLineId); |
|
|
|
try { |
|
|
|
const n = Number(submitQty); |
|
|
|
const qtyPayload = |
|
|
|
Number.isFinite(n) && n >= 0 ? { qty: n } : {}; |
|
|
|
await onWorkbenchScanPick({ inventoryLotLineId, lotNo, ...qtyPayload }); |
|
|
|
setSnackbar({ |
|
|
|
open: true, |
|
|
|
message: `掃碼提貨成功:Lot ${lotNo}`, |
|
|
|
severity: "success", |
|
|
|
}); |
|
|
|
} catch (e) { |
|
|
|
setSnackbar({ |
|
|
|
open: true, |
|
|
|
message: e instanceof Error ? e.message : "掃碼提貨失敗", |
|
|
|
severity: "error", |
|
|
|
}); |
|
|
|
} finally { |
|
|
|
setWorkbenchScanPickLotLineId(null); |
|
|
|
} |
|
|
|
}, |
|
|
|
[onWorkbenchScanPick, submitQty], |
|
|
|
); |
|
|
|
|
|
|
|
return ( |
|
|
|
<Dialog open={open} onClose={onClose} maxWidth="md" fullWidth> |
|
|
|
<DialogTitle>批號標籤列印(提貨台)</DialogTitle> |
|
|
|
@@ -664,14 +640,20 @@ const WorkbenchLotLabelPrintModal: React.FC<WorkbenchLotLabelPrintModalProps> = |
|
|
|
{filteredLots.map((lot) => { |
|
|
|
const isPrinting = |
|
|
|
printingLotLineId === lot.inventoryLotLineId; |
|
|
|
const isScanPicking = |
|
|
|
workbenchScanPickLotLineId === lot.inventoryLotLineId; |
|
|
|
const loc = String(lot.warehouseCode ?? "").trim(); |
|
|
|
const canWorkbenchPick = |
|
|
|
const canShowLotQr = |
|
|
|
!!onWorkbenchScanPick && |
|
|
|
!!analysis && |
|
|
|
!analysisLoading && |
|
|
|
!disableScanPick; |
|
|
|
const lotQrPayload = |
|
|
|
Number.isFinite(Number(analysis?.itemId)) && |
|
|
|
Number.isFinite(Number(lot.stockInLineId)) |
|
|
|
? { |
|
|
|
itemId: Number(analysis?.itemId), |
|
|
|
stockInLineId: Number(lot.stockInLineId), |
|
|
|
} |
|
|
|
: null; |
|
|
|
return ( |
|
|
|
<Box |
|
|
|
key={lot.inventoryLotLineId} |
|
|
|
@@ -713,7 +695,7 @@ const WorkbenchLotLabelPrintModal: React.FC<WorkbenchLotLabelPrintModalProps> = |
|
|
|
> |
|
|
|
<Button |
|
|
|
variant="contained" |
|
|
|
disabled={!canPrint || isPrinting || isScanPicking} |
|
|
|
disabled={!canPrint || isPrinting} |
|
|
|
onClick={() => |
|
|
|
void handlePrintOne( |
|
|
|
lot.inventoryLotLineId, |
|
|
|
@@ -732,30 +714,48 @@ const WorkbenchLotLabelPrintModal: React.FC<WorkbenchLotLabelPrintModalProps> = |
|
|
|
variant="outlined" |
|
|
|
color="secondary" |
|
|
|
title={ |
|
|
|
disableScanPick |
|
|
|
? "此出庫行已掃碼或已完成,無法再掃碼提貨" |
|
|
|
!lotQrPayload |
|
|
|
? "此列無法取得 QR payload(需 stockInLineId)" |
|
|
|
: disableScanPick |
|
|
|
? "此出庫行已掃碼或已完成,無法顯示 QR" |
|
|
|
: undefined |
|
|
|
} |
|
|
|
disabled={ |
|
|
|
!canWorkbenchPick || |
|
|
|
isPrinting || |
|
|
|
isScanPicking |
|
|
|
!canShowLotQr || !lotQrPayload || isPrinting |
|
|
|
} |
|
|
|
onClick={() => |
|
|
|
void handleWorkbenchScanPickOne( |
|
|
|
lot.inventoryLotLineId, |
|
|
|
lot.lotNo, |
|
|
|
setQrVisibleLotLineId((prev) => |
|
|
|
prev === lot.inventoryLotLineId |
|
|
|
? null |
|
|
|
: lot.inventoryLotLineId, |
|
|
|
) |
|
|
|
} |
|
|
|
> |
|
|
|
{isScanPicking ? ( |
|
|
|
<CircularProgress size={18} /> |
|
|
|
) : ( |
|
|
|
"掃碼提貨" |
|
|
|
)} |
|
|
|
顯示 QR |
|
|
|
</Button> |
|
|
|
) : null} |
|
|
|
</Stack> |
|
|
|
{qrVisibleLotLineId === lot.inventoryLotLineId && |
|
|
|
lotQrPayload ? ( |
|
|
|
<Box |
|
|
|
sx={{ |
|
|
|
mt: 1.5, |
|
|
|
ml: "auto", |
|
|
|
p: 1.5, |
|
|
|
borderRadius: 1, |
|
|
|
border: "1px dashed", |
|
|
|
borderColor: "divider", |
|
|
|
textAlign: "center", |
|
|
|
minWidth: 220, |
|
|
|
}} |
|
|
|
> |
|
|
|
<QRCodeSVG |
|
|
|
value={JSON.stringify(lotQrPayload)} |
|
|
|
size={160} |
|
|
|
includeMargin |
|
|
|
/> |
|
|
|
</Box> |
|
|
|
) : null} |
|
|
|
</Box> |
|
|
|
); |
|
|
|
})} |
|
|
|
|