From 8e64686a40a67137201f411f9b3f1b78bb18e7dd Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Thu, 27 Nov 2025 17:00:53 +0800 Subject: [PATCH] update --- src/app/api/jo/actions.ts | 1 + src/components/JoSearch/JoCreateFormModal.tsx | 46 ++++-- src/components/PickOrderSearch/LotTable.tsx | 145 +++++++++++++++++- .../ProductionProcessJobOrderDetail.tsx | 4 +- src/i18n/zh/common.json | 5 + 5 files changed, 176 insertions(+), 25 deletions(-) diff --git a/src/app/api/jo/actions.ts b/src/app/api/jo/actions.ts index 33ad64a..dc0d844 100644 --- a/src/app/api/jo/actions.ts +++ b/src/app/api/jo/actions.ts @@ -211,6 +211,7 @@ export interface ProductProcessWithLinesResponse { jobOrderId?: number; jobOrderCode: string; jobOrderStatus: string; + jobType: string; isDark: string; isDense: number; isFloat: string; diff --git a/src/components/JoSearch/JoCreateFormModal.tsx b/src/components/JoSearch/JoCreateFormModal.tsx index 0a7a28d..27d44d7 100644 --- a/src/components/JoSearch/JoCreateFormModal.tsx +++ b/src/components/JoSearch/JoCreateFormModal.tsx @@ -56,6 +56,7 @@ const JoCreateFormModal: React.FC = ({ const dateDayjs = dateStringToDayjs(data.planStart) data.planStart = dayjsToDateTimeString(dateDayjs.startOf('day')) } + data.jobTypeId = Number(data.jobTypeId); const response = await manualCreateJo(data) if (response) { onSearch(); @@ -168,21 +169,36 @@ const JoCreateFormModal: React.FC = ({ /> - - {t("Job Type")} - - - - + ( + + {t("Job Type")} + + {/*{error && {error.message}}*/} + + )} + /> + = ({ return t("Please finish QR code scan and pick order."); } }, [t]); - + const handleOpenQrModal = useCallback((lot: LotPickData) => { + setSelectedLotForQr(lot); + setManualQrInput(lot.lotNo ?? ""); + setValidationErrors({}); + setQrModalOpen(true); + resetScan(); + startScan(); + }, [startScan, resetScan]); + + const handleCloseQrModal = useCallback(() => { + setQrModalOpen(false); + setSelectedLotForQr(null); + stopScan(); + resetScan(); + }, [stopScan, resetScan]); const prepareLotTableData = useMemo(() => { return lotData.map((lot) => ({ ...lot, @@ -477,9 +491,55 @@ const LotTable: React.FC = ({ }, [calculateRemainingAvailableQty, calculateRemainingRequiredQty, t]); const handleQrCodeSubmit = useCallback(async (lotNo: string) => { - // ... 保持你原本的 QR 提交邏輯 ... - }, [selectedLotForQr, selectedRowId, onPickQtyChange, onLotDataRefresh]); - + if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) { + console.log(` QR Code verified for lot: ${lotNo}`); + if (!selectedLotForQr.stockOutLineId) { + console.error("No stock out line ID found for this lot"); + alert("No stock out line found for this lot. Please contact administrator."); + return; + } + // Store the required quantity before creating stock out line + const requiredQty = selectedLotForQr.requiredQty; + const lotId = selectedLotForQr.lotId; + + try { + // Update stock out line status to 'checked' (QR scan completed) + const stockOutLineUpdate = await updateStockOutLineStatus({ + id: selectedLotForQr.stockOutLineId, + status: 'checked', + qty: selectedLotForQr.stockOutLineQty || 0 + }); + + console.log(" Stock out line updated to 'checked':", stockOutLineUpdate); + + // Close modal + setQrModalOpen(false); + setSelectedLotForQr(null); + if (onLotDataRefresh) { + await onLotDataRefresh(); + } + // Set pick quantity AFTER stock out line update is complete + if (selectedRowId) { + // Add a small delay to ensure the data refresh is complete + setTimeout(() => { + onPickQtyChange(selectedRowId, lotId ?? 0, requiredQty); + console.log(` Auto-set pick quantity to ${requiredQty} for lot ${lotNo}`); + }, 500); // 500ms delay to ensure refresh is complete + } + + // Show success message + console.log("Stock out line updated successfully!"); + + } catch (error) { + console.error("❌ Error updating stock out line status:", error); + alert("Failed to update lot status. Please try again."); + } + } else { + // Handle case where lot numbers don't match + console.error("QR scan mismatch:", { scanned: lotNo, expected: selectedLotForQr?.lotNo }); + alert(`QR scan mismatch! Expected: ${selectedLotForQr?.lotNo}, Scanned: ${lotNo}`); + } +}, [selectedLotForQr, selectedRowId, onPickQtyChange]); // PickExecutionForm 狀態與提交(保持原本邏輯) const [pickExecutionFormOpen, setPickExecutionFormOpen] = useState(false); const [selectedLotForExecutionForm, setSelectedLotForExecutionForm] = useState(null); @@ -606,9 +666,73 @@ const LotTable: React.FC = ({ })()} - {/* 已掃碼後的實際數量 + Issue 按鈕(保持原有邏輯,略) */} - {/* 對 noLot 行而言這裡通常保持為 0/禁用 */} - + {lot.stockOutLineStatus?.toLowerCase() === 'pending' ? ( + + ) : ( + + { + if (selectedRowId && lot.lotId != null) { + onPickQtyChange(selectedRowId, lot.lotId, Number(e.target.value) || 0); + } + }} + disabled={ + lot.lotAvailability === 'expired' || + lot.lotAvailability === 'status_unavailable' || + lot.lotAvailability === 'rejected' || + selectedLotRowId !== `row_${index}` || + lot.stockOutLineStatus === 'completed' + } + error={!!validationErrors[`lot_${lot.lotId}`]} + helperText={validationErrors[`lot_${lot.lotId}`]} + inputProps={{ min: 0, max: calculateRemainingRequiredQty(lot) }} + sx={{ width: 70 }} + placeholder="0" + /> + + + )} + {calculateRemainingAvailableQty(lot).toLocaleString()} @@ -680,7 +804,12 @@ const LotTable: React.FC = ({ {/* Status message & pagination & modals 保持原有程式不變(略) */} - + {pickExecutionFormOpen && selectedLotForExecutionForm && selectedRow && ( { label={t("Job Type")} fullWidth disabled={true} - // value={processData?.jobType || ""} - value={t("N/A")} + value={t(processData?.jobType) || t("N/A")} + //value={t("N/A")} /> diff --git a/src/i18n/zh/common.json b/src/i18n/zh/common.json index 28ec3d7..56fe019 100644 --- a/src/i18n/zh/common.json +++ b/src/i18n/zh/common.json @@ -12,6 +12,11 @@ "code": "編號", "Name": "名稱", "Type": "類型", + + "WIP": "半成品", + "R&D": "研發", + "STF": "樣品", + "Other": "其他", "Add some entries!": "添加條目", "Add Record": "新增", "Clean Record": "重置",