Browse Source

補印Label

stable1
kelvin.yau 2 weeks ago
parent
commit
29dc796f43
2 changed files with 186 additions and 6 deletions
  1. +27
    -0
      src/app/api/do/actions.tsx
  2. +159
    -6
      src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx

+ 27
- 0
src/app/api/do/actions.tsx View File

@@ -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[];


+ 159
- 6
src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx View File

@@ -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<Props> = ({
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<Props> = ({
}, [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<Props> = ({
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<Props> = ({

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<Props> = ({
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<Props> = ({
}
}, [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: `
<div style="display:flex;flex-direction:column;gap:10px;text-align:left;">
<div style="display:flex;align-items:center;gap:12px;">
<label for="swal-from-carton" style="min-width:120px;">${t("From carton")}</label>
<input id="swal-from-carton" class="swal2-input" type="number" min="1" step="1" value="1" style="margin:0;flex:1;outline:none;box-shadow:none;border:1px solid #d9d9d9;" onfocus="this.style.outline='none';this.style.boxShadow='none';this.style.borderColor='#d9d9d9';" />
</div>
<div style="display:flex;align-items:center;gap:12px;">
<label for="swal-to-carton" style="min-width:120px;">${t("To carton")}</label>
<input id="swal-to-carton" class="swal2-input" type="number" min="1" step="1" value="1" style="margin:0;flex:1;outline:none;box-shadow:none;border:1px solid #d9d9d9;" onfocus="this.style.outline='none';this.style.boxShadow='none';this.style.borderColor='#d9d9d9';" />
</div>
<div style="display:flex;align-items:center;gap:12px;">
<label for="swal-total-carton" style="min-width:120px;">${t("Total cartons on shipment")}</label>
<input id="swal-total-carton" class="swal2-input" type="number" min="1" step="1" value="${defaultTotalCartons}" style="margin:0;flex:1;outline:none;box-shadow:none;border:1px solid #d9d9d9;" onfocus="this.style.outline='none';this.style.boxShadow='none';this.style.borderColor='#d9d9d9';" />
</div>
</div>
`,
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")}
</Button>
<Button
variant="contained"
onClick={() => handleLabelReprint(doPickOrder)}
>
{t("Reprint Label(s)")}
</Button>
</>
</CardActions>


Loading…
Cancel
Save