Browse Source

no message

MergeProblem1
PC-20260115JRSN\Administrator 3 days ago
parent
commit
1343362dc5
3 changed files with 140 additions and 0 deletions
  1. +68
    -0
      src/app/(main)/testing/page.tsx
  2. +31
    -0
      src/app/error.tsx
  3. +41
    -0
      src/app/global-error.tsx

+ 68
- 0
src/app/(main)/testing/page.tsx View File

@@ -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 }) => (
<Paper sx={{ p: 3, minHeight: '450px', display: 'flex', flexDirection: 'column' }}>
@@ -227,6 +267,7 @@ export default function TestingPage() {
<Tab label="3. OnPack" />
<Tab label="4. Laser" />
<Tab label="5. HANS600S-M" />
<Tab label="6. GRN Preview" />
</Tabs>

<TabPanel value={tabValue} index={0}>
@@ -455,6 +496,33 @@ export default function TestingPage() {
</Section>
</TabPanel>

<TabPanel value={tabValue} index={5}>
<Section title="6. GRN Preview (M18)">
<Stack direction="row" spacing={2} sx={{ mb: 2, alignItems: "center" }}>
<TextField
size="small"
label="Receipt Date"
type="date"
value={grnPreviewReceiptDate}
onChange={(e) => setGrnPreviewReceiptDate(e.target.value)}
InputLabelProps={{ shrink: true }}
/>
<Button
variant="contained"
color="success"
size="medium"
startIcon={<FileDownload />}
onClick={handleDownloadGrnPreviewXlsx}
>
Download GRN Preview XLSX
</Button>
</Stack>
<Typography variant="body2" color="textSecondary">
Backend endpoint: <code>/report/grn-preview-m18?receiptDate=YYYY-MM-DD</code>
</Typography>
</Section>
</TabPanel>

{/* Dialog for OnPack */}
<Dialog open={isPrinterModalOpen} onClose={() => setIsPrinterModalOpen(false)} fullWidth maxWidth="sm">
<DialogTitle sx={{ bgcolor: 'success.main', color: 'white' }}>OnPack Printer Job Details</DialogTitle>


+ 31
- 0
src/app/error.tsx View File

@@ -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 (
<div className="flex min-h-[200px] flex-col items-center justify-center gap-2 p-4 text-center">
<p className="text-sm text-slate-600 dark:text-slate-400">
連線異常,正在導向登入頁…
</p>
</div>
);
}

+ 41
- 0
src/app/global-error.tsx View File

@@ -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 <html> and <body> because this replaces the root layout.
*/
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
window.location.href = "/login";
}, []);

return (
<html lang="zh-TW">
<body>
<div
style={{
display: "flex",
minHeight: "100vh",
alignItems: "center",
justifyContent: "center",
fontFamily: "system-ui, sans-serif",
padding: "1rem",
}}
>
<p style={{ color: "#64748b", fontSize: "0.875rem" }}>
連線異常,正在導向登入頁…
</p>
</div>
</body>
</html>
);
}

Loading…
Cancel
Save