ERP-node/frontend/components/report/designer/ReportPreviewModal.tsx

193 lines
6.5 KiB
TypeScript

"use client";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Printer, FileDown } from "lucide-react";
import { useReportDesigner } from "@/contexts/ReportDesignerContext";
interface ReportPreviewModalProps {
isOpen: boolean;
onClose: () => void;
}
export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) {
const { components, canvasWidth, canvasHeight, getQueryResult } = useReportDesigner();
// 컴포넌트의 실제 표시 값 가져오기
const getComponentValue = (component: any): string => {
if (component.queryId && component.fieldName) {
const queryResult = getQueryResult(component.queryId);
if (queryResult && queryResult.rows.length > 0) {
const value = queryResult.rows[0][component.fieldName];
if (value !== null && value !== undefined) {
return String(value);
}
}
return `{${component.fieldName}}`;
}
return component.defaultValue || "텍스트";
};
const handlePrint = () => {
// 현재 미리보기 영역만 인쇄
const printContent = document.getElementById("preview-content");
if (!printContent) return;
const printWindow = window.open("", "_blank");
if (!printWindow) return;
printWindow.document.write(`
<html>
<head>
<title>리포트 인쇄</title>
<style>
body { margin: 0; padding: 20px; }
@media print {
body { margin: 0; padding: 0; }
}
</style>
</head>
<body>
${printContent.innerHTML}
</body>
</html>
`);
printWindow.document.close();
printWindow.print();
};
const handleDownloadPDF = () => {
alert("PDF 다운로드 기능은 추후 구현 예정입니다.");
};
const handleDownloadWord = () => {
alert("WORD 다운로드 기능은 추후 구현 예정입니다.");
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-4xl">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>
. .
</DialogDescription>
</DialogHeader>
{/* 미리보기 영역 */}
<div className="max-h-[500px] overflow-auto rounded border bg-gray-100 p-4">
<div
id="preview-content"
className="relative mx-auto bg-white shadow-lg"
style={{
width: `${canvasWidth}mm`,
minHeight: `${canvasHeight}mm`,
}}
>
{components.map((component) => {
const displayValue = getComponentValue(component);
const queryResult = component.queryId ? getQueryResult(component.queryId) : null;
return (
<div
key={component.id}
className="absolute"
style={{
left: `${component.x}px`,
top: `${component.y}px`,
width: `${component.width}px`,
height: `${component.height}px`,
backgroundColor: component.backgroundColor,
border: component.borderWidth
? `${component.borderWidth}px solid ${component.borderColor}`
: "none",
padding: "8px",
}}
>
{component.type === "text" && (
<div
style={{
fontSize: `${component.fontSize}px`,
color: component.fontColor,
fontWeight: component.fontWeight,
textAlign: component.textAlign as "left" | "center" | "right",
}}
>
{displayValue}
</div>
)}
{component.type === "label" && (
<div
style={{
fontSize: `${component.fontSize}px`,
color: component.fontColor,
fontWeight: component.fontWeight,
textAlign: component.textAlign as "left" | "center" | "right",
}}
>
{displayValue}
</div>
)}
{component.type === "table" && queryResult && queryResult.rows.length > 0 ? (
<table className="w-full border-collapse text-xs">
<thead>
<tr className="bg-gray-100">
{queryResult.fields.map((field) => (
<th key={field} className="border border-gray-300 p-1">
{field}
</th>
))}
</tr>
</thead>
<tbody>
{queryResult.rows.map((row, idx) => (
<tr key={idx}>
{queryResult.fields.map((field) => (
<td key={field} className="border border-gray-300 p-1">
{String(row[field] ?? "")}
</td>
))}
</tr>
))}
</tbody>
</table>
) : component.type === "table" ? (
<div className="text-xs text-gray-400"> </div>
) : null}
</div>
);
})}
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={onClose}>
</Button>
<Button variant="outline" onClick={handlePrint} className="gap-2">
<Printer className="h-4 w-4" />
</Button>
<Button onClick={handleDownloadPDF} className="gap-2">
<FileDown className="h-4 w-4" />
PDF
</Button>
<Button onClick={handleDownloadWord} variant="secondary" className="gap-2">
<FileDown className="h-4 w-4" />
WORD
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}