From c5cb4336e582b8520d3d0dd054be2933a34fbee2 Mon Sep 17 00:00:00 2001 From: dohyeons Date: Mon, 22 Dec 2025 11:29:35 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B0=94=EC=BD=94=EB=93=9C/QR=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=ED=88=AC=EB=AA=85=20=EB=B0=B0=EA=B2=BD=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20QR=EC=BD=94=EB=93=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=B3=B5=EA=B5=AC=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/designer/CanvasComponent.tsx | 260 ++++++++++-------- .../report/designer/ReportDesignerCanvas.tsx | 2 +- 2 files changed, 145 insertions(+), 117 deletions(-) diff --git a/frontend/components/report/designer/CanvasComponent.tsx b/frontend/components/report/designer/CanvasComponent.tsx index ee0f9c4b..f87ed322 100644 --- a/frontend/components/report/designer/CanvasComponent.tsx +++ b/frontend/components/report/designer/CanvasComponent.tsx @@ -19,7 +19,16 @@ interface BarcodeRendererProps { margin: number; } -function BarcodeRenderer({ value, format, width, height, displayValue, lineColor, background, margin }: BarcodeRendererProps) { +function BarcodeRenderer({ + value, + format, + width, + height, + displayValue, + lineColor, + background, + margin, +}: BarcodeRendererProps) { const svgRef = useRef(null); const [error, setError] = useState(null); @@ -53,14 +62,16 @@ function BarcodeRenderer({ value, format, width, height, displayValue, lineColor // JsBarcode는 format을 소문자로 받음 const barcodeFormat = format.toLowerCase(); - + // transparent는 빈 문자열로 변환 (SVG 배경 없음) + const bgColor = background === "transparent" ? "" : background; + JsBarcode(svgRef.current, trimmedValue, { format: barcodeFormat, width: 2, height: Math.max(30, height - (displayValue ? 30 : 10)), displayValue: displayValue, lineColor: lineColor, - background: background, + background: bgColor, margin: margin, fontSize: 12, textMargin: 2, @@ -74,10 +85,7 @@ function BarcodeRenderer({ value, format, width, height, displayValue, lineColor return (
{/* SVG는 항상 렌더링 (에러 시 숨김) */} - + {/* 에러 메시지 오버레이 */} {error && (
@@ -103,40 +111,48 @@ function QRCodeRenderer({ value, size, fgColor, bgColor, level }: QRCodeRenderer const [error, setError] = useState(null); useEffect(() => { - if (canvasRef.current && value) { - QRCode.toCanvas( - canvasRef.current, - value, - { - width: Math.max(50, size), - margin: 2, - color: { - dark: fgColor, - light: bgColor, - }, - errorCorrectionLevel: level, + if (!canvasRef.current || !value) return; + + // 매번 에러 상태 초기화 후 재시도 + setError(null); + + // qrcode 라이브러리는 hex 색상만 지원, transparent는 흰색으로 대체 + const lightColor = bgColor === "transparent" ? "#ffffff" : bgColor; + + QRCode.toCanvas( + canvasRef.current, + value, + { + width: Math.max(50, size), + margin: 2, + color: { + dark: fgColor, + light: lightColor, }, - (err) => { - if (err) { - setError("QR코드 생성 실패"); - } else { - setError(null); - } + errorCorrectionLevel: level, + }, + (err) => { + if (err) { + // 실제 에러 메시지 표시 + setError(err.message || "QR코드 생성 실패"); } - ); - } + }, + ); }, [value, size, fgColor, bgColor, level]); - if (error) { - return ( -
- {error} - {value} -
- ); - } - - return ; + return ( +
+ {/* Canvas는 항상 렌더링 (에러 시 숨김) */} + + {/* 에러 메시지 오버레이 */} + {error && ( +
+ {error} + {value} +
+ )} +
+ ); } interface CanvasComponentProps { @@ -560,7 +576,7 @@ export function CanvasComponent({ component }: CanvasComponentProps) { backgroundColor: "transparent", }), ...(component.lineStyle === "double" && { - boxShadow: isHorizontal + boxShadow: isHorizontal ? `0 ${dividerLineWidth * 2}px 0 0 ${dividerLineColor}` : `${dividerLineWidth * 2}px 0 0 0 ${dividerLineColor}`, }), @@ -814,7 +830,12 @@ export function CanvasComponent({ component }: CanvasComponentProps) { }; // 쿼리 바인딩된 값 가져오기 - const getCalcItemValue = (item: { label: string; value: number | string; operator: string; fieldName?: string }): number => { + const getCalcItemValue = (item: { + label: string; + value: number | string; + operator: string; + fieldName?: string; + }): number => { if (item.fieldName && component.queryId) { const queryResult = getQueryResult(component.queryId); if (queryResult && queryResult.rows && queryResult.rows.length > 0) { @@ -829,14 +850,18 @@ 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 }); - + 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]; - const val = getCalcItemValue(item as { label: string; value: number | string; operator: string; fieldName?: string }); + const val = getCalcItemValue( + item as { label: string; value: number | string; operator: string; fieldName?: string }, + ); switch (item.operator) { case "+": result += val; @@ -861,38 +886,40 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
{/* 항목 목록 */}
- {calcItems.map((item: { label: string; value: number | string; operator: string; fieldName?: string }, index: number) => { - const itemValue = getCalcItemValue(item); - return ( -
- - {item.label} - - - {formatNumber(itemValue)} - -
- ); - })} + {calcItems.map( + ( + item: { label: string; value: number | string; operator: string; fieldName?: string }, + index: number, + ) => { + const itemValue = getCalcItemValue(item); + return ( +
+ + {item.label} + + + {formatNumber(itemValue)} + +
+ ); + }, + )}
{/* 구분선 */} -
+
{/* 결과 */}
@@ -1003,39 +1030,39 @@ export function CanvasComponent({ component }: CanvasComponentProps) { const isChecked = getCheckboxValue(); return ( -
+ {/* 체크박스 */} +
- {/* 체크박스 */} -
- {isChecked && ( - - - - )} -
- {/* 레이블 */} + {isChecked && ( + + + + )} +
+ {/* 레이블 */} {/* 레이블 */} {checkboxLabel && ( diff --git a/frontend/components/report/designer/ReportDesignerCanvas.tsx b/frontend/components/report/designer/ReportDesignerCanvas.tsx index 47bfa7b5..08bf9c1b 100644 --- a/frontend/components/report/designer/ReportDesignerCanvas.tsx +++ b/frontend/components/report/designer/ReportDesignerCanvas.tsx @@ -217,7 +217,7 @@ export function ReportDesignerCanvas() { barcodeFieldName: "", showBarcodeText: true, barcodeColor: "#000000", - barcodeBackground: "#ffffff", + barcodeBackground: "transparent", barcodeMargin: 10, qrErrorCorrectionLevel: "M" as const, }),