From 859d68fff8125fe7e99538b8db80d81d2e03239e Mon Sep 17 00:00:00 2001 From: dohyeons Date: Tue, 23 Dec 2025 17:37:22 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=B8=EC=87=84=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0=20-=20=EC=A4=91=EB=B3=B5=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=A0=95=ED=99=95=EB=8F=84=20=ED=96=A5?= =?UTF-8?q?=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/designer/CanvasComponent.tsx | 84 +++++++++---------- .../report/designer/ReportPreviewModal.tsx | 44 ++++++---- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/frontend/components/report/designer/CanvasComponent.tsx b/frontend/components/report/designer/CanvasComponent.tsx index 554c7065..ccc3aa8a 100644 --- a/frontend/components/report/designer/CanvasComponent.tsx +++ b/frontend/components/report/designer/CanvasComponent.tsx @@ -357,11 +357,11 @@ export function CanvasComponent({ component }: CanvasComponentProps) { height: snappedSize, }); } else { - // Grid Snap 적용 - updateComponent(component.id, { - width: snapValueToGrid(boundedWidth), - height: snapValueToGrid(boundedHeight), - }); + // Grid Snap 적용 + updateComponent(component.id, { + width: snapValueToGrid(boundedWidth), + height: snapValueToGrid(boundedHeight), + }); } } }; @@ -444,17 +444,17 @@ export function CanvasComponent({ component }: CanvasComponentProps) { case "text": case "label": return ( -
- {displayValue} + style={{ + fontSize: `${component.fontSize}px`, + color: component.fontColor, + fontWeight: component.fontWeight, + textAlign: component.textAlign as "left" | "center" | "right", + whiteSpace: "pre-wrap", + }} + > + {displayValue}
); @@ -534,7 +534,7 @@ export function CanvasComponent({ component }: CanvasComponentProps) { // 기본 테이블 (데이터 없을 때) return (
- 쿼리를 연결하세요 + 쿼리를 연결하세요
); @@ -858,12 +858,12 @@ export function CanvasComponent({ component }: CanvasComponentProps) { // 계산 결과 (첫 번째 항목은 기준값, 두 번째부터 연산자 적용) const calculateResult = (): number => { if (calcItems.length === 0) return 0; - + // 첫 번째 항목은 기준값 let result = getCalcItemValue( calcItems[0] as { label: string; value: number | string; operator: string; fieldName?: string }, ); - + // 두 번째 항목부터 연산자 적용 for (let i = 1; i < calcItems.length; i++) { const item = calcItems[i]; @@ -899,30 +899,30 @@ export function CanvasComponent({ component }: CanvasComponentProps) { item: { label: string; value: number | string; operator: string; fieldName?: string }, index: number, ) => { - const itemValue = getCalcItemValue(item); - return ( -
- - {item.label} - - - {formatNumber(itemValue)} - -
- ); + const itemValue = getCalcItemValue(item); + return ( +
+ + {item.label} + + + {formatNumber(itemValue)} + +
+ ); }, )} diff --git a/frontend/components/report/designer/ReportPreviewModal.tsx b/frontend/components/report/designer/ReportPreviewModal.tsx index bf0603b7..7069bb75 100644 --- a/frontend/components/report/designer/ReportPreviewModal.tsx +++ b/frontend/components/report/designer/ReportPreviewModal.tsx @@ -17,6 +17,9 @@ import { getFullImageUrl } from "@/lib/api/client"; import JsBarcode from "jsbarcode"; import QRCode from "qrcode"; +// mm -> px 변환 상수 +const MM_TO_PX = 4; + interface ReportPreviewModalProps { isOpen: boolean; onClose: () => void; @@ -149,8 +152,8 @@ function PreviewWatermarkLayer({ watermark, pageWidth, pageHeight }: PreviewWate // 타일 스타일 if (watermark.style === "tile") { const tileSize = watermark.type === "text" ? (watermark.fontSize || 48) * 4 : 150; - const cols = Math.ceil((pageWidth * 3.7795) / tileSize) + 2; - const rows = Math.ceil((pageHeight * 3.7795) / tileSize) + 2; + const cols = Math.ceil((pageWidth * MM_TO_PX) / tileSize) + 2; + const rows = Math.ceil((pageHeight * MM_TO_PX) / tileSize) + 2; return (
@@ -514,7 +517,7 @@ export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) printWindow.document.write(printHtml); printWindow.document.close(); - printWindow.print(); + // print()는 HTML 내 스크립트에서 이미지 로드 완료 후 자동 호출됨 }; // 워터마크 HTML 생성 헬퍼 함수 @@ -554,8 +557,8 @@ export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) if (watermark.style === "tile") { const tileSize = watermark.type === "text" ? (watermark.fontSize || 48) * 4 : 150; - const cols = Math.ceil((pageWidth * 3.7795) / tileSize) + 2; - const rows = Math.ceil((pageHeight * 3.7795) / tileSize) + 2; + const cols = Math.ceil((pageWidth * MM_TO_PX) / tileSize) + 2; + const rows = Math.ceil((pageHeight * MM_TO_PX) / tileSize) + 2; const tileItems = Array.from({ length: rows * cols }) .map(() => `
${textContent}
`) .join(""); @@ -650,9 +653,9 @@ export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) : ""; content = ` -
- ${personName ? `
${personName}
` : ""} -
+
+ ${personName ? `
${personName}
` : ""} +
${imageUrl ? `` : ""} ${showLabel ? `
${labelText}
` : ""}
@@ -891,8 +894,15 @@ export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) `; } + // 컴포넌트 값은 px로 저장됨 (캔버스는 pageWidth * MM_TO_PX px) + // 인쇄용 mm 단위로 변환: px / MM_TO_PX = mm + const xMm = component.x / MM_TO_PX; + const yMm = component.y / MM_TO_PX; + const widthMm = component.width / MM_TO_PX; + const heightMm = component.height / MM_TO_PX; + return ` -
+
${content}
`; }) @@ -901,7 +911,7 @@ export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) const watermarkHTML = generateWatermarkHTML(watermark, pageWidth, pageHeight); return ` -
+ `; @@ -933,20 +943,18 @@ export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) 리포트 인쇄