diff --git a/.gitignore b/.gitignore index f3b61bd7..a235b0ff 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ next-env.d.ts yarn.lock package-lock.json pnpm-lock.yaml -certificates \ No newline at end of file +certificates +.ai \ No newline at end of file diff --git a/src/common/common.js b/src/common/common.js index 4220e5f5..60a57c76 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -219,7 +219,8 @@ export const SAVE_KEY = [ 'originWidth', 'originHeight', 'skeletonLines', - 'skeleton' + 'skeleton', + 'viewportTransform', ] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype] diff --git a/src/components/common/draggable/WithDraggable.jsx b/src/components/common/draggable/WithDraggable.jsx index 7ebdf067..fa87910a 100644 --- a/src/components/common/draggable/WithDraggable.jsx +++ b/src/components/common/draggable/WithDraggable.jsx @@ -24,7 +24,7 @@ export default function WithDraggable({ isShow, children, pos = { x: 0, y: 0 }, handleOnDrag(e, data)} - handle= ''//{handle === '' ? '.modal-handle' : handle} //전체 handle + handle="" //{handle === '' ? '.modal-handle' : handle} //전체 handle cancel="input, button, select, textarea, [contenteditable], .sort-select" >
@@ -38,15 +38,18 @@ export default function WithDraggable({ isShow, children, pos = { x: 0, y: 0 }, ) } -function WithDraggableHeader({ title, onClose, children }) { +function WithDraggableHeader({ title, onClose, children, isFold, onFold = null }) { return (

{title}

- {onClose && ( - - )} +
+ {onFold && } + {onClose && ( + + )} +
) } diff --git a/src/components/common/input/CalcInput.jsx b/src/components/common/input/CalcInput.jsx index 32323560..17af010e 100644 --- a/src/components/common/input/CalcInput.jsx +++ b/src/components/common/input/CalcInput.jsx @@ -48,14 +48,23 @@ export const CalculatorInput = forwardRef( const calculator = calculatorRef.current let newDisplayValue = '' + // 소수점 이하 2자리 제한 로직 추가 + const shouldPreventInput = (value) => { + const decimalParts = (value || '').split('.') + return decimalParts.length > 1 && decimalParts[1].length >= 2 + } + if (hasOperation) { // 연산자 이후 숫자 입력 시 if (calculator.currentOperand === '0' || calculator.shouldResetDisplay) { calculator.currentOperand = num.toString() calculator.shouldResetDisplay = false - } else { + }else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리 calculator.currentOperand = (calculator.currentOperand || '') + num } + // else { + // calculator.currentOperand = (calculator.currentOperand || '') + num + // } newDisplayValue = calculator.previousOperand + calculator.operation + calculator.currentOperand setDisplayValue(newDisplayValue) } else { @@ -68,7 +77,7 @@ export const CalculatorInput = forwardRef( if (!hasOperation) { onChange(calculator.currentOperand) } - } else { + } else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리 calculator.currentOperand = (calculator.currentOperand || '') + num newDisplayValue = calculator.currentOperand setDisplayValue(newDisplayValue) @@ -76,6 +85,14 @@ export const CalculatorInput = forwardRef( onChange(newDisplayValue) } } + // else { + // calculator.currentOperand = (calculator.currentOperand || '') + num + // newDisplayValue = calculator.currentOperand + // setDisplayValue(newDisplayValue) + // if (!hasOperation) { + // onChange(newDisplayValue) + // } + // } } // 커서를 텍스트 끝으로 이동하고 스크롤 처리 diff --git a/src/components/community/modal/QnaRegModal.jsx b/src/components/community/modal/QnaRegModal.jsx index 8f9437f9..00c444c6 100644 --- a/src/components/community/modal/QnaRegModal.jsx +++ b/src/components/community/modal/QnaRegModal.jsx @@ -89,7 +89,7 @@ let fileCheck = false; siteTpCd: "QC", schNoticeClsCd: "QNA", regId: sessionState?.userId || '', - storeId: sessionState?.userId || '', + storeId: sessionState?.storeId || '', qstMail: sessionState?.email || '', qnaClsLrgCd: '', qnaClsMidCd: '', diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index 4b718c05..63dc523a 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -2,7 +2,7 @@ import { useContext, useEffect, useRef } from 'react' -import { useRecoilValue, useResetRecoilState } from 'recoil' +import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import QContextMenu from '@/components/common/context-menu/QContextMenu' import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' @@ -11,7 +11,7 @@ import { useCanvas } from '@/hooks/useCanvas' import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' -import { currentMenuState } from '@/store/canvasAtom' +import { canvasZoomState, currentMenuState } from '@/store/canvasAtom' import { totalDisplaySelector } from '@/store/settingAtom' import { POLYGON_TYPE } from '@/common/common' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' @@ -50,6 +50,7 @@ export default function CanvasFrame() { const resetSeriesState = useResetRecoilState(seriesState) const resetModelsState = useResetRecoilState(modelsState) const resetCompasDeg = useResetRecoilState(compasDegAtom) + const [zoom, setCanvasZoom] = useRecoilState(canvasZoomState) const resetSelectedModelsState = useResetRecoilState(selectedModelsState) const resetPcsCheckState = useResetRecoilState(pcsCheckState) const { handleModuleSelectionTotal } = useCanvasPopupStatusController() @@ -67,6 +68,13 @@ export default function CanvasFrame() { canvasLoadInit() //config된 상태로 캔버스 객체를 그린다 canvas?.renderAll() // 캔버스를 다시 그립니다. + if (canvas.viewportTransform) { + if (canvas.viewportTransform[0] !== 1) { + setCanvasZoom(Number((canvas.viewportTransform[0] * 100).toFixed(0))) + } + } + canvas.originViewPortTransform = canvas.viewportTransform + if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length > 0) { setTimeout(() => { setSelectedMenu('module') diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 6ddd94c7..97d878a0 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -2,7 +2,7 @@ import { useContext, useEffect, useState } from 'react' -import { usePathname, useRouter, useSearchParams } from 'next/navigation' +import { usePathname, useRouter } from 'next/navigation' import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil' @@ -25,17 +25,18 @@ import { useCommonUtils } from '@/hooks/common/useCommonUtils' import useMenu from '@/hooks/common/useMenu' import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' import { useAxios } from '@/hooks/useAxios' -import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState, currentCanvasPlanState } from '@/store/canvasAtom' +import { + canvasSettingState, + canvasState, + canvasZoomState, + currentCanvasPlanState, + currentMenuState, + verticalHorizontalModeState, +} from '@/store/canvasAtom' import { sessionStore } from '@/store/commonAtom' import { outerLinePointsState } from '@/store/outerLineAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -import { - addedRoofsState, - basicSettingState, - corridorDimensionSelector, - selectedRoofMaterialSelector, - settingModalFirstOptionsState, -} from '@/store/settingAtom' +import { addedRoofsState, basicSettingState, selectedRoofMaterialSelector, settingModalFirstOptionsState } from '@/store/settingAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import { commonUtilsState } from '@/store/commonUtilsAtom' import { menusState } from '@/store/menuAtom' @@ -51,6 +52,7 @@ import { QcastContext } from '@/app/QcastProvider' import { useRoofFn } from '@/hooks/common/useRoofFn' import { usePolygon } from '@/hooks/usePolygon' import { useTrestle } from '@/hooks/module/useTrestle' + export default function CanvasMenu(props) { const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const { selectedMenu, setSelectedMenu } = props @@ -515,7 +517,10 @@ export default function CanvasMenu(props) { if (createUser === 'T01' && sessionState.storeId !== 'T01') { setAllButtonStyles('none') } else { - setEstimateContextState({ tempFlg: estimateRecoilState.tempFlg, lockFlg: estimateRecoilState.lockFlg }) + setEstimateContextState({ + tempFlg: estimateRecoilState.tempFlg, + lockFlg: estimateRecoilState.lockFlg, + }) handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg, estimateContextState.docNo) } } diff --git a/src/components/floor-plan/modal/Slope.jsx b/src/components/floor-plan/modal/Slope.jsx index df4a25d7..849920bf 100644 --- a/src/components/floor-plan/modal/Slope.jsx +++ b/src/components/floor-plan/modal/Slope.jsx @@ -4,6 +4,7 @@ import { globalPitchState, pitchSelector, pitchTextSelector } from '@/store/canv import { useRecoilState } from 'recoil' import { useRef } from 'react' import { usePopup } from '@/hooks/usePopup' +import { CalculatorInput } from '@/components/common/input/CalcInput' export default function Slope({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() @@ -22,7 +23,19 @@ export default function Slope({ id, pos = { x: 50, y: 230 } }) { {getMessage('slope')}
- + {/**/} +
{pitchText}
diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index a70b9a22..ac2b3ca4 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -1,4 +1,4 @@ -import { POLYGON_TYPE, MODULE_SETUP_TYPE } from '@/common/common' +import { MODULE_SETUP_TYPE, POLYGON_TYPE } from '@/common/common' import WithDraggable from '@/components/common/draggable/WithDraggable' import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation' import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement' @@ -74,6 +74,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const { trigger: trestleTrigger } = useCanvasPopupStatusController(2) const { trigger: placementTrigger } = useCanvasPopupStatusController(3) const [roofsStore, setRoofsStore] = useRecoilState(roofsState) + const [isFold, setIsFold] = useState(false) // const { initEvent } = useContext(EventContext) const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup, manualModuleLayoutSetup, restoreModuleInstArea } = @@ -282,35 +283,42 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { return ( - handleClosePopup(id)} /> + handleClosePopup(id)} + onFold={() => setIsFold(!isFold)} + /> -
-
{getMessage('modal.module.basic.setting.orientation.setting')}
- - {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && ( - <> -
{getMessage('modal.module.basic.setting.module.setting')}
- -
{getMessage('modal.module.basic.setting.module.placement')}
- +
+
+
{getMessage('modal.module.basic.setting.orientation.setting')}
+ + {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && ( + <> +
{getMessage('modal.module.basic.setting.module.setting')}
+ +
{getMessage('modal.module.basic.setting.module.placement')}
+ + )} + {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && ( + <> +
{getMessage('modal.module.basic.setting.module.placement')}
+ + )} +
+ {tabNum === 1 && } + {/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/} + {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && } + {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && ( + )} - {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && ( - <> -
{getMessage('modal.module.basic.setting.module.placement')}
- + {/*배치면 초기설정 - 입력방법: 육지붕*/} + {/* {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 3 && } */} + {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 2 && ( + )}
- {tabNum === 1 && } - {/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/} - {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && } - {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && ( - - )} - {/*배치면 초기설정 - 입력방법: 육지붕*/} - {/* {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 3 && } */} - {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 2 && ( - - )}
{/* {tabNum === 1 && } */} diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 68893c23..f86a7ead 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -20,8 +20,8 @@ import { useEstimate } from '@/hooks/useEstimate' import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle' import { useImgLoader } from '@/hooks/floorPlan/useImgLoader' import { QcastContext } from '@/app/QcastProvider' -import { fabric } from 'fabric' import { fontSelector } from '@/store/fontAtom' +import { fabric } from 'fabric' const ALLOCATION_TYPE = { AUTO: 'auto', @@ -59,6 +59,9 @@ export default function CircuitTrestleSetting({ id }) { const passivityCircuitAllocationRef = useRef() const { setIsGlobalLoading } = useContext(QcastContext) + const originCanvasViewPortTransform = useRef([]) + const [isFold, setIsFold] = useState(false) + const { makers, setMakers, @@ -83,6 +86,7 @@ export default function CircuitTrestleSetting({ id }) { } = useCircuitTrestle() // const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2) useEffect(() => { + originCanvasViewPortTransform.current = [...canvas.viewportTransform] if (!managementState) { } // setCircuitData({ @@ -171,15 +175,12 @@ export default function CircuitTrestleSetting({ id }) { }) } - canvas.renderAll() - - // roof polygon들의 중간점 계산 - const roofPolygons = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) let x, y x = canvas.width / 2 y = canvas.height / 2 - + canvas.zoomToPoint(new fabric.Point(x, y), 0.4) + changeFontSize('lengthText', '28') changeFontSize('circuitNumber', '28') changeFontSize('flowText', '28') @@ -188,9 +189,12 @@ export default function CircuitTrestleSetting({ id }) { // 캡쳐 후 처리 const afterCapture = (type) => { - setCanvasZoom(100) - canvas.set({ zoom: 1 }) - canvas.viewportTransform = [1, 0, 0, 1, 0, 0] + if (originCanvasViewPortTransform.current[0] !== 1) { + setCanvasZoom(Number((originCanvasViewPortTransform.current[0] * 100).toFixed(0))) + } + canvas.viewportTransform = [...originCanvasViewPortTransform.current] + canvas.renderAll() + changeFontSize('lengthText', lengthText.fontSize.value) changeFontSize('circuitNumber', circuitNumberText.fontSize.value) changeFontSize('flowText', flowText.fontSize.value) @@ -223,11 +227,33 @@ export default function CircuitTrestleSetting({ id }) { return } + const isMultiModule = selectedModules.itemList.length > 1 + + let isAllIndfcs = false + + if (isMultiModule) { + //INDFCS 실내집중, OUTDMULTI 옥외멀티 + // 1. 모듈이 혼합형일 경우 선택한 pcs가 실내집중인 경우 alert + if (selectedModels.length > 0) { + isAllIndfcs = selectedModels.every((model) => model.pcsTpCd === 'INDFCS') + } else { + isAllIndfcs = models.every((model) => model.pcsTpCd === 'INDFCS') + } + } + + if (isAllIndfcs) { + swalFire({ + title: getMessage('module.circuit.indoor.focused.error'), + type: 'alert', + }) + return + } + const params = { ...getOptYn(), useModuleItemList: getUseModuleItemList(), roofSurfaceList: getRoofSurfaceList(), - pcsItemList: getPcsItemList(), + pcsItemList: getPcsItemList(isMultiModule), } // 파워컨디셔너 추천 목록 조회 @@ -288,12 +314,12 @@ export default function CircuitTrestleSetting({ id }) { }) } else { // 회로 구성 가능 여부 체크 - getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList() }).then((res) => { + getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList(isMultiModule) }).then((res) => { if (res.resultCode === 'S') { // 회로 구성 가능 여부 체크 통과 시 승압설정 정보 조회 getPcsVoltageStepUpList({ ...params, - pcsItemList: getSelectedPcsItemList(), + pcsItemList: getSelectedPcsItemList(isMultiModule), }).then((res) => { if (res?.result.resultCode === 'S' && res?.data) { setTabNum(2) @@ -519,6 +545,7 @@ export default function CircuitTrestleSetting({ id }) { obj.circuit = null obj.pcsItemId = null obj.circuitNumber = null + obj.pcs = null }) setSelectedModels( JSON.parse(JSON.stringify(selectedModels)).map((model) => { @@ -788,20 +815,30 @@ export default function CircuitTrestleSetting({ id }) { return ( - handleClose()} /> + handleClose()} + isFold={isFold} + onFold={() => setIsFold(!isFold)} + /> -
-
{getMessage('modal.circuit.trestle.setting.power.conditional.select')}
- -
- {getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')}) +
+
+
+
{getMessage('modal.circuit.trestle.setting.power.conditional.select')}
+ +
+ {getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')}) +
+
+ {tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && } + {tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && ( + + )} + {tabNum === 2 && }
- {tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && } - {tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && ( - - )} - {tabNum === 2 && } + {tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
diff --git a/src/components/floor-plan/modal/lineTypes/Angle.jsx b/src/components/floor-plan/modal/lineTypes/Angle.jsx index 880aac04..0faad2a4 100644 --- a/src/components/floor-plan/modal/lineTypes/Angle.jsx +++ b/src/components/floor-plan/modal/lineTypes/Angle.jsx @@ -1,6 +1,7 @@ import Image from 'next/image' import { useMessage } from '@/hooks/useMessage' import { normalizeDecimalLimit, normalizeDigits } from '@/util/input-utils' +import { CalculatorInput } from '@/components/common/input/CalcInput' export default function Angle({ props }) { const { getMessage } = useMessage() @@ -14,14 +15,29 @@ export default function Angle({ props }) {
{getMessage('modal.cover.outline.angle')}
- (angle1Ref.current.value = '')}*/} + {/* onChange={(e) => setAngle1(normalizeDecimalLimit(e.target.value, 2))}*/} + {/* placeholder="45"*/} + {/*/>*/} + (angle1Ref.current.value = '')} - onChange={(e) => setAngle1(normalizeDecimalLimit(e.target.value, 2))} + onChange={(value) => setAngle1(value)} placeholder="45" + onFocus={() => (angle1Ref.current.value = '')} + options={{ + allowNegative: false, + allowDecimal: true + }} />
diff --git a/src/components/floor-plan/modal/lineTypes/DoublePitch.jsx b/src/components/floor-plan/modal/lineTypes/DoublePitch.jsx index 92e63e07..12ed66be 100644 --- a/src/components/floor-plan/modal/lineTypes/DoublePitch.jsx +++ b/src/components/floor-plan/modal/lineTypes/DoublePitch.jsx @@ -1,6 +1,7 @@ import { useMessage } from '@/hooks/useMessage' import { normalizeDecimalLimit, normalizeDigits } from '@/util/input-utils' import { getDegreeByChon } from '@/util/canvas-util' +import { CalculatorInput } from '@/components/common/input/CalcInput' export default function DoublePitch({ props }) { const { getMessage } = useMessage() @@ -50,14 +51,29 @@ export default function DoublePitch({ props }) {
{getMessage('modal.cover.outline.angle')}
- (angle1Ref.current.value = '')}*/} + {/* onChange={(e) => setAngle1(normalizeDecimalLimit(e.target.value, 2))}*/} + {/* placeholder="45"*/} + {/*/>*/} + (angle1Ref.current.value = '')} - onChange={(e) => setAngle1(normalizeDecimalLimit(e.target.value, 2))} + onChange={(value) => setAngle1(value)} placeholder="45" + onFocus={() => (angle1Ref.current.value = '')} + options={{ + allowNegative: false, + allowDecimal: true + }} />
@@ -67,14 +83,29 @@ export default function DoublePitch({ props }) {
{getMessage('modal.cover.outline.length')}
- (length1Ref.current.value = '')}*/} + {/* onChange={(e) => setLength1(normalizeDigits(e.target.value))}*/} + {/* placeholder="3000"*/} + {/*/>*/} + (length1Ref.current.value = '')} - onChange={(e) => setLength1(normalizeDigits(e.target.value))} + onChange={(value) => setLength1(value)} placeholder="3000" + onFocus={() => (length1Ref.current.value = '')} + options={{ + allowNegative: false, + allowDecimal: false + }} />