Browse Source

batch release update

master
kelvin.yau 2 months ago
parent
commit
2afa8895ff
2 changed files with 75 additions and 89 deletions
  1. +72
    -88
      src/components/DoSearch/DoSearch.tsx
  2. +3
    -1
      src/i18n/zh/do.json

+ 72
- 88
src/components/DoSearch/DoSearch.tsx View File

@@ -26,12 +26,13 @@ import {
SubmitHandler, SubmitHandler,
useForm, useForm,
} from "react-hook-form"; } from "react-hook-form";
import { Box, Button, Grid, Stack, Typography, TablePagination } from "@mui/material";
import { Box, Button, Grid, Stack, Typography, TablePagination} from "@mui/material";
import StyledDataGrid from "../StyledDataGrid"; import StyledDataGrid from "../StyledDataGrid";
import { GridRowSelectionModel } from "@mui/x-data-grid"; import { GridRowSelectionModel } from "@mui/x-data-grid";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig"; import { SessionWithTokens } from "@/config/authConfig";

type Props = { type Props = {
filterArgs?: Record<string, any>; filterArgs?: Record<string, any>;
searchQuery?: Record<string, any>; searchQuery?: Record<string, any>;
@@ -64,7 +65,7 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear
const { data: session } = useSession() as { data: SessionWithTokens | null }; const { data: session } = useSession() as { data: SessionWithTokens | null };
const currentUserId = session?.id ? parseInt(session.id) : undefined; const currentUserId = session?.id ? parseInt(session.id) : undefined;
console.log("🔍 DoSearch - session:", session); console.log("🔍 DoSearch - session:", session);
console.log("🔍 DoSearch - currentUserId:", currentUserId);
console.log("🔍 DoSearch - currentUserId:", currentUserId);
const [searchTimeout, setSearchTimeout] = useState<NodeJS.Timeout | null>(null); const [searchTimeout, setSearchTimeout] = useState<NodeJS.Timeout | null>(null);
const [rowSelectionModel, setRowSelectionModel] = const [rowSelectionModel, setRowSelectionModel] =
useState<GridRowSelectionModel>([]); useState<GridRowSelectionModel>([]);
@@ -356,43 +357,32 @@ console.log("🔍 DoSearch - currentUserId:", currentUserId);
setSearchTimeout(timeout); setSearchTimeout(timeout);
}, [handleSearch, searchTimeout]); }, [handleSearch, searchTimeout]);

const handleBatchRelease = useCallback(async () => { const handleBatchRelease = useCallback(async () => {
const selectedIds = rowSelectionModel as number[];
if (!selectedIds.length) return;
console.log("🔍 handleBatchRelease - currentUserId:", currentUserId);
console.log("🔍 handleBatchRelease - selectedIds:", selectedIds);
const totalDeliveryOrderLines = searchAllDos.reduce((sum, doItem) => {
return sum + (doItem.deliveryOrderLines?.length || 0);
}, 0);

const result = await Swal.fire({ const result = await Swal.fire({
icon: "question", icon: "question",
title: t("Batch Release"), title: t("Batch Release"),
html: ` html: `
<div> <div>
<p>${t("Selected items on current page")}: ${selectedIds.length}</p>
<p>${t("Total search results")}: ${searchAllDos.length}</p>
<hr>
<p><strong>${t("Choose release option")}:</strong></p>
<p>${t("Selected Shop(s): ")}${searchAllDos.length}</p>
<p>${t("Selected Item(s): ")}${totalDeliveryOrderLines}</p>
</div> </div>
`, `,
showCancelButton: true, showCancelButton: true,
confirmButtonText: t("Release All Search Results"),
cancelButtonText: t("Release Selected Only"),
denyButtonText: t("Cancel"),
showDenyButton: true,
confirmButtonText: t("Confirm"),
cancelButtonText: t("Cancel"),
confirmButtonColor: "#8dba00", confirmButtonColor: "#8dba00",
cancelButtonColor: "#2196f3",
denyButtonColor: "#F04438"
cancelButtonColor: "#F04438"
}); });
if (result.isDenied) return;
let idsToRelease: number[];
if (result.isConfirmed) { if (result.isConfirmed) {
idsToRelease = searchAllDos.map(d => d.id);
} else {
idsToRelease = selectedIds;
}
const idsToRelease = searchAllDos.map(d => d.id);

try { try {
const startRes = await startBatchReleaseAsync({ ids: idsToRelease, userId: currentUserId ?? 1 }); const startRes = await startBatchReleaseAsync({ ids: idsToRelease, userId: currentUserId ?? 1 });
const jobId = startRes?.entity?.jobId; const jobId = startRes?.entity?.jobId;
@@ -401,70 +391,64 @@ console.log("🔍 DoSearch - currentUserId:", currentUserId);
await Swal.fire({ icon: "error", title: t("Error"), text: t("Failed to start batch release") }); await Swal.fire({ icon: "error", title: t("Error"), text: t("Failed to start batch release") });
return; return;
} }
await Swal.fire({
title: t("Releasing"),
html: `
<div style="text-align:left">
<div id="br-total">${t("Total")}: 0</div>
<div id="br-finished">${t("Finished")}: 0</div>
<div style="margin-top:8px;height:8px;background:#eee;border-radius:4px;">
<div id="br-bar" style="height:8px;width:0%;background:#8dba00;border-radius:4px;"></div>
</div>
</div>
`,
allowOutsideClick: false,
allowEscapeKey: false,
showConfirmButton: false,
didOpen: async () => {
const update = (total:number, finished:number, success:number, failed:number) => {
const bar = document.getElementById("br-bar") as HTMLElement;
const pct = total > 0 ? Math.floor((finished / total) * 100) : 0;
(document.getElementById("br-total") as HTMLElement).innerText = `${t("Total")}: ${total}`;
(document.getElementById("br-finished") as HTMLElement).innerText = `${t("Finished")}: ${finished}`;
if (bar) bar.style.width = `${pct}%`;
};
const timer = setInterval(async () => {
try {
const p = await getBatchReleaseProgress(jobId);
const e = p?.entity || {};
update(e.total ?? 0, e.finished ?? 0, e.success ?? 0, e.failedCount ?? 0);
if (p.code === "FINISHED" || e.running === false) {
clearInterval(timer);
Swal.close();
// 简化完成提示 - 只显示完成,不显示成功/失败统计
await Swal.fire({
icon: "success",
title: t("Completed"),
text: t("Batch release completed"),
confirmButtonText: t("OK")
});
if (currentSearchParams && Object.keys(currentSearchParams).length > 0) {
await handleSearch(currentSearchParams);
}
setRowSelectionModel([]);
}
} catch (err) {
console.error("progress poll error:", err);
}
}, 800);


const progressSwal = Swal.fire({
title: t("Releasing"),
text: "0% (0 / 0)",
allowOutsideClick: false,
allowEscapeKey: false,
showConfirmButton: false,
didOpen: () => {
Swal.showLoading();
}
});
const timer = setInterval(async () => {
try {
const p = await getBatchReleaseProgress(jobId);
const e = p?.entity || {};
const total = e.total ?? 0;
const finished = e.finished ?? 0;
const percentage = total > 0 ? Math.round((finished / total) * 100) : 0;
const textContent = document.querySelector('.swal2-html-container');
if (textContent) {
textContent.textContent = `${percentage}% (${finished} / ${total})`;
} }
});
} catch (error) {
console.error("Batch release error:", error);
await Swal.fire({
icon: "error",
title: t("Error"),
text: t("An error occurred during batch release"),
confirmButtonText: t("OK")
});
}
}, [rowSelectionModel, t, currentUserId, searchAllDos, currentSearchParams, handleSearch]);

if (p.code === "FINISHED" || e.running === false) {
clearInterval(timer);
await new Promise(resolve => setTimeout(resolve, 500));
Swal.close();
await Swal.fire({
icon: "success",
title: t("Completed"),
text: t("Batch release completed successfully."),
confirmButtonText: t("Confirm"),
confirmButtonColor: "#8dba00"
});
if (currentSearchParams && Object.keys(currentSearchParams).length > 0) {
await handleSearch(currentSearchParams);
}
}
} catch (err) {
console.error("progress poll error:", err);
}
}, 800);
} catch (error) {
console.error("Batch release error:", error);
await Swal.fire({
icon: "error",
title: t("Error"),
text: t("An error occurred during batch release"),
confirmButtonText: t("OK")
});
}}
}, [t, currentUserId, searchAllDos, currentSearchParams, handleSearch]);




return ( return (


+ 3
- 1
src/i18n/zh/do.json View File

@@ -55,5 +55,7 @@
"Pick Order Assignment": "提料單分配", "Pick Order Assignment": "提料單分配",
"Release 2/F": "放單2/F", "Release 2/F": "放單2/F",
"Release 4/F": "放單4/F", "Release 4/F": "放單4/F",
"Stock Status": "庫存狀態"
"Stock Status": "庫存狀態",
"Finished: ": "已放送貨訂單:",
"Total:": "已選擇送貨訂單:"
} }

Loading…
Cancel
Save