|
|
@@ -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 ( |
|
|
|