From a319df0120d8a28211b12f89b639c469759a5e0f Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 21 Jul 2025 15:05:08 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EC=BA=A1=EC=B3=90=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/image/canvas/route.js | 67 +++++++++---------- .../circuitTrestle/CircuitTrestleSetting.jsx | 24 ++----- 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/src/app/api/image/canvas/route.js b/src/app/api/image/canvas/route.js index 600951fb..b216319f 100644 --- a/src/app/api/image/canvas/route.js +++ b/src/app/api/image/canvas/route.js @@ -81,44 +81,35 @@ const cropImage = async (Key, width, height, left, top) => { } } -//크롭된 이미지를 가지고 높이 기준 -> 너비 기준으로 비율 변경 후 이미지에 추가 +//크롭된 이미지를 배경 크기에 맞게 리사이즈 const resizeImage = async (image) => { - // //이미지를 cm로 변환 - let imageHeightCm = Math.round((image.bitmap.height * 2.54) / 96) //원본 이미지 센치로 변환 - let imageWidthCm = Math.round((image.bitmap.width * 2.54) / 96) //원본 이미지 센치로 변환 - const calcWidthRatio = 12.89 / imageHeightCm //원본 비율 계산 - - let convertHeightCm = Math.round(imageHeightCm * calcWidthRatio) //변환된 이미지 CM - let convertWidthCm = Math.round(imageWidthCm * calcWidthRatio) //변환된 이미지 CM - - let convertHeightBitmap = Math.round((convertHeightCm * 96) / 2.54) //비트맵 사이즈로 변환 - let convertWidthBitmap = Math.round((convertWidthCm * 96) / 2.54) //비트맵 사이즈로 변환 - - //높이 기준으로 리사이즈를 함 - image.resize({ w: convertWidthBitmap, h: convertHeightBitmap, mode: Jimp.RESIZE_BILINEAR }) - - //높이를 기준으로 변경 후에 가로 폭이 더 넓으면 가로폭 기준으로 다시 사이즈를 조절한다 - if (convertWidthCm > 35.4) { - //너비가 더 클때 - imageHeightCm = Math.round((image.bitmap.height * 2.54) / 96) //높이 기준으로 리사이즈된 이미지 크기 - imageWidthCm = Math.round((image.bitmap.width * 2.54) / 96) //높이 기준으로 리사이즈된 이미지 크기 - - const calcWidthRatio = 35.4 / imageWidthCm //리사이즈된 이미지 가로 비율 계산 - - convertHeightCm = Math.round(imageHeightCm * calcWidthRatio) //너비 기준 이미지 비율 계산 - convertWidthCm = Math.round(imageWidthCm * calcWidthRatio) //변환된 이미지 CM - - convertHeightBitmap = Math.round((convertHeightCm * 96) / 2.54) //비트맵 사이즈로 변환 - convertWidthBitmap = Math.round((convertWidthCm * 96) / 2.54) //비트맵 사이즈로 변환 - - image.resize({ w: convertWidthBitmap, h: convertHeightBitmap, mode: Jimp.RESIZE_BILINEAR }) //이미지 리사이즈 - } - //엑셀 템플릿 너비 35.4cm, 높이 12.89cm const convertStandardWidth = Math.round((35.4 * 96) / 2.54) const convertStandardHeight = Math.round((12.89 * 96) / 2.54) - //엑셀 템플릿 사이즈로 배경 이미지를 생성 + // 이미지를 배경의 98%까지 확대 (훨씬 더 크게) + const targetImageWidth = convertStandardWidth * 0.98 + const targetImageHeight = convertStandardHeight * 0.98 + + const scaleX = targetImageWidth / image.bitmap.width + const scaleY = targetImageHeight / image.bitmap.height + let scale = Math.min(scaleX, scaleY) // 비율 유지하면서 최대한 크게 + + // scale 저장 (나중에 전체 확대에 사용) + const originalScale = scale + + let finalWidth = Math.round(image.bitmap.width * scale) + let finalHeight = Math.round(image.bitmap.height * scale) + + if (scale < 0.6) { + finalWidth = targetImageWidth + finalHeight = targetImageHeight + } + + // 실제 리사이즈 실행 + image.resize({ w: finalWidth, h: finalHeight }) + + //배경 이미지를 생성 const mixedImage = new Jimp({ width: convertStandardWidth, height: convertStandardHeight, color: 0xffffffff }) //이미지를 중앙에 배치 @@ -127,11 +118,19 @@ const resizeImage = async (image) => { //이미지를 배경 이미지에 합성 mixedImage.composite(image, x, y, { - mode: Jimp.BLEND_SOURCE_OVER, opacitySource: 1, // 원본 투명도 유지 opacityDest: 1, }) + // scale이 0.8 이하인 경우 완성된 이미지를 전체적으로 확대 + if (originalScale <= 0.8) { + const enlargeRatio = 1.5 // 25% 확대 + const newWidth = Math.round(mixedImage.bitmap.width * enlargeRatio) + const newHeight = Math.round(mixedImage.bitmap.height * enlargeRatio) + + mixedImage.resize({ w: newWidth, h: newHeight }) + } + return mixedImage } diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 47711421..50e35342 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -1,16 +1,13 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' -import { useState, useEffect, useContext, useRef } from 'react' +import { useContext, useEffect, useRef, useState } from 'react' import PowerConditionalSelect from '@/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect' import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp' import { useMessage } from '@/hooks/useMessage' import { usePopup } from '@/hooks/usePopup' import PassivityCircuitAllocation from './step/type/PassivityCircuitAllocation' import { useMasterController } from '@/hooks/common/useMasterController' -import { correntObjectNoState } from '@/store/settingAtom' -import { useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { GlobalDataContext } from '@/app/GlobalDataProvider' -import { useRecoilState } from 'recoil' -import { makersState, modelsState, modelState, pcsCheckState, selectedMakerState, selectedModelsState, seriesState } from '@/store/circuitTrestleAtom' import { POLYGON_TYPE } from '@/common/common' import { useSwal } from '@/hooks/useSwal' import { canvasState, canvasZoomState } from '@/store/canvasAtom' @@ -21,9 +18,7 @@ import { v4 as uuidv4 } from 'uuid' import { useEstimate } from '@/hooks/useEstimate' import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle' -import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useImgLoader } from '@/hooks/floorPlan/useImgLoader' -import { usePlan } from '@/hooks/usePlan' import { QcastContext } from '@/app/QcastProvider' import { fabric } from 'fabric' import { fontSelector } from '@/store/fontAtom' @@ -107,10 +102,10 @@ export default function CircuitTrestleSetting({ id }) { } }, []) - const capture = (type) => { + const capture = async (type) => { beforeCapture() - handleCanvasToPng(type) + await handleCanvasToPng(type) afterCapture() @@ -123,20 +118,15 @@ export default function CircuitTrestleSetting({ id }) { // 캡쳐 전 처리 const beforeCapture = () => { - // setCanvasZoom(100) - const arrows = canvas.getObjects().filter((obj) => obj.name === 'arrow') + setCanvasZoom(100) + canvas.set({ zoom: 1 }) + canvas.viewportTransform = [1, 0, 0, 1, 0, 0] let x, y x = canvas.width / 2 y = canvas.height / 2 - // 화살표가 음수 영역에 있을 경우 0,0 기준으로 50% 축소 - if (arrows.some((arrow) => arrow.left < 0) || arrows.some((arrow) => arrow.top < 0)) { - x = 0 - y = 0 - } - canvas.zoomToPoint(new fabric.Point(x, y), 0.5) changeFontSize('lengthText', '28') changeFontSize('circuitNumber', '28') From fb9ed9949d8e6ce229527ca8e8f4bb6b9335f6e4 Mon Sep 17 00:00:00 2001 From: ysCha Date: Mon, 21 Jul 2025 15:36:23 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[1196]=20=EC=9D=BC=EC=8B=9C=EC=A0=81?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=202=EC=B0=A8=EC=A0=90=20=EC=88=A8=EA=B9=80?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/estimate/Estimate.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 2fe098cf..4a3337db 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -1458,7 +1458,7 @@ export default function Estimate({}) { - {session?.storeLvl === '1' && agencyCustList.length > 0 ? ( + {session?.storeLvl === '100000' && agencyCustList.length > 0 ? ( //일시적으로 1 => 100000로 정리
From ef607afcf389bc2f8a100c9113380d478a963438 Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 22 Jul 2025 09:07:16 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[1196]=20=EC=9E=90=EB=8F=99=ED=9A=8C?= =?UTF-8?q?=EB=A1=9C=EA=B5=AC=EC=84=B1=EC=8B=9C=20=ED=9A=8C=EB=A1=9C?= =?UTF-8?q?=EA=B5=AC=EC=84=B1=ED=9B=84=20=EB=82=A8=EB=8A=94=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=EC=97=90=EB=8C=80=ED=95=B4=20=EC=96=BC=EB=9F=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/circuitTrestle/step/StepUp.jsx | 11 +++++++++-- src/locales/ja.json | 1 + src/locales/ko.json | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 5b706264..b0222aa3 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -109,6 +109,7 @@ export default function StepUp(props) { /** 캔버스에 회로 정보 적용 */ // 병설일때 pcs 있으면 setSubOpsions, 없으면 setMainOptions console.log('stepUpListData', stepUpListData) + let mChk = 0; stepUpListData[0].pcsItemList.forEach((pcsItem, index) => { const optionList = formatOptionCodes(pcsItem.optionList) if (isMultiOptions()) { @@ -164,6 +165,8 @@ export default function StepUp(props) { targetModule.pcsItemId = module.pcsItemId targetModule.circuitNumber = module.circuit canvas.add(moduleCircuitText) + } else { + mChk++; } }) }) @@ -172,6 +175,10 @@ export default function StepUp(props) { canvas.renderAll() setModuleStatisticsData() + + if (mChk > 0) { + swalFire({ text: getMessage('modal.circuit.trestle.setting.step.up.allocation.module.over.count') }) + } } else { swalFire({ text: getMessage('common.message.send.error') }) } @@ -467,7 +474,7 @@ export default function StepUp(props) { module.pcsItemId = null }) - /** 선택된 모듈 목록 추가 */ + /** 선택된 모듈 목록 추가 */ selectedData.roofSurfaceList.forEach((roofSurface) => { const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0] const moduleIds = targetSurface.modules.map((module) => { @@ -516,7 +523,7 @@ export default function StepUp(props) { canvas.renderAll() setModuleStatisticsData() - } + } /** * 현재 선택된 값들을 가져오는 함수 추가 diff --git a/src/locales/ja.json b/src/locales/ja.json index 5cd08828..ec579c8e 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -197,6 +197,7 @@ "modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "昇圧回路数", "modal.circuit.trestle.setting.step.up.allocation.option": "昇圧オプション", "modal.circuit.trestle.setting.step.up.allocation.select.monitor": "オプションを選択", + "modal.circuit.trestle.setting.step.up.allocation.module.over.count": "一部モジュールに回路を構成できません", "plan.menu.module.circuit.setting.plan.orientation": "図面方位の適用", "plan.menu.estimate": "見積書", "plan.menu.estimate.roof.alloc": "屋根面の割り当て", diff --git a/src/locales/ko.json b/src/locales/ko.json index 19864ac4..de8f56c2 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -197,6 +197,7 @@ "modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "승압회로수", "modal.circuit.trestle.setting.step.up.allocation.option": "승압옵션", "modal.circuit.trestle.setting.step.up.allocation.select.monitor": "옵션선택", + "modal.circuit.trestle.setting.step.up.allocation.module.over.count": "일부 모듈에서는 회로를 구성할 수 없습니다.", "plan.menu.module.circuit.setting.plan.orientation": "도면 방위 적용", "plan.menu.estimate": "견적서", "plan.menu.estimate.roof.alloc": "지붕면 할당", From eb03054804b798f8e28b39cd6f4d5bedcce3c606 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 22 Jul 2025 09:53:43 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/image/canvas/route.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/image/canvas/route.js b/src/app/api/image/canvas/route.js index b216319f..347c88df 100644 --- a/src/app/api/image/canvas/route.js +++ b/src/app/api/image/canvas/route.js @@ -124,7 +124,7 @@ const resizeImage = async (image) => { // scale이 0.8 이하인 경우 완성된 이미지를 전체적으로 확대 if (originalScale <= 0.8) { - const enlargeRatio = 1.5 // 25% 확대 + const enlargeRatio = 1.5 // 50% 확대 const newWidth = Math.round(mixedImage.bitmap.width * enlargeRatio) const newHeight = Math.round(mixedImage.bitmap.height * enlargeRatio) From d52fdb23a1378ead660746778e80a7a8b20cbce9 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 22 Jul 2025 13:53:06 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=EC=98=A4=EB=B8=8C=EC=A0=9D=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=B0=EC=B9=98=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/object/useObjectBatch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index accb6866..0e0c24c2 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -102,7 +102,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { const pointer = getIntersectMousePoint(e) surfaceShapePolygons.forEach((surface) => { - if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { + if (surface.inPolygonImproved({ x: pointer.x, y: pointer.y })) { selectedSurface = surface } }) From ca0620bd23742186836ecf699b3fa5fb9c8b2804 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 22 Jul 2025 14:03:48 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EB=82=B4=EB=B6=80=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/object/useObjectBatch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 0e0c24c2..8fe24364 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -212,7 +212,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { const pointer = getIntersectMousePoint(e) surfaceShapePolygons.forEach((surface) => { - if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { + if (surface.inPolygonImproved({ x: pointer.x, y: pointer.y })) { selectedSurface = surface rect = new fabric.Rect({