diff --git a/src/components/common/select/QSelectBox.jsx b/src/components/common/select/QSelectBox.jsx index 12c72b5e..f1041da3 100644 --- a/src/components/common/select/QSelectBox.jsx +++ b/src/components/common/select/QSelectBox.jsx @@ -1,6 +1,7 @@ 'use client' import { useEffect, useRef, useState } from 'react' import { useOnClickOutside } from 'usehooks-ts' +import { useMessage } from '@/hooks/useMessage' /** * @@ -26,13 +27,15 @@ export default function QSelectBox({ showKey = '', params = {}, }) { + const { getMessage } = useMessage() + /** * 초기 상태 처리 * useState 초기 값으로 사용해야 해서 useState 보다 위에 작성 * @returns {string} 초기 상태 */ const handleInitState = () => { - if (options.length === 0) return title !== '' ? title : '선택하세요.' + if (options.length === 0) return title !== '' ? title : getMessage('selectbox.title') if (showKey !== '' && !value) { //value가 없으면 showKey가 있으면 우선 보여준다 // return options[0][showKey] @@ -44,13 +47,13 @@ export default function QSelectBox({ return option[sourceKey] === value[targetKey] }) if (!option) { - return title !== '' ? title : '선택하세요.' + return title !== '' ? title : getMessage('selectbox.title') } else { return option[showKey] } } else { //일치하는 조건이 없으면 기본값을 보여준다. - return title !== '' ? title : '선택하세요.' + return title !== '' ? title : getMessage('selectbox.title') } } diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 52afaf8e..af57a32b 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -25,26 +25,29 @@ 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 { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom' import { sessionStore } from '@/store/commonAtom' import { outerLinePointsState } from '@/store/outerLineAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -import { addedRoofsState, basicSettingState, selectedRoofMaterialSelector, settingModalFirstOptionsState } from '@/store/settingAtom' +import { + addedRoofsState, + basicSettingState, + corridorDimensionSelector, + selectedRoofMaterialSelector, + settingModalFirstOptionsState, +} from '@/store/settingAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import { commonUtilsState } from '@/store/commonUtilsAtom' import { menusState, menuTypeState } from '@/store/menuAtom' import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' import { pwrGnrSimTypeState } from '@/store/simulatorAtom' import { isObjectNotEmpty } from '@/util/common-utils' +import { POLYGON_TYPE } from '@/common/common' import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' -import { MENU, POLYGON_TYPE } from '@/common/common' - import { QcastContext } from '@/app/QcastProvider' - export default function CanvasMenu(props) { const { menuNumber, setMenuNumber } = props const pathname = usePathname() @@ -238,6 +241,16 @@ export default function CanvasMenu(props) { if (menuNumber === 1) { onClickPlacementInitialMenu() } + if (menuNumber === 3) { + const moduleSurfacesArray = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + if (moduleSurfacesArray.length > 0) { + moduleSurfacesArray.forEach((moduleSurface) => { + moduleSurface.modules = [] + canvas.remove(moduleSurface) + }) + canvas.renderAll() + } + } }, [menuNumber, type]) // 저장버튼(btn08) 클릭 시 호출되는 함수 @@ -508,8 +521,12 @@ export default function CanvasMenu(props) {
{ { + return { ...roof, name: globalLocale === 'ko' ? roof.roofMatlNm : roof.roofMatlNmJp } + })} + //showKey={'roofMatlNm'} + showKey={'name'} value={selectedRoofMaterial} onChange={changeSelectedRoofMaterial} sourceKey={'index'} diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index f4fc830d..67e2faa1 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -34,7 +34,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) // const { initEvent } = useContext(EventContext) - const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting() + const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting(1) const { updateObjectDate } = useMasterController() const handleBtnNextStep = () => { if (tabNum === 1) { diff --git a/src/components/floor-plan/modal/basic/step/ModuleTabContents.jsx b/src/components/floor-plan/modal/basic/step/ModuleTabContents.jsx index 706fad9f..149ffbd9 100644 --- a/src/components/floor-plan/modal/basic/step/ModuleTabContents.jsx +++ b/src/components/floor-plan/modal/basic/step/ModuleTabContents.jsx @@ -120,7 +120,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro value={selectedTrestle} sourceKey={'trestleMkrCd'} targetKey={'trestleMkrCd'} - showKey={'trestleMkrCdNm'} + showKey={'trestleMkrCdJp'} onChange={handleChangeTrestle} /> )} @@ -138,7 +138,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro value={selectedConstMthd} sourceKey={'constMthdCd'} targetKey={'constMthdCd'} - showKey={'constMthdCdNm'} + showKey={'constMthdCdJp'} onChange={handleChangeConstMthd} /> )} @@ -156,7 +156,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro value={selectedRoofBase} sourceKey={'roofBaseCd'} targetKey={'roofBaseCd'} - showKey={'roofBaseCdNm'} + showKey={'roofBaseCdJp'} onChange={handleChangeRoofBase} /> )} diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index eff568cd..d7d31ffa 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -4,20 +4,17 @@ import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' import { checkedModuleState, currentCanvasPlanState } from '@/store/canvasAtom' import { useRecoilValue, useSetRecoilState } from 'recoil' import { moduleSelectionDataState } from '@/store/selectedModuleOptions' -import { useModulePlace } from '@/hooks/module/useModulePlace' const Placement = forwardRef((props, refs) => { const { getMessage } = useMessage() const [isChidori, setIsChidori] = useState(false) const [isChidoriNotAble, setIsChidoriNotAble] = useState(false) - const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) const [setupLocation, setSetupLocation] = useState('center') const [isMaxSetup, setIsMaxSetup] = useState('false') const [selectedItems, setSelectedItems] = useState({}) - const { makeModuleInstArea } = useModuleBasicSetting() - const { selectedModules } = useModulePlace() + const { selectedModules } = useModuleBasicSetting(3) const setCheckedModules = useSetRecoilState(checkedModuleState) const moduleSelectionData = useRecoilValue(moduleSelectionDataState) diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 109da999..7301f0d7 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -356,7 +356,7 @@ export default function CircuitTrestleSetting({ id }) { } // 회로할당(승압설정) 저장 버튼 클릭 시 - const onApply = () => { + const onApply = async () => { canvas .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) @@ -364,8 +364,7 @@ export default function CircuitTrestleSetting({ id }) { obj.pcses = getStepUpListData() }) - console.log(canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)) - apply() + const result = await apply() } const onClickPrev = () => { diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 1a5ea92a..5439b303 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -258,7 +258,11 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
{ diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index c790da89..baaa7dfe 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -21,7 +21,7 @@ export function useCommonUtils() { const commonTextFont = useRecoilValue(fontSelector('commonText')) const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState) const { addPopup } = usePopup() - const { drawDirectionArrow } = usePolygon() + const { drawDirectionArrow, addLengthText } = usePolygon() useEffect(() => { // initEvent() @@ -610,17 +610,17 @@ export function useCommonUtils() { //객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다 if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() }) - initEvent() - //배치면일 경우 if (obj.name === 'roof') { clonedObj.setCoords() clonedObj.fire('polygonMoved') clonedObj.set({ direction: obj.direction, directionText: obj.directionText }) - clonedObj.addLengthText() canvas.renderAll() - drawDirectionArrow(clonedObj) + addLengthText(clonedObj) //수치 추가 + drawDirectionArrow(clonedObj) //방향 화살표 추가 } + + initEvent() }) } } diff --git a/src/hooks/common/useMasterController.js b/src/hooks/common/useMasterController.js index b090df81..f2ca3adf 100644 --- a/src/hooks/common/useMasterController.js +++ b/src/hooks/common/useMasterController.js @@ -229,9 +229,7 @@ export function useMasterController() { * @returns */ const updateObjectDate = async (params = null) => { - return await put({ url: '/api/object/update-object-date', data: params }).then((res) => { - console.log('updateObjectDate', res) - }) + return await put({ url: '/api/object/update-object-date', data: params }) } return { diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index f003982c..20575fd7 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1,5 +1,6 @@ +import { useState } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { canvasSettingState, canvasState, checkedModuleState, isManualModuleSetupState, selectedModuleState } from '@/store/canvasAtom' +import { canvasSettingState, canvasState, checkedModuleState, isManualModuleSetupState } from '@/store/canvasAtom' import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon } from '@/util/canvas-util' import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom' import offsetPolygon, { calculateAngle } from '@/util/qpolygon-utils' @@ -15,14 +16,17 @@ import { useRoofFn } from '@/hooks/common/useRoofFn' import { useEffect } from 'react' import { useMessage } from '@/hooks/useMessage' import { moduleStatisticsState } from '@/store/circuitTrestleAtom' +import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' +import { useMasterController } from '@/hooks/common/useMasterController' +import { v4 as uuidv4 } from 'uuid' -export function useModuleBasicSetting() { +export function useModuleBasicSetting(tabNum) { const canvas = useRecoilValue(canvasState) const { getMessage } = useMessage() const roofDisplay = useRecoilValue(roofDisplaySelector) const [moduleSetupSurface, setModuleSetupSurface] = useRecoilState(moduleSetupSurfaceState) const [moduleIsSetup, setModuleIsSetup] = useRecoilState(moduleIsSetupState) - const { addCanvasMouseEventListener, initEvent, removeMouseEvent } = useEvent() + const { addCanvasMouseEventListener, initEvent, removeMouseEvent, addTargetMouseEventListener } = useEvent() const { swalFire } = useSwal() const compasDeg = useRecoilValue(compasDegAtom) @@ -34,6 +38,13 @@ export function useModuleBasicSetting() { const canvasSetting = useRecoilValue(canvasSettingState) + const moduleSelectionData = useRecoilValue(moduleSelectionDataState) + const [trestleDetailParams, setTrestleDetailParams] = useState([]) + const [trestleDetailList, setTrestleDetailList] = useState([]) + const selectedModules = useRecoilValue(selectedModuleState) + const { getTrestleDetailList } = useMasterController() + const [saleStoreNorthFlg, setSaleStoreNorthFlg] = useState(false) + useEffect(() => { // console.log('basicSetting', basicSetting) if (canvas) { @@ -47,6 +58,247 @@ export function useModuleBasicSetting() { // const { addTargetMouseEventListener, addCanvasMouseEventListener, initEvent } = useContext(EventContext) + //모듈 선택에서 선택된 값들 넘어옴 + useEffect(() => { + if (moduleSelectionData && tabNum === 3) { + const common = moduleSelectionData.common + + const roofConstructions = moduleSelectionData.roofConstructions + + const listParams = roofConstructions.map((item) => { + return { + ...common, + moduleTpCd: selectedModules.itemTp, + roofMatlCd: item.trestle.roofMatlCd, + trestleMkrCd: item.trestle.trestleMkrCd, + constMthdCd: item.trestle.constMthdCd, + roofBaseCd: item.trestle.roofBaseCd, + constTp: item.construction.constTp, + mixMatlNo: selectedModules.mixMatlNo, + roofPitch: item.addRoof.hajebichi ? item.addRoof.hajebichi : 0, + inclCd: String(item.addRoof.pitch), + roofIndex: item.addRoof.index, + workingWidth: item.addRoof.lenBase, + } + }) + setTrestleDetailParams(listParams) + + //북면 설치 가능 판매점 + if (moduleSelectionData.common.saleStoreNorthFlg === '1') { + setSaleStoreNorthFlg(true) + } + } + }, [moduleSelectionData]) + + //가대 상세 데이터 조회 + const getTrestleDetailListData = async () => { + const trestleDetailList = await getTrestleDetailList(trestleDetailParams) + if (trestleDetailList.length > 0) { + setTrestleDetailList(trestleDetailList) + } + } + + //가대 상세 데이터 파라메터 담기면 실행 + useEffect(() => { + if (trestleDetailParams.length > 0) { + getTrestleDetailListData(trestleDetailParams) + } + }, [trestleDetailParams]) + + //가대 상세 데이터 들어오면 실행 + useEffect(() => { + if (trestleDetailList.length > 0) { + //지붕을 가져옴 + canvas + .getObjects() + .filter((roof) => roof.name === 'roof') + .forEach((roof) => { + const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번 + trestleDetailList.forEach((detail) => { + if (detail.data !== null) { + if (Number(detail.data.roofIndex) === roofIndex) { + //roof에 상세 데이터 추가 + roof.set({ trestleDetail: detail.data }) + //배치면 설치 영역 + makeModuleInstArea(roof, detail.data) + //surface에 상세 데이터 추가 + } else { + console.log('가대 데이터가 없네요...') + } + } + }) + }) + } + }, [trestleDetailList]) + + //가대 상세 데이터 기준으로 모듈 설치 배치면 생성 + const makeModuleInstArea = (roof, trestleDetail) => { + //지붕 객체 반환 + + if (!roof) { + return + } + + //도머등 오브젝트 객체가 있으면 아웃라인 낸다 + const batchObjects = canvas + ?.getObjects() + .filter( + (obj) => + obj.name === BATCH_TYPE.OPENING || + obj.name === BATCH_TYPE.SHADOW || + obj.name === BATCH_TYPE.TRIANGLE_DORMER || + obj.name === BATCH_TYPE.PENTAGON_DORMER, + ) //도머s 객체 + + //도머도 외곽을 따야한다 + const batchObjectOptions = { + stroke: 'red', + fill: 'transparent', + strokeDashArray: [10, 4], + strokeWidth: 1, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + selectable: true, + name: POLYGON_TYPE.OBJECT_SURFACE, + originX: 'center', + originY: 'center', + } + + //도머등 오브젝트 객체가 있으면 아웃라인 낸다 + batchObjects.forEach((obj) => { + //도머일때 + if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) { + const groupPoints = obj.groupPoints + const offsetObjects = offsetPolygon(groupPoints, 10) + const dormerOffset = new QPolygon(offsetObjects, batchObjectOptions) + dormerOffset.setViewLengthText(false) + canvas.add(dormerOffset) //모듈설치면 만들기 + } else { + //개구, 그림자일때 + const points = obj.points + const offsetObjects = offsetPolygon(points, 10) + const offset = new QPolygon(offsetObjects, batchObjectOptions) + offset.setViewLengthText(false) + canvas.add(offset) //모듈설치면 만들기 + } + }) + + const isExistSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.parentId === roof.id) + if (isExistSurface) { + return + } + + let offsetLength = canvasSetting.roofSizeSet === 3 ? -90 : (trestleDetail.eaveIntvl / 10) * -1 + setSurfaceShapePattern(roof, roofDisplay.column, true) //패턴 변경 + const offsetPoints = offsetPolygon(roof.points, offsetLength) //안쪽 offset + //모듈설치영역?? 생성 + + const surfaceId = uuidv4() + + let isNorth = false + + //북면이 있지만 + if (roof.directionText && roof.directionText.indexOf('北') > -1) { + //북쪽일때 해당 서북서, 동북동은 제외한다고 한다 + if (!(roof.directionText.indexOf('西北西') > -1 || roof.directionText.indexOf('東北東') > -1)) { + isNorth = true + } + } + + //모듈설치면 생성 + let setupSurface = new QPolygon(offsetPoints, { + stroke: 'red', + fill: 'rgba(255,255,255,0.1)', + strokeDashArray: [10, 4], + strokeWidth: 1, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + selectable: true, + parentId: roof.id, //가대 폴리곤의 임시 인덱스를 넣어줌 + name: POLYGON_TYPE.MODULE_SETUP_SURFACE, + flowDirection: roof.direction, + direction: roof.direction, + flipX: roof.flipX, + flipY: roof.flipY, + surfaceId: surfaceId, + originX: 'center', + originY: 'center', + modules: [], + roofMaterial: roof.roofMaterial, + trestleDetail: trestleDetail, + isNorth: isNorth, + perPixelTargetFind: true, + // angle: -compasDeg, + }) + + setupSurface.setViewLengthText(false) + canvas.add(setupSurface) //모듈설치면 만들기 + + //지붕면 선택 금지 + roof.set({ + selectable: false, //선택 금지 + evented: false, //클릭 이벤트도 금지 + }) + + canvas.renderAll() + + //모듈설치면 클릭이벤트 + addTargetMouseEventListener('mousedown', setupSurface, function () { + toggleSelection(setupSurface) + }) + } + + let selectedModuleInstSurfaceArray = [] + + //설치 범위 지정 클릭 이벤트 + const toggleSelection = (setupSurface) => { + const isExist = selectedModuleInstSurfaceArray.some((obj) => obj.parentId === setupSurface.parentId) + //최초 선택일때 + if (!isExist) { + //설치면이 북면이고 북면설치 허용점이 아니면 + if (setupSurface.isNorth && !saleStoreNorthFlg) { + swalFire({ text: getMessage('module.not.batch.north'), icon: 'warning' }) + return + } + + //기본 선택이랑 스트로크 굵기가 같으면 선택 안됨으로 봄 + setupSurface.set({ + ...setupSurface, + strokeWidth: 3, + strokeDashArray: [0], + fill: 'rgba(255,255,255,0.1)', + }) + canvas.discardActiveObject() // 객체의 활성 상태 해제 + //중복으로 들어가는걸 방지하기 위한 코드 + + canvas?.renderAll() + selectedModuleInstSurfaceArray.push(setupSurface) + } else { + //선택후 재선택하면 선택안됨으로 변경 + setupSurface.set({ + ...setupSurface, + fill: 'rgba(255,255,255,0.1)', + strokeDashArray: [10, 4], + strokeWidth: 1, + }) + canvas.discardActiveObject() // 객체의 활성 상태 해제 + + //폴리곤에 커스텀 인덱스를 가지고 해당 배열 인덱스를 찾아 삭제함 + const removeIndex = setupSurface.parentId + const removeArrayIndex = selectedModuleInstSurfaceArray.findIndex((obj) => obj.parentId === removeIndex) + selectedModuleInstSurfaceArray.splice(removeArrayIndex, 1) + } + + canvas?.renderAll() + setModuleSetupSurface([...selectedModuleInstSurfaceArray]) + } + //모듈,회로에서 다른메뉴 -> 배치면으로 갈 경수 초기화 const restoreModuleInstArea = () => { //설치면 삭제 @@ -76,6 +328,7 @@ export function useModuleBasicSetting() { */ const manualModuleSetup = () => { // console.log('isManualModuleSetup', isManualModuleSetup) + const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 if (isManualModuleSetup) { if (checkedModule.length === 0) { @@ -90,8 +343,14 @@ export function useModuleBasicSetting() { return } - const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체 + //수동모드 모듈 설치면 선택 잠금 + moduleSetupSurfaces.forEach((obj) => { + obj.set({ + selectable: false, + evented: false, + }) + }) const moduleOptions = { fill: checkedModule[0].color, @@ -168,7 +427,12 @@ export function useModuleBasicSetting() { parentId: moduleSetupSurfaces[i].parentId, }) - canvas?.add(tempModule) //움직여가면서 추가됨 + //북면이고 북면설치상점이 아니면 그냥 return + if (trestlePolygon.isNorth && !saleStoreNorthFlg) { + return + } else { + canvas?.add(tempModule) //움직여가면서 추가됨 + } /** * 스냅기능 @@ -361,6 +625,7 @@ export function useModuleBasicSetting() { const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 if (!isOverlap) { canvas?.remove(tempModule) + //안겹치면 넣는다 // tempModule.setCoords() moduleOptions.surfaceId = trestlePolygon.id @@ -379,6 +644,14 @@ export function useModuleBasicSetting() { }) } } else { + //수동모드 해제시 모듈 설치면 선택 잠금 + moduleSetupSurfaces.forEach((obj) => { + obj.set({ + selectable: true, + evented: true, + }) + }) + removeMouseEvent('mouse:up') removeMouseEvent('mouse:move') canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임 @@ -2209,6 +2482,7 @@ export function useModuleBasicSetting() { } return { + selectedModules, manualModuleSetup, autoModuleSetup, restoreModuleInstArea, diff --git a/src/hooks/module/useModulePlace.js b/src/hooks/module/useModulePlace.js index bc9913f6..38e628a0 100644 --- a/src/hooks/module/useModulePlace.js +++ b/src/hooks/module/useModulePlace.js @@ -10,6 +10,8 @@ import offsetPolygon from '@/util/qpolygon-utils' import { v4 as uuidv4 } from 'uuid' import { QPolygon } from '@/components/fabric/QPolygon' import { useEvent } from '@/hooks/useEvent' +import { useSwal } from '@/hooks/useSwal' +import { useMessage } from '@/hooks/useMessage' export function useModulePlace() { const canvas = useRecoilValue(canvasState) @@ -23,211 +25,9 @@ export function useModulePlace() { const roofDisplay = useRecoilValue(roofDisplaySelector) const { addTargetMouseEventListener } = useEvent() const setModuleSetupSurface = useSetRecoilState(moduleSetupSurfaceState) - - useEffect(() => { - if (moduleSelectionData) { - const common = moduleSelectionData.common - const roofConstructions = moduleSelectionData.roofConstructions - - const listParams = roofConstructions.map((item) => { - return { - ...common, - moduleTpCd: selectedModules.itemTp, - roofMatlCd: item.trestle.roofMatlCd, - trestleMkrCd: item.trestle.trestleMkrCd, - constMthdCd: item.trestle.constMthdCd, - roofBaseCd: item.trestle.roofBaseCd, - constTp: item.construction.constTp, - mixMatlNo: selectedModules.mixMatlNo, - roofPitch: item.addRoof.hajebichi ? item.addRoof.hajebichi : 0, - inclCd: String(item.addRoof.pitch), - roofIndex: item.addRoof.index, - workingWidth: item.addRoof.lenBase, - } - }) - setTrestleDetailParams(listParams) - } - }, [moduleSelectionData]) - - const getTrestleDetailListData = async () => { - const trestleDetailList = await getTrestleDetailList(trestleDetailParams) - if (trestleDetailList.length > 0) { - setTrestleDetailList(trestleDetailList) - } - } - - useEffect(() => { - if (trestleDetailParams.length > 0) { - getTrestleDetailListData(trestleDetailParams) - } - }, [trestleDetailParams]) - - useEffect(() => { - if (trestleDetailList.length > 0) { - //지붕을 가져옴 - canvas - .getObjects() - .filter((roof) => roof.name === 'roof') - .forEach((roof) => { - const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번 - trestleDetailList.forEach((detail) => { - if (detail.data !== null) { - if (Number(detail.data.roofIndex) === roofIndex) { - //roof에 상세 데이터 추가 - roof.set({ trestleDetail: detail.data }) - //배치면 설치 영역 - makeModuleInstArea(roof, detail.data) - //surface에 상세 데이터 추가 - } else { - console.log('가대 데이터가 없네요...') - } - } - }) - }) - } - }, [trestleDetailList]) - - const makeModuleInstArea = (roof, trestleDetail) => { - //지붕 객체 반환 - - if (!roof) { - return - } - - const batchObjects = canvas - ?.getObjects() - .filter( - (obj) => - obj.name === BATCH_TYPE.OPENING || - obj.name === BATCH_TYPE.SHADOW || - obj.name === BATCH_TYPE.TRIANGLE_DORMER || - obj.name === BATCH_TYPE.PENTAGON_DORMER, - ) //도머s 객체 - - //도머도 외곽을 따야한다 - - const batchObjectOptions = { - stroke: 'red', - fill: 'transparent', - strokeDashArray: [10, 4], - strokeWidth: 1, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - selectable: true, - name: POLYGON_TYPE.OBJECT_SURFACE, - originX: 'center', - originY: 'center', - } - - batchObjects.forEach((obj) => { - if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) { - const groupPoints = obj.groupPoints - const offsetObjects = offsetPolygon(groupPoints, 10) - const dormerOffset = new QPolygon(offsetObjects, batchObjectOptions) - dormerOffset.setViewLengthText(false) - canvas.add(dormerOffset) //모듈설치면 만들기 - } else { - const points = obj.points - const offsetObjects = offsetPolygon(points, 10) - const offset = new QPolygon(offsetObjects, batchObjectOptions) - offset.setViewLengthText(false) - canvas.add(offset) //모듈설치면 만들기 - } - }) - - const isExistSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.parentId === roof.id) - if (isExistSurface) { - return - } - - let offsetLength = canvasSetting.roofSizeSet === 3 ? -90 : (trestleDetail.eaveIntvl / 10) * -1 - setSurfaceShapePattern(roof, roofDisplay.column, true) //패턴 변경 - const offsetPoints = offsetPolygon(roof.points, offsetLength) //안쪽 offset - //모듈설치영역?? 생성 - - const surfaceId = uuidv4() - - let setupSurface = new QPolygon(offsetPoints, { - stroke: 'red', - fill: 'transparent', - strokeDashArray: [10, 4], - strokeWidth: 1, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - selectable: true, - parentId: roof.id, //가대 폴리곤의 임시 인덱스를 넣어줌 - name: POLYGON_TYPE.MODULE_SETUP_SURFACE, - flowDirection: roof.direction, - direction: roof.direction, - flipX: roof.flipX, - flipY: roof.flipY, - surfaceId: surfaceId, - originX: 'center', - originY: 'center', - modules: [], - roofMaterial: roof.roofMaterial, - trestleDetail: trestleDetail, - // angle: -compasDeg, - }) - - setupSurface.setViewLengthText(false) - canvas.add(setupSurface) //모듈설치면 만들기 - - //지붕면 선택 금지 - roof.set({ - selectable: false, - }) - - //모듈설치면 클릭이벤트 - addTargetMouseEventListener('mousedown', setupSurface, function () { - toggleSelection(setupSurface) - }) - } - - let selectedModuleInstSurfaceArray = [] - - //설치 범위 지정 클릭 이벤트 - const toggleSelection = (setupSurface) => { - const isExist = selectedModuleInstSurfaceArray.some((obj) => obj.parentId === setupSurface.parentId) - //최초 선택일때 - if (!isExist) { - //기본 선택이랑 스트로크 굵기가 같으면 선택 안됨으로 봄 - setupSurface.set({ - ...setupSurface, - strokeWidth: 3, - strokeDashArray: [0], - fill: 'transparent', - }) - canvas.discardActiveObject() // 객체의 활성 상태 해제 - //중복으로 들어가는걸 방지하기 위한 코드 - - canvas?.renderAll() - selectedModuleInstSurfaceArray.push(setupSurface) - } else { - //선택후 재선택하면 선택안됨으로 변경 - setupSurface.set({ - ...setupSurface, - fill: 'transparent', - strokeDashArray: [10, 4], - strokeWidth: 1, - }) - canvas.discardActiveObject() // 객체의 활성 상태 해제 - - //폴리곤에 커스텀 인덱스를 가지고 해당 배열 인덱스를 찾아 삭제함 - const removeIndex = setupSurface.parentId - const removeArrayIndex = selectedModuleInstSurfaceArray.findIndex((obj) => obj.parentId === removeIndex) - selectedModuleInstSurfaceArray.splice(removeArrayIndex, 1) - } - - canvas?.renderAll() - setModuleSetupSurface([...selectedModuleInstSurfaceArray]) - } + const [saleStoreNorthFlg, setSaleStoreNorthFlg] = useState(false) + const { swalFire } = useSwal() + const { getMessage } = useMessage() return { selectedModules, diff --git a/src/hooks/module/useModuleSelection.js b/src/hooks/module/useModuleSelection.js index 0321abaa..d0b812e5 100644 --- a/src/hooks/module/useModuleSelection.js +++ b/src/hooks/module/useModuleSelection.js @@ -5,8 +5,11 @@ import { useMasterController } from '@/hooks/common/useMasterController' import { useCommonCode } from '@/hooks/common/useCommonCode' import { selectedModuleState, moduleSelectionInitParamsState, moduleSelectionDataState } from '@/store/selectedModuleOptions' import { isObjectNotEmpty } from '@/util/common-utils' +import { canvasState } from '@/store/canvasAtom' +import { POLYGON_TYPE } from '@/common/common' export function useModuleSelection(props) { + const canvas = useRecoilValue(canvasState) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const [roughnessCodes, setRoughnessCodes] = useState([]) //면조도 목록 @@ -41,6 +44,7 @@ export function useModuleSelection(props) { instHt: managementState?.installHeight, //설치높이 stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속 stdSnowLd: managementState?.verticalSnowCover, //기준적설량 + saleStoreNorthFlg: managementState?.saleStoreNorthFlg, //북쪽 설치 여부 } if (selectedModules) { @@ -62,6 +66,7 @@ export function useModuleSelection(props) { // 202000 풍속 const windCodeList = findCommonCode('202000') + windCodeList.forEach((obj) => { obj.name = obj.clCodeNm obj.id = obj.clCode @@ -83,6 +88,16 @@ export function useModuleSelection(props) { } getModuleData(roofsIds) + + //메뉴 이동시 배치면 삭제 + const moduleSurfacesArray = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + if (moduleSurfacesArray.length > 0) { + moduleSurfacesArray.forEach((moduleSurface) => { + moduleSurface.module = [] + canvas.remove(moduleSurface) + }) + canvas.renderAll() + } }, []) const getModuleData = async (roofsIds) => { diff --git a/src/hooks/module/useModuleTabContents.js b/src/hooks/module/useModuleTabContents.js index 95317cdd..63ab7722 100644 --- a/src/hooks/module/useModuleTabContents.js +++ b/src/hooks/module/useModuleTabContents.js @@ -299,6 +299,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab //거대메이커, 공법, 지붕밑바탕 api 조회 const getModuleOptionsListData = async (params, type) => { const optionsList = await getTrestleList(params) + console.log('optionsList', optionsList) if (optionsList.data.length > 0) { if (type === 'trestle') { diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index eb7ecbc2..083c24c3 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -1,5 +1,5 @@ import { useRecoilState, useRecoilValue } from 'recoil' -import { canvasState } from '@/store/canvasAtom' +import { canvasState, currentAngleTypeSelector } from '@/store/canvasAtom' import { POLYGON_TYPE } from '@/common/common' import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { getDegreeByChon, getTrestleLength } from '@/util/canvas-util' @@ -13,220 +13,207 @@ export const useTrestle = () => { const moduleSelectionData = useRecoilValue(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터 const { getQuotationItem } = useMasterController() const [estimateParam, setEstimateParam] = useRecoilState(estimateParamAtom) + const currentAngleType = useRecoilValue(currentAngleTypeSelector) const apply = () => { - //처마력바가 체크되어 있는 경우 exposedBottomPoints를 이용해 처마력바 그려줘야함. - // exposedBottomPoints는 노출 최하면 들의 centerPoint 배열. + try { + //처마력바가 체크되어 있는 경우 exposedBottomPoints를 이용해 처마력바 그려줘야함. + // exposedBottomPoints는 노출 최하면 들의 centerPoint 배열. - const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) - // 기존 eaveBar를 삭제 - canvas.getObjects().forEach((obj) => { - if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack') { - canvas.remove(obj) - } - }) - canvas.getObjects().forEach((obj) => { - if (obj.name === 'bracket') { - canvas.remove(obj) - } - }) - surfaces.forEach((surface) => { - const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId) - const roofMaterialIndex = parent.roofMaterial.index - const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction - if (!construction) { - alert('앞에서 셋팅 안됨') - return - } - - let moduleRowsTotCnt = 0 - let isEaveBar = construction.setupCover - let isSnowGuard = construction.setupSnowCover - const direction = parent.direction - const rack = surface.trestleDetail.rack - let { rackQty, rackIntvlPct, rackYn, cvrPlvrYn } = surface.trestleDetail - - if (!rack) { - //25/01/16 기준 랙이 없는 경우는 그냥 안그려준다. - return - } - - const rackInfos = Object.keys(rack).map((key) => { - return { key, value: rack[key] } - }) - - const result = calculateForApi(surface) - - if (!result) { - return - } - const centerPoints = result.centerPoints - - const exposedBottomModules = [] // 아래 두면이 모두 노출 되어있는 경우 - const leftExposedHalfBottomModules = [] // 왼쪽 면만 노출되어있는 경우 - const rightExposedHalfBottomPoints = [] // 오른쪽 면만 노출되어 있는 경우 - const leftExposedHalfTopModules = [] // 왼쪽 면만 노출되어 있는 경우 - const rightExposedHalfTopPoints = [] // 오른쪽 면만 노출되어 있는 경우 - const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) - - modules.forEach((module) => { - const { x, y } = module.getCenterPoint() - const isExposedBottom = result.exposedBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) - const isLeftExposedHalfBottom = result.leftExposedHalfBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) - const isRightExposedHalfBottom = result.rightExposedHalfBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) - const isRightExposedHalfTop = result.rightExposedHalfTopPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) - const isLeftExposedHalfTop = result.leftExposedHalfTopPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) - if (isExposedBottom) { - exposedBottomModules.push(module) - } - if (isLeftExposedHalfBottom) { - leftExposedHalfBottomModules.push(module) - } - if (isRightExposedHalfBottom) { - rightExposedHalfBottomPoints.push(module) - } - if (isRightExposedHalfTop) { - leftExposedHalfTopModules.push(module) - } - if (isLeftExposedHalfTop) { - rightExposedHalfTopPoints.push(module) - } - }) - - // 4개중 한개라도 있는 경우 치조배치로 간주한다. - const isChidory = - leftExposedHalfBottomModules.length > 0 || - rightExposedHalfBottomPoints.length > 0 || - leftExposedHalfTopModules.length > 0 || - rightExposedHalfTopPoints.length > 0 - - surface.set({ isChidory: isChidory }) - - canvas - .getObjects() - .filter((obj) => ['eaveBar', 'halfEaveBar'].includes(obj.name) && obj.parentId === surface.id) - .forEach((obj) => { + const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + // 기존 eaveBar를 삭제 + canvas.getObjects().forEach((obj) => { + if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack') { canvas.remove(obj) + } + }) + canvas.getObjects().forEach((obj) => { + if (obj.name === 'bracket') { + canvas.remove(obj) + } + }) + surfaces.forEach((surface) => { + const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId) + const roofMaterialIndex = parent.roofMaterial.index + const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction + if (!construction) { + alert('앞에서 셋팅 안됨') + return + } + + let moduleRowsTotCnt = 0 + let isEaveBar = construction.setupCover + let isSnowGuard = construction.setupSnowCover + const direction = parent.direction + const rack = surface.trestleDetail.rack + let { rackQty, rackIntvlPct, rackYn, cvrPlvrYn } = surface.trestleDetail + + if (!rack) { + //25/01/16 기준 랙이 없는 경우는 그냥 안그려준다. + return + } + + const rackInfos = Object.keys(rack).map((key) => { + return { key, value: rack[key] } }) - if (isEaveBar) { - // 처마력바설치 true인 경우 설치 - exposedBottomModules.forEach((module) => { - //TODO : 방향별로 처마력바 설치해야함 - const bottomPoints = findTopTwoPoints([...module.points], direction) - if (!bottomPoints) return - const eaveBar = new fabric.Line([bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y], { - parent: surface, - name: 'eaveBar', - stroke: 'blue', - strokeWidth: 4, - selectable: false, - surfaceId: surface.id, - parentId: module.id, + const result = calculateForApi(surface) + + if (!result) { + return + } + const centerPoints = result.centerPoints + + const exposedBottomModules = [] // 아래 두면이 모두 노출 되어있는 경우 + const leftExposedHalfBottomModules = [] // 왼쪽 면만 노출되어있는 경우 + const rightExposedHalfBottomPoints = [] // 오른쪽 면만 노출되어 있는 경우 + const leftExposedHalfTopModules = [] // 왼쪽 면만 노출되어 있는 경우 + const rightExposedHalfTopPoints = [] // 오른쪽 면만 노출되어 있는 경우 + const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) + + modules.forEach((module) => { + const { x, y } = module.getCenterPoint() + const isExposedBottom = result.exposedBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) + const isLeftExposedHalfBottom = result.leftExposedHalfBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) + const isRightExposedHalfBottom = result.rightExposedHalfBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) + const isRightExposedHalfTop = result.rightExposedHalfTopPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) + const isLeftExposedHalfTop = result.leftExposedHalfTopPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2) + if (isExposedBottom) { + exposedBottomModules.push(module) + } + if (isLeftExposedHalfBottom) { + leftExposedHalfBottomModules.push(module) + } + if (isRightExposedHalfBottom) { + rightExposedHalfBottomPoints.push(module) + } + if (isRightExposedHalfTop) { + leftExposedHalfTopModules.push(module) + } + if (isLeftExposedHalfTop) { + rightExposedHalfTopPoints.push(module) + } + }) + + // 4개중 한개라도 있는 경우 치조배치로 간주한다. + const isChidory = + leftExposedHalfBottomModules.length > 0 || + rightExposedHalfBottomPoints.length > 0 || + leftExposedHalfTopModules.length > 0 || + rightExposedHalfTopPoints.length > 0 + + surface.set({ isChidory: isChidory }) + + canvas + .getObjects() + .filter((obj) => ['eaveBar', 'halfEaveBar'].includes(obj.name) && obj.parentId === surface.id) + .forEach((obj) => { + canvas.remove(obj) }) - canvas.add(eaveBar) - canvas.renderAll() - }) - if (isChidory && cvrPlvrYn === 'Y') { - leftExposedHalfBottomModules.forEach((module) => { + if (isEaveBar) { + // 처마력바설치 true인 경우 설치 + exposedBottomModules.forEach((module) => { + //TODO : 방향별로 처마력바 설치해야함 const bottomPoints = findTopTwoPoints([...module.points], direction) - let barPoints = [] - //설치해야할 반처마커버 포인트를 방향에 따라 설정 - - if (direction === 'south') { - barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x - module.width / 2, bottomPoints[1].y] - } else if (direction === 'north') { - barPoints = [bottomPoints[0].x + module.width / 2, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y] - } else if (direction === 'east') { - barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[0].y - module.height / 2] - } else if (direction === 'west') { - barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y - module.height / 2] - } - if (!bottomPoints) return - const halfEaveBar = new fabric.Line(barPoints, { + const eaveBar = new fabric.Line([bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y], { parent: surface, - name: 'halfEaveBar', + name: 'eaveBar', stroke: 'blue', strokeWidth: 4, selectable: false, surfaceId: surface.id, parentId: module.id, }) - canvas.add(halfEaveBar) + canvas.add(eaveBar) canvas.renderAll() }) - rightExposedHalfBottomPoints.forEach((module) => { - const bottomPoints = findTopTwoPoints([...module.points], direction) - let barPoints = [] - //설치해야할 반처마커버 포인트를 방향에 따라 설정 + if (isChidory && cvrPlvrYn === 'Y') { + leftExposedHalfBottomModules.forEach((module) => { + const bottomPoints = findTopTwoPoints([...module.points], direction) + let barPoints = [] + //설치해야할 반처마커버 포인트를 방향에 따라 설정 - if (direction === 'south') { - barPoints = [bottomPoints[0].x + module.width / 2, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y] - } else if (direction === 'north') { - barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[0].x + module.width / 2, bottomPoints[1].y] - } else if (direction === 'east') { - barPoints = [bottomPoints[0].x, bottomPoints[1].y + module.height / 2, bottomPoints[1].x, bottomPoints[1].y] - } else if (direction === 'west') { - barPoints = [bottomPoints[0].x, bottomPoints[1].y - module.height / 2, bottomPoints[1].x, bottomPoints[1].y] - } + if (direction === 'south') { + barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x - module.width / 2, bottomPoints[1].y] + } else if (direction === 'north') { + barPoints = [bottomPoints[0].x + module.width / 2, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y] + } else if (direction === 'east') { + barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[0].y - module.height / 2] + } else if (direction === 'west') { + barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y - module.height / 2] + } - if (!bottomPoints) return - const halfEaveBar = new fabric.Line(barPoints, { - parent: surface, - name: 'halfEaveBar', - stroke: 'blue', - strokeWidth: 4, - selectable: false, - parentId: module.id, + if (!bottomPoints) return + const halfEaveBar = new fabric.Line(barPoints, { + parent: surface, + name: 'halfEaveBar', + stroke: 'blue', + strokeWidth: 4, + selectable: false, + surfaceId: surface.id, + parentId: module.id, + }) + canvas.add(halfEaveBar) + canvas.renderAll() }) - canvas.add(halfEaveBar) - canvas.renderAll() - }) + + rightExposedHalfBottomPoints.forEach((module) => { + const bottomPoints = findTopTwoPoints([...module.points], direction) + let barPoints = [] + //설치해야할 반처마커버 포인트를 방향에 따라 설정 + + if (direction === 'south') { + barPoints = [bottomPoints[0].x + module.width / 2, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y] + } else if (direction === 'north') { + barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[0].x + module.width / 2, bottomPoints[1].y] + } else if (direction === 'east') { + barPoints = [bottomPoints[0].x, bottomPoints[1].y + module.height / 2, bottomPoints[1].x, bottomPoints[1].y] + } else if (direction === 'west') { + barPoints = [bottomPoints[0].x, bottomPoints[1].y - module.height / 2, bottomPoints[1].x, bottomPoints[1].y] + } + + if (!bottomPoints) return + const halfEaveBar = new fabric.Line(barPoints, { + parent: surface, + name: 'halfEaveBar', + stroke: 'blue', + strokeWidth: 4, + selectable: false, + parentId: module.id, + }) + canvas.add(halfEaveBar) + canvas.renderAll() + }) + } } - } - const horizontal = ['south', 'north'].includes(direction) ? surface.trestleDetail.moduleIntvlHor : surface.trestleDetail.moduleIntvlVer + const horizontal = ['south', 'north'].includes(direction) ? surface.trestleDetail.moduleIntvlHor : surface.trestleDetail.moduleIntvlVer - const vertical = ['south', 'north'].includes(direction) ? surface.trestleDetail.moduleIntvlVer : surface.trestleDetail.moduleIntvlHor + const vertical = ['south', 'north'].includes(direction) ? surface.trestleDetail.moduleIntvlVer : surface.trestleDetail.moduleIntvlHor - let mostRowsModule = 0 // 모듈 최대 단 수 - // 가대 설치를 위한 가장 아래 모듈로부터 위로 몇단인지 계산 - // 오른쪽,왼쪽 둘 다 아래에 아무것도 없는, 처마 커버를 필요로 하는 모듈 - exposedBottomModules.forEach((module) => { - let { width, height } = { ...module } - width = Math.floor(width) - height = Math.floor(height) - let { x: startX, y: startY } = { ...module.getCenterPoint() } - let { x, y } = { ...module.getCenterPoint() } + let mostRowsModule = 0 // 모듈 최대 단 수 + // 가대 설치를 위한 가장 아래 모듈로부터 위로 몇단인지 계산 + // 오른쪽,왼쪽 둘 다 아래에 아무것도 없는, 처마 커버를 필요로 하는 모듈 + exposedBottomModules.forEach((module) => { + let { width, height } = { ...module } + width = Math.floor(width) + height = Math.floor(height) + let { x: startX, y: startY } = { ...module.getCenterPoint() } + let { x, y } = { ...module.getCenterPoint() } - let leftRows = 1 - let rightRows = 1 - let centerRows = 1 - let hasNextModule = true - let findLeft = true - let findRight = true + let leftRows = 1 + let rightRows = 1 + let centerRows = 1 + let hasNextModule = true + let findLeft = true + let findRight = true - //우선 절반을 나눈 뒤 왼쪽부터 찾는다. - while (hasNextModule) { - //바로 위에 있는지 확인한다. - let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - - if (nextModule) { - // 바로 위 모듈을 찾는다. - leftRows++ - x = nextModule.x - y = nextModule.y - } else { - // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. - if (findLeft) { - nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findLeft = false - } else { - nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findLeft = true - } + //우선 절반을 나눈 뒤 왼쪽부터 찾는다. + while (hasNextModule) { + //바로 위에 있는지 확인한다. + let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) if (nextModule) { // 바로 위 모듈을 찾는다. @@ -234,126 +221,126 @@ export const useTrestle = () => { x = nextModule.x y = nextModule.y } else { - hasNextModule = false + // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. + if (findLeft) { + nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + findLeft = false + } else { + nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + findLeft = true + } + + if (nextModule) { + // 바로 위 모듈을 찾는다. + leftRows++ + x = nextModule.x + y = nextModule.y + } else { + hasNextModule = false + } } } - } - hasNextModule = true - x = startX - y = startY + hasNextModule = true + x = startX + y = startY - // 오른쪽 찾는다. - while (hasNextModule) { - //바로 위에 있는지 확인한다. - let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - - if (nextModule) { - // 바로 위 모듈을 찾는다. - rightRows++ - x = nextModule.x - y = nextModule.y - } else { - // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. - if (findRight) { - nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findRight = false - } else { - nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findRight = true - } + // 오른쪽 찾는다. + while (hasNextModule) { + //바로 위에 있는지 확인한다. + let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) if (nextModule) { // 바로 위 모듈을 찾는다. rightRows++ x = nextModule.x y = nextModule.y + } else { + // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. + if (findRight) { + nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + findRight = false + } else { + nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + findRight = true + } + + if (nextModule) { + // 바로 위 모듈을 찾는다. + rightRows++ + x = nextModule.x + y = nextModule.y + } else { + hasNextModule = false + } + } + } + + hasNextModule = true + x = startX + y = startY + + // 센터 찾는다. + while (hasNextModule) { + //바로 위에 있는지 확인한다. + let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + + if (nextModule) { + // 바로 위 모듈을 찾는다. + centerRows++ + x = nextModule.x + y = nextModule.y } else { hasNextModule = false } } - } - hasNextModule = true - x = startX - y = startY + // 모듈의 왼쪽 부터 그릴 랙 정보를 가져온다. + const leftRacks = rackInfos.find((rack) => { + return rack.value.moduleRows === leftRows + })?.value.racks - // 센터 찾는다. - while (hasNextModule) { - //바로 위에 있는지 확인한다. - let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + // 모듈의 오른쪽 부터 그릴 랙 정보를 가져온다. + const rightRacks = rackInfos.find((rack) => { + return rack.value.moduleRows === rightRows + })?.value.racks + // 해당 rack으로 그려준다. - if (nextModule) { - // 바로 위 모듈을 찾는다. - centerRows++ - x = nextModule.x - y = nextModule.y - } else { - hasNextModule = false - } - } + const centerRacks = rackInfos.find((rack) => { + return rack.value.moduleRows === centerRows + })?.value.racks - // 모듈의 왼쪽 부터 그릴 랙 정보를 가져온다. - const leftRacks = rackInfos.find((rack) => { - return rack.value.moduleRows === leftRows - })?.value.racks + mostRowsModule = Math.max(leftRows, rightRows, centerRows, mostRowsModule) - // 모듈의 오른쪽 부터 그릴 랙 정보를 가져온다. - const rightRacks = rackInfos.find((rack) => { - return rack.value.moduleRows === rightRows - })?.value.racks - // 해당 rack으로 그려준다. + if (rackYn === 'Y') { + drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn) + drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn) - const centerRacks = rackInfos.find((rack) => { - return rack.value.moduleRows === centerRows - })?.value.racks - - mostRowsModule = Math.max(leftRows, rightRows, centerRows, mostRowsModule) - - if (rackYn === 'Y') { - drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn) - drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn) - - if (rackQty === 3) { - //rack 갯수가 3개인 경우는 중간렉도 추가해줘야함 - drawRacks(centerRacks, rackQty, rackIntvlPct, module, direction, 'C', rackYn) - } else if (rackQty === 4) { - drawRacks(leftRacks, rackQty, rackIntvlPct / 3, module, direction, 'L', rackYn) - drawRacks(rightRacks, rackQty, rackIntvlPct / 3, module, direction, 'R', rackYn) - } - } - module.set({ leftRows, rightRows, centerRows }) - }) - // 왼쪽아래에 모듈이 없는 모듈들 - leftExposedHalfBottomModules.forEach((module) => { - const { width, height } = module - let { x: startX, y: startY } = { ...module.getCenterPoint() } - let { x, y } = { ...module.getCenterPoint() } - //TODO : 방향별로 가대 설치해야함 - - let leftRows = 1 - let hasNextModule = true - let findLeft = true - - //우선 절반을 나눈 뒤 왼쪽부터 찾는다. - while (hasNextModule) { - //바로 위에 있는지 확인한다. - let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - - if (nextModule) { - // 바로 위 모듈을 찾는다. - leftRows++ - x = nextModule.x - y = nextModule.y - } else { - // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. - if (findLeft) { - nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findLeft = false - } else { - nextModule = nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findLeft = true + if (rackQty === 3) { + //rack 갯수가 3개인 경우는 중간렉도 추가해줘야함 + drawRacks(centerRacks, rackQty, rackIntvlPct, module, direction, 'C', rackYn) + } else if (rackQty === 4) { + drawRacks(leftRacks, rackQty, rackIntvlPct / 3, module, direction, 'L', rackYn) + drawRacks(rightRacks, rackQty, rackIntvlPct / 3, module, direction, 'R', rackYn) } + } + module.set({ leftRows, rightRows, centerRows }) + }) + // 왼쪽아래에 모듈이 없는 모듈들 + leftExposedHalfBottomModules.forEach((module) => { + const { width, height } = module + let { x: startX, y: startY } = { ...module.getCenterPoint() } + let { x, y } = { ...module.getCenterPoint() } + //TODO : 방향별로 가대 설치해야함 + + let leftRows = 1 + let hasNextModule = true + let findLeft = true + + //우선 절반을 나눈 뒤 왼쪽부터 찾는다. + while (hasNextModule) { + //바로 위에 있는지 확인한다. + let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) if (nextModule) { // 바로 위 모듈을 찾는다. @@ -361,52 +348,63 @@ export const useTrestle = () => { x = nextModule.x y = nextModule.y } else { - hasNextModule = false + // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. + if (findLeft) { + nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + findLeft = false + } else { + nextModule = nextModule = findNextRightModule( + { + x, + y, + width, + height, + horizontal, + vertical, + }, + centerPoints, + direction, + ) + findLeft = true + } + + if (nextModule) { + // 바로 위 모듈을 찾는다. + leftRows++ + x = nextModule.x + y = nextModule.y + } else { + hasNextModule = false + } } } - } - // 모듈의 왼쪽 부터 그릴 랙 정보를 가져온다. - const leftRacks = rackInfos.find((rack) => { - return rack.value.moduleRows === leftRows - })?.value.racks - mostRowsModule = Math.max(leftRows, mostRowsModule) - if (rackYn === 'Y') { - drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn) - } + // 모듈의 왼쪽 부터 그릴 랙 정보를 가져온다. + const leftRacks = rackInfos.find((rack) => { + return rack.value.moduleRows === leftRows + })?.value.racks + mostRowsModule = Math.max(leftRows, mostRowsModule) + if (rackYn === 'Y') { + drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn) + } - module.set({ leftRows }) - }) - // 오른쪽 아래에 모듈이 없는 모듈들 - rightExposedHalfBottomPoints.forEach((module) => { - const { width, height } = module - let { x: startX, y: startY } = { ...module.getCenterPoint() } - let { x, y } = { ...module.getCenterPoint() } - //TODO : 방향별로 가대 설치해야함 + module.set({ leftRows }) + }) + // 오른쪽 아래에 모듈이 없는 모듈들 + rightExposedHalfBottomPoints.forEach((module) => { + const { width, height } = module + let { x: startX, y: startY } = { ...module.getCenterPoint() } + let { x, y } = { ...module.getCenterPoint() } + //TODO : 방향별로 가대 설치해야함 - let rightRows = 1 - let hasNextModule = true - let findRight = true + let rightRows = 1 + let hasNextModule = true + let findRight = true - // 오른쪽 찾는다. - while (hasNextModule) { - //바로 위에 있는지 확인한다. - let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - - if (nextModule) { - // 바로 위 모듈을 찾는다. - rightRows++ - x = nextModule.x - y = nextModule.y - } else { - // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. - if (findRight) { - nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findRight = false - } else { - nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) - findRight = true - } + // 오른쪽 찾는다. + while (hasNextModule) { + //바로 위에 있는지 확인한다. + let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) if (nextModule) { // 바로 위 모듈을 찾는다. @@ -414,43 +412,62 @@ export const useTrestle = () => { x = nextModule.x y = nextModule.y } else { - hasNextModule = false + // 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다. + if (findRight) { + nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + findRight = false + } else { + nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction) + findRight = true + } + + if (nextModule) { + // 바로 위 모듈을 찾는다. + rightRows++ + x = nextModule.x + y = nextModule.y + } else { + hasNextModule = false + } } } + + // 모듈의 오른쪽 부터 그릴 랙 정보를 가져온다. + const rightRacks = rackInfos.find((rack) => { + return rack.value.moduleRows === rightRows + })?.value.racks + + mostRowsModule = Math.max(rightRows, mostRowsModule) + // 해당 rack으로 그려준다. + if (rackYn === 'Y') { + drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn) + } + + module.set({ rightRows }) + }) + + surface.set({ moduleRowsTotCnt: mostRowsModule }) + + if (rackYn === 'N') { + // rack이 없을경우 + installBracketWithOutRack(surface, exposedBottomModules, leftExposedHalfBottomModules, rightExposedHalfBottomPoints, isChidory) + } else if (rackYn === 'Y') { + installBracket(surface) } - // 모듈의 오른쪽 부터 그릴 랙 정보를 가져온다. - const rightRacks = rackInfos.find((rack) => { - return rack.value.moduleRows === rightRows - })?.value.racks + const quotationParam = getTrestleParams(surface) - mostRowsModule = Math.max(rightRows, mostRowsModule) - // 해당 rack으로 그려준다. - if (rackYn === 'Y') { - drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn) - } - - module.set({ rightRows }) + surface.set({ quotationParam }) }) - surface.set({ moduleRowsTotCnt: mostRowsModule }) - - if (rackYn === 'N') { - // rack이 없을경우 - installBracketWithOutRack(surface, exposedBottomModules, leftExposedHalfBottomModules, rightExposedHalfBottomPoints, isChidory) - } else if (rackYn === 'Y') { - installBracket(surface) - } - - const quotationParam = getTrestleParams(surface) - - surface.set({ quotationParam }) - }) - setQuoationItem() + return setEstimateData() + } catch (e) { + return false + } } // itemList 조회 후 estimateParam에 저장 - const setQuoationItem = () => { + const setEstimateData = async () => { const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //surfaces.pcses들을 배열로 묶는다 const pcses = surfaces[0].pcses @@ -461,16 +478,72 @@ export const useTrestle = () => { }) const params = { trestles: surfaces.map((surface) => surface.quotationParam), pcses } //견적서 itemList 조회 - getQuotationItem(params).then((res) => { - if (!res.data) { - return - } - const itemList = res.data - //northArrangement 북면 설치 여부 - const northArrangement = getNorthArrangement() + const res = await getQuotationItem(params) + if (!res.data) { + return false + } + const itemList = res.data + //northArrangement 북면 설치 여부 + const northArrangement = getNorthArrangement() + // circuitItemList의 경우는 moduleList에서 circuitId만 groupBy한다. + let circuitItemList = [] - setEstimateParam({ ...estimateParam, itemList, northArrangement }) + // roofSurfaceList 생성 + const roofSurfaceList = surfaces.map((surface) => { + const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId) + const { directionText, roofMaterial, pitch: slope, moduleCompass, surfaceCompass } = parent + const roofMaterialIndex = parent.roofMaterial.index + const { nameJp: roofMaterialIdMulti } = roofMaterial + const moduleSelection = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex) + const { constTp: constructSpecification, constTpJp: constructSpecificationMulti } = moduleSelection.construction + const { + trestleMkrCd, + constMthdCd: supportMethodId, + roofBaseCd, + trestleMkrCdJp: supportMeaker, + constMthdCdJp: supportMethodIdMulti, + } = moduleSelection.trestle + + const modules = surface.modules + const moduleList = modules.map((module) => { + circuitItemList.push(module.pcsItemId) + return { + itemId: module.moduleInfo.itemId, + circuit: module.circuitNumber, + pcItemId: module.pcsItemId, + } + }) + + return { + roofSurfaceId: surface.id, + roofSurface: directionText.replace(/[^0-9]/g, ''), + roofMaterialId: roofMaterial.roofMatlCd, + supportMethodId, + constructSpecification, + constructSpecificationMulti, + roofMaterialIdMulti, + supportMethodIdMulti, + supportMeaker, + slope, + classType: currentAngleType === 'slope' ? '0' : '1', + angle: getDegreeByChon(slope), + azimuth: surfaceCompass ?? moduleCompass ?? 0, + moduleList, + } }) + + // circuitItemList 중복제거 + circuitItemList = circuitItemList.filter((item, index) => circuitItemList.indexOf(item) === index) + circuitItemList = circuitItemList.map((circuitId) => { + return { + itemId: circuitId, + } + }) + + setEstimateParam({ ...estimateParam, itemList, northArrangement, roofSurfaceList, circuitItemList }) + + // 정상적으로 완료 되면 true 반환 + return true } const getNorthArrangement = () => { diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index ee865d65..6471f644 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -273,7 +273,8 @@ export function useRoofAllocationSetting(id) { setRoofList(newRoofList) const selectedRoofMaterial = newRoofList.find((roof) => roof.selected) - setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial) + setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial, true) + drawDirectionArrow(currentObject) modifyModuleSelectionData() closeAll() } diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 6b468405..b904611d 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -129,7 +129,7 @@ export function usePlan(params = {}) { * objectNo에 해당하는 canvas 목록을 조회 */ const getCanvasByObjectNo = async (userId, objectNo, planNo) => { - return await get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) => + return await get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` }).then((res) => res.map((item) => ({ id: item.id, objectNo: item.objectNo, diff --git a/src/locales/ja.json b/src/locales/ja.json index 0d13f153..067b92a6 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -515,9 +515,9 @@ "common.finish": "完了", "common.ok": "確認", "common.cancel": "キャンセル", - "commons.west": "立つ", - "commons.east": "ドン", - "commons.south": "M", + "commons.west": "西", + "commons.east": "東", + "commons.south": "南", "commons.north": "北", "commons.none": "選択しない", "common.type": "分類", diff --git a/src/locales/ko.json b/src/locales/ko.json index f389807c..5552dbb0 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -997,5 +997,6 @@ "construction.length.difference": "지붕면 공법을 전부 선택해주세요.", "menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.", "batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.", - "batch.object.notinstall.cross": "오브젝트는 겹쳐서 설치 할 수 없습니다." + "batch.object.notinstall.cross": "오브젝트는 겹쳐서 설치 할 수 없습니다.", + "module.not.batch.north": "북쪽에는 모듈을 배치할 수 없습니다." } diff --git a/src/store/estimateAtom.js b/src/store/estimateAtom.js index 20cdaa7c..410921fc 100644 --- a/src/store/estimateAtom.js +++ b/src/store/estimateAtom.js @@ -14,7 +14,7 @@ export const estimateParamAtom = atom({ standardWindSpeedId: '', snowfall: '', northArrangement: '', - drawingFlg: '', + drawingFlg: '1', userId: '', roofSurfaceList: [], circuitItemList: [],