diff --git a/src/app/api/jo/actions.ts b/src/app/api/jo/actions.ts index 1d191ce..76f6284 100644 --- a/src/app/api/jo/actions.ts +++ b/src/app/api/jo/actions.ts @@ -324,9 +324,11 @@ export interface AllJoborderProductProcessInfoResponse { assignedTo: number; pickOrderId: number; pickOrderStatus: string; + itemCode: string; itemName: string; requiredQty: number; jobOrderId: number; + uom: string; stockInLineId: number; jobOrderCode: string; productProcessLineCount: number; @@ -908,9 +910,9 @@ export const fetchCompletedJobOrderPickOrdersrecords = cache(async () => { }, ); }); -export const fetchJoForPrintQrCode = cache(async () => { +export const fetchJoForPrintQrCode = cache(async (date: string) => { return serverFetchJson( - `${BASE_API_URL}/jo/joForPrintQrCode`, + `${BASE_API_URL}/jo/joForPrintQrCode/${date}`, { method: "GET", next: { tags: ["jo-print-qr-code"] }, diff --git a/src/components/ProductionProcess/FinishedQcJobOrderList.tsx b/src/components/ProductionProcess/FinishedQcJobOrderList.tsx index 99bb252..1d05b5c 100644 --- a/src/components/ProductionProcess/FinishedQcJobOrderList.tsx +++ b/src/components/ProductionProcess/FinishedQcJobOrderList.tsx @@ -17,6 +17,10 @@ import { Paper, IconButton, Tooltip, + FormControl, + InputLabel, + Select, + MenuItem, } from "@mui/material"; import QrCodeIcon from '@mui/icons-material/QrCode'; import { useTranslation } from "react-i18next"; @@ -50,11 +54,28 @@ const FinishedQcJobOrderList: React.FC = ({ const [page, setPage] = useState(0); const [isPrinting, setIsPrinting] = useState(false); const [printingId, setPrintingId] = useState(null); + const [selectedDate, setSelectedDate] = useState("today"); + const getDateLabel = (offset: number) => { + return dayjs().subtract(offset, 'day').format('YYYY-MM-DD'); + }; + + // 根据选择的日期获取实际日期字符串 + const getDateParam = (dateOption: string): string => { + if (dateOption === "today") { + return dayjs().format('YYYY-MM-DD'); + } else if (dateOption === "yesterday") { + return dayjs().subtract(1, 'day').format('YYYY-MM-DD'); + } else if (dateOption === "dayBeforeYesterday") { + return dayjs().subtract(2, 'day').format('YYYY-MM-DD'); + } + return dayjs().format('YYYY-MM-DD'); + }; const fetchJobOrders = useCallback(async () => { setLoading(true); try { - const data = await fetchJoForPrintQrCode(); + const dateParam = getDateParam(selectedDate); + const data = await fetchJoForPrintQrCode(dateParam); setJobOrders(data || []); setPage(0); } catch (e) { @@ -63,7 +84,9 @@ const FinishedQcJobOrderList: React.FC = ({ } finally { setLoading(false); } - }, []); + }, [selectedDate]); + + useEffect(() => { fetchJobOrders(); @@ -114,6 +137,34 @@ const FinishedQcJobOrderList: React.FC = ({ return ( + {/* Date Selector */} + + + + {t("Select Date")} + + + + + {loading ? ( diff --git a/src/components/ProductionProcess/ProductionProcessDetail.tsx b/src/components/ProductionProcess/ProductionProcessDetail.tsx index 3d70605..e972450 100644 --- a/src/components/ProductionProcess/ProductionProcessDetail.tsx +++ b/src/components/ProductionProcess/ProductionProcessDetail.tsx @@ -56,7 +56,7 @@ const ProductionProcessDetail: React.FC = ({ onBack, fromJosave, }) => { - const { t } = useTranslation(); + const { t } = useTranslation("common"); const { data: session } = useSession() as { data: SessionWithTokens | null }; const currentUserId = session?.id ? parseInt(session.id) : undefined; const { values: qrValues, startScan, stopScan, resetScan } = useQrCodeScannerContext(); @@ -334,16 +334,6 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { const effectiveEquipmentCode = scannedEquipmentCode ?? null; - if (!effectiveEquipmentCode) { - console.error("No equipment code available"); - alert(t("Please scan equipment code or equipment detail ID")); - setIsAutoSubmitting(false); - if (autoSubmitTimerRef.current) { - clearTimeout(autoSubmitTimerRef.current); - autoSubmitTimerRef.current = null; - } - return false; - } console.log("Submitting scan data with equipmentCode:", { productProcessLineId: lineId, @@ -353,7 +343,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { const response = await newUpdateProductProcessLineQrscan({ productProcessLineId: lineId, - equipmentCode: effectiveEquipmentCode, + equipmentCode: effectiveEquipmentCode ?? "", staffNo: scannedStaffNo, }); @@ -423,6 +413,8 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { setProcessedQrCodes(new Set()); setScannedOperatorId(null); setScannedEquipmentId(null); + setScannedStaffNo(null); // ✅ Add this + setScannedEquipmentCode(null); setIsAutoSubmitting(false); // 添加:重置自动提交状态 setLineDetailForScan(null); // 获取 line detail 以获取 bomProcessEquipmentId @@ -446,7 +438,9 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { } setIsManualScanning(false); - setIsAutoSubmitting(false); // 添加:重置自动提交状态 + setIsAutoSubmitting(false); + setScannedStaffNo(null); // ✅ Add this + setScannedEquipmentCode(null); stopScan(); resetScan(); }, [stopScan, resetScan]); @@ -461,7 +455,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { } }; // 提交扫描结果并验证 - + /* useEffect(() => { console.log("Auto-submit check:", { scanningLineId, @@ -501,6 +495,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { // 只在组件卸载时清除 }; }, [scanningLineId, scannedStaffNo, scannedEquipmentCode, isAutoSubmitting, isManualScanning, submitScanAndStart]); + */ useEffect(() => { return () => { if (autoSubmitTimerRef.current) { @@ -518,6 +513,9 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { setScannedEquipmentId(null); setProcessedQrCodes(new Set()); + setScannedStaffNo(null); + setScannedEquipmentCode(null); + setProcessedQrCodes(new Set()); // 清除之前的定时器 if (autoSubmitTimerRef.current) { clearTimeout(autoSubmitTimerRef.current); @@ -783,7 +781,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { {/* ✅ Show both options */} {scannedEquipmentCode ? `${t("Equipment Code")}: ${scannedEquipmentCode}` - : t("Please scan equipment code or equipment detail id") + : t("Please scan equipment code") } @@ -809,7 +807,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { diff --git a/src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx b/src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx index cd1ea10..1e1ca0b 100644 --- a/src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx +++ b/src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx @@ -316,7 +316,7 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { headerAlign: "left", type: "number", renderCell: (params) => { - return {params.value}; + return {params.value}; }, }, { @@ -326,16 +326,28 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { align: "left", headerAlign: "left", renderCell: (params) => { - return {params.value || ""}; + return( + +   + {params.value || ""} + +   + + ) + }, }, + ]; const productionProcessesLineRemarkTableRows = processData?.productProcessLines?.map((line: any) => ({ id: line.seqNo, seqNo: line.seqNo, + description: line.description ?? "", + + })) ?? []; @@ -487,21 +499,37 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { /> ); - const ProductionProcessesLineRemarkTableContent = () => ( - - - 'auto'} - - /> - - ); + const ProductionProcessesLineRemarkTableContent = () => ( + + + 'auto'} + hideFooter={false} // ✅ Ensure footer is visible + /> + +); return ( diff --git a/src/components/ProductionProcess/ProductionProcessList.tsx b/src/components/ProductionProcess/ProductionProcessList.tsx index d68a821..d52128d 100644 --- a/src/components/ProductionProcess/ProductionProcessList.tsx +++ b/src/components/ProductionProcess/ProductionProcessList.tsx @@ -235,10 +235,10 @@ const ProductProcessList: React.FC = ({ onSelectProcess - {t("Item Name")}: {process.itemName} + {t("Item Name")}: {process.itemCode} {process.itemName} - {t("Required Qty")}: {process.requiredQty} + {t("Required Qty")}: {process.requiredQty} {process.uom} {t("Production date")}: {process.date ? dayjs(process.date as any).format(OUTPUT_DATE_FORMAT) : "-"} diff --git a/src/components/ProductionProcess/ProductionProcessStepExecution.tsx b/src/components/ProductionProcess/ProductionProcessStepExecution.tsx index de16ef9..03cc773 100644 --- a/src/components/ProductionProcess/ProductionProcessStepExecution.tsx +++ b/src/components/ProductionProcess/ProductionProcessStepExecution.tsx @@ -410,7 +410,7 @@ const ProductionProcessStepExecution: React.FC - {t("Completed Step")}: {lineDetail?.name} (Seq: {lineDetail?.seqNo}) + {t("Completed Step")}: {lineDetail?.name} ({t("Seq")}: {lineDetail?.seqNo}) {/**/} @@ -420,27 +420,27 @@ const ProductionProcessStepExecution: React.FC - - - {t("Description")}: {lineDetail?.description || "-"} - - - - - {t("Operator")}: {lineDetail?.operatorName || "-"} - - - - - {t("Equipment")}: {equipmentName} - - - - - {t("Status")}: {lineDetail?.status || "-"} - - + + + {t("Description")}: {lineDetail?.description || "-"} + + + + {t("Operator")}: {lineDetail?.operatorName || "-"} + + + + + {t("Equipment")}: {equipmentName} + + + + + {t("Status")}: {t(lineDetail?.status || "-")} + + + {/**/} @@ -563,7 +563,7 @@ const ProductionProcessStepExecution: React.FC - {t("Executing")}: {lineDetail?.name} (Seq: {lineDetail?.seqNo}) + {t("Executing")}: {lineDetail?.name} ({t("Seq")}:{lineDetail?.seqNo}) {lineDetail?.description} diff --git a/src/components/Qc/QcStockInModal.tsx b/src/components/Qc/QcStockInModal.tsx index 6dcac0c..035325b 100644 --- a/src/components/Qc/QcStockInModal.tsx +++ b/src/components/Qc/QcStockInModal.tsx @@ -397,7 +397,7 @@ const QcStockInModal: React.FC = ({ // confirmButtonText: t("confirm putaway"), html: ""}); // onOpenPutaway(); const isJobOrderBom = (stockInLineInfo?.jobOrderId != null || printSource === "productionProcess") - && stockInLineInfo?.bomDescription === "半成品"; + && stockInLineInfo?.bomDescription === "WIP"; if (isJobOrderBom) { // Auto putaway to default warehouse const defaultWarehouseId = stockInLineInfo?.defaultWarehouseId ?? 1; @@ -417,7 +417,7 @@ const QcStockInModal: React.FC = ({ itemId: stockInLineInfo?.itemId, // Include Item ID purchaseOrderId: stockInLineInfo?.purchaseOrderId, // Include PO ID if exists purchaseOrderLineId: stockInLineInfo?.purchaseOrderLineId, // Include POL ID if exists - acceptedQty: stockInLineInfo?.acceptedQty, // Include acceptedQty + acceptedQty:acceptQty, // Include acceptedQty acceptQty: stockInLineInfo?.acceptedQty, // Putaway quantity warehouseId: defaultWarehouseId, status: "received", // Use string like PutAwayModal diff --git a/src/i18n/zh/common.json b/src/i18n/zh/common.json index bf77270..92f914f 100644 --- a/src/i18n/zh/common.json +++ b/src/i18n/zh/common.json @@ -84,7 +84,14 @@ "Detail Scheduling": "詳細排程", "Customer": "客戶", "qcItem": "品檢項目", - "Item": "物料", + "Item": "成品/半成品", + "Today": "今天", + "Yesterday": "昨天", + "Input Equipment is not match with process": "輸入的設備與流程不匹配", + "Staff No is required": "員工編號必填", + + "Day Before Yesterday": "前天", + "Select Date": "選擇日期", "Production Date": "生產日期", "QC Check Item": "QC品檢項目", "QC Category": "QC品檢模板", @@ -179,7 +186,6 @@ "Production Process Information": "生產流程信息", "Production Process Steps": "生產流程步驟", "Scan Operator & Equipment": "掃描操作員和設備", - "Seq": "序號", "Setup Time (mins)": "生產前預備時間(分鐘)", "Start": "開始", "Start QR Scan": "開始掃碼", @@ -195,10 +201,13 @@ "Validation failed. Please check operator and equipment.": "驗證失敗. 請檢查操作員和設備.", "View": "查看", "Back": "返回", - "BoM Material": "物料清單", + "BoM Material": "成品/半成品清單", "N/A": "不適用", "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度", - "Item Code": "物料編號", + "Item Code": "成品/半成品名稱", + "Please scan equipment code": "請掃描設備編號", + "Equipment Code": "設備編號", + "Seq": "步驟", "Item Name": "物料名稱", "Job Order Info": "工單信息", "Matching Stock": "工單對料", diff --git a/src/i18n/zh/jo.json b/src/i18n/zh/jo.json index 678306e..1bdeec4 100644 --- a/src/i18n/zh/jo.json +++ b/src/i18n/zh/jo.json @@ -8,7 +8,7 @@ "Code": "工單編號", "Name": "成品/半成品名稱", "Picked Qty": "已提料數量", - "Confirm All": "確認所有", + "Confirm All": "確認所有提料", "UoM": "銷售單位", "No": "沒有", "User not found with staffNo:": "用戶不存在", @@ -156,7 +156,9 @@ "Reject": "拒絕", "Stock Unit": "庫存單位", "Group": "組", - "Item": "物料", + "Input Equipment is not match with process": "輸入的設備與流程不匹配", + "Item": "成品/半成品", + "Select Date": "選擇日期", "No Group": "沒有組", "No created items": "沒有創建物料", "Order Quantity": "需求數量", @@ -284,7 +286,6 @@ "acceptQty must not greater than": "接受數量不能大於", "escalation": "升級", "failedQty": "失敗數量", - "qcItem": "QC物料", "qcResult": "QC結果", "remarks": "備註", "supervisor": "主管", @@ -334,13 +335,15 @@ "pending": "待處理", "Please scan equipment code (optional if not required)": "請掃描設備編號(可選)", + "Please scan equipment code": "請掃描設備編號", + "Equipment Code": "設備編號", "Please scan operator code": "請掃描操作員編號", "Please scan operator code first": "請先掃描操作員編號", "Processing Time (mins)": "步驟時間(分鐘)", "Production Process Information": "生產流程信息", "Production Process Steps": "生產流程步驟", "Scan Operator & Equipment": "掃描操作員和設備", - "Seq": "序號", + "Seq:": "步驟", "Setup Time (mins)": "生產前預備時間(分鐘)", "Start": "開始", "Start QR Scan": "開始掃碼", @@ -366,18 +369,13 @@ "View": "查看", "Back": "返回", "N/A": "不適用", - "BoM Material": "物料清單", + "BoM Material": "成品/半成品清單", "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間順序 | 複雜度", - "Item Code": "物料編號", - "Item Name": "物料名稱", "Enter the number of cartons: ": "請輸入箱數:", "Number of cartons": "箱數", "You need to enter a number": "您需要輸入一個數字", "Number must be at least 1": "數字必須至少為1", - "Cancel": "取消", - "Print Pick Record": "打印板頭紙", - "Printed Successfully.": "成功列印", "Job Order Info": "工單信息", "Matching Stock": "工單對料", "No data found": "沒有找到資料",