From 1343362dc5829d7dab60e4cac2cd4a884144d626 Mon Sep 17 00:00:00 2001 From: "PC-20260115JRSN\\Administrator" Date: Wed, 18 Mar 2026 23:56:13 +0800 Subject: [PATCH] no message --- src/app/(main)/testing/page.tsx | 68 +++++++++++++++++++++++++++++++++ src/app/error.tsx | 31 +++++++++++++++ src/app/global-error.tsx | 41 ++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 src/app/error.tsx create mode 100644 src/app/global-error.tsx diff --git a/src/app/(main)/testing/page.tsx b/src/app/(main)/testing/page.tsx index ae22386..21c4048 100644 --- a/src/app/(main)/testing/page.tsx +++ b/src/app/(main)/testing/page.tsx @@ -11,6 +11,7 @@ import { FileDownload, Print, SettingsEthernet, Lan, Router } from "@mui/icons-m import dayjs from "dayjs"; import { NEXT_PUBLIC_API_URL } from "@/config/api"; import { clientAuthFetch } from "@/app/utils/clientAuthFetch"; +import * as XLSX from "xlsx"; // Simple TabPanel component for conditional rendering interface TabPanelProps { @@ -87,6 +88,9 @@ export default function TestingPage() { }, ]); + // --- 6. GRN Preview (M18) --- + const [grnPreviewReceiptDate, setGrnPreviewReceiptDate] = useState("2026-03-16"); + // Generic handler for inline table edits const handleItemChange = (setter: any, id: number, field: string, value: string) => { setter((prev: any[]) => prev.map(item => @@ -207,6 +211,42 @@ export default function TestingPage() { } }; + // GRN Preview CSV Download (Section 6) + const handleDownloadGrnPreviewXlsx = async () => { + try { + const response = await clientAuthFetch( + `${NEXT_PUBLIC_API_URL}/report/grn-preview-m18?receiptDate=${encodeURIComponent(grnPreviewReceiptDate)}`, + { method: "GET" }, + ); + if (response.status === 401 || response.status === 403) return; + if (!response.ok) throw new Error(`Download failed: ${response.status}`); + + const data = await response.json(); + const rows = Array.isArray(data?.rows) ? data.rows : []; + + const ws = XLSX.utils.json_to_sheet(rows); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, "GRN Preview"); + + const xlsxArrayBuffer = XLSX.write(wb, { bookType: "xlsx", type: "array" }); + const blob = new Blob([xlsxArrayBuffer], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + + const url = window.URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.setAttribute("download", `grn-preview-m18-${grnPreviewReceiptDate}.xlsx`); + document.body.appendChild(link); + link.click(); + link.remove(); + window.URL.revokeObjectURL(url); + } catch (e) { + console.error("GRN Preview XLSX Download Error:", e); + alert("GRN Preview XLSX download failed. Check console/network."); + } + }; + // Layout Helper const Section = ({ title, children }: { title: string, children?: React.ReactNode }) => ( @@ -227,6 +267,7 @@ export default function TestingPage() { + @@ -455,6 +496,33 @@ export default function TestingPage() { + +
+ + setGrnPreviewReceiptDate(e.target.value)} + InputLabelProps={{ shrink: true }} + /> + + + + Backend endpoint: /report/grn-preview-m18?receiptDate=YYYY-MM-DD + +
+
+ {/* Dialog for OnPack */} setIsPrinterModalOpen(false)} fullWidth maxWidth="sm"> OnPack Printer Job Details diff --git a/src/app/error.tsx b/src/app/error.tsx new file mode 100644 index 0000000..c365aa8 --- /dev/null +++ b/src/app/error.tsx @@ -0,0 +1,31 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; + +/** + * When a server-side exception occurs (e.g. backend down during deploy), + * redirect to login instead of showing the default error page. + */ +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + const router = useRouter(); + + useEffect(() => { + // Redirect to login so user can re-authenticate after backend restart + router.replace("/login"); + }, [router]); + + return ( +
+

+ 連線異常,正在導向登入頁… +

+
+ ); +} diff --git a/src/app/global-error.tsx b/src/app/global-error.tsx new file mode 100644 index 0000000..cce15b9 --- /dev/null +++ b/src/app/global-error.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { useEffect } from "react"; + +/** + * Catches root-level errors (e.g. backend down during deploy). + * Redirects to login instead of showing the default "Application error" page. + * Must define and because this replaces the root layout. + */ +export default function GlobalError({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + useEffect(() => { + window.location.href = "/login"; + }, []); + + return ( + + +
+

+ 連線異常,正在導向登入頁… +

+
+ + + ); +}