From 16be668c6f864fa9efc8989115d0979d6311515f Mon Sep 17 00:00:00 2001 From: "kelvin.yau" Date: Sat, 18 Oct 2025 16:09:24 +0800 Subject: [PATCH 1/6] update --- .../FGPickOrderTicketReleaseTable.tsx | 91 ++++++ .../FinishedGoodSearch/FinishedGoodSearch.tsx | 292 +----------------- .../GoodPickExecutionRecord.tsx | 237 +++++++++++++- src/i18n/zh/pickOrder.json | 10 +- 4 files changed, 335 insertions(+), 295 deletions(-) create mode 100644 src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx diff --git a/src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx b/src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx new file mode 100644 index 0000000..b63c939 --- /dev/null +++ b/src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx @@ -0,0 +1,91 @@ +"use client"; + +import React, { useState } from 'react'; +import { + Box, + Typography, + FormControl, + InputLabel, + Select, + MenuItem, + Card, + CardContent, + Stack, +} from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; + +const FGPickOrderTicketReleaseTable: React.FC = () => { + const { t } = useTranslation("pickOrder"); + const [selectedDate, setSelectedDate] = useState("today"); + const [selectedFloor, setSelectedFloor] = useState(""); + + const getDateLabel = (offset: number) => { + return dayjs().add(offset, 'day').format('YYYY-MM-DD'); + }; + + return ( + + + {/* Title */} + + Ticket Release Table + + + {/* Dropdown Menus */} + + {/* Date Selection Dropdown */} + + {t("Select Date")} + + + + {/* Floor Selection Dropdown */} + + {t("Floor")} + + + + + {/* Table content will go here */} + + + {/* Add your table component here */} + Table content goes here... + + + + + ); +}; + +export default FGPickOrderTicketReleaseTable; \ No newline at end of file diff --git a/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx b/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx index 1186aa3..e6b43df 100644 --- a/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx +++ b/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx @@ -38,6 +38,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import dayjs, { Dayjs } from 'dayjs'; +import FGPickOrderTicketReleaseTable from "./FGPickOrderTicketReleaseTable"; interface Props { pickOrders: PickOrderResult[]; @@ -217,228 +218,7 @@ const PickOrderSearch: React.FC = ({ pickOrders }) => { },[t]); - const handleDN = useCallback(async () =>{ - const askNumofCarton = await Swal.fire({ - title: t("Enter the number of cartons: "), - icon: "info", - input: "number", - inputPlaceholder: t("Number of cartons"), - inputAttributes:{ - min: "1", - step: "1" - }, - inputValidator: (value) => { - if(!value){ - return t("You need to enter a number") - } - if(parseInt(value) < 1){ - return t("Number must be at least 1"); - } - return null - }, - showCancelButton: true, - confirmButtonText: t("Confirm"), - cancelButtonText: t("Cancel"), - confirmButtonColor: "#8dba00", - cancelButtonColor: "#F04438", - showLoaderOnConfirm: true, - allowOutsideClick: () => !Swal.isLoading() - }); - - if (askNumofCarton.isConfirmed) { - const numOfCartons = askNumofCarton.value; - try{ - if (fgPickOrdersData.length === 0) { - console.error("No FG Pick order data available"); - return; - } - - const currentFgOrder = fgPickOrdersData[0]; - - const printRequest = { - printerId: 1, - printQty: 1, - isDraft: false, - numOfCarton: numOfCartons, - deliveryOrderId: currentFgOrder.deliveryOrderId, - pickOrderId: currentFgOrder.pickOrderId - }; - - console.log("Printing Delivery Note with request: ", printRequest); - - const response = await printDN(printRequest); - - console.log("Print Delivery Note response: ", response); - - if(response.success){ - Swal.fire({ - position: "bottom-end", - icon: "success", - text: t("Printed Successfully."), - showConfirmButton: false, - timer: 1500 - }); - } else { - console.error("Print failed: ", response.message); - } - } catch(error){ - console.error("error: ", error) - } - } - },[t, fgPickOrdersData]); - - const handleDNandLabel = useCallback(async () =>{ - const askNumofCarton = await Swal.fire({ - title: t("Enter the number of cartons: "), - icon: "info", - input: "number", - inputPlaceholder: t("Number of cartons"), - inputAttributes:{ - min: "1", - step: "1" - }, - inputValidator: (value) => { - if(!value){ - return t("You need to enter a number") - } - if(parseInt(value) < 1){ - return t("Number must be at least 1"); - } - return null - }, - showCancelButton: true, - confirmButtonText: t("Confirm"), - cancelButtonText: t("Cancel"), - confirmButtonColor: "#8dba00", - cancelButtonColor: "#F04438", - showLoaderOnConfirm: true, - allowOutsideClick: () => !Swal.isLoading() - }); - - if (askNumofCarton.isConfirmed) { - const numOfCartons = askNumofCarton.value; - try{ - if (fgPickOrdersData.length === 0) { - console.error("No FG Pick order data available"); - return; - } - - const currentFgOrder = fgPickOrdersData[0]; - - const printDNRequest = { - printerId: 1, - printQty: 1, - isDraft: false, - numOfCarton: numOfCartons, - deliveryOrderId: currentFgOrder.deliveryOrderId, - pickOrderId: currentFgOrder.pickOrderId - }; - - const printDNLabelsRequest = { - printerId: 1, - printQty: 1, - numOfCarton: numOfCartons, - deliveryOrderId: currentFgOrder.deliveryOrderId - }; - - console.log("Printing Labels with request: ", printDNLabelsRequest); - console.log("Printing DN with request: ", printDNRequest); - - const LabelsResponse = await printDNLabels(printDNLabelsRequest); - const DNResponse = await printDN(printDNRequest); - - console.log("Print Labels response: ", LabelsResponse); - console.log("Print DN response: ", DNResponse); - - if(LabelsResponse.success && DNResponse.success){ - Swal.fire({ - position: "bottom-end", - icon: "success", - text: t("Printed Successfully."), - showConfirmButton: false, - timer: 1500 - }); - } else { - if(!LabelsResponse.success){ - console.error("Print failed: ", LabelsResponse.message); - } - else{ - console.error("Print failed: ", DNResponse.message); - } - } - } catch(error){ - console.error("error: ", error) - } - } - },[t, fgPickOrdersData]); - - const handleLabel = useCallback(async () =>{ - const askNumofCarton = await Swal.fire({ - title: t("Enter the number of cartons: "), - icon: "info", - input: "number", - inputPlaceholder: t("Number of cartons"), - inputAttributes:{ - min: "1", - step: "1" - }, - inputValidator: (value) => { - if(!value){ - return t("You need to enter a number") - } - if(parseInt(value) < 1){ - return t("Number must be at least 1"); - } - return null - }, - showCancelButton: true, - confirmButtonText: t("Confirm"), - cancelButtonText: t("Cancel"), - confirmButtonColor: "#8dba00", - cancelButtonColor: "#F04438", - showLoaderOnConfirm: true, - allowOutsideClick: () => !Swal.isLoading() - }); - - if (askNumofCarton.isConfirmed) { - const numOfCartons = askNumofCarton.value; - try{ - if (fgPickOrdersData.length === 0) { - console.error("No FG Pick order data available"); - return; - } - - const currentFgOrder = fgPickOrdersData[0]; - - const printRequest = { - printerId: 1, - printQty: 1, - numOfCarton: numOfCartons, - deliveryOrderId: currentFgOrder.deliveryOrderId, - }; - console.log("Printing Labels with request: ", printRequest); - - const response = await printDNLabels(printRequest); - - console.log("Print Labels response: ", response); - - if(response.success){ - Swal.fire({ - position: "bottom-end", - icon: "success", - text: t("Printed Successfully."), - showConfirmButton: false, - timer: 1500 - }); - } else { - console.error("Print failed: ", response.message); - } - } catch(error){ - console.error("error: ", error) - } - } - },[t, fgPickOrdersData]); useEffect(() => { fetchReleasedOrderCount(); @@ -776,7 +556,6 @@ const handleAssignByLane = useCallback(async ( > - - - @@ -895,6 +607,7 @@ const handleAssignByLane = useCallback(async ( + @@ -906,6 +619,7 @@ const handleAssignByLane = useCallback(async ( {tabIndex === 0 && } {tabIndex === 1 && } {tabIndex === 2 && } + {tabIndex === 3 && } ); diff --git a/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx b/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx index 5b02999..8ea96b2 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx @@ -41,10 +41,10 @@ import { checkPickOrderCompletion, PickOrderCompletionResponse, checkAndCompletePickOrderByConsoCode, - fetchCompletedDoPickOrders, // ✅ 新增:使用新的 API + fetchCompletedDoPickOrders, CompletedDoPickOrderResponse, CompletedDoPickOrderSearchParams, - fetchLotDetailsByPickOrderId // ✅ 修复:导入类型 + fetchLotDetailsByPickOrderId } from "@/app/api/pickOrder/actions"; import { fetchNameList, NameList } from "@/app/api/user/actions"; import { @@ -63,6 +63,9 @@ import GoodPickExecutionForm from "./GoodPickExecutionForm"; import FGPickOrderCard from "./FGPickOrderCard"; import dayjs from "dayjs"; import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; +import { printDN, printDNLabels } from "@/app/api/do/actions"; +import Swal from "sweetalert2"; + interface Props { filterArgs: Record; @@ -108,6 +111,205 @@ const GoodPickExecutionRecord: React.FC = ({ filterArgs }) => { const formProps = useForm(); const errors = formProps.formState.errors; + // ✅ Print handler functions + const handleDN = useCallback(async (deliveryOrderId: number, pickOrderId: number) => { + const askNumofCarton = await Swal.fire({ + title: t("Enter the number of cartons: "), + icon: "info", + input: "number", + inputPlaceholder: t("Number of cartons"), + inputAttributes:{ + min: "1", + step: "1" + }, + inputValidator: (value) => { + if(!value){ + return t("You need to enter a number") + } + if(parseInt(value) < 1){ + return t("Number must be at least 1"); + } + return null + }, + showCancelButton: true, + confirmButtonText: t("Confirm"), + cancelButtonText: t("Cancel"), + confirmButtonColor: "#8dba00", + cancelButtonColor: "#F04438", + showLoaderOnConfirm: true, + allowOutsideClick: () => !Swal.isLoading() + }); + + if (askNumofCarton.isConfirmed) { + const numOfCartons = askNumofCarton.value; + try{ + const printRequest = { + printerId: 1, + printQty: 1, + isDraft: false, + numOfCarton: numOfCartons, + deliveryOrderId: deliveryOrderId, + pickOrderId: pickOrderId + }; + + console.log("Printing Delivery Note with request: ", printRequest); + const response = await printDN(printRequest); + console.log("Print Delivery Note response: ", response); + + if(response.success){ + Swal.fire({ + position: "bottom-end", + icon: "success", + text: t("Printed Successfully."), + showConfirmButton: false, + timer: 1500 + }); + } else { + console.error("Print failed: ", response.message); + } + } catch(error){ + console.error("error: ", error) + } + } + }, [t]); + + const handleDNandLabel = useCallback(async (deliveryOrderId: number, pickOrderId: number) => { + const askNumofCarton = await Swal.fire({ + title: t("Enter the number of cartons: "), + icon: "info", + input: "number", + inputPlaceholder: t("Number of cartons"), + inputAttributes:{ + min: "1", + step: "1" + }, + inputValidator: (value) => { + if(!value){ + return t("You need to enter a number") + } + if(parseInt(value) < 1){ + return t("Number must be at least 1"); + } + return null + }, + showCancelButton: true, + confirmButtonText: t("Confirm"), + cancelButtonText: t("Cancel"), + confirmButtonColor: "#8dba00", + cancelButtonColor: "#F04438", + showLoaderOnConfirm: true, + allowOutsideClick: () => !Swal.isLoading() + }); + + if (askNumofCarton.isConfirmed) { + const numOfCartons = askNumofCarton.value; + try{ + const printDNRequest = { + printerId: 1, + printQty: 1, + isDraft: false, + numOfCarton: numOfCartons, + deliveryOrderId: deliveryOrderId, + pickOrderId: pickOrderId + }; + + const printDNLabelsRequest = { + printerId: 1, + printQty: 1, + numOfCarton: numOfCartons, + deliveryOrderId: deliveryOrderId + }; + + console.log("Printing Labels with request: ", printDNLabelsRequest); + console.log("Printing DN with request: ", printDNRequest); + + const LabelsResponse = await printDNLabels(printDNLabelsRequest); + const DNResponse = await printDN(printDNRequest); + + console.log("Print Labels response: ", LabelsResponse); + console.log("Print DN response: ", DNResponse); + + if(LabelsResponse.success && DNResponse.success){ + Swal.fire({ + position: "bottom-end", + icon: "success", + text: t("Printed Successfully."), + showConfirmButton: false, + timer: 1500 + }); + } else { + if(!LabelsResponse.success){ + console.error("Print failed: ", LabelsResponse.message); + } + else{ + console.error("Print failed: ", DNResponse.message); + } + } + } catch(error){ + console.error("error: ", error) + } + } + }, [t]); + + const handleLabel = useCallback(async (deliveryOrderId: number) => { + const askNumofCarton = await Swal.fire({ + title: t("Enter the number of cartons: "), + icon: "info", + input: "number", + inputPlaceholder: t("Number of cartons"), + inputAttributes:{ + min: "1", + step: "1" + }, + inputValidator: (value) => { + if(!value){ + return t("You need to enter a number") + } + if(parseInt(value) < 1){ + return t("Number must be at least 1"); + } + return null + }, + showCancelButton: true, + confirmButtonText: t("Confirm"), + cancelButtonText: t("Cancel"), + confirmButtonColor: "#8dba00", + cancelButtonColor: "#F04438", + showLoaderOnConfirm: true, + allowOutsideClick: () => !Swal.isLoading() + }); + + if (askNumofCarton.isConfirmed) { + const numOfCartons = askNumofCarton.value; + try{ + const printRequest = { + printerId: 1, + printQty: 1, + numOfCarton: numOfCartons, + deliveryOrderId: deliveryOrderId, + }; + + console.log("Printing Labels with request: ", printRequest); + const response = await printDNLabels(printRequest); + console.log("Print Labels response: ", response); + + if(response.success){ + Swal.fire({ + position: "bottom-end", + icon: "success", + text: t("Printed Successfully."), + showConfirmButton: false, + timer: 1500 + }); + } else { + console.error("Print failed: ", response.message); + } + } catch(error){ + console.error("error: ", error) + } + } + }, [t]); + // ✅ 修改:使用新的 API 获取已完成的 DO Pick Orders const fetchCompletedDoPickOrdersData = useCallback(async (searchParams?: CompletedDoPickOrderSearchParams) => { if (!currentUserId) return; @@ -406,6 +608,37 @@ const GoodPickExecutionRecord: React.FC = ({ filterArgs }) => { > {t("View Details")} + + {doPickOrder.fgPickOrders && doPickOrder.fgPickOrders.length > 0 && ( + <> + + + + + )} ))} diff --git a/src/i18n/zh/pickOrder.json b/src/i18n/zh/pickOrder.json index 00df638..31f6e3e 100644 --- a/src/i18n/zh/pickOrder.json +++ b/src/i18n/zh/pickOrder.json @@ -275,9 +275,9 @@ "Confirm":"確認", "Update your suggested lot to the this scanned lot":"更新您的建議批次為此掃描的批次", "Print Draft":"列印草稿", - "Print Pick Order and DN Label":"列印提料單和送貨單標貼", + "Print Pick Order and DN Label":"列印提料單和送貨單標籤", "Print Pick Order":"列印提料單", - "Print DN Label":"列印送貨單標貼", + "Print DN Label":"列印送貨單標籤", "Print All Draft" : "列印全部草稿", "If you confirm, the system will:":"如果您確認,系統將:", "QR code verified.":"QR 碼驗證成功。", @@ -289,7 +289,6 @@ "Completed DO pick orders: ":"已完成送貨單提料單:", "No completed DO pick orders found":"沒有已完成送貨單提料單", - "Print DN Label":"列印送貨單標貼", "Enter the number of cartons: ": "請輸入總箱數", "Number of cartons": "箱數", "Select an action for the assigned pick orders.": "選擇分配提料單的動作。", @@ -387,5 +386,8 @@ "Today": "是日", "Tomorrow": "翌日", "Day After Tomorrow": "後日", - "Select Date": "請選擇日期" + "Select Date": "請選擇日期", + "Print DN & Label": "列印提料單和送貨單標籤", + "Print Label": "列印送貨單標籤", + "Ticket Release Table": "查看提貨情況" } \ No newline at end of file From d4ecb82aa429ff5047e7bf2287f468fdf4000ced Mon Sep 17 00:00:00 2001 From: "kelvin.yau" Date: Mon, 20 Oct 2025 17:45:46 +0800 Subject: [PATCH 2/6] update --- src/app/api/pickOrder/actions.ts | 3 +- .../GoodPickExecutiondetail.tsx | 1015 +++++++++-------- 2 files changed, 567 insertions(+), 451 deletions(-) diff --git a/src/app/api/pickOrder/actions.ts b/src/app/api/pickOrder/actions.ts index 48417b2..ea0b95e 100644 --- a/src/app/api/pickOrder/actions.ts +++ b/src/app/api/pickOrder/actions.ts @@ -111,8 +111,9 @@ export interface GetPickOrderLineInfo { itemName: string; availableQty: number| null; requiredQty: number; - uomCode: string; + uomShortDesc: string; uomDesc: string; + suggestedList: any[]; pickedQty: number; } diff --git a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx index 2710883..1d97df1 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx @@ -18,6 +18,7 @@ import { Checkbox, TablePagination, Modal, + Chip, } from "@mui/material"; import TestQrCodeProvider from '../QrCodeScannerProvider/TestQrCodeProvider'; import { fetchLotDetail } from "@/app/api/inventory/actions"; @@ -32,16 +33,16 @@ import { recordPickExecutionIssue, fetchFGPickOrders, // ✅ Add this import FGPickOrderResponse, - autoAssignAndReleasePickOrder, - AutoAssignReleaseResponse, + checkPickOrderCompletion, fetchAllPickOrderLotsHierarchical, PickOrderCompletionResponse, checkAndCompletePickOrderByConsoCode, updateSuggestedLotLineId, - confirmLotSubstitution + confirmLotSubstitution, // ✅ 必须添加 + fetchFGPickOrdersByUserId } from "@/app/api/pickOrder/actions"; - +import FGPickOrderInfoCard from "./FGPickOrderInfoCard"; import LotConfirmationModal from "./LotConfirmationModal"; //import { fetchItem } from "@/app/api/settings/item"; import { updateInventoryLotLineStatus, analyzeQrCode } from "@/app/api/inventory/actions"; @@ -75,7 +76,9 @@ const QrCodeModal: React.FC<{ const { t } = useTranslation("pickOrder"); const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext(); const [manualInput, setManualInput] = useState(''); - + +const [selectedPickOrderId, setSelectedPickOrderId] = useState(null); +const [pickOrderSwitching, setPickOrderSwitching] = useState(false); const [manualInputSubmitted, setManualInputSubmitted] = useState(false); const [manualInputError, setManualInputError] = useState(false); const [isProcessingQr, setIsProcessingQr] = useState(false); @@ -322,7 +325,9 @@ const PickExecution: React.FC = ({ filterArgs }) => { const { t } = useTranslation("pickOrder"); const router = useRouter(); const { data: session } = useSession() as { data: SessionWithTokens | null }; - + const [availablePickOrders, setAvailablePickOrders] = useState([]); +const [selectedPickOrderId, setSelectedPickOrderId] = useState(null); +const [pickOrderSwitching, setPickOrderSwitching] = useState(false); const currentUserId = session?.id ? parseInt(session.id) : undefined; const [allLotsCompleted, setAllLotsCompleted] = useState(false); const [combinedLotData, setCombinedLotData] = useState([]); @@ -369,38 +374,25 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false); const [lastProcessedQr, setLastProcessedQr] = useState(''); const [isRefreshingData, setIsRefreshingData] = useState(false); const [isSubmittingAll, setIsSubmittingAll] = useState(false); - const fetchFgPickOrdersData = useCallback(async () => { - if (!currentUserId) return; - - setFgPickOrdersLoading(true); - try { - // Get all pick order IDs from combinedLotData - const pickOrderIds = Array.from(new Set(combinedLotData.map(lot => lot.pickOrderId))); + const fetchFgPickOrdersData = useCallback(async () => { + if (!currentUserId) return; - if (pickOrderIds.length === 0) { + setFgPickOrdersLoading(true); + try { + const fgPickOrders = await fetchFGPickOrdersByUserId(currentUserId); + + setFgPickOrders(fgPickOrders); + + // ✅ 移除:不需要再单独调用 fetchDoPickOrderDetail + // all-lots-hierarchical API 已经包含了所有需要的数据 + + } catch (error) { + console.error("❌ Error fetching FG pick orders:", error); setFgPickOrders([]); - return; + } finally { + setFgPickOrdersLoading(false); } - - // Fetch FG pick orders for each pick order ID - const fgPickOrdersPromises = pickOrderIds.map(pickOrderId => - fetchFGPickOrders(pickOrderId) - ); - - const fgPickOrdersResults = await Promise.all(fgPickOrdersPromises); - - // Flatten the results (each fetchFGPickOrders returns an array) - const allFgPickOrders = fgPickOrdersResults.flat(); - - setFgPickOrders(allFgPickOrders); - console.log("✅ Fetched FG pick orders:", allFgPickOrders); - } catch (error) { - console.error("❌ Error fetching FG pick orders:", error); - setFgPickOrders([]); - } finally { - setFgPickOrdersLoading(false); - } - }, [currentUserId, combinedLotData]); + }, [currentUserId]); useEffect(() => { if (combinedLotData.length > 0) { fetchFgPickOrdersData(); @@ -444,12 +436,12 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false); setAllLotsCompleted(allCompleted); return allCompleted; }, []); - const fetchAllCombinedLotData = useCallback(async (userId?: number) => { + const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdOverride?: number) => { setCombinedDataLoading(true); try { const userIdToUse = userId || currentUserId; - console.log(" fetchAllCombinedLotData called with userId:", userIdToUse); + console.log("🔍 fetchAllCombinedLotData called with userId:", userIdToUse); if (!userIdToUse) { console.warn("⚠️ No userId available, skipping API call"); @@ -459,77 +451,178 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false); return; } - // ✅ Use the hierarchical endpoint that includes rejected lots + // ✅ 获取新结构的层级数据 const hierarchicalData = await fetchAllPickOrderLotsHierarchical(userIdToUse); - console.log("✅ Hierarchical lot details:", hierarchicalData); + console.log("✅ Hierarchical data (new structure):", hierarchicalData); + + // ✅ 检查数据结构 + if (!hierarchicalData.fgInfo || !hierarchicalData.pickOrders) { + console.warn("⚠️ No FG info or pick orders found"); + setCombinedLotData([]); + setOriginalCombinedData([]); + setAllLotsCompleted(false); + return; + } + + // ✅ 设置 FG info 到 fgPickOrders(用于显示 FG 信息卡片) + const fgOrder: FGPickOrderResponse = { + ticketNo: hierarchicalData.fgInfo.ticketNo, + storeId: hierarchicalData.fgInfo.storeId, + shopCode: hierarchicalData.fgInfo.shopCode, + shopName: hierarchicalData.fgInfo.shopName, + truckLanceCode: hierarchicalData.fgInfo.truckLanceCode, + DepartureTime: hierarchicalData.fgInfo.departureTime, + shopAddress: "", + + // ✅ 从第一个 pick order 获取兼容字段 + pickOrderId: hierarchicalData.pickOrders[0]?.pickOrderId || 0, + pickOrderCode: hierarchicalData.pickOrders[0]?.pickOrderCode || "", + pickOrderConsoCode: hierarchicalData.pickOrders[0]?.consoCode || "", + pickOrderTargetDate: hierarchicalData.pickOrders[0]?.targetDate || "", + pickOrderStatus: hierarchicalData.pickOrders[0]?.status || "", + deliveryOrderId: hierarchicalData.pickOrders[0]?.doOrderId || 0, + deliveryNo: hierarchicalData.pickOrders[0]?.deliveryOrderCode || "", + deliveryDate: "", + shopId: 0, + shopPoNo: "", + numberOfCartons: 0, + qrCodeData: hierarchicalData.fgInfo.doPickOrderId, + + // ✅ 新增:多个 pick orders 信息 + // numberOfPickOrders: hierarchicalData.pickOrders.length, + // pickOrderIds: hierarchicalData.pickOrders.map((po: any) => po.pickOrderId), + //pickOrderCodes: hierarchicalData.pickOrders.map((po: any) => po.pickOrderCode).join(", "), + // deliveryOrderIds: hierarchicalData.pickOrders.map((po: any) => po.doOrderId), + //deliveryNos: hierarchicalData.pickOrders.map((po: any) => po.deliveryOrderCode).join(", ") + }; + + setFgPickOrders([fgOrder]); + setAvailablePickOrders(hierarchicalData.pickOrders); + // ✅ 构建 doPickOrderDetail(用于 switcher) + + + // ✅ 确定要显示的 pick order + const targetPickOrderId = pickOrderIdOverride || selectedPickOrderId || hierarchicalData.pickOrders[0]?.pickOrderId; + + // ✅ 找到对应的 pick order 数据 + const targetPickOrder = hierarchicalData.pickOrders.find((po: any) => + po.pickOrderId === targetPickOrderId + ); + + if (!targetPickOrder) { + console.warn("⚠️ Target pick order not found:", targetPickOrderId); + setCombinedLotData([]); + setOriginalCombinedData([]); + setAllLotsCompleted(false); + return; + } + + console.log("🎯 Displaying pick order:", targetPickOrder.pickOrderCode); - // ✅ Transform hierarchical data to flat structure for the table + // ✅ 将层级数据转换为平铺格式(用于表格显示) const flatLotData: any[] = []; - if (hierarchicalData.pickOrder && hierarchicalData.pickOrderLines) { - hierarchicalData.pickOrderLines.forEach((line: any) => { - if (line.lots && line.lots.length > 0) { - line.lots.forEach((lot: any) => { - flatLotData.push({ - // Pick order info - pickOrderId: hierarchicalData.pickOrder.id, - pickOrderCode: hierarchicalData.pickOrder.code, - pickOrderConsoCode: hierarchicalData.pickOrder.consoCode, - pickOrderTargetDate: hierarchicalData.pickOrder.targetDate, - pickOrderType: hierarchicalData.pickOrder.type, - pickOrderStatus: hierarchicalData.pickOrder.status, - pickOrderAssignTo: hierarchicalData.pickOrder.assignTo, - - // Pick order line info - pickOrderLineId: line.id, - pickOrderLineRequiredQty: line.requiredQty, - pickOrderLineStatus: line.status, - - // Item info - itemId: line.item.id, - itemCode: line.item.code, - itemName: line.item.name, - uomCode: line.item.uomCode, - uomDesc: line.item.uomDesc, - - // Lot info - lotId: lot.id, - lotNo: lot.lotNo, - expiryDate: lot.expiryDate, - location: lot.location, - stockUnit: lot.stockUnit, - availableQty: lot.availableQty, - requiredQty: lot.requiredQty, - actualPickQty: lot.actualPickQty, - inQty: lot.inQty, - outQty: lot.outQty, - holdQty: lot.holdQty, - lotStatus: lot.lotStatus, - lotAvailability: lot.lotAvailability, - processingStatus: lot.processingStatus, - suggestedPickLotId: lot.suggestedPickLotId, - stockOutLineId: lot.stockOutLineId, - stockOutLineStatus: lot.stockOutLineStatus, - stockOutLineQty: lot.stockOutLineQty, - - // Router info - routerId: lot.router?.id, - routerIndex: lot.router?.index, - routerRoute: lot.router?.route, - routerArea: lot.router?.area, - uomShortDesc: lot.router?.uomId - }); + targetPickOrder.pickOrderLines.forEach((line: any) => { + if (line.lots && line.lots.length > 0) { + // ✅ 有 lots 的情况 + line.lots.forEach((lot: any) => { + flatLotData.push({ + pickOrderId: targetPickOrder.pickOrderId, + pickOrderCode: targetPickOrder.pickOrderCode, + pickOrderConsoCode: targetPickOrder.consoCode, + pickOrderTargetDate: targetPickOrder.targetDate, + pickOrderStatus: targetPickOrder.status, + + pickOrderLineId: line.id, + pickOrderLineRequiredQty: line.requiredQty, + pickOrderLineStatus: line.status, + + itemId: line.item.id, + itemCode: line.item.code, + itemName: line.item.name, + //uomCode: line.item.uomCode, + uomDesc: line.item.uomDesc, + uomShortDesc: line.item.uomShortDesc, + lotId: lot.id, + lotNo: lot.lotNo, + expiryDate: lot.expiryDate, + location: lot.location, + stockUnit: lot.stockUnit, + availableQty: lot.availableQty, + requiredQty: lot.requiredQty, + actualPickQty: lot.actualPickQty, + inQty: lot.inQty, + outQty: lot.outQty, + holdQty: lot.holdQty, + lotStatus: lot.lotStatus, + lotAvailability: lot.lotAvailability, + processingStatus: lot.processingStatus, + suggestedPickLotId: lot.suggestedPickLotId, + stockOutLineId: lot.stockOutLineId, + stockOutLineStatus: lot.stockOutLineStatus, + stockOutLineQty: lot.stockOutLineQty, + + routerId: lot.router?.id, + routerIndex: lot.router?.index, + routerRoute: lot.router?.route, + routerArea: lot.router?.area, }); - } - }); - } + }); + } else { + // ✅ 没有 lots 的情况(null stock)- 也要显示 + flatLotData.push({ + pickOrderId: targetPickOrder.pickOrderId, + pickOrderCode: targetPickOrder.pickOrderCode, + pickOrderConsoCode: targetPickOrder.consoCode, + pickOrderTargetDate: targetPickOrder.targetDate, + pickOrderStatus: targetPickOrder.status, + + pickOrderLineId: line.id, + pickOrderLineRequiredQty: line.requiredQty, + pickOrderLineStatus: line.status, + + itemId: line.item.id, + itemCode: line.item.code, + itemName: line.item.name, + //uomCode: line.item.uomCode, + uomDesc: line.item.uomDesc, + + // ✅ Null stock 字段 + lotId: null, + lotNo: null, + expiryDate: null, + location: null, + stockUnit: line.item.uomDesc, + availableQty: 0, + requiredQty: line.requiredQty, + actualPickQty: 0, + inQty: 0, + outQty: 0, + holdQty: 0, + lotStatus: 'unavailable', + lotAvailability: 'insufficient_stock', + processingStatus: 'pending', + suggestedPickLotId: null, + stockOutLineId: null, + stockOutLineStatus: null, + stockOutLineQty: 0, + + routerId: null, + routerIndex: 999999, // ✅ 放到最后 + routerRoute: null, + routerArea: null, + uomShortDesc: line.item.uomShortDesc + }); + } + }); console.log("✅ Transformed flat lot data:", flatLotData); + console.log("🔍 Total items (including null stock):", flatLotData.length); + setCombinedLotData(flatLotData); setOriginalCombinedData(flatLotData); - - // ✅ Check completion status checkAllLotsCompleted(flatLotData); + } catch (error) { console.error("❌ Error fetching combined lot data:", error); setCombinedLotData([]); @@ -538,8 +631,7 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false); } finally { setCombinedDataLoading(false); } - }, [currentUserId, checkAllLotsCompleted]); - + }, [currentUserId, selectedPickOrderId, checkAllLotsCompleted]); // ✅ Add effect to check completion when lot data changes useEffect(() => { if (combinedLotData.length > 0) { @@ -1357,7 +1449,22 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe setQrScanSuccess(false); startScan(); }, [startScan]); - + const handlePickOrderSwitch = useCallback(async (pickOrderId: number) => { + if (pickOrderSwitching) return; + + setPickOrderSwitching(true); + try { + console.log("🔍 Switching to pick order:", pickOrderId); + setSelectedPickOrderId(pickOrderId); + + // ✅ 强制刷新数据,确保显示正确的 pick order 数据 + await fetchAllCombinedLotData(currentUserId, pickOrderId); + } catch (error) { + console.error("Error switching pick order:", error); + } finally { + setPickOrderSwitching(false); + } + }, [pickOrderSwitching, currentUserId, fetchAllCombinedLotData]); const handleStopScan = useCallback(() => { console.log("⏹️ Stopping manual QR scan..."); setIsManualScanning(false); @@ -1488,370 +1595,378 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe }, [t]); return ( ( - lot.lotAvailability !== 'rejected' && - lot.stockOutLineStatus !== 'rejected' && - lot.stockOutLineStatus !== 'completed' - )} - > - + lotData={combinedLotData} + onScanLot={handleQrCodeSubmit} + filterActive={(lot) => ( + lot.lotAvailability !== 'rejected' && + lot.stockOutLineStatus !== 'rejected' && + lot.stockOutLineStatus !== 'completed' + )} + > + + + {/* DO Header */} + {fgPickOrdersLoading ? ( + + + + ) : ( + fgPickOrders.length > 0 && ( + + + {/* 基本信息 */} + + + {t("Shop Name")}: {fgPickOrders[0].shopName || '-'} + + + {t("Store ID")}: {fgPickOrders[0].storeId || '-'} + + + {t("Ticket No.")}: {fgPickOrders[0].ticketNo || '-'} + + + {t("Departure Time")}: {fgPickOrders[0].DepartureTime || '-'} + + + + + + ) + )} + + {/* ✅ FG Info Card */} - - - - {/* DO Header */} - {fgPickOrdersLoading ? ( - - - - ) : ( - fgPickOrders.length > 0 && ( - - - - {t("Shop Name")}: {fgPickOrders[0].shopName || '-'} - - - {t("Pick Order Code")}:{fgPickOrders[0].pickOrderCode || '-'} - - - {t("Store ID")}: {fgPickOrders[0].storeId || '-'} - - - {t("Ticket No.")}: {fgPickOrders[0].ticketNo || '-'} - - - {t("Departure Time")}: {fgPickOrders[0].DepartureTime || '-'} - - - - - ) - )} - - - {/* Combined Lot Table */} - - - - {t("All Pick Order Lots")} - - - - {!isManualScanning ? ( + {/* ✅ Pick Order Switcher - 放在 FG Info 下面,QR 按钮上面 */} + {availablePickOrders.length > 1 && ( + + + {t("Select Pick Order:")} + + + {availablePickOrders.map((po: any) => ( + handlePickOrderSwitch(po.pickOrderId)} + color={selectedPickOrderId === po.pickOrderId ? "primary" : "default"} + variant={selectedPickOrderId === po.pickOrderId ? "filled" : "outlined"} + sx={{ + cursor: 'pointer', + '&:hover': { backgroundColor: 'primary.light', color: 'white' } + }} + /> + ))} + + +)} + + {/* ✅ 保留:Combined Lot Table - 包含所有 QR 扫描功能 */} + + + + {t("All Pick Order Lots")} + + + + {!isManualScanning ? ( + + ) : ( + + )} + + {/* ✅ 保留:Submit All Scanned Button */} - ) : ( - - )} - - {/* ✅ ADD THIS: Submit All Scanned Button */} - - + - - - {qrScanError && !qrScanSuccess && ( - - {t("QR code does not match any item in current orders.")} - - )} - {qrScanSuccess && ( - - {t("QR code verified.")} - - )} - - - - - - {t("Index")} - {t("Route")} - {t("Item Code")} - {t("Item Name")} - {t("Lot#")} - {/* {t("Target Date")} */} - {/* {t("Lot Location")} */} - {t("Lot Required Pick Qty")} - {/* {t("Original Available Qty")} */} - {t("Scan Result")} - {t("Submit Required Pick Qty")} - {/* {t("Remaining Available Qty")} */} - - {/* {t("Action")} */} - - - - {paginatedData.length === 0 ? ( + + {qrScanError && !qrScanSuccess && ( + + {t("QR code does not match any item in current orders.")} + + )} + {qrScanSuccess && ( + + {t("QR code verified.")} + + )} + + +
+ - - - {t("No data available")} - - + {t("Index")} + {t("Route")} + {t("Item Code")} + {t("Item Name")} + {t("Lot#")} + {t("Lot Required Pick Qty")} + {t("Scan Result")} + {t("Submit Required Pick Qty")} - ) : ( - paginatedData.map((lot, index) => ( - - - - {index + 1} - - - - - {lot.routerRoute || '-'} + + + {paginatedData.length === 0 ? ( + + + + {t("No data available")} - {lot.itemCode} - {lot.itemName+'('+lot.stockUnit+')'} - - - - {lot.lotNo} - - - - {/* {lot.pickOrderTargetDate} */} - {/* {lot.location} */} - {/* {calculateRemainingRequiredQty(lot).toLocaleString()} */} - - {(() => { - const inQty = lot.inQty || 0; - const requiredQty = lot.requiredQty || 0; - const actualPickQty = lot.actualPickQty || 0; - const outQty = lot.outQty || 0; - const result = requiredQty; - return result.toLocaleString()+'('+lot.uomShortDesc+')'; - })()} - - - - {lot.stockOutLineStatus?.toLowerCase() !== 'pending' ? ( - - - - ) : null} - - - - - - - - - - - - - - )) - )} - -
-
- {/* ✅ Status Messages Display - Move here, outside the table */} - {/* -{paginatedData.length > 0 && ( - - {paginatedData.map((lot, index) => ( - - - {t("Lot")} {lot.lotNo}: {getStatusMessage(lot)} + + ) : ( +// 在第 1797-1938 行之间,将整个 map 函数修改为: +paginatedData.map((lot, index) => { + // ✅ 检查是否是 issue lot + const isIssueLot = lot.stockOutLineStatus === 'rejected' || !lot.lotNo; + + return ( + + + + {index + 1} - - ))} - -)} -*/} - - `${from}-${to} of ${count !== -1 ? count : `more than ${to}`}` - } - /> + + + + {lot.routerRoute || '-'} + + + {lot.itemCode} + {lot.itemName + '(' + lot.stockUnit + ')'} + + + + {lot.lotNo || t('⚠️ No Stock Available')} + -
- - {/* ✅ QR Code Modal */} - { - setQrModalOpen(false); - setSelectedLotForQr(null); - stopScan(); - resetScan(); - }} - lot={selectedLotForQr} - combinedLotData={combinedLotData} // ✅ Add this prop - onQrCodeSubmit={handleQrCodeSubmitFromModal} - /> - {/* ✅ Lot Confirmation Modal */} - {lotConfirmationOpen && expectedLotData && scannedLotData && ( - { - setLotConfirmationOpen(false); - setExpectedLotData(null); - setScannedLotData(null); - }} - onConfirm={handleLotConfirmation} - expectedLot={expectedLotData} - scannedLot={scannedLotData} - isLoading={isConfirmingLot} - /> - )} - {/* ✅ Good Pick Execution Form Modal */} - {pickExecutionFormOpen && selectedLotForExecutionForm && ( - + + {(() => { + const requiredQty = lot.requiredQty || 0; + return requiredQty.toLocaleString() + '(' + lot.uomShortDesc + ')'; + })()} + + + + {/* ✅ Issue lot 不显示扫描状态 */} + {!isIssueLot && lot.stockOutLineStatus?.toLowerCase() !== 'pending' ? ( + + + + ) : isIssueLot ? ( + null + ) : null} + + + + + {isIssueLot ? ( + // ✅ Issue lot 只显示 Issue 按钮 + + ) : ( + // ✅ Normal lot 显示两个按钮 + + + + + + )} + + + + ); +}) + )} + + + + + + `${from}-${to} of ${count !== -1 ? count : `more than ${to}`}` + } + /> +
+
+ + {/* ✅ 保留:QR Code Modal */} + { - setPickExecutionFormOpen(false); - setSelectedLotForExecutionForm(null); - }} - onSubmit={handlePickExecutionFormSubmit} - selectedLot={selectedLotForExecutionForm} - selectedPickOrderLine={{ - id: selectedLotForExecutionForm.pickOrderLineId, - itemId: selectedLotForExecutionForm.itemId, - itemCode: selectedLotForExecutionForm.itemCode, - itemName: selectedLotForExecutionForm.itemName, - pickOrderCode: selectedLotForExecutionForm.pickOrderCode, - // ✅ Add missing required properties from GetPickOrderLineInfo interface - availableQty: selectedLotForExecutionForm.availableQty || 0, - requiredQty: selectedLotForExecutionForm.requiredQty || 0, - uomCode: selectedLotForExecutionForm.uomCode || '', - uomDesc: selectedLotForExecutionForm.uomDesc || '', - pickedQty: selectedLotForExecutionForm.actualPickQty || 0, // ✅ Use pickedQty instead of actualPickQty - suggestedList: [] // ✅ Add required suggestedList property + setQrModalOpen(false); + setSelectedLotForQr(null); + stopScan(); + resetScan(); }} - pickOrderId={selectedLotForExecutionForm.pickOrderId} - pickOrderCreateDate={new Date()} + lot={selectedLotForQr} + combinedLotData={combinedLotData} + onQrCodeSubmit={handleQrCodeSubmitFromModal} /> - )} -
+ + {/* ✅ 保留:Lot Confirmation Modal */} + {lotConfirmationOpen && expectedLotData && scannedLotData && ( + { + setLotConfirmationOpen(false); + setExpectedLotData(null); + setScannedLotData(null); + }} + onConfirm={handleLotConfirmation} + expectedLot={expectedLotData} + scannedLot={scannedLotData} + isLoading={isConfirmingLot} + /> + )} + + {/* ✅ 保留:Good Pick Execution Form Modal */} + {pickExecutionFormOpen && selectedLotForExecutionForm && ( + { + setPickExecutionFormOpen(false); + setSelectedLotForExecutionForm(null); + }} + onSubmit={handlePickExecutionFormSubmit} + selectedLot={selectedLotForExecutionForm} + selectedPickOrderLine={{ + id: selectedLotForExecutionForm.pickOrderLineId, + itemId: selectedLotForExecutionForm.itemId, + itemCode: selectedLotForExecutionForm.itemCode, + itemName: selectedLotForExecutionForm.itemName, + pickOrderCode: selectedLotForExecutionForm.pickOrderCode, + availableQty: selectedLotForExecutionForm.availableQty || 0, + requiredQty: selectedLotForExecutionForm.requiredQty || 0, + // uomCode: selectedLotForExecutionForm.uomCode || '', + uomDesc: selectedLotForExecutionForm.uomDesc || '', + pickedQty: selectedLotForExecutionForm.actualPickQty || 0, + uomShortDesc: selectedLotForExecutionForm.uomShortDesc || '', + suggestedList: [] + }} + pickOrderId={selectedLotForExecutionForm.pickOrderId} + pickOrderCreateDate={new Date()} + /> + )} +
); }; From b248fda35c5dd0349f5841ad7a6dd94459a362af Mon Sep 17 00:00:00 2001 From: kelvinsuen Date: Tue, 21 Oct 2025 12:36:32 +0800 Subject: [PATCH 3/6] update stock in form sx --- src/components/StockIn/FgStockInForm.tsx | 2 +- src/components/StockIn/StockInForm.tsx | 2 +- src/i18n/zh/purchaseOrder.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/StockIn/FgStockInForm.tsx b/src/components/StockIn/FgStockInForm.tsx index af46970..467f3e6 100644 --- a/src/components/StockIn/FgStockInForm.tsx +++ b/src/components/StockIn/FgStockInForm.tsx @@ -67,7 +67,7 @@ const textfieldSx = { transform: "translate(14px, 1.2rem) scale(1)", "&.MuiInputLabel-shrink": { fontSize: 24, - transform: "translate(14px, -0.5rem) scale(1)", + transform: "translate(14px, -9px) scale(1)", }, // [theme.breakpoints.down("sm")]: { // fontSize: "1rem", diff --git a/src/components/StockIn/StockInForm.tsx b/src/components/StockIn/StockInForm.tsx index 8b88692..e48c0d9 100644 --- a/src/components/StockIn/StockInForm.tsx +++ b/src/components/StockIn/StockInForm.tsx @@ -60,7 +60,7 @@ const textfieldSx = { transform: "translate(14px, 1.2rem) scale(1)", "&.MuiInputLabel-shrink": { fontSize: 24, - transform: "translate(14px, -0.5rem) scale(1)", + transform: "translate(14px, -9px) scale(1)", }, // [theme.breakpoints.down("sm")]: { // fontSize: "1rem", diff --git a/src/i18n/zh/purchaseOrder.json b/src/i18n/zh/purchaseOrder.json index 806a1e8..6dd7d9c 100644 --- a/src/i18n/zh/purchaseOrder.json +++ b/src/i18n/zh/purchaseOrder.json @@ -164,5 +164,6 @@ "Expiry Date cannot be earlier than Production Date": "到期日不可早於生產日期", "Production Date must be earlier than Expiry Date": "生產日期必須早於到期日", "confirm expiry date": "確認到期日", - "Invalid Date": "無效日期" + "Invalid Date": "無效日期", + "Missing QC Template, please contact administrator": "找不到品檢模板,請聯絡管理員" } From 9de4dd601f35f9e687798c6805a5b177e7f30736 Mon Sep 17 00:00:00 2001 From: kelvinsuen Date: Tue, 21 Oct 2025 12:44:59 +0800 Subject: [PATCH 4/6] update jo printer --- src/components/JoSearch/JoSearch.tsx | 8 +++++--- src/components/JoSearch/JoSearchWrapper.tsx | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/components/JoSearch/JoSearch.tsx b/src/components/JoSearch/JoSearch.tsx index 2cb7fd7..b05ee0d 100644 --- a/src/components/JoSearch/JoSearch.tsx +++ b/src/components/JoSearch/JoSearch.tsx @@ -16,7 +16,7 @@ import { Button, Stack } from "@mui/material"; import { BomCombo } from "@/app/api/bom"; import JoCreateFormModal from "./JoCreateFormModal"; import AddIcon from '@mui/icons-material/Add'; -import QcStockInModal from "../PoDetail/QcStockInModal"; +import QcStockInModal from "../Qc/QcStockInModal"; import { useSession } from "next-auth/react"; import { SessionWithTokens } from "@/config/authConfig"; import { createStockInLine } from "@/app/api/stockIn/actions"; @@ -25,17 +25,19 @@ import dayjs from "dayjs"; import { fetchInventories } from "@/app/api/inventory/actions"; import { InventoryResult } from "@/app/api/inventory"; +import { PrinterCombo } from "@/app/api/settings/printer"; interface Props { defaultInputs: SearchJoResultRequest, bomCombo: BomCombo[] + printerCombo: PrinterCombo[]; } type SearchQuery = Partial>; type SearchParamNames = keyof SearchQuery; -const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { +const JoSearch: React.FC = ({ defaultInputs, bomCombo, printerCombo }) => { const { t } = useTranslation("jo"); const router = useRouter() const [filteredJos, setFilteredJos] = useState([]); @@ -426,7 +428,7 @@ const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { open={openModal} onClose={closeNewModal} inputDetail={modalInfo} - printerCombo={[]} + printerCombo={printerCombo} // skipQc={true} /> diff --git a/src/components/JoSearch/JoSearchWrapper.tsx b/src/components/JoSearch/JoSearchWrapper.tsx index 7972d56..78470d6 100644 --- a/src/components/JoSearch/JoSearchWrapper.tsx +++ b/src/components/JoSearch/JoSearchWrapper.tsx @@ -3,6 +3,7 @@ import GeneralLoading from "../General/GeneralLoading"; import JoSearch from "./JoSearch"; import { SearchJoResultRequest } from "@/app/api/jo/actions"; import { fetchBomCombo } from "@/app/api/bom"; +import { fetchPrinterCombo } from "@/app/api/settings/printer"; interface SubComponents { Loading: typeof GeneralLoading; @@ -15,12 +16,14 @@ const JoSearchWrapper: React.FC & SubComponents = async () => { } const [ - bomCombo + bomCombo, + printerCombo ] = await Promise.all([ - fetchBomCombo() + fetchBomCombo(), + fetchPrinterCombo() ]) - return + return } JoSearchWrapper.Loading = GeneralLoading; From d9605e7b79c9f70f80e8332993e4ee69fb9cf841 Mon Sep 17 00:00:00 2001 From: kelvinsuen Date: Tue, 21 Oct 2025 12:47:39 +0800 Subject: [PATCH 5/6] quick fix --- src/components/JoSearch/JoSearch.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/JoSearch/JoSearch.tsx b/src/components/JoSearch/JoSearch.tsx index b05ee0d..bb6d596 100644 --- a/src/components/JoSearch/JoSearch.tsx +++ b/src/components/JoSearch/JoSearch.tsx @@ -16,7 +16,7 @@ import { Button, Stack } from "@mui/material"; import { BomCombo } from "@/app/api/bom"; import JoCreateFormModal from "./JoCreateFormModal"; import AddIcon from '@mui/icons-material/Add'; -import QcStockInModal from "../Qc/QcStockInModal"; +import QcStockInModal from "../PoDetail/QcStockInModal"; import { useSession } from "next-auth/react"; import { SessionWithTokens } from "@/config/authConfig"; import { createStockInLine } from "@/app/api/stockIn/actions"; From a4cd85419e833bdc707f2c67f2b01580a9d42e3b Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 22 Oct 2025 14:29:03 +0800 Subject: [PATCH 6/6] fix bugs --- src/components/Logo/Logo.tsx | 8 ++++---- src/components/MailField/MailField.css | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx index 4750e72..de2ea41 100644 --- a/src/components/Logo/Logo.tsx +++ b/src/components/Logo/Logo.tsx @@ -14,16 +14,16 @@ const Logo: React.FC = ({ width, height }) => { diff --git a/src/components/MailField/MailField.css b/src/components/MailField/MailField.css index 50237e1..96e7fb9 100644 --- a/src/components/MailField/MailField.css +++ b/src/components/MailField/MailField.css @@ -123,7 +123,7 @@ /* Input styles */ /* .tiptap-input { - font-size: 14px; + fontSize: 14px; font-weight: 500; line-height: 12px; } */ \ No newline at end of file