diff --git a/src/app/api/do/actions.tsx b/src/app/api/do/actions.tsx index 76304b7..2e27cba 100644 --- a/src/app/api/do/actions.tsx +++ b/src/app/api/do/actions.tsx @@ -100,6 +100,15 @@ export interface PrintDNLabelsRequest{ numOfCarton: number; } +export interface PrintDNLabelsReprintRequest{ + doPickOrderId: number; + printerId: number; + printQty: number; + fromCarton: number; + toCarton: number; + totalCartonsOnShipment: number; +} + export interface PrintDNLabelsRespone{ success: boolean; message?: string @@ -423,6 +432,24 @@ export async function printDNLabels(request: PrintDNLabelsRequest){ return { success: true, message: "Print job sent successfully (labels)"} as PrintDeliveryNoteResponse } + +export async function printDNLabelsReprint(request: PrintDNLabelsReprintRequest){ + const params = new URLSearchParams(); + params.append('doPickOrderId', request.doPickOrderId.toString()); + params.append('printerId', request.printerId.toString()); + if (request.printQty !== null && request.printQty !== undefined) { + params.append('printQty', request.printQty.toString()); + } + params.append('fromCarton', request.fromCarton.toString()); + params.append('toCarton', request.toCarton.toString()); + params.append('totalCartonsOnShipment', request.totalCartonsOnShipment.toString()); + + await serverFetchWithNoContent(`${BASE_API_URL}/do/print-DNLabels-reprint?${params.toString()}`,{ + method: "GET" + }); + + return { success: true, message: "Print job sent successfully (reprint labels)"} as PrintDeliveryNoteResponse +} export interface Check4FTruckBatchResponse { hasProblem: boolean; problems: ProblemDoDto[]; diff --git a/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx b/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx index 0eb72ed..e8510bb 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx @@ -66,7 +66,7 @@ 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 { printDN, printDNLabels, printDNLabelsReprint } from "@/app/api/do/actions"; import Swal from "sweetalert2"; @@ -173,7 +173,20 @@ const GoodPickExecutionRecord: React.FC = ({ confirmButtonColor: "#8dba00", cancelButtonColor: "#F04438", showLoaderOnConfirm: true, - allowOutsideClick: () => !Swal.isLoading() + allowOutsideClick: () => !Swal.isLoading(), + didOpen: () => { + const input = Swal.getInput() as HTMLInputElement | null; + if (input) { + input.style.outline = "none"; + input.style.boxShadow = "none"; + input.style.border = "1px solid #d9d9d9"; + input.onfocus = () => { + input.style.outline = "none"; + input.style.boxShadow = "none"; + input.style.borderColor = "#d9d9d9"; + }; + } + } }); if (askNumofCarton.isConfirmed) { @@ -209,7 +222,7 @@ const GoodPickExecutionRecord: React.FC = ({ }, [t, a4Printer]); const handleDNandLabel = useCallback(async (recordId: number) => { - if (!a4Printer || !labelPrinter) { + if (!a4Printer) { Swal.fire({ position: "bottom-end", icon: "warning", @@ -253,7 +266,20 @@ const GoodPickExecutionRecord: React.FC = ({ confirmButtonColor: "#8dba00", cancelButtonColor: "#F04438", showLoaderOnConfirm: true, - allowOutsideClick: () => !Swal.isLoading() + allowOutsideClick: () => !Swal.isLoading(), + didOpen: () => { + const input = Swal.getInput() as HTMLInputElement | null; + if (input) { + input.style.outline = "none"; + input.style.boxShadow = "none"; + input.style.border = "1px solid #d9d9d9"; + input.onfocus = () => { + input.style.outline = "none"; + input.style.boxShadow = "none"; + input.style.borderColor = "#d9d9d9"; + }; + } + } }); if (askNumofCarton.isConfirmed) { @@ -307,6 +333,17 @@ const GoodPickExecutionRecord: React.FC = ({ const handleLabel = useCallback(async (recordId: number) => { console.log(" [Print Label] Button clicked for recordId:", recordId); + if (!labelPrinter) { + Swal.fire({ + position: "bottom-end", + icon: "warning", + text: t("Please select a label printer first"), + showConfirmButton: false, + timer: 1500 + }); + return; + } + const askNumofCarton = await Swal.fire({ title: t("Enter the number of cartons: "), icon: "info", @@ -331,14 +368,27 @@ const GoodPickExecutionRecord: React.FC = ({ confirmButtonColor: "#8dba00", cancelButtonColor: "#F04438", showLoaderOnConfirm: true, - allowOutsideClick: () => !Swal.isLoading() + allowOutsideClick: () => !Swal.isLoading(), + didOpen: () => { + const input = Swal.getInput() as HTMLInputElement | null; + if (input) { + input.style.outline = "none"; + input.style.boxShadow = "none"; + input.style.border = "1px solid #d9d9d9"; + input.onfocus = () => { + input.style.outline = "none"; + input.style.boxShadow = "none"; + input.style.borderColor = "#d9d9d9"; + }; + } + } }); if (askNumofCarton.isConfirmed) { const numOfCartons = askNumofCarton.value; try{ const printRequest = { - printerId: labelPrinter?.id ?? 0, + printerId: labelPrinter.id, printQty: 1, numOfCarton: numOfCartons, doPickOrderId: recordId @@ -365,6 +415,103 @@ const GoodPickExecutionRecord: React.FC = ({ } }, [t, labelPrinter]); + const handleLabelReprint = useCallback(async (doPickOrder: CompletedDoPickOrderResponse) => { + if (!labelPrinter) { + Swal.fire({ + position: "bottom-end", + icon: "warning", + text: t("Please select a label printer first"), + showConfirmButton: false, + timer: 1500 + }); + return; + } + + const defaultTotalCartons = Math.max(1, doPickOrder.numberOfCartons || 1); + const result = await Swal.fire({ + title: t("Reprint DN Label"), + html: ` +
+
+ + +
+
+ + +
+
+ + +
+
+ `, + showCancelButton: true, + confirmButtonText: t("Confirm"), + cancelButtonText: t("Cancel"), + confirmButtonColor: "#8dba00", + cancelButtonColor: "#F04438", + focusConfirm: false, + preConfirm: () => { + const fromCarton = Number((document.getElementById("swal-from-carton") as HTMLInputElement | null)?.value || "0"); + const toCarton = Number((document.getElementById("swal-to-carton") as HTMLInputElement | null)?.value || "0"); + const totalCartonsOnShipment = Number((document.getElementById("swal-total-carton") as HTMLInputElement | null)?.value || "0"); + + if (!Number.isInteger(fromCarton) || fromCarton < 1) { + Swal.showValidationMessage(t("From carton must be at least 1")); + return null; + } + if (!Number.isInteger(toCarton) || toCarton < fromCarton) { + Swal.showValidationMessage(t("To carton must be greater than or equal to from carton")); + return null; + } + if (!Number.isInteger(totalCartonsOnShipment) || totalCartonsOnShipment < 1) { + Swal.showValidationMessage(t("Total cartons on shipment must be at least 1")); + return null; + } + if (toCarton > totalCartonsOnShipment) { + Swal.showValidationMessage(t("To carton cannot be greater than total cartons on shipment")); + return null; + } + + return { + fromCarton, + toCarton, + totalCartonsOnShipment, + }; + } + }); + + if (!result.isConfirmed || !result.value) { + return; + } + + try { + const response = await printDNLabelsReprint({ + doPickOrderId: doPickOrder.doPickOrderRecordId, + printerId: labelPrinter.id, + printQty: 1, + fromCarton: result.value.fromCarton, + toCarton: result.value.toCarton, + totalCartonsOnShipment: result.value.totalCartonsOnShipment, + }); + + if (response.success) { + Swal.fire({ + position: "bottom-end", + icon: "success", + text: t("Printed Successfully."), + showConfirmButton: false, + timer: 1500 + }); + } else { + console.error("Reprint failed:", response.message); + } + } catch (error) { + console.error("reprint error: ", error); + } + }, [labelPrinter, t]); + // 修改:使用新的 API 获取已完成的 DO Pick Orders const fetchCompletedDoPickOrdersData = useCallback(async (searchParams?: CompletedDoPickOrderSearchParams) => { if (listScope === "mine" && !currentUserId) return; @@ -843,6 +990,12 @@ if (showDetailView && selectedDoPickOrder) { > {t("Print Label")} +