167 lines
7.1 KiB
TypeScript
167 lines
7.1 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
||
import { Head } from '@inertiajs/react';
|
||
import JsBarcode from 'jsbarcode';
|
||
|
||
interface PrintProps {
|
||
doc: {
|
||
doc_no: string;
|
||
warehouse_name: string;
|
||
snapshot_date: string;
|
||
created_at: string;
|
||
print_date: string;
|
||
created_by: string;
|
||
items: Array<{
|
||
id: string;
|
||
product_name: string;
|
||
product_code: string;
|
||
specification: string;
|
||
unit: string;
|
||
quantity: number;
|
||
counted_qty: number | null;
|
||
notes: string;
|
||
}>;
|
||
};
|
||
}
|
||
|
||
export default function Print({ doc }: PrintProps) {
|
||
const barcodeRef = useRef<SVGSVGElement>(null);
|
||
|
||
useEffect(() => {
|
||
if (barcodeRef.current) {
|
||
try {
|
||
JsBarcode(barcodeRef.current, doc.doc_no, {
|
||
format: "CODE128",
|
||
width: 2, // Thicker bars for better scanning
|
||
height: 50, // Taller
|
||
displayValue: false,
|
||
margin: 10, // Mandatory quiet zone for scanners
|
||
marginBottom: 5
|
||
});
|
||
} catch (e) {
|
||
console.error("Barcode generation failed", e);
|
||
}
|
||
}
|
||
|
||
// Delay print slightly to ensure render
|
||
const timer = setTimeout(() => {
|
||
window.print();
|
||
}, 500);
|
||
|
||
return () => clearTimeout(timer);
|
||
}, [doc.doc_no]);
|
||
|
||
return (
|
||
<div className="bg-white text-black font-sans text-sm min-h-screen">
|
||
<Head title={`列印盤點單 ${doc.doc_no}`} />
|
||
|
||
<style>{`
|
||
@media print {
|
||
@page {
|
||
size: A4 landscape;
|
||
margin: 10mm;
|
||
}
|
||
body {
|
||
-webkit-print-color-adjust: exact;
|
||
print-color-adjust: exact;
|
||
}
|
||
/* Hide browser default header/footer if possible (browser dependent) */
|
||
}
|
||
`}</style>
|
||
|
||
{/* Header Section */}
|
||
<div className="relative mb-6">
|
||
{/* Barcode - Top Right */}
|
||
<div className="absolute top-0 right-0 flex flex-col items-end">
|
||
<svg ref={barcodeRef}></svg>
|
||
{/* <span className="text-xs font-mono mt-1">{doc.doc_no}</span> */}
|
||
</div>
|
||
|
||
{/* Company & Title - Center */}
|
||
<div className="text-center pt-4">
|
||
<h1 className="text-2xl font-bold tracking-widest mb-2">台灣心零售股份有限公司</h1>
|
||
<h2 className="text-xl font-bold tracking-widest">盤點單</h2>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Info Section */}
|
||
<div className="flex justify-between items-end mb-2 border-b-2 border-black pb-2">
|
||
<div className="space-y-1">
|
||
<div className="flex gap-4">
|
||
<span className="font-bold">單號:</span>
|
||
<span className="font-mono font-bold">{doc.doc_no}</span>
|
||
</div>
|
||
<div className="flex gap-4">
|
||
<span className="font-bold">日期:</span>
|
||
<span>{doc.created_at}</span>
|
||
</div>
|
||
<div className="flex gap-4">
|
||
<span className="font-bold">倉庫:</span>
|
||
<span>{doc.warehouse_name}</span>
|
||
</div>
|
||
</div>
|
||
<div className="text-right">
|
||
<div className="flex gap-4">
|
||
<span className="font-bold">印單日期:</span>
|
||
<span>{doc.print_date}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Table Section */}
|
||
<table className="w-full border-collapse border border-black mb-8">
|
||
<thead>
|
||
<tr className="bg-gray-100">
|
||
<th className="border border-black px-2 py-1 w-12 text-center">序號</th>
|
||
<th className="border border-black px-2 py-1 w-32 text-left">品號</th>
|
||
<th className="border border-black px-2 py-1 text-left">品名</th>
|
||
<th className="border border-black px-2 py-1 w-32 text-left">規格</th>
|
||
<th className="border border-black px-2 py-1 w-20 text-right">數量</th>
|
||
<th className="border border-black px-2 py-1 w-16 text-center">單位</th>
|
||
<th className="border border-black px-2 py-1 w-32 text-left">備註</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{doc.items.map((item, index) => (
|
||
<tr key={item.id}>
|
||
<td className="border border-black px-2 py-2 text-center">{index + 1}</td>
|
||
<td className="border border-black px-2 py-2 font-mono">{item.product_code}</td>
|
||
<td className="border border-black px-2 py-2">{item.product_name}</td>
|
||
<td className="border border-black px-2 py-2">{item.specification || '-'}</td>
|
||
<td className="border border-black px-2 py-2 text-right">
|
||
{item.counted_qty !== null ? Number(item.counted_qty).toFixed(2) : ''}
|
||
</td>
|
||
<td className="border border-black px-2 py-2 text-center">{item.unit || '-'}</td>
|
||
<td className="border border-black px-2 py-2">{item.notes}</td>
|
||
</tr>
|
||
))}
|
||
{/* Empty rows filler if needed, but usually not required unless strictly paging */}
|
||
</tbody>
|
||
</table>
|
||
|
||
{/* Footer Section */}
|
||
<div className="fixed bottom-0 w-full mb-4">
|
||
<div className="flex justify-between items-end px-4">
|
||
<div className="w-1/3 border-b border-black pb-1 mb-1">
|
||
<span className="font-bold">製單人員:</span>
|
||
<span className="ml-2">{doc.created_by}</span>
|
||
</div>
|
||
<div className="w-1/3 border-b border-black pb-1 mb-1 mx-4">
|
||
<span className="font-bold">盤點人員:</span>
|
||
</div>
|
||
<div className="w-1/3 border-b border-black pb-1 mb-1">
|
||
<span className="font-bold">核對人員:</span>
|
||
</div>
|
||
</div>
|
||
<div className="flex justify-between items-center text-xs mt-4 px-4">
|
||
<div>
|
||
製單人員:系統管理員 印單人員:{doc.created_by}
|
||
</div>
|
||
<div>
|
||
第 1 頁 / 共 1 頁
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|