diff --git a/src/components/common/select/QSelectBox.jsx b/src/components/common/select/QSelectBox.jsx index a027cb55..3e797071 100644 --- a/src/components/common/select/QSelectBox.jsx +++ b/src/components/common/select/QSelectBox.jsx @@ -39,7 +39,7 @@ export default function QSelectBox({ if (showKey !== '' && !value) { //value가 없으면 showKey가 있으면 우선 보여준다 // return options[0][showKey] - return title + return title !== '' ? title : getMessage('selectbox.title') } else if (showKey !== '' && value) { //value가 있으면 sourceKey와 targetKey를 비교하여 보여준다 diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index f312d5ea..3e22c508 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -1,12 +1,17 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' import { useContext, useEffect, useRef, useState } from 'react' -import Module from '@/components/floor-plan/modal/basic/step/Module' -import PitchModule from '@/components/floor-plan/modal/basic/step/pitch/PitchModule' import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement' import Placement from '@/components/floor-plan/modal/basic/step/Placement' import { useRecoilValue, useRecoilState } from 'recoil' -import { canvasSettingState, canvasState, checkedModuleState, isManualModuleSetupState } from '@/store/canvasAtom' +import { + canvasSettingState, + canvasState, + checkedModuleState, + isManualModuleLayoutSetupState, + isManualModuleSetupState, + toggleManualSetupModeState, +} from '@/store/canvasAtom' import { usePopup } from '@/hooks/usePopup' import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' @@ -20,31 +25,133 @@ import { useMasterController } from '@/hooks/common/useMasterController' import { loginUserStore } from '@/store/commonAtom' import { currentCanvasPlanState } from '@/store/canvasAtom' import { POLYGON_TYPE } from '@/common/common' +import { useModuleSelection } from '@/hooks/module/useModuleSelection' +import { useOrientation } from '@/hooks/module/useOrientation' +import Trestle from './step/Trestle' +import { roofsState } from '@/store/roofAtom' export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() const { closePopup } = usePopup() const [tabNum, setTabNum] = useState(1) - const canvasSetting = useRecoilValue(canvasSettingState) const orientationRef = useRef(null) - const { initEvent } = useEvent() const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState) - const moduleSelectionData = useRecoilValue(moduleSelectionDataState) - const addedRoofs = useRecoilValue(addedRoofsState) + const [isManualModuleLayoutSetup, setIsManualModuleLayoutSetup] = useRecoilState(isManualModuleLayoutSetupState) + const trestleRef = useRef(null) + const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) + const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState) const loginUserState = useRecoilValue(loginUserStore) const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) const canvas = useRecoilValue(canvasState) const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState) const [isClosePopup, setIsClosePopup] = useState({ close: false, id: 0 }) const [checkedModules, setCheckedModules] = useRecoilState(checkedModuleState) + const [roofs, setRoofs] = useState(addedRoofs) + const [manualSetupMode, setManualSetupMode] = useRecoilState(toggleManualSetupModeState) + const [layoutSetup, setLayoutSetup] = useState([{}]) + + const { + moduleSelectionInitParams, + selectedModules, + roughnessCodes, + windSpeedCodes, + managementState, + setManagementState, + moduleList, + setSelectedModules, + selectedSurfaceType, + setSelectedSurfaceType, + installHeight, + setInstallHeight, + standardWindSpeed, + setStandardWindSpeed, + verticalSnowCover, + setVerticalSnowCover, + handleChangeModule, + handleChangeSurfaceType, + handleChangeWindSpeed, + handleChangeInstallHeight, + handleChangeVerticalSnowCover, + } = useModuleSelection({ addedRoofs }) + const { nextStep, compasDeg, setCompasDeg } = useOrientation() + const { trigger: orientationTrigger } = useCanvasPopupStatusController(1) + const { trigger: trestleTrigger } = useCanvasPopupStatusController(2) + const { trigger: placementTrigger } = useCanvasPopupStatusController(3) + const roofsStore = useRecoilValue(roofsState) // const { initEvent } = useContext(EventContext) - const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting(tabNum) + const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup, manualModuleLayoutSetup } = + useModuleBasicSetting(tabNum) const { updateObjectDate } = useMasterController() + useEffect(() => { + if (managementState) console.log('managementState', managementState) + }, [managementState]) + + useEffect(() => { + if (roofsStore && addedRoofs) { + console.log('🚀 ~ useEffect ~ roofsStore, addedRoofs:', roofsStore, addedRoofs) + setRoofs( + addedRoofs.map((roof, index) => { + return { + ...roof, + ...roofsStore[index]?.addRoof, + } + }), + ) + + setModuleSelectionData({ + ...moduleSelectionData, + roofConstructions: roofsStore.map((roof) => { + return { + addRoof: { + ...roof.addRoof, + }, + construction: { + ...roof.construction, + }, + trestle: { + ...roof.trestle, + }, + } + }), + }) + } + }, [roofsStore, addedRoofs]) + + useEffect(() => { + let hasModules = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + .some((obj) => obj.modules?.length > 0) + + if (hasModules) { + orientationRef.current.handleNextStep() + setTabNum(3) + } + }, []) + + useEffect(() => { + if (basicSetting.roofSizeSet !== '3') { + manualModuleSetup() + } else { + manualFlatroofModuleSetup(placementFlatRef) + } + if (isClosePopup.close) { + closePopup(isClosePopup.id) + } + }, [isManualModuleSetup, isClosePopup]) + + useEffect(() => { + setIsManualModuleSetup(false) + }, [checkedModules]) + const handleBtnNextStep = () => { if (tabNum === 1) { + console.log('moduleSelectionData', moduleSelectionData) orientationRef.current.handleNextStep() + setAddedRoofs(roofs) + return } else if (tabNum === 2) { if (basicSetting.roofSizeSet !== '3') { if (!isObjectNotEmpty(moduleSelectionData.module)) { @@ -55,7 +162,15 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { return } - if (addedRoofs.length !== moduleSelectionData.roofConstructions.length) { + // if (addedRoofs.length !== moduleSelectionData.roofConstructions.length) { + // Swal.fire({ + // title: getMessage('construction.length.difference'), + // icon: 'warning', + // }) + // return + // } + + if (!trestleRef.current.isComplete()) { Swal.fire({ title: getMessage('construction.length.difference'), icon: 'warning', @@ -63,14 +178,6 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { return } //물건정보 갱신일 수정 - updateObjectDataApi({ - objectNo: currentCanvasPlan.objectNo, //오브젝트_no - standardWindSpeedId: moduleSelectionData.common.stdWindSpeed, //기준풍속코드 - verticalSnowCover: moduleSelectionData.common.stdSnowLd, //적설량 - surfaceType: moduleSelectionData.common.illuminationTpNm, //면조도구분 - installHeight: moduleSelectionData.common.instHt, //설치높이 - userId: loginUserState.userId, //작성자아아디 - }) } else { if (!isObjectNotEmpty(moduleSelectionData.module)) { Swal.fire({ @@ -85,84 +192,149 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { setTabNum(tabNum + 1) } - const placementRef = { - isChidori: useRef('false'), - setupLocation: useRef('eaves'), - isMaxSetup: useRef('false'), - } - const placementFlatRef = { setupLocation: useRef('south'), } const handleManualModuleSetup = () => { + setManualSetupMode(`manualSetup_${!isManualModuleSetup}`) setIsManualModuleSetup(!isManualModuleSetup) } + const handleManualModuleLayoutSetup = () => { + setManualSetupMode(`manualLayoutSetup_${!isManualModuleLayoutSetup}`) + setIsManualModuleLayoutSetup(!isManualModuleLayoutSetup) + } + const updateObjectDataApi = async (params) => { const res = await updateObjectDate(params) } - useEffect(() => { - let hasModules = canvas - .getObjects() - .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) - .some((obj) => obj.modules?.length > 0) - - if (hasModules) { - orientationRef.current.handleNextStep() - setTabNum(3) - } - }, []) - //팝업 닫기 버튼 이벤트 const handleClosePopup = (id) => { if (tabNum == 3) { if (isManualModuleSetup) { setIsManualModuleSetup(false) } + if (isManualModuleLayoutSetup) { + setIsManualModuleLayoutSetup(false) + } } setIsClosePopup({ close: true, id: id }) } + const orientationProps = { + roofs, + setRoofs, + tabNum, + setTabNum, + compasDeg, // 방위각 + setCompasDeg, + moduleSelectionInitParams, + selectedModules, + moduleSelectionData, + setModuleSelectionData, + roughnessCodes, // 면조도 목록 + windSpeedCodes, // 기준풍속 목록 + managementState, + setManagementState, + moduleList, // 모듈 리스트 + setSelectedModules, + selectedSurfaceType, + setSelectedSurfaceType, + installHeight, // 설치높이 + setInstallHeight, + standardWindSpeed, // 기준풍속 + setStandardWindSpeed, + verticalSnowCover, // 적설량 + setVerticalSnowCover, + currentCanvasPlan, + loginUserState, + handleChangeModule, + handleChangeSurfaceType, + handleChangeWindSpeed, + handleChangeInstallHeight, + handleChangeVerticalSnowCover, + orientationTrigger, + nextStep, + updateObjectDataApi, + } + const trestleProps = { + roofs, + setRoofs, + setTabNum, + moduleSelectionData, + setModuleSelectionData, + trestleTrigger, + } + const placementProps = {} + useEffect(() => { if (basicSetting.roofSizeSet !== '3') { - manualModuleSetup(placementRef) + if (manualSetupMode.indexOf('manualSetup') > -1) { + manualModuleSetup() + } else if (manualSetupMode.indexOf('manualLayoutSetup') > -1) { + manualModuleLayoutSetup(layoutSetup) + } else if (manualSetupMode.indexOf('off') > -1) { + manualModuleSetup() + manualModuleLayoutSetup(layoutSetup) + } } else { manualFlatroofModuleSetup(placementFlatRef) } + if (isClosePopup.close) { closePopup(isClosePopup.id) } - }, [isManualModuleSetup, isClosePopup]) + }, [manualSetupMode, isClosePopup]) + + useEffect(() => { + if (isManualModuleLayoutSetup) { + manualModuleLayoutSetup(layoutSetup) + } + }, [layoutSetup]) useEffect(() => { setIsManualModuleSetup(false) + setIsManualModuleLayoutSetup(false) + setManualSetupMode(`off`) }, [checkedModules]) return ( - + handleClosePopup(id)} />
{getMessage('modal.module.basic.setting.orientation.setting')}
-
{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.setting')}
+ +
{getMessage('modal.module.basic.setting.module.placement')}
+ + )} + {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && ( + <> +
{getMessage('modal.module.basic.setting.module.placement')}
+ + )}
- {tabNum === 1 && } + {tabNum === 1 && } {/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/} - {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && } - {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && } - + {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && } + {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && ( + + )} {/*배치면 초기설정 - 입력방법: 육지붕*/} - {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 && } */} + {tabNum !== 1 && ( - )} {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && ( <> + diff --git a/src/components/floor-plan/modal/basic/step/Orientation.jsx b/src/components/floor-plan/modal/basic/step/Orientation.jsx index 4e279f04..2ce0d536 100644 --- a/src/components/floor-plan/modal/basic/step/Orientation.jsx +++ b/src/components/floor-plan/modal/basic/step/Orientation.jsx @@ -1,35 +1,153 @@ -import { forwardRef, useContext, useEffect, useImperativeHandle, useState } from 'react' +import { forwardRef, use, useContext, useEffect, useImperativeHandle, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useOrientation } from '@/hooks/module/useOrientation' import { getDegreeInOrientation } from '@/util/canvas-util' import { numberCheck } from '@/util/common-utils' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' +import { addedRoofsState, basicSettingState } from '@/store/settingAtom' +import { useRecoilState, useRecoilValue } from 'recoil' +import QSelectBox from '@/components/common/select/QSelectBox' +import { moduleSelectionDataState } from '@/store/selectedModuleOptions' -export const Orientation = forwardRef(({ tabNum }, ref) => { +export const Orientation = forwardRef((props, ref) => { const { getMessage } = useMessage() - - const { trigger: canvasPopupStatusTrigger } = useCanvasPopupStatusController(1) - - const { nextStep, compasDeg, setCompasDeg } = useOrientation() - const [hasAnglePassivity, setHasAnglePassivity] = useState(false) + const basicSetting = useRecoilValue(basicSettingState) + const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState) //지붕재 선택 + const [roofTab, setRoofTab] = useState(0) //지붕재 탭 + const { + roofs, + setRoofs, + tabNum, + setTabNum, + compasDeg, + setCompasDeg, + moduleSelectionInitParams, + selectedModules, + roughnessCodes, + windSpeedCodes, + managementState, + setManagementState, + moduleList, + moduleSelectionData, + setModuleSelectionData, + setSelectedModules, + selectedSurfaceType, + setSelectedSurfaceType, + installHeight, + setInstallHeight, + standardWindSpeed, + setStandardWindSpeed, + verticalSnowCover, + setVerticalSnowCover, + orientationTrigger, + nextStep, + currentCanvasPlan, + loginUserState, + updateObjectDataApi, + } = props + const [inputCompasDeg, setInputCompasDeg] = useState(compasDeg ?? 0) + const [inputInstallHeight, setInputInstallHeight] = useState('0') + const [inputVerticalSnowCover, setInputVerticalSnowCover] = useState('0') + const [inputRoughness, setInputRoughness] = useState(selectedSurfaceType) + const [inputStandardWindSpeed, setInputStandardWindSpeed] = useState(standardWindSpeed) + const moduleData = { + header: [ + { name: getMessage('module'), width: 150, prop: 'module', type: 'color-box' }, + { + name: `${getMessage('height')} (mm)`, + prop: 'height', + }, + { name: `${getMessage('width')} (mm)`, prop: 'width' }, + { name: `${getMessage('output')} (W)`, prop: 'output' }, + ], + } + + useEffect(() => { + if (selectedSurfaceType) { + console.log(roughnessCodes, selectedSurfaceType) + setInputRoughness(roughnessCodes.find((code) => code.clCode === managementState?.surfaceTypeValue)) + } + }, [selectedSurfaceType]) + + useEffect(() => { + if (standardWindSpeed) setInputStandardWindSpeed(windSpeedCodes.find((code) => code.clCode === managementState?.standardWindSpeedId)) + }, [standardWindSpeed]) + + useEffect(() => { + if (managementState?.installHeight && managementState?.installHeight) { + console.log('🚀 ~ useEffect ~ managementState:', managementState) + setSelectedSurfaceType(roughnessCodes.find((code) => code.clCode === managementState?.surfaceTypeValue)) + setInputInstallHeight(managementState?.installHeight) + setStandardWindSpeed(windSpeedCodes.find((code) => code.clCode === managementState?.standardWindSpeedId)) + setInputVerticalSnowCover(managementState?.verticalSnowCover) + } + }, [managementState]) + + useEffect(() => { + if (moduleSelectionData) { + console.log('moduleSelectionData', moduleSelectionData) + } + }, [moduleSelectionData]) useImperativeHandle(ref, () => ({ handleNextStep, })) const handleNextStep = () => { - nextStep() - canvasPopupStatusTrigger(compasDeg) + if (isComplete()) { + const common = { + illuminationTp: inputRoughness.clCode, + illuminationTpNm: inputRoughness.clCodeNm, + instHt: inputInstallHeight, + stdWindSpeed: inputStandardWindSpeed.clCode, + stdSnowLd: inputVerticalSnowCover, + saleStoreNorthFlg: managementState?.saleStoreNorthFlg, + moduleTpCd: selectedModules.itemTp, + moduleItemId: selectedModules.itemId, + } + setCompasDeg(inputCompasDeg) + setInstallHeight(inputInstallHeight) + setVerticalSnowCover(inputVerticalSnowCover) + setSelectedSurfaceType(inputRoughness) + setStandardWindSpeed(inputStandardWindSpeed) + nextStep() + setManagementState({ + ...managementState, + installHeight: inputInstallHeight, + verticalSnowCover: inputVerticalSnowCover, + standardWindSpeedId: inputStandardWindSpeed.clCode, + surfaceType: inputRoughness.clCodeNm, + surfaceTypeValue: inputRoughness.clCode, + }) + setModuleSelectionData({ + ...moduleSelectionData, + module: { + ...selectedModules, + }, + }) + orientationTrigger({ + compasDeg: inputCompasDeg, + common: common, + module: { + ...selectedModules, + }, + }) + updateObjectDataApi({ + objectNo: currentCanvasPlan.objectNo, //오브젝트_no + standardWindSpeedId: inputStandardWindSpeed.clCode, //기준풍속코드 + verticalSnowCover: inputVerticalSnowCover, //적설량 + surfaceType: inputRoughness.clCodeNm, //면조도구분 + installHeight: inputInstallHeight, //설치높이 + userId: loginUserState.userId, //작성자아아디 + }) + setTabNum(2) + } } - useEffect(() => { - checkDegree(compasDeg) - }, [compasDeg]) - const checkDegree = (e) => { if (e === '-0' || e === '-') { - setCompasDeg('-') + setInputCompasDeg('-') return } if (e === '0-') { @@ -45,71 +163,273 @@ export const Orientation = forwardRef(({ tabNum }, ref) => { } } + const isComplete = () => { + if (basicSetting && basicSetting.roofSizeSet !== '3') { + if (inputInstallHeight <= 0) { + return false + } + + if (+inputVerticalSnowCover <= 0) { + return false + } + + if (!inputStandardWindSpeed) return false + if (!inputRoughness) return false + } + + return true + } + + const handleChangeModule = (e) => { + resetRoofs() + setSelectedModules(e) + } + + const handleChangeRoughness = (e) => { + resetRoofs() + setInputRoughness(e) + } + + const handleChangeInstallHeight = (e) => { + resetRoofs() + setInputInstallHeight(e) + } + + const handleChangeStandardWindSpeed = (e) => { + resetRoofs() + setInputStandardWindSpeed(e) + } + + const handleChangeVerticalSnowCover = (e) => { + resetRoofs() + setInputVerticalSnowCover(e) + } + + const resetRoofs = () => { + const newRoofs = addedRoofs.map((roof) => { + return { + ...roof, + lengthBase: null, + trestleMkrCd: null, + constMthdCd: null, + constTp: null, + roofBaseCd: null, + ridgeMargin: null, + kerabaMargin: null, + eavesMargin: null, + roofPchBase: null, + cvrYn: 'N', + snowGdPossYn: 'N', + cvrChecked: false, + snowGdChecked: false, + } + }) + setRoofs(newRoofs) + } + return ( <>
-
{getMessage('modal.module.basic.setting.orientation.setting.info')}
-
-
-
- {Array.from({ length: 180 / 15 }).map((dot, index) => ( -
= 172 && index === 0 && compasDeg <= 180) || (compasDeg === -180 && index === 0) ? 'act' : ''}`} - onClick={() => { - if (index === 0) { - setCompasDeg(180) - return - } - setCompasDeg(-1 * (-15 * index + 180)) - }} - > - {index === 0 && 180°} - {index === 6 && -90°} +
+
+
{getMessage('modal.module.basic.setting.orientation.setting.info')}
+
+
+
+ {Array.from({ length: 180 / 15 }).map((dot, index) => ( +
= 172 && index === 0 && inputCompasDeg <= 180) || (inputCompasDeg === -180 && index === 0) ? 'act' : ''}`} + onClick={() => { + if (index === 0) { + setInputCompasDeg(180) + return + } + setInputCompasDeg(-1 * (-15 * index + 180)) + }} + > + {index === 0 && 180°} + {index === 6 && -90°} +
+ ))} + {Array.from({ length: 180 / 15 }).map((dot, index) => ( +
setInputCompasDeg(15 * index)} + > + {index === 0 && } + {index === 6 && 90°} +
+ ))} +
+
+
- ))} - {Array.from({ length: 180 / 15 }).map((dot, index) => ( -
setCompasDeg(15 * index)} - > - {index === 0 && } - {index === 6 && 90°} +
+
+
+
+
+ setHasAnglePassivity(!hasAnglePassivity)} /> +
- ))} -
-
+
+ checkDegree(e.target.value)} + /> +
+ ° + ( -180 〜 180 )
-
-
-
- setHasAnglePassivity(!hasAnglePassivity)} /> - -
-
-
- checkDegree(e.target.value) - // setCompasDeg( - - // e.target.value === '-' || (e.target.value !== '' && parseInt(e.target.value) <= 180 && parseInt(e.target.value) >= -180) - // ? e.target.value - // : 0, - // ) - } - /> +
+
+
+ {getMessage('modal.module.basic.setting.module.setting')} +
+ {moduleList && ( + handleChangeModule(e)} + /> + )} +
+
+
+ + + + {moduleData.header.map((header) => { + return ( + + ) + })} + + + + {Array.from({ length: 3 }).map((_, index) => { + return selectedModules && selectedModules?.itemList && selectedModules?.itemList?.length >= index + 1 ? ( + + + + + + + ) : ( + + + + + + + ) + })} + +
+ {header.name} +
+
+ + {selectedModules.itemList[index].itemNm} +
+
{Number(selectedModules.itemList[index].shortAxis).toFixed(0)}{Number(selectedModules.itemList[index].longAxis).toFixed(0)}{Number(selectedModules.itemList[index].wpOut).toFixed(0)}
+
+
+
+ {basicSetting && basicSetting.roofSizeSet === '3' && ( +
+ {getMessage('modal.module.basic.setting.module.placement.area')} +
+ setInputInstallHeight(e.target.value)} + /> +
+ m +
+ )}
- ° + + {basicSetting && basicSetting.roofSizeSet !== '3' && ( +
+
+
+ {getMessage('modal.module.basic.setting.module.surface.type')} +
+ {roughnessCodes.length > 0 && managementState && ( + handleChangeRoughness(e)} + /> + )} +
+
+
+ {getMessage('modal.module.basic.setting.module.fitting.height')} +
+ handleChangeInstallHeight(e.target.value)} + /> +
+ m +
+
+ {getMessage('modal.module.basic.setting.module.standard.wind.speed')} +
+ {windSpeedCodes.length > 0 && managementState && ( + handleChangeStandardWindSpeed(e)} + /> + )} +
+
+
+ {getMessage('modal.module.basic.setting.module.standard.snowfall.amount')} +
+ handleChangeVerticalSnowCover(e.target.value)} + /> +
+ cm +
+
+
+ )}
diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index 80672471..726d3c24 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -1,29 +1,43 @@ import { forwardRef, useEffect, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' -import { checkedModuleState, currentCanvasPlanState, isManualModuleSetupState } from '@/store/canvasAtom' -import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { + checkedModuleState, + isManualModuleLayoutSetupState, + isManualModuleSetupState, + moduleRowColArrayState, + moduleSetupOptionState, + toggleManualSetupModeState, +} from '@/store/canvasAtom' +import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil' import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' import { isObjectNotEmpty } from '@/util/common-utils' const Placement = forwardRef((props, refs) => { const { getMessage } = useMessage() - const [isChidori, setIsChidori] = useState(false) + const [useTab, setUseTab] = useState(true) + const [isChidoriNotAble, setIsChidoriNotAble] = useState(false) - const [setupLocation, setSetupLocation] = useState('eaves') - const [isMaxSetup, setIsMaxSetup] = useState('false') const [selectedItems, setSelectedItems] = useState({}) - const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) const setCheckedModules = useSetRecoilState(checkedModuleState) const moduleSelectionData = useRecoilValue(moduleSelectionDataState) - const { makeModuleInitArea } = useModuleBasicSetting(3) + const { makeModuleInitArea, roofOutlineColor } = useModuleBasicSetting(3) const [isMultiModule, setIsMultiModule] = useState(false) - const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState) + //언마운트시 버튼 초기화 + const setIsManualModuleSetup = useSetRecoilState(isManualModuleSetupState) + const setIsManualModuleLayoutSetup = useSetRecoilState(isManualModuleLayoutSetupState) + const setManualSetupMode = useSetRecoilState(toggleManualSetupModeState) + + const [moduleSetupOption, setModuleSetupOption] = useRecoilState(moduleSetupOptionState) //모듈 설치 옵션 + const resetModuleSetupOption = useResetRecoilState(moduleSetupOptionState) + + const [colspan, setColspan] = useState(1) + const [moduleRowColArray, setModuleRowColArray] = useRecoilState(moduleRowColArrayState) //모듈 배치면 생성 useEffect(() => { @@ -36,13 +50,24 @@ const Placement = forwardRef((props, refs) => { makeModuleInitArea(moduleSelectionData) } + if (moduleSelectionData.module.itemList.length > 1) { + setColspan(2) + } + return () => { - refs.isChidori.current = 'false' - refs.setupLocation.current = 'eaves' + // refs.isChidori.current = 'false' + // refs.setupLocation.current = 'eaves' setIsManualModuleSetup(false) + setIsManualModuleLayoutSetup(false) + setManualSetupMode('off') + resetModuleSetupOption() } }, []) + useEffect(() => { + console.log('moduleRowColArray', moduleRowColArray) + }, [moduleRowColArray]) + //최초 지입시 체크 useEffect(() => { if (isObjectNotEmpty(moduleSelectionData)) { @@ -56,8 +81,10 @@ const Placement = forwardRef((props, refs) => { initCheckedModule = { ...initCheckedModule, [obj.itemId]: true } } }) + setSelectedItems(initCheckedModule) setSelectedModules(moduleSelectionData.module) + props.setLayoutSetup(moduleSelectionData.module.itemList.map((item) => ({ moduleId: item.itemId, col: 0, row: 0, checked: true }))) } //모듈 배치면 생성 @@ -82,59 +109,75 @@ const Placement = forwardRef((props, refs) => { header: [ { type: 'check', name: '', prop: 'check', width: 70 }, { type: 'color-box', name: getMessage('module'), prop: 'module' }, - { type: 'text', name: `${getMessage('output')} (W)`, prop: 'output', width: 70 }, + { type: 'text', name: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn'), prop: 'mixAsgYn', width: 50 }, + { type: 'text', name: `単数`, prop: 'rows', width: 60 }, + { type: 'text', name: `熱水`, prop: 'cols', width: 60 }, ], rows: [], } const handleChangeChidori = (e) => { const bool = e.target.value === 'true' ? true : false - setIsChidori(bool) - refs.isChidori.current = e.target.value + setModuleSetupOption({ ...moduleSetupOption, isChidori: bool }) + + //변경하면 수동 다 꺼짐 + setIsManualModuleSetup(false) + setIsManualModuleLayoutSetup(false) + setManualSetupMode('off') } const handleSetupLocation = (e) => { - setSetupLocation(e.target.value) - refs.setupLocation.current = e.target.value - } + setModuleSetupOption({ ...moduleSetupOption, setupLocation: e.target.value }) - const handleMaxSetup = (e) => { - if (e.target.checked) { - setIsMaxSetup('true') - refs.isMaxSetup.current = 'true' - } else { - setIsMaxSetup('false') - refs.isMaxSetup.current = 'false' - } + //변경하면 수동 다 꺼짐 + setIsManualModuleSetup(false) + setIsManualModuleLayoutSetup(false) + setManualSetupMode('off') } //체크된 모듈 아이디 추출 - const handleSelectedItem = (e) => { + const handleSelectedItem = (e, itemId) => { setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked }) + + const newLayoutSetup = [...props.layoutSetup] + props.layoutSetup.forEach((item, index) => { + if (item.moduleId === itemId) { + newLayoutSetup[index] = { ...props.layoutSetup[index], checked: e.target.checked } + } + }) + props.setLayoutSetup(newLayoutSetup) + } + + const handleLayoutSetup = (e, itemId, index) => { + const newLayoutSetup = [...props.layoutSetup] + newLayoutSetup[index] = { + ...newLayoutSetup[index], + moduleId: itemId, + [e.target.name]: Number(e.target.value), + } + props.setLayoutSetup(newLayoutSetup) } return ( <> -
+
- - {moduleData.header.map((data) => ( - - ))} - + {moduleData.header.map((data) => ( + + ))} {selectedModules.itemList && @@ -147,7 +190,7 @@ const Placement = forwardRef((props, refs) => { id={item.itemId} name={item.itemId} checked={selectedItems[item.itemId]} - onChange={handleSelectedItem} + onChange={(e) => handleSelectedItem(e, item.itemId)} /> @@ -158,93 +201,174 @@ const Placement = forwardRef((props, refs) => { {item.itemNm} - + + + ))} + + + + + + +
- {data.type === 'check' ? ( -
- - -
- ) : ( - data.name - )} -
+ {data.type === 'check' ? ( +
+ + +
+ ) : ( + data.name + )} +
{item.wpOut} +
+ {item.mixAsgYn} +
+
+
+ handleLayoutSetup(e, item.itemId, index)} + /> +
+
+
+ handleLayoutSetup(e, item.itemId, index)} + /> +
+
-
+
-
{getMessage('modal.module.basic.setting.module.placement.select.fitting.type')}
-
-
-
{getMessage('modal.module.basic.setting.module.placement.waterfowl.arrangement')}
-
-
-
- handleChangeChidori(e)} - /> - -
-
- handleChangeChidori(e)} /> - -
-
-
-
-
-
{getMessage('modal.module.basic.setting.module.placement.arrangement.standard')}
-
-
-
- - -
-
- - -
-
- - -
-
-
-
-
-
- {/*
- - -
*/} +
+ + + + + + + + + + + + + +
{getMessage('modal.module.basic.setting.module.placement.waterfowl.arrangement')}{getMessage('modal.module.basic.setting.module.placement.arrangement.standard')}
+
+
+ handleChangeChidori(e)} + /> + +
+
+ handleChangeChidori(e)} + /> + +
+
+
+
+
+ + +
+
+ + +
+
+
+
+ {getMessage('modal.module.basic.setting.module.placement.max.size.check')} + +
+
+
+
+ + + + + {selectedModules && + selectedModules.itemList.map((item) => ( + + ))} + + + {selectedModules.itemList.map((item) => ( + <> + + {colspan > 1 && } + + ))} + + + + {moduleSelectionData.roofConstructions.map((item, index) => ( + + + {moduleRowColArray[index]?.map((item) => ( + <> + + {colspan > 1 && } + + ))} + + ))} + +
+
+ + {item.itemNm} +
+
{getMessage('modal.module.basic.setting.module.placement.max.row')}{getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}
+
+ + {item.addRoof.roofMatlNmJp} +
+
{item.moduleMaxRows}{item.mixModuleMaxRows}
+
+
+
) }) diff --git a/src/components/floor-plan/modal/basic/step/Trestle.jsx b/src/components/floor-plan/modal/basic/step/Trestle.jsx new file mode 100644 index 00000000..529b2fcb --- /dev/null +++ b/src/components/floor-plan/modal/basic/step/Trestle.jsx @@ -0,0 +1,555 @@ +import { GlobalDataContext } from '@/app/GlobalDataProvider' +import QSelectBox from '@/components/common/select/QSelectBox' +import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' +import { useModuleTrestle } from '@/hooks/module/useModuleTrestle' +import { useMessage } from '@/hooks/useMessage' +import { currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom' +import { roofsState } from '@/store/roofAtom' +import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' +import { isObjectNotEmpty } from '@/util/common-utils' +import { forwardRef, useContext, useEffect, useImperativeHandle, useState } from 'react' +import { useRecoilState, useRecoilValue } from 'recoil' + +const Trestle = forwardRef((props, ref) => { + const { setTabNum, trestleTrigger, roofs, setRoofs, moduleSelectionData, setModuleSelectionData } = props + const { getMessage } = useMessage() + // const [selectedTrestle, setSelectedTrestle] = useState() + const currentAngleType = useRecoilValue(currentAngleTypeSelector) + const pitchText = useRecoilValue(pitchTextSelector) + const [selectedRoof, setSelectedRoof] = useState() + const { + trestleState, + trestleDetail, + dispatch, + raftBaseList, + trestleList, + constMthdList, + roofBaseList, + constructionList, + eavesMargin, + ridgeMargin, + kerabaMargin, + setEavesMargin, + setRidgeMargin, + setKerabaMargin, + cvrYn, + cvrChecked, + snowGdPossYn, + snowGdChecked, + setCvrYn, + setCvrChecked, + setSnowGdPossYn, + setSnowGdChecked, + } = useModuleTrestle({ + selectedRoof, + }) + const selectedModules = useRecoilValue(selectedModuleState) //선택된 모듈 + // const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) + const [lengthBase, setLengthBase] = useState(0) + const [hajebichi, setHajebichi] = useState(0) + const [selectedRaftBase, setSelectedRaftBase] = useState(null) + const [selectedTrestle, setSelectedTrestle] = useState(null) + const [selectedConstMthd, setSelectedConstMthd] = useState(null) + const [selectedConstruction, setSelectedConstruction] = useState(null) + const [selectedRoofBase, setSelectedRoofBase] = useState(null) + const { managementState } = useContext(GlobalDataContext) + const { restoreModuleInstArea } = useModuleBasicSetting() + + useEffect(() => { + if (roofs && !selectedRoof) { + setSelectedRoof(roofs[0]) + } + + //모듈 설치 영역 복구 + restoreModuleInstArea() + }, [roofs]) + + useEffect(() => { + if (selectedRoof) { + dispatch({ type: 'SET_INITIALIZE', roof: { ...selectedRoof, moduleTpCd: selectedModules.itemTp } }) + } + }, [selectedRoof]) + + useEffect(() => { + if (raftBaseList.length > 0) setSelectedRaftBase(raftBaseList.find((raft) => raft.clCode === trestleState?.raftBaseCd) ?? null) + }, [raftBaseList]) + + useEffect(() => { + if (trestleList.length > 0) setSelectedTrestle(trestleList.find((trestle) => trestle.trestleMkrCd === trestleState?.trestleMkrCd) ?? null) + }, [trestleList]) + + useEffect(() => { + if (roofBaseList.length > 0) setSelectedRoofBase(roofBaseList.find((roofBase) => roofBase.roofBaseCd === trestleState?.roofBaseCd) ?? null) + }, [roofBaseList]) + + useEffect(() => { + if (constMthdList.length > 0) setSelectedConstMthd(constMthdList.find((constMthd) => constMthd.constMthdCd === trestleState?.constMthdCd) ?? null) + }, [constMthdList]) + + useEffect(() => { + if (constructionList.length > 0) { + setSelectedConstruction(constructionList.find((construction) => construction.constTp === trestleState?.constTp) ?? null) + } + }, [constructionList]) + + const getConstructionState = (index) => { + if (constructionList && constructionList.length > 0) { + if (constructionList[index].constPossYn === 'Y') { + if (trestleState && trestleState.constTp === constructionList[index].constTp) { + return 'blue' + } + return 'white' + } + return 'no-click' + } + return 'no-click' + } + + const onChangeRaftBase = (e) => { + setSelectedRaftBase(e) + dispatch({ + type: 'SET_RAFT_BASE', + roof: { + moduleTpCd: selectedModules.itemTp ?? '', + roofMatlCd: selectedRoof?.roofMatlCd ?? '', + raftBaseCd: e.clCode, + }, + }) + } + + const onChangeTrestleMaker = (e) => { + setSelectedTrestle(e) + dispatch({ + type: 'SET_TRESTLE_MAKER', + roof: { + moduleTpCd: selectedModules.itemTp ?? '', + roofMatlCd: selectedRoof?.roofMatlCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + trestleMkrCd: e.trestleMkrCd, + }, + }) + } + + const onChangeConstMthd = (e) => { + setSelectedConstMthd(e) + dispatch({ + type: 'SET_CONST_MTHD', + roof: { + moduleTpCd: selectedModules.itemTp ?? '', + roofMatlCd: selectedRoof?.roofMatlCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + trestleMkrCd: trestleState.trestleMkrCd, + constMthdCd: e.constMthdCd, + }, + }) + } + + const onChangeRoofBase = (e) => { + setSelectedRoofBase(e) + dispatch({ + type: 'SET_ROOF_BASE', + roof: { + moduleTpCd: selectedModules.itemTp ?? '', + roofMatlCd: selectedRoof?.roofMatlCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + trestleMkrCd: trestleState.trestleMkrCd, + constMthdCd: trestleState.constMthdCd, + roofBaseCd: e.roofBaseCd, + illuminationTp: managementState?.surfaceTypeValue ?? '', + instHt: managementState?.installHeight ?? '', + stdWindSpeed: managementState?.standardWindSpeedId ?? '', + stdSnowLd: managementState?.verticalSnowCover ?? '', + inclCd: selectedRoof?.pitch ?? 0, + roofPitch: Math.round(selectedRoof?.roofPchBase ?? 0), + }, + }) + } + const handleChangeRoofMaterial = (index) => { + const newAddedRoofs = roofs.map((roof, i) => { + if (i === selectedRoof.index) { + return { + ...selectedRoof, + ...trestleState, + eavesMargin, + ridgeMargin, + kerabaMargin, + cvrYn, + snowGdPossYn, + cvrChecked, + snowGdChecked, + } + } + return { ...roof } + }) + setRoofs(newAddedRoofs) + setSelectedRoof(newAddedRoofs[index]) + } + + const handleConstruction = (index) => { + if (constructionList[index]?.constPossYn === 'Y') { + dispatch({ + type: 'SET_CONSTRUCTION', + roof: { + moduleTpCd: selectedModules.itemTp ?? '', + roofMatlCd: selectedRoof?.roofMatlCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + trestleMkrCd: trestleState.trestleMkrCd, + constMthdCd: trestleState.constMthdCd, + roofBaseCd: trestleState.roofBaseCd, + illuminationTp: managementState?.surfaceTypeValue ?? '', + instHt: managementState?.installHeight ?? '', + stdWindSpeed: managementState?.standardWindSpeedId ?? '', + stdSnowLd: +managementState?.verticalSnowCover ?? '', + inclCd: selectedRoof?.pitch.toString() ?? 0, + roofPitch: Math.round(selectedRoof?.roofPchBase ?? 0), + constTp: constructionList[index].constTp, + mixMatlNo: selectedModules.mixMatlNo, + workingWidth: selectedRoof?.length.toString() ?? '', + // snowGdPossYn: constructionList[index].snowGdPossYn, + // cvrYn: constructionList[index].cvrYn, + }, + }) + + setCvrYn(constructionList[index].cvrYn) + setSnowGdPossYn(constructionList[index].snowGdPossYn) + setCvrChecked(false) + setSnowGdChecked(false) + } + } + + const isComplete = () => { + const newAddedRoofs = roofs.map((roof, i) => { + if (i === selectedRoof?.index) { + return { + ...selectedRoof, + ...trestleState, + eavesMargin, + ridgeMargin, + kerabaMargin, + cvrYn, + snowGdPossYn, + cvrChecked, + snowGdChecked, + trestleDetail, + } + } + return { ...roof } + }) + + let result = true + newAddedRoofs.forEach((roof) => { + if (roof.eavesMargin && roof.ridgeMargin && roof.kerabaMargin) { + return true + } + + if (!roof.trestleMkrCd) result = false + if (!roof.constMthdCd) result = false + if (!roof.roofBaseCd) result = false + if (!roof.constTp) result = false + + if (selectedRoof.lenAuth === 'C') { + if (!trestleState?.lengthBase) result = false + } + if (['C', 'R'].includes(selectedRoof.raftAuth)) { + if (!roof.raftBaseCd) result = false + } + + if (['C', 'R'].includes(selectedRoof.roofPchAuth)) { + if (!roof.roofPchBase) result = false + } + }) + + console.log('newAddedRoofs', newAddedRoofs) + + if (result) { + setRoofs(newAddedRoofs) + setModuleSelectionData({ + ...moduleSelectionData, + roofConstructions: newAddedRoofs.map((roof, index) => { + return { + addRoof: { + ...moduleSelectionData.roofConstructions[index]?.addRoof, + ...roof.addRoof, + }, + trestle: { + ...roof.trestle, + ...moduleSelectionData.roofConstructions[index]?.trestle, + }, + construction: { + ...roof.construction, + ...moduleSelectionData.roofConstructions[index]?.construction, + }, + trestleDetail: { + ...roof.trestleDetail, + }, + } + }), + }) + trestleTrigger({ + roofConstruction: newAddedRoofs.map((roof) => { + return { + roofIndex: roof.index, + addRoof: { + ...roof, + }, + trestle: { + ...selectedTrestle, + raftBaseCd: roof.raftBaseCd, + }, + construction: { + ...constructionList.find((construction) => trestleState.constTp === construction.constTp), + roofIndex: roof.index, + setupCover: roof.cvrYn === 'Y', + setupSnowCover: roof.snowGdYn === 'Y', + selectedIndex: roof.index, + }, + } + }), + }) + } + + return result + } + + useImperativeHandle(ref, () => ({ + isComplete, + })) + + return ( +
+
+
+ {roofs && + roofs.map((roof, index) => ( + + ))} +
+
+
+
+
+ {selectedRoof && selectedRoof.lenAuth === 'C' && ( + <> +
+
L
+
+
+ setLengthBase(e.target.value)} + disabled={selectedRoof.lenAuth === 'R'} + /> +
+
+
+ + )} + {selectedRoof && ['C', 'R'].includes(selectedRoof.raftAuth) && ( + <> +
+
{getMessage('modal.module.basic.setting.module.rafter.margin')}
+
+
+ {raftBaseList.length > 0 && ( + onChangeRaftBase(e)} + /> + )} +
+
+
+ + )} + {selectedRoof && ['C', 'R'].includes(selectedRoof.roofPchAuth) && ( + <> +
+
{getMessage('modal.module.basic.setting.module.hajebichi')}
+
+
+ handleHajebichiAndLength(e, 'hajebichi')} + value={hajebichi} + /> +
+
+
+ + )} +
+
{getMessage('modal.module.basic.setting.module.trestle.maker')}
+
+
+ {trestleList && ( + onChangeTrestleMaker(e)} + /> + )} +
+
+
+
+
{getMessage('modal.module.basic.setting.module.construction.method')}
+
+
+ {constMthdList && ( + onChangeConstMthd(e)} + /> + )} +
+
+
+
+
{getMessage('modal.module.basic.setting.module.under.roof')}
+
+
+ {roofBaseList && ( + onChangeRoofBase(e)} + /> + )} +
+
+
+
+
+
+
+ + + + + +
+
+
+ dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, cvrChecked: !trestleState.cvrChecked } })} + onChange={() => setCvrChecked(!cvrChecked)} + /> + +
+
+ dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, snowGdChecked: !trestleState.snowGdChecked } })} + onChange={() => setSnowGdChecked(!snowGdChecked)} + /> + +
+
+
+
+ +
+
{getMessage('modal.module.basic.setting.module.placement.area')}
+
+ {getMessage('modal.module.basic.setting.module.placement.area.eaves')} +
+ dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, eavesMargin: e.target.value } })} + onChange={(e) => setEavesMargin(e.target.value)} + /> +
+ mm +
+
+ {getMessage('modal.module.basic.setting.module.placement.area.ridge')} +
+ dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, ridgeMargin: e.target.value } })} + onChange={(e) => setRidgeMargin(e.target.value)} + /> +
+ mm +
+
+ {getMessage('modal.module.basic.setting.module.placement.area.keraba')} +
+ dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, kerabaMargin: e.target.value } })} + onChange={(e) => setKerabaMargin(e.target.value)} + /> +
+ mm +
+
+
+
+
+
+
+
+ {getMessage('modal.module.basic.setting.module.setting.info1')} +
+ {getMessage('modal.module.basic.setting.module.setting.info2')} +
+
+
+
+
+ ) +}) + +export default Trestle diff --git a/src/components/floor-plan/modal/object/ObjectSetting.jsx b/src/components/floor-plan/modal/object/ObjectSetting.jsx index 1bbddfe6..b893bf75 100644 --- a/src/components/floor-plan/modal/object/ObjectSetting.jsx +++ b/src/components/floor-plan/modal/object/ObjectSetting.jsx @@ -100,7 +100,7 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) { ] return ( - + closePopup(id)} />
diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index e2e499b6..0ac134ef 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -46,7 +46,6 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla const { setSurfaceShapePattern } = useRoofFn() const canvas = useRecoilValue(canvasState) const roofDisplay = useRecoilValue(roofDisplaySelector) - const { saveCanvas } = usePlan() const roofRef = { roofCd: useRef(null), @@ -55,7 +54,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla rafter: useRef(null), hajebichi: useRef(null), } - + const { saveCanvas } = usePlan() /** * 치수 입력방법(복시도입력/실측값입력/육지붕) */ @@ -263,8 +262,6 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla -
-
diff --git a/src/hooks/common/useCanvasPopupStatusController.js b/src/hooks/common/useCanvasPopupStatusController.js index a31bd0ed..4a6ed6dd 100644 --- a/src/hooks/common/useCanvasPopupStatusController.js +++ b/src/hooks/common/useCanvasPopupStatusController.js @@ -1,6 +1,6 @@ 'use client' -import { useRecoilState, useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import useSWRMutation from 'swr/mutation' import { useAxios } from '../useAxios' import { unescapeString } from '@/util/common-utils' @@ -10,6 +10,8 @@ import { canvasState, currentCanvasPlanState } from '@/store/canvasAtom' import { POLYGON_TYPE } from '@/common/common' import { useCircuitTrestle } from '../useCirCuitTrestle' import { useEffect } from 'react' +import { addedRoofsState } from '@/store/settingAtom' +import { roofsState } from '@/store/roofAtom' /** * 캔버스 팝업 상태 관리 @@ -19,13 +21,14 @@ import { useEffect } from 'react' export function useCanvasPopupStatusController(param = 1) { const popupType = parseInt(param) - const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom) - const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState) - const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) + const setCompasDeg = useSetRecoilState(compasDegAtom) + const setModuleSelectionDataStore = useSetRecoilState(moduleSelectionDataState) + const setSelectedModules = useSetRecoilState(selectedModuleState) const { get, promiseGet, getFetcher, postFetcher } = useAxios() const canvas = useRecoilValue(canvasState) const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) - + const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState) + const [roofs, setRoofs] = useRecoilState(roofsState) /** * 팝업 상태 조회 * @param {number} popupTypeParam @@ -53,19 +56,27 @@ export function useCanvasPopupStatusController(param = 1) { const handleModuleSelectionTotal = async () => { for (let i = 1; i < 3; i++) { const result = await getModuleSelection(i) - console.log('🚀 ~ handleModuleSelectionTotal ~ result:', result) if (!result.objectNo) return if (i === 1) { - setCompasDeg(result.popupStatus) + if (result.popupStatus && unescapeString(result.popupStatus)) { + const data = JSON.parse(unescapeString(result.popupStatus)) + + if (data?.compasDeg) setCompasDeg(data.compasDeg) + if (data?.module) setSelectedModules(data.module) + setModuleSelectionDataStore(data) + } } else if (i === 2) { const data = JSON.parse(unescapeString(result.popupStatus)) - setModuleSelectionDataStore(data) const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) roofSurfaceList.forEach((surface) => { surface.modules = modules.filter((module) => module.surfaceId === surface.id) }) - if (data.module) setSelectedModules(data.module) + if (data.roofConstruction) { + setRoofs(data.roofConstruction) + // setManagementState({ ...managementState, roofs: data.roofConstruction.map((roof) => roof.construction.managementState) }) + } + // if (data?.module) setManagementState(data.common.managementState) } } } @@ -80,7 +91,8 @@ export function useCanvasPopupStatusController(param = 1) { objectNo: currentCanvasPlan.objectNo, planNo: parseInt(currentCanvasPlan.planNo), popupType: popupType.toString(), - popupStatus: popupType === 1 ? arg : JSON.stringify(arg).replace(/"/g, '\"'), + // popupStatus: popupType === 1 ? arg : JSON.stringify(arg).replace(/"/g, '\"'), + popupStatus: JSON.stringify(arg).replace(/"/g, '\"'), } postFetcher(`/api/v1/canvas-popup-status`, params) }, diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 69f790e8..7b2bc999 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1,6 +1,18 @@ import { useState } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { canvasSettingState, canvasState, checkedModuleState, currentObjectState, isManualModuleSetupState } from '@/store/canvasAtom' + +import { + canvasSettingState, + canvasState, + checkedModuleState, + currentObjectState, + isManualModuleLayoutSetupState, + isManualModuleSetupState, + moduleSetupOptionState, + toggleManualSetupModeState, + moduleRowColArrayState, +} from '@/store/canvasAtom' + import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon, toFixedWithoutRounding } from '@/util/canvas-util' import { roofDisplaySelector } from '@/store/settingAtom' import offsetPolygon, { calculateAngle, createLinesFromPolygon } from '@/util/qpolygon-utils' @@ -21,6 +33,7 @@ import { v4 as uuidv4 } from 'uuid' import { isObjectNotEmpty } from '@/util/common-utils' import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle' import { useMode } from '@/hooks/useMode' +import { usePolygon } from '@/hooks/usePolygon' export function useModuleBasicSetting(tabNum) { const canvas = useRecoilValue(canvasState) @@ -33,9 +46,8 @@ export function useModuleBasicSetting(tabNum) { const { setSurfaceShapePattern } = useRoofFn() const checkedModule = useRecoilValue(checkedModuleState) const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState) - + const [isManualModuleLayoutSetup, setIsManualModuleLayoutSetup] = useRecoilState(isManualModuleLayoutSetupState) const canvasSetting = useRecoilValue(canvasSettingState) - const moduleSelectionData = useRecoilValue(moduleSelectionDataState) const [trestleDetailParams, setTrestleDetailParams] = useState([]) const [trestleDetailList, setTrestleDetailList] = useState([]) @@ -47,17 +59,32 @@ export function useModuleBasicSetting(tabNum) { const { setModuleStatisticsData } = useCircuitTrestle() const { createRoofPolygon, createMarginPolygon, createPaddingPolygon } = useMode() + const { drawDirectionArrow } = usePolygon() + const moduleSetupOption = useRecoilValue(moduleSetupOptionState) + const setManualSetupMode = useSetRecoilState(toggleManualSetupModeState) + const [moduleRowColArray, setModuleRowColArray] = useRecoilState(moduleRowColArrayState) + useEffect(() => { return () => { //수동 설치시 초기화 removeMouseEvent('mouse:up') removeMouseEvent('mouse:move') canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임 + canvas?.getObjects().forEach((obj) => { + if (obj.name === POLYGON_TYPE.ROOF) { + obj.set({ + stroke: 'black', + strokeWidth: 3, + }) + } + }) } }, []) //모듈 선택에서 선택된 값들 넘어옴 const makeModuleInitArea = () => { + console.log('moduleSelectionData', moduleSelectionData) + if (isObjectNotEmpty(moduleSelectionData) && tabNum === 3) { if (canvasSetting.roofSizeSet !== '3') { const common = moduleSelectionData.common @@ -67,11 +94,11 @@ export function useModuleBasicSetting(tabNum) { const listParams = roofConstructions.map((item) => { return { ...common, - roofMatlCd: item.trestle.roofMatlCd, - trestleMkrCd: item.trestle.trestleMkrCd, - constMthdCd: item.trestle.constMthdCd, - roofBaseCd: item.trestle.roofBaseCd, - constTp: item.construction.constTp, + roofMatlCd: item.addRoof.roofMatlCd, + trestleMkrCd: item.addRoof.trestleMkrCd, + constMthdCd: item.addRoof.constMthdCd, + roofBaseCd: item.addRoof.roofBaseCd, + constTp: item.addRoof.constTp, mixMatlNo: selectedModules.mixMatlNo, roofPitch: item.addRoof.hajebichi ? item.addRoof.hajebichi : 0, inclCd: String(item.addRoof.pitch), @@ -91,7 +118,7 @@ export function useModuleBasicSetting(tabNum) { //육지붕 일경우에는 바로 배치면 설치LL canvas .getObjects() - .filter((roof) => roof.name === 'roof') + .filter((roof) => roof.name === POLYGON_TYPE.ROOF) .forEach((roof) => { makeModuleInstArea(roof, null) }) @@ -117,41 +144,69 @@ export function useModuleBasicSetting(tabNum) { //가대 상세 데이터 들어오면 실행 useEffect(() => { if (trestleDetailList.length > 0) { - console.log('trestleDetailList', trestleDetailList) + let rowColArray = [] //지붕을 가져옴 canvas .getObjects() - .filter((roof) => roof.name === 'roof') + .filter((roof) => roof.name === POLYGON_TYPE.ROOF) .forEach((roof) => { if (!roof.roofMaterial) return const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번 + trestleDetailList.forEach((detail) => { if (detail.data !== null) { if (Number(detail.data.roofIndex) === roofIndex) { //roof에 상세 데이터 추가 - roof.set({ trestleDetail: detail.data }) + roof.set({ + trestleDetail: detail.data, + stroke: roofOutlineColor(roofIndex), + strokeWidth: 7, + }) + + const offsetObjects = moduleSelectionData.roofConstructions.find((item) => item.addRoof.index === roofIndex) + roof.lines.forEach((line) => { - line.attributes = { ...line.attributes, offset: getOffset(detail.data, line.attributes.type) } + line.attributes = { ...line.attributes, offset: getOffset(offsetObjects.addRoof, line.attributes.type) } }) //배치면 설치 영역 makeModuleInstArea(roof, detail.data) - //surface에 상세 데이터 추가 } } }) }) + + trestleDetailList.forEach((detail) => { + const moduleRowArray = [] + detail.data.module.forEach((module) => { + moduleRowArray.push({ moduleMaxRows: module.moduleMaxRows, mixModuleMaxRows: module.mixModuleMaxRows }) + }) + rowColArray.push(moduleRowArray) + }) + setModuleRowColArray(rowColArray) } }, [trestleDetailList]) + const roofOutlineColor = (roofIndex) => { + if (roofIndex === 1) { + return '#FFC000' + } else if (roofIndex === 2) { + return '#7030A0' + } else if (roofIndex === 3) { + return '#385723' + } else { + return '#FFFF00' + } + } + const getOffset = (data, type) => { switch (type) { case LINE_TYPE.WALLLINE.EAVES: - return data.eaveIntvl / 10 + return data.eavesMargin / 10 case LINE_TYPE.WALLLINE.GABLE: - return data.kerabaIntvl / 10 + return data.kerabaMargin / 10 case LINE_TYPE.SUBLINE.RIDGE: case LINE_TYPE.WALLLINE.SHED: - return data.ridgeIntvl / 10 + return data.ridgeMargin / 10 default: return 200 / 10 } @@ -171,13 +226,7 @@ export function useModuleBasicSetting(tabNum) { //도머등 오브젝트 객체가 있으면 아웃라인 낸다 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 객체 + .filter((obj) => obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) //그림자 제외 나머지 오브젝트들 //도머도 외곽을 따야한다 const batchObjectOptions = { @@ -224,7 +273,6 @@ export function useModuleBasicSetting(tabNum) { setSurfaceShapePattern(roof, roofDisplay.column, true, roof.roofMaterial) //패턴 변경 // let offsetPoints = createPaddingPolygon(createRoofPolygon(roof.points), roof.lines).vertices //안쪽 offset let offsetPoints = null - console.log(roof, roof.getCurrentPoints()) const polygon = createRoofPolygon(roof.getCurrentPoints()) const originPolygon = new QPolygon(roof.getCurrentPoints(), { fontSize: 0 }) @@ -344,7 +392,7 @@ export function useModuleBasicSetting(tabNum) { canvas?.renderAll() selectedModuleInstSurfaceArray.push(setupSurface) - setCurrentObject({ name: 'moduleSetupSurface', arrayData: [...selectedModuleInstSurfaceArray] }) + setCurrentObject({ name: POLYGON_TYPE.MODULE_SETUP_SURFACE, arrayData: [...selectedModuleInstSurfaceArray] }) } else { //선택후 재선택하면 선택안됨으로 변경 setupSurface.set({ ...setupSurface, fill: 'rgba(255,255,255,0.1)', strokeDashArray: [10, 4], strokeWidth: 1 }) @@ -354,7 +402,7 @@ export function useModuleBasicSetting(tabNum) { const removeIndex = setupSurface.parentId const removeArrayIndex = selectedModuleInstSurfaceArray.findIndex((obj) => obj.parentId === removeIndex) selectedModuleInstSurfaceArray.splice(removeArrayIndex, 1) - setCurrentObject({ name: 'moduleSetupSurface', arrayData: [...selectedModuleInstSurfaceArray] }) + setCurrentObject({ name: POLYGON_TYPE.MODULE_SETUP_SURFACE, arrayData: [...selectedModuleInstSurfaceArray] }) } canvas?.renderAll() @@ -391,25 +439,34 @@ export function useModuleBasicSetting(tabNum) { setSaleStoreNorthFlg(true) } } - }, [isManualModuleSetup]) + }, [isManualModuleSetup, isManualModuleLayoutSetup]) /** * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 로 진입여부를 확인 * 확인 후 셀을 이동시킴 */ - const manualModuleSetup = (placementRef) => { + const manualModuleSetup = () => { + //레이아웃 수동설치 토글 const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 + const isChidori = moduleSetupOption.isChidori if (isManualModuleSetup) { + if (isManualModuleLayoutSetup) { + setIsManualModuleLayoutSetup(false) + // setManualSetupMode(`manualLayoutSetup_false`) + } + if (checkedModule.length === 0) { swalFire({ text: getMessage('module.place.select.module') }) - setIsManualModuleSetup(!isManualModuleSetup) + setIsManualModuleSetup(false) + setManualSetupMode(`manualSetup_false`) return } if (checkedModule.length > 1) { swalFire({ text: getMessage('module.place.select.one.module') }) - setIsManualModuleSetup(!isManualModuleSetup) + setIsManualModuleSetup(false) + setManualSetupMode(`manualSetup_false`) return } @@ -517,7 +574,8 @@ export function useModuleBasicSetting(tabNum) { /** * 스냅기능 */ - let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 70 : 40 + + let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 50 : 50 let sideSnapDistance = 15 let trestleSnapDistance = 15 @@ -565,15 +623,16 @@ export function useModuleBasicSetting(tabNum) { tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2) } - //움직이는 모듈왼쪽 -> 가운데 - if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { - tempModule.left = holdCellCenterX + intvHor / 2 + if (isChidori) { + //움직이는 모듈왼쪽 -> 가운데 + if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { + tempModule.left = holdCellCenterX + intvHor / 2 + } + // 오른쪽 -> 가운데 + if (Math.abs(smallRight - holdCellCenterX) < snapDistance) { + tempModule.left = holdCellCenterX - width - intvHor / 2 + } } - // 오른쪽 -> 가운데 - if (Math.abs(smallRight - holdCellCenterX) < snapDistance) { - tempModule.left = holdCellCenterX - width - intvHor / 2 - } - //설치된 셀에 좌측에 스냅 if (Math.abs(smallRight - holdCellLeft) < snapDistance) { // console.log('모듈 좌측 스냅') @@ -607,21 +666,16 @@ export function useModuleBasicSetting(tabNum) { tempModule.top = holdCellCenterY - toFixedWithoutRounding(width / 2, 2) } - //위쪽 -> 가운데 - if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { - // console.log('holdCellCenterX', holdCellCenterX) - // console.log('smallLeft', smallLeft) - - // console.log('모듈 센터에 스냅') - tempModule.top = holdCellCenterY + intvHor / 2 - - // console.log('tempModule.left', tempModule.left) + if (isChidori) { + //위쪽 -> 가운데 + if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { + tempModule.top = holdCellCenterY + intvHor / 2 + } + // 밑 -> 가운데 + if (Math.abs(smallBottom - holdCellCenterY) < snapDistance) { + tempModule.top = holdCellCenterY - height - intvHor / 2 + } } - // 밑 -> 가운데 - if (Math.abs(smallBottom - holdCellCenterY) < snapDistance) { - tempModule.top = holdCellCenterY - height - intvHor / 2 - } - //설치된 셀에 좌측에 스냅 if (Math.abs(smallRight - holdCellLeft) < snapDistance) { // console.log('모듈 좌측 스냅') @@ -665,6 +719,7 @@ export function useModuleBasicSetting(tabNum) { }) } + //여기서부턴 배치면 설치 외곽선 라인 // 위쪽 변에 스냅 if (Math.abs(smallTop - trestleTop) < trestleSnapDistance) { tempModule.top = trestleTop + 1 @@ -729,6 +784,18 @@ export function useModuleBasicSetting(tabNum) { addCanvasMouseEventListener('mouse:up', (e) => { let isIntersection = true + + // 혼합 설치 불가능한 모듈인지 확인 Y는 Y끼리 N은 N끼리만 설치 가능 + if (trestlePolygon.modules.length > 0) { + //이미 설치된 모듈중에 한개만 가져옴 + const mixAsgYn = trestlePolygon.modules[0].moduleInfo.mixAsgYn + //현재 체크된 모듈기준으로 혼합가능인지 확인 Y === Y, N === N 일때만 설치 가능 + if (checkedModule[0].mixAsgYn !== mixAsgYn) { + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + return + } + } + if (!inside) return if (tempModule) { const rectPoints = [ @@ -791,6 +858,13 @@ export function useModuleBasicSetting(tabNum) { canvas?.add(manualModule) manualDrawModules.push(manualModule) setModuleStatisticsData() + + //그림자는 무조건 가장 앞으로 + const shadowObj = canvas?.getObjects().find((obj) => obj.name === BATCH_TYPE.SHADOW) + if (shadowObj) { + shadowObj.bringToFront() + } + // getModuleStatistics() } else { swalFire({ text: getMessage('module.place.overlab') }) @@ -815,6 +889,874 @@ export function useModuleBasicSetting(tabNum) { } } + const manualModuleLayoutSetup = (layoutSetupRef) => { + const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 + + const isChidori = moduleSetupOption.isChidori //치도리 여부 + const setupLocation = moduleSetupOption.setupLocation //모듈 설치 위치 처마, 용마루 + + if (isManualModuleLayoutSetup) { + if (isManualModuleSetup) { + setIsManualModuleSetup(false) + // setManualSetupMode(`manualSetup_false`) + } + + if (checkedModule.length === 0) { + swalFire({ text: getMessage('module.place.select.module') }) + setIsManualModuleLayoutSetup(false) + setManualSetupMode(`manualLayoutSetup_false`) + return + } + + //숫자 0이 하나라도 있으면 설치 불가 + const hasZeroLength = checkedModule.some((item) => + layoutSetupRef.some( + (layoutItem) => layoutItem.checked && item.itemId === layoutItem.moduleId && (layoutItem.row === 0 || layoutItem.col === 0), + ), + ) + + if (hasZeroLength) { + swalFire({ text: getMessage('module.layout.setup.has.zero.value') }) + setIsManualModuleLayoutSetup(false) + setManualSetupMode(`manualLayoutSetup_false`) + return + } + + //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 + const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') + const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') + + //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 + if (mixAsgY.length > 0 && mixAsgN.length > 0) { + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + return + } + + 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, + stroke: 'black', + strokeWidth: 0.3, + selectable: true, // 선택 가능하게 설정 + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 + name: POLYGON_TYPE.MODULE, + } + + const objectsIncludeSurface = (turfModuleSetupSurface) => { + let containsBatchObjects = [] + containsBatchObjects = batchObjects.filter((batchObject) => { + let convertBatchObject = polygonToTurfPolygon(batchObject) + // 폴리곤 안에 도머 폴리곤이 포함되어있는지 확인해서 반환하는 로직 + return ( + turf.booleanContains(turfModuleSetupSurface, convertBatchObject) || + turf.booleanWithin(convertBatchObject, turfModuleSetupSurface) || + turf.booleanOverlap(turfModuleSetupSurface, convertBatchObject) + ) + }) + + return containsBatchObjects + } + + if (moduleSetupSurfaces.length !== 0) { + // const col = layoutSetupRef.reduce((acc, cur) => acc + cur.col, 0) + // const row = layoutSetupRef.reduce((acc, cur) => acc + cur.row, 0) + + let tempModule + let manualDrawModules = [] + let inside = false + let turfPolygon + let flowDirection + let trestlePolygon + let width, height, intvHor, intvVer + let containsBatchObjects + + addCanvasMouseEventListener('mouse:move', (e) => { + //마우스 이벤트 삭제 후 재추가 + const mousePoint = canvas.getPointer(e.e) + + for (let i = 0; i < moduleSetupSurfaces.length; i++) { + //배치면이 여러개 일때 옮겨가면서 동작해야함 + turfPolygon = polygonToTurfPolygon(moduleSetupSurfaces[i]) + trestlePolygon = moduleSetupSurfaces[i] + manualDrawModules = moduleSetupSurfaces[i].modules // 앞에서 자동으로 했을때 추가됨 + flowDirection = moduleSetupSurfaces[i].direction //도형의 방향 + + containsBatchObjects = objectsIncludeSurface(turfPolygon) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 + + const moduleWidth = Number(checkedModule[0].longAxis) / 10 + const moduleHeight = Number(checkedModule[0].shortAxis) / 10 + let tmpWidth = flowDirection === 'south' || flowDirection === 'north' ? moduleWidth : moduleHeight + let tmpHeight = flowDirection === 'south' || flowDirection === 'north' ? moduleHeight : moduleWidth + + width = + canvasSetting.roofSizeSet == '1' + ? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(moduleSetupSurfaces[i].roofMaterial.pitch), flowDirection).width + : tmpWidth + height = + canvasSetting.roofSizeSet == '1' + ? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(moduleSetupSurfaces[i].roofMaterial.pitch), flowDirection).height + : tmpHeight + + intvHor = + flowDirection === 'south' || flowDirection === 'north' + ? moduleSetupSurfaces[i].trestleDetail.moduleIntvlHor / 10 + : moduleSetupSurfaces[i].trestleDetail.moduleIntvlVer / 10 + intvVer = + flowDirection === 'south' || flowDirection === 'north' + ? moduleSetupSurfaces[i].trestleDetail.moduleIntvlVer / 10 + : moduleSetupSurfaces[i].trestleDetail.moduleIntvlHor / 10 + + //큰버전용 계산 + // let calcHalfWidth = (Number((width * col).toFixed(1)) + Number((intvHor * (col - 1)).toFixed(1))) / 2 + // let calcHalfHeight = (Number((height * row).toFixed(1)) + Number((intvVer * (row - 1)).toFixed(1))) / 2 + + //작은버전용 + const points = [ + { + x: toFixedWithoutRounding(mousePoint.x, 2) + toFixedWithoutRounding(width / 2, 2), + y: toFixedWithoutRounding(mousePoint.y, 2) - toFixedWithoutRounding(height / 2, 2), + }, + { + x: toFixedWithoutRounding(mousePoint.x, 2) + toFixedWithoutRounding(width / 2, 2), + y: toFixedWithoutRounding(mousePoint.y, 2) + toFixedWithoutRounding(height / 2, 2), + }, + { + x: toFixedWithoutRounding(mousePoint.x, 2) - toFixedWithoutRounding(width / 2, 2), + y: toFixedWithoutRounding(mousePoint.y, 2) - toFixedWithoutRounding(height / 2, 2), + }, + { + x: toFixedWithoutRounding(mousePoint.x, 2) - toFixedWithoutRounding(width / 2, 2), + y: toFixedWithoutRounding(mousePoint.y, 2) + toFixedWithoutRounding(height / 2, 2), + }, + ] + + //아래래 + // let points = [ + // { + // x: Number(mousePoint.x.toFixed(1)) - calcHalfWidth, + // y: Number(mousePoint.y.toFixed(1)) - calcHalfHeight, + // }, + // { + // x: Number(mousePoint.x.toFixed(1)) - calcHalfWidth, + // y: Number(mousePoint.y.toFixed(1)) + calcHalfHeight, + // }, + // { + // x: Number(mousePoint.x.toFixed(1)) + calcHalfWidth, + // y: Number(mousePoint.y.toFixed(1)) + calcHalfHeight, + // }, + // { + // x: Number(mousePoint.x.toFixed(1)) + calcHalfWidth, + // y: Number(mousePoint.y.toFixed(1)) - calcHalfHeight, + // }, + // ] + + const turfPoints = coordToTurfPolygon(points) + + if (turf.booleanWithin(turfPoints, turfPolygon)) { + let isDrawing = false + + if (isDrawing) return + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임 + + tempModule = new fabric.Rect({ + fill: 'rgba(224, 221, 222, 0.7)', + stroke: 'black', + strokeWidth: 1, + strokeDashArray: [10, 5], + width: toFixedWithoutRounding(width, 2), //작은버전 + height: toFixedWithoutRounding(height, 2), //작은버전 + left: toFixedWithoutRounding(mousePoint.x, 2) - toFixedWithoutRounding(width / 2, 2), //작은버전 + top: toFixedWithoutRounding(mousePoint.y, 2) - toFixedWithoutRounding(height / 2, 2), //작은버전 + // width: Number((width * col).toFixed(1)) + Number((intvHor * (col - 1)).toFixed(1)), //큰버전 + // height: Number((height * row).toFixed(1)) + Number((intvVer * (row - 1)).toFixed(1)), //큰버전 + // left: Number(mousePoint.x.toFixed(1)) - calcHalfWidth.toFixed(1), //큰버전 + // top: Number(mousePoint.y.toFixed(1)) - calcHalfHeight.toFixed(1), //큰버전 + selectable: false, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + name: 'tempModule', + parentId: moduleSetupSurfaces[i].parentId, + }) + + //북면이고 북면설치상점이 아니면 그냥 return + if (trestlePolygon.isNorth && !saleStoreNorthFlg) { + return + } else { + canvas?.add(tempModule) //움직여가면서 추가됨 + } + + /** + * 스냅기능 + */ + let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 70 : 40 + let sideSnapDistance = 15 + let trestleSnapDistance = 15 + + const trestleLeft = toFixedWithoutRounding(moduleSetupSurfaces[i].left, 2) - toFixedWithoutRounding(moduleSetupSurfaces[i].width / 2, 2) + const trestleTop = toFixedWithoutRounding(moduleSetupSurfaces[i].top, 2) - toFixedWithoutRounding(moduleSetupSurfaces[i].height / 2, 2) + const trestleRight = + toFixedWithoutRounding(moduleSetupSurfaces[i].left, 2) + toFixedWithoutRounding(moduleSetupSurfaces[i].width / 2, 2) + const trestleBottom = + toFixedWithoutRounding(moduleSetupSurfaces[i].top, 2) + toFixedWithoutRounding(moduleSetupSurfaces[i].height / 2, 2) + const bigCenterY = (trestleTop + trestleTop + moduleSetupSurfaces[i].height) / 2 + + // 이동하는 모듈의 경계 좌표 + const smallLeft = toFixedWithoutRounding(tempModule.left, 2) + const smallTop = toFixedWithoutRounding(tempModule.top, 2) + const smallRight = smallLeft + toFixedWithoutRounding(tempModule.width, 2) + const smallBottom = smallTop + toFixedWithoutRounding(tempModule.height, 2) + const smallCenterX = smallLeft + toFixedWithoutRounding(tempModule.width / 2, 2) + const smallCenterY = smallTop + toFixedWithoutRounding(tempModule.height / 2, 2) + + /** + * 미리 깔아놓은 셀이 있을때 셀에 흡착됨 + */ + if (manualDrawModules) { + manualDrawModules.forEach((cell) => { + const holdCellLeft = toFixedWithoutRounding(cell.left, 2) + const holdCellTop = toFixedWithoutRounding(cell.top, 2) + const holdCellRight = holdCellLeft + toFixedWithoutRounding(cell.width, 2) + const holdCellBottom = holdCellTop + toFixedWithoutRounding(cell.height, 2) + const holdCellCenterX = holdCellLeft + toFixedWithoutRounding(cell.width / 2, 2) + const holdCellCenterY = holdCellTop + toFixedWithoutRounding(cell.height / 2, 2) + + //흐름방향따라 달라야 한다. + if (flowDirection === 'south' || flowDirection === 'north') { + if (Math.abs(smallCenterX - holdCellCenterX) < snapDistance) { + //움직이는 모듈 가운데 -> 설치 모듈 가운데 + tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2) + } + + if (isChidori) { + //움직이는 모듈왼쪽 -> 가운데 + if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { + tempModule.left = holdCellCenterX + intvHor / 2 + } + // 오른쪽 -> 가운데 + if (Math.abs(smallRight - holdCellCenterX) < snapDistance) { + tempModule.left = holdCellCenterX - width - intvHor / 2 + } + } + //설치된 셀에 좌측에 스냅 + if (Math.abs(smallRight - holdCellLeft) < snapDistance) { + // console.log('모듈 좌측 스냅') + tempModule.left = holdCellLeft - width - intvHor + } + + //설치된 셀에 우측에 스냅 + if (Math.abs(smallLeft - holdCellRight) < snapDistance) { + // console.log('모듈 우측 스냅') + tempModule.left = holdCellRight + intvHor + } + //설치된 셀에 위쪽에 스냅 + if (Math.abs(smallBottom - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop - height - intvVer + } + + //설치된 셀에 밑쪽에 스냅 + if (Math.abs(smallTop - holdCellBottom) < sideSnapDistance) { + tempModule.top = holdCellBottom + intvVer + } + + //설치된 셀에 윗쪽에 스냅 + if (Math.abs(smallTop - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop + } + } else { + //흐름방향 west, east + + //가운데 가운데 + if (Math.abs(smallCenterY - holdCellCenterY) < snapDistance) { + tempModule.top = holdCellCenterY - toFixedWithoutRounding(width / 2, 2) + } + + if (isChidori) { + //위쪽 -> 가운데 + if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { + tempModule.top = holdCellCenterY + intvHor / 2 + } + // 밑 -> 가운데 + if (Math.abs(smallBottom - holdCellCenterY) < snapDistance) { + tempModule.top = holdCellCenterY - height - intvHor / 2 + } + } + //설치된 셀에 좌측에 스냅 + if (Math.abs(smallRight - holdCellLeft) < snapDistance) { + // console.log('모듈 좌측 스냅') + tempModule.left = holdCellLeft - width - intvHor + } + + //설치된 셀에 우측에 스냅 + if (Math.abs(smallLeft - holdCellRight) < snapDistance) { + // console.log('모듈 우측 스냅') + tempModule.left = holdCellRight + intvHor + } + //설치된 셀에 위쪽에 스냅 + if (Math.abs(smallBottom - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop - height - intvVer + } + + //설치된 셀에 밑쪽에 스냅 + if (Math.abs(smallTop - holdCellBottom) < sideSnapDistance) { + tempModule.top = holdCellBottom + intvVer + } + + //설치된 셀에 윗쪽에 스냅 + if (Math.abs(smallTop - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop + } + + if (Math.abs(smallLeft - holdCellLeft) < snapDistance) { + tempModule.left = holdCellLeft + } + } + }) + } + + // 위쪽 변에 스냅 + if (Math.abs(smallTop - trestleTop) < trestleSnapDistance) { + tempModule.top = trestleTop + 1 + } + + // 아래쪽 변에 스냅 + if (Math.abs(smallBottom - trestleBottom) < trestleSnapDistance) { + tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height - 1 + } + + // 왼쪽변에 스냅 + if (Math.abs(smallLeft - trestleLeft) < trestleSnapDistance) { + tempModule.left = trestleLeft + 1 + } + //오른쪽 변에 스냅 + if (Math.abs(smallRight - trestleRight) < trestleSnapDistance) { + tempModule.left = trestleRight - tempModule.width - 1 + } + + if (flowDirection === 'south' || flowDirection === 'north') { + // 모듈이 가운데가 세로중앙선에 붙게 스냅 + if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) { + tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width / 2 + } + } else { + // 모듈이 가로중앙선에 스냅 + if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < trestleSnapDistance) { + tempModule.top = bigCenterY - tempModule.height / 2 + } + } + + tempModule.setCoords() + canvas?.renderAll() + inside = true + break + } else { + inside = false + } + } + + if (!inside) { + // tempModule.set({ fill: 'red' }) + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) + canvas?.renderAll() + } + }) + + addCanvasMouseEventListener('mouse:up', (e) => { + if (trestlePolygon.modules.length > 0) { + //이미 설치된 모듈중에 한개만 가져옴 + const mixAsgYn = trestlePolygon.modules[0].moduleInfo.mixAsgYn + //현재 체크된 모듈기준으로 혼합가능인지 확인 Y === Y, N === N 일때만 설치 가능 + if (checkedModule[0].mixAsgYn !== mixAsgYn) { + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + return + } + } + + if (!inside) return + + //입력받은 값의 합 + //지붕재+공법에 따라 최대 모듈 갯수가 달라지므로 클릭시점에 validate 체크해야함 + const isMultipleModules = checkedModule.length > 1 //모듈이 여러개면 + const maxCol = trestlePolygon.trestleDetail.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + const maxRow = isMultipleModules + ? trestlePolygon.trestleDetail.moduleMaxRows + : trestlePolygon.trestleDetail.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + + //단수 합단수 + const sumRowCount = isMultipleModules + ? layoutSetupRef.filter((item) => item.checked).reduce((acc, cur) => acc + cur.row, 0) + : layoutSetupRef.find((item) => item.moduleId === checkedModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 + + // + const sumColCount = layoutSetupRef.filter((item) => item.col).some((item) => item.col > maxCol) + + if (sumRowCount > maxRow || sumColCount) { + swalFire({ text: getMessage('module.layout.setup.max.count', [maxRow, maxCol]), icon: 'warning' }) + return + } + + // 혼합일때 모듈 개별의 row를 체크함 + const isPassedObject = + isMultipleModules && + layoutSetupRef.find((item, index) => item.checked && item.row > trestlePolygon.trestleDetail.module[index].mixModuleMaxRows) + + if (isPassedObject) { + swalFire({ + text: getMessage('module.layout.setup.max.count.multiple', [ + layoutSetupRef.indexOf(isPassedObject) + 1, + trestlePolygon.trestleDetail.module[layoutSetupRef.indexOf(isPassedObject)].mixModuleMaxRows, + maxCol, + ]), + icon: 'warning', + }) + return + } + + if (tempModule) { + let startX, startY + let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표 + let installedHeightModuleCount = 0 + + checkedModule.forEach((module, index) => { + //모듈 사이즈 + const moduleWidth = toFixedWithoutRounding(module.longAxis / 10, 1) + const moduleHeight = toFixedWithoutRounding(module.shortAxis / 10, 1) + + //흐름 방향에 따른 모듈 사이즈 + let tmpWidth = flowDirection === 'south' || flowDirection === 'north' ? moduleWidth : moduleHeight + let tmpHeight = flowDirection === 'south' || flowDirection === 'north' ? moduleHeight : moduleWidth + + //복시도, 실치수에 따른 모듈 높이 조정 + width = + canvasSetting.roofSizeSet == '1' + ? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(trestlePolygon.roofMaterial.pitch), flowDirection).width + : tmpWidth + height = + canvasSetting.roofSizeSet == '1' + ? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(trestlePolygon.roofMaterial.pitch), flowDirection).height + : tmpHeight + + //그려진 가이드 라인의 포인트를 기준으로 시작점을 만든다 + //남쪽에 처마방향이나 북쪽에 용마루면 + //tempModule에 좌,하 좌표를 기준으로 우측으로 위로 그림 + if ((flowDirection === 'south' && setupLocation === 'eaves') || (flowDirection === 'north' && setupLocation === 'ridge')) { + //남 + startX = toFixedWithoutRounding(tempModule.left, 1) + startY = toFixedWithoutRounding(tempModule.top + tempModule.height, 1) + + moduleOptions.fill = module.color + + let col = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].col + let row = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].row + let tempCol = col + + for (let i = 0; i < row; i++) { + let tempY = startY - i * height + let isInstalled = false + + if (index > 0) { + //두번째 모듈일때 마지막 설치 지점 + tempY = index > 0 && i === 0 ? installedLastHeightCoord - intvVer : installedLastHeightCoord + } + + let tempHeightMargin = i === 0 ? 0 : i * intvVer + + //치도리 설치시 컬럼 조정 + if (isChidori) { + //치도리면 짝수열은 안으로 넣기 + tempCol = installedHeightModuleCount % 2 === 0 ? col : col - 1 + } + + for (let j = 0; j < tempCol; j++) { + let chidoriMargin = 0 + let tempX = startX + j * width + let tempWidthMargin = j === 0 ? 0 : j * intvHor + + if (isChidori) { + chidoriMargin = installedHeightModuleCount % 2 === 0 ? 0 : width / 2 + intvHor + } + + let rectPoints = [ + { x: tempX + tempWidthMargin + chidoriMargin, y: tempY - height - tempHeightMargin }, + { x: tempX + tempWidthMargin + chidoriMargin, y: tempY - tempHeightMargin }, + { x: tempX + width + tempWidthMargin + chidoriMargin, y: tempY - tempHeightMargin }, + { x: tempX + width + tempWidthMargin + chidoriMargin, y: tempY - height - tempHeightMargin }, + ] + + tempModule.set({ points: rectPoints }) + const tempTurfModule = polygonToTurfPolygon(tempModule) + tempModule.setCoords() //좌표 재정렬 + + if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) { + //마우스 클릭시 set으로 해당 위치에 셀을 넣음 + const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 + if (!isOverlap) { + canvas?.remove(tempModule) + + //안겹치면 넣는다 + // tempModule.setCoords() + moduleOptions.surfaceId = trestlePolygon.id + + let manualModule = new QPolygon(tempModule.points, { + ...moduleOptions, + moduleInfo: module, + // left: toFixedWithoutRounding(tempX + tempWidthMargin, 1), + // top: toFixedWithoutRounding(tempY - height - tempHeightMargin, 1), + width: toFixedWithoutRounding(width, 1), + height: toFixedWithoutRounding(height, 1), + }) + + let isDisjoint = checkModuleDisjointObjects(tempTurfModule, containsBatchObjects) + + //오브젝트와 겹치지 않으면 넣는다 + if (isDisjoint) { + canvas?.add(manualModule) + canvas?.renderAll() + manualDrawModules.push(manualModule) + setModuleStatisticsData() + installedLastHeightCoord = tempY - height - tempHeightMargin + + if (j === 0) { + isInstalled = true + } + } else { + //디버깅용 + // manualModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) + // canvas?.add(manualModule) + // canvas.renderAll() + } + } else { + swalFire({ text: getMessage('module.place.overlab') }) + return + } + } + } + + if (isInstalled) { + ++installedHeightModuleCount + } + } + //북쪽에 처마거나 남쪽에 용마루일경우 + //tempModule에 우,상 좌표를 기준으로 좌측으로 아래로 그림 + } else if ((flowDirection === 'north' && setupLocation === 'eaves') || (flowDirection === 'south' && setupLocation === 'ridge')) { + //북북 + startX = toFixedWithoutRounding(tempModule.left + tempModule.width, 1) + startY = toFixedWithoutRounding(tempModule.top, 1) + + moduleOptions.fill = module.color + + const col = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].col + const row = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].row + let tempCol = col //치도리시 하나 빼려고 임시로 + + for (let i = 0; i < row; i++) { + let tempY = startY + i * height + let isInstalled = false + + if (index > 0) { + //두번째 모듈일때 마지막 설치 지점 + tempY = index > 0 && i === 0 ? installedLastHeightCoord + intvVer : installedLastHeightCoord + } + + let tempHeightMargin = i === 0 ? 0 : i * intvVer + + if (isChidori) { + tempCol = installedHeightModuleCount % 2 === 0 ? col : col - 1 + } + + for (let j = 0; j < tempCol; j++) { + let chidoriMargin = 0 + let tempX = startX - j * width + let tempWidthMargin = j === 0 ? 0 : j * intvHor + + if (isChidori) { + chidoriMargin = installedHeightModuleCount % 2 === 0 ? 0 : width / 2 + intvHor + } + + let rectPoints = [ + { x: tempX - tempWidthMargin - chidoriMargin, y: tempY + height + tempHeightMargin }, + { x: tempX - tempWidthMargin - chidoriMargin, y: tempY + tempHeightMargin }, + { x: tempX - width - tempWidthMargin - chidoriMargin, y: tempY + tempHeightMargin }, + { x: tempX - width - tempWidthMargin - chidoriMargin, y: tempY + height + tempHeightMargin }, + ] + + tempModule.set({ points: rectPoints }) + const tempTurfModule = polygonToTurfPolygon(tempModule) + tempModule.setCoords() //좌표 재정렬 + + if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) { + //마우스 클릭시 set으로 해당 위치에 셀을 넣음 + const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 + if (!isOverlap) { + canvas?.remove(tempModule) + + //안겹치면 넣는다 + // tempModule.setCoords() + moduleOptions.surfaceId = trestlePolygon.id + + let manualModule = new QPolygon(tempModule.points, { + ...moduleOptions, + moduleInfo: module, + width: toFixedWithoutRounding(width, 1), + height: toFixedWithoutRounding(height, 1), + }) + + let isDisjoint = checkModuleDisjointObjects(tempTurfModule, containsBatchObjects) + + //오브젝트와 겹치지 않으면 넣는다 + if (isDisjoint) { + canvas?.add(manualModule) + canvas?.renderAll() + manualDrawModules.push(manualModule) + setModuleStatisticsData() + installedLastHeightCoord = tempY + height + tempHeightMargin + + if (j === 0) { + isInstalled = true + } + } else { + //디버깅용 + // manualModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) + // canvas?.add(manualModule) + // canvas.renderAll() + } + } else { + swalFire({ text: getMessage('module.place.overlab') }) + return + } + } + } + if (isInstalled) { + ++installedHeightModuleCount + } + } + //서쪽에 처마 또는 동쪽의 용마루일경우 + //tempModule에 좌,상 좌표를 기준으로 아래로 좌측으로 그림 + } else if ((flowDirection === 'west' && setupLocation === 'eaves') || (flowDirection === 'east' && setupLocation === 'ridge')) { + startX = toFixedWithoutRounding(tempModule.left, 1) + startY = toFixedWithoutRounding(tempModule.top, 1) + moduleOptions.fill = module.color + + const col = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].col + const row = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].row + let tempCol = col //치도리시 하나 빼려고 임시로 + + for (let i = 0; i < row; i++) { + //옆으로 올라가는거라 height가 아니고 width로 변경 + let tempX = startX + i * width + let tempWidthMargin = i === 0 ? 0 : i * intvHor + let isInstalled = false + + if (index > 0) { + //두번째 모듈일때 마지막 설치 지점 //명칭은 그대로 쓴다 + tempX = index > 0 && i === 0 ? installedLastHeightCoord + intvHor : installedLastHeightCoord + } + + if (isChidori) { + tempCol = installedHeightModuleCount % 2 === 0 ? col : col - 1 + } + + for (let j = 0; j < tempCol; j++) { + let tempY = startY + j * height + let tempHeightMargin = j === 0 ? 0 : j * intvVer + + let chidoriMargin = 0 + + if (isChidori) { + chidoriMargin = installedHeightModuleCount % 2 === 0 ? 0 : height / 2 + intvVer + } + + let rectPoints = [ + { x: tempX + tempWidthMargin, y: tempY + tempHeightMargin + chidoriMargin }, + { x: tempX + tempWidthMargin, y: tempY + height + tempHeightMargin + chidoriMargin }, + { x: tempX + width + tempWidthMargin, y: tempY + height + tempHeightMargin + chidoriMargin }, + { x: tempX + width + tempWidthMargin, y: tempY + tempHeightMargin + chidoriMargin }, + ] + + tempModule.set({ points: rectPoints }) + const tempTurfModule = polygonToTurfPolygon(tempModule) + tempModule.setCoords() //좌표 재정렬 + + if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) { + //마우스 클릭시 set으로 해당 위치에 셀을 넣음 + const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 + if (!isOverlap) { + canvas?.remove(tempModule) + + //안겹치면 넣는다 + // tempModule.setCoords() + moduleOptions.surfaceId = trestlePolygon.id + + let manualModule = new QPolygon(tempModule.points, { + ...moduleOptions, + moduleInfo: module, + width: toFixedWithoutRounding(width, 1), + height: toFixedWithoutRounding(height, 1), + }) + + let isDisjoint = checkModuleDisjointObjects(tempTurfModule, containsBatchObjects) + + //오브젝트와 겹치지 않으면 넣는다 + if (isDisjoint) { + canvas?.add(manualModule) + canvas?.renderAll() + manualDrawModules.push(manualModule) + setModuleStatisticsData() + installedLastHeightCoord = tempX + width + tempWidthMargin + + if (j === 0) { + isInstalled = true + } + } else { + //디버깅용 + // manualModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) + // canvas?.add(manualModule) + // canvas.renderAll() + } + } else { + swalFire({ text: getMessage('module.place.overlab') }) + return + } + } + } + if (isInstalled) { + ++installedHeightModuleCount + } + } + //동쪽의 처마 또는 서쪽의 용마루일경우 + //tempModule에 우,하 좌표를 기준으로 위로 우측으로 그림 + } else if ((flowDirection === 'east' && setupLocation === 'eaves') || (flowDirection === 'west' && setupLocation === 'ridge')) { + startX = toFixedWithoutRounding(tempModule.left + width, 1) + startY = toFixedWithoutRounding(tempModule.top + height, 1) + moduleOptions.fill = module.color + + const col = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].col + const row = layoutSetupRef.filter((item) => item.moduleId === module.itemId)[0].row + let tempCol = col //치도리시 하나 빼려고 임시로 + + for (let i = 0; i < row; i++) { + //옆으로 올라가는거라 height가 아니고 width로 변경 + let tempX = startX - i * width + let tempWidthMargin = i === 0 ? 0 : i * intvHor + let isInstalled = false + + if (index > 0) { + //두번째 모듈일때 마지막 설치 지점 //명칭은 그대로 쓴다 + tempX = index > 0 && i === 0 ? installedLastHeightCoord - intvHor : installedLastHeightCoord + } + + if (isChidori) { + tempCol = installedHeightModuleCount % 2 === 0 ? col : col - 1 + } + + for (let j = 0; j < tempCol; j++) { + let chidoriMargin = 0 + let tempY = startY - j * height + let tempHeightMargin = j === 0 ? 0 : j * intvVer + + if (isChidori) { + chidoriMargin = installedHeightModuleCount % 2 === 0 ? 0 : height / 2 + intvVer + } + + let rectPoints = [ + { x: tempX - tempWidthMargin, y: tempY - tempHeightMargin - chidoriMargin }, + { x: tempX - tempWidthMargin, y: tempY - height - tempHeightMargin - chidoriMargin }, + { x: tempX - width - tempWidthMargin, y: tempY - height - tempHeightMargin - chidoriMargin }, + { x: tempX - width - tempWidthMargin, y: tempY - tempHeightMargin - chidoriMargin }, + ] + + tempModule.set({ points: rectPoints }) + const tempTurfModule = polygonToTurfPolygon(tempModule) + tempModule.setCoords() //좌표 재정렬 + + if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) { + //마우스 클릭시 set으로 해당 위치에 셀을 넣음 + const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 + if (!isOverlap) { + canvas?.remove(tempModule) + + //안겹치면 넣는다 + // tempModule.setCoords() + moduleOptions.surfaceId = trestlePolygon.id + + let manualModule = new QPolygon(tempModule.points, { + ...moduleOptions, + moduleInfo: module, + width: toFixedWithoutRounding(width, 1), + height: toFixedWithoutRounding(height, 1), + }) + + let isDisjoint = checkModuleDisjointObjects(tempTurfModule, containsBatchObjects) + + //오브젝트와 겹치지 않으면 넣는다 + if (isDisjoint) { + canvas?.add(manualModule) + canvas?.renderAll() + manualDrawModules.push(manualModule) + setModuleStatisticsData() + installedLastHeightCoord = tempX - width - tempWidthMargin + + if (j === 0) { + isInstalled = true + } + } else { + //디버깅용 + // manualModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) + // canvas?.add(manualModule) + // canvas.renderAll() + } + } else { + swalFire({ text: getMessage('module.place.overlab') }) + return + } + } + } + if (isInstalled) { + ++installedHeightModuleCount + } + } + } + }) + //그림자가 있다면 무조건 그림자를 가장 앞으로 올림 + const shadowObj = canvas?.getObjects().find((obj) => obj.name === BATCH_TYPE.SHADOW) + if (shadowObj) { + shadowObj.bringToFront() + } + } + }) + } + } else { + if (moduleSetupSurfaces) { + //수동모드 해제시 모듈 설치면 선택 잠금 + moduleSetupSurfaces.forEach((obj) => { + obj.set({ + selectable: true, + evented: true, + }) + }) + } + + removeMouseEvent('mouse:up') + removeMouseEvent('mouse:move') + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임 + } + } + //자동 모듈 설치(그리드 방식) const autoModuleSetup = (placementRef) => { initEvent() //마우스 이벤트 초기화 @@ -824,9 +1766,19 @@ export function useModuleBasicSetting(tabNum) { return } - const isChidori = placementRef.isChidori.current === 'true' ? true : false - const setupLocation = placementRef.setupLocation.current - const isMaxSetup = placementRef.isMaxSetup.current === 'true' ? true : false + //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 + const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') + const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') + + //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 + if (mixAsgY.length > 0 && mixAsgN.length > 0) { + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + return + } + + const isChidori = moduleSetupOption.isChidori + const setupLocation = moduleSetupOption.setupLocation + const isMaxSetup = false const moduleSetupSurfaces = moduleSetupSurface //선택 설치면 const notSelectedTrestlePolygons = canvas @@ -842,24 +1794,11 @@ export function useModuleBasicSetting(tabNum) { //어짜피 자동으로 누르면 선택안된데도 다 날아간다 canvas.getObjects().forEach((obj) => { - if (obj.name === 'module') { + if (obj.name === POLYGON_TYPE.MODULE) { canvas.remove(obj) } }) - // if (moduleIsSetup.length > 0) { - // swalFire({ text: 'alert 아이콘 테스트입니다.', icon: 'error' }) - // } - - // moduleSetupSurfaces.forEach((obj) => { - // if (obj.modules) { - // obj.modules.forEach((module) => { - // canvas?.remove(module) - // }) - // obj.modules = [] - // } - // }) - notSelectedTrestlePolygons.forEach((obj) => { if (obj.modules) { obj.modules.forEach((module) => { @@ -878,11 +1817,9 @@ export function useModuleBasicSetting(tabNum) { lockRotation: true, // 회전 잠금 lockScalingX: true, // X 축 크기 조정 잠금 lockScalingY: true, // Y 축 크기 조정 잠금 - name: 'module', + name: POLYGON_TYPE.MODULE, } - let leftMargin, bottomMargin, square, chidoriLength - //선택된 지붕안에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 포함되면 배열 반환 const objectsIncludeSurface = (turfModuleSetupSurface) => { let containsBatchObjects = [] @@ -899,36 +1836,6 @@ export function useModuleBasicSetting(tabNum) { return containsBatchObjects } - // /** - // * 도머나 개구가 모듈에 걸치는지 확인하는 로직 - // * @param {*} squarePolygon - // * @param {*} containsBatchObjects - // * @returns - // */ - // const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { - // let isDisjoint = false - // - // if (containsBatchObjects.length > 0) { - // let convertBatchObject - // //도머가 있으면 적용되는 로직 - // isDisjoint = containsBatchObjects.every((batchObject) => { - // if (batchObject.type === 'group') { - // convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) - // } else { - // convertBatchObject = polygonToTurfPolygon(batchObject) - // } - // /** - // * 도머가 여러개일수있으므로 겹치는게 있다면... - // * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 - // */ - // return turf.booleanDisjoint(squarePolygon, convertBatchObject) - // }) - // } else { - // isDisjoint = true - // } - // return isDisjoint - // } - /** * 배치면 안에 있는지 확인 * @param {*} squarePolygon @@ -963,7 +1870,7 @@ export function useModuleBasicSetting(tabNum) { checkedModule.forEach((module, moduleIndex) => { const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0] //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임 - let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows + // let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows //모듈의 넓이 높이를 가져옴 (복시도 촌수 적용) //1번 깔았던 모듈 기준으로 잡야아함 @@ -1544,37 +2451,8 @@ export function useModuleBasicSetting(tabNum) { if (moduleSetupSurface.direction === 'north') { downFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) } - } else if (setupLocation === 'center') { - //중가면 - if (moduleSetupSurface.direction === 'south') { - downFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true, intvHor, intvVer) - } - if (moduleSetupSurface.direction === 'west') { - leftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true, intvHor, intvVer) - } - if (moduleSetupSurface.direction === 'east') { - rightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true, intvHor, intvVer) - } - if (moduleSetupSurface.direction === 'north') { - topFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true, intvHor, intvVer) - } } - // const setupedModules = moduleSetupArray.filter((module, index) => { - // let disjointFromTrestle = checkModuleDisjointSurface(module.turfPoints, turfModuleSetupSurface) - // let isDisjoint = checkModuleDisjointObjects(module.turfPoints, containsBatchObjects) - - // if (!(disjointFromTrestle && isDisjoint)) { - // canvas?.remove(module) - // // module.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 }) - // return false - // } else { - // return module - // } - // }) - - // canvas?.renderAll() - //나간애들 제외하고 설치된 애들로 겹친애들 삭제 하기 moduleSetupArray.forEach((module, index) => { if (isMaxSetup && index > 0) { @@ -1600,6 +2478,12 @@ export function useModuleBasicSetting(tabNum) { // moduleSetupArray: setupedModules, // }) // setModuleIsSetup(moduleArray) + + //그림자는 무조건 가장 앞으로 + const shadowObj = canvas?.getObjects().find((obj) => obj.name === BATCH_TYPE.SHADOW) + if (shadowObj) { + shadowObj.bringToFront() + } }) // calculateForApi() } @@ -1931,7 +2815,7 @@ export function useModuleBasicSetting(tabNum) { ) //도머s 객체 let moduleOptions = { - fill: '#BFFD9F', + fill: checkedModule[0].color, stroke: 'black', strokeWidth: 0.3, selectable: true, // 선택 가능하게 설정 @@ -1964,14 +2848,15 @@ export function useModuleBasicSetting(tabNum) { const angle = calculateAngle(points1, points2) //변별로 선택으로 되어있을때 모듈면을 회전시키기 - const targetdSurface = moduleSetupSurfaces.filter((surface) => surface.surfaceId === obj.surfaceId)[0] - targetdSurface.angle = -angle + const targetSurface = moduleSetupSurfaces.filter((surface) => surface.surfaceId === obj.surfaceId)[0] + targetSurface.angle = -angle //변별로 선택되어있는 지붕도 회전시키기 - const targetRoof = canvas.getObjects().filter((roof) => roof.name === POLYGON_TYPE.ROOF && roof.id === targetdSurface.parentId)[0] + const targetRoof = canvas.getObjects().filter((roof) => roof.name === POLYGON_TYPE.ROOF && roof.id === targetSurface.parentId)[0] targetRoof.angle = -angle targetRoof.fire('modified') - targetdSurface.fire('modified') + targetSurface.fire('modified') + drawDirectionArrow(targetRoof) } canvas.remove(obj) }) @@ -1980,6 +2865,10 @@ export function useModuleBasicSetting(tabNum) { const targetRoof = canvas.getObjects().filter((roof) => roof.name === POLYGON_TYPE.ROOF && roof.id === surface.parentId)[0] if (targetRoof) targetRoof.angle = -compasDeg surface.angle = -compasDeg + + targetRoof.fire('modified') + surface.fire('modified') + drawDirectionArrow(targetRoof) }) } canvas.renderAll() @@ -2043,131 +2932,158 @@ export function useModuleBasicSetting(tabNum) { /** * 스냅기능 */ - let snapDistance = 10 - let cellSnapDistance = 50 + let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 70 : 40 + let sideSnapDistance = 15 + let trestleSnapDistance = 15 - let intvHor = flowDirection === 'south' || flowDirection === 'north' ? 1 : 3 - let intvVer = flowDirection === 'south' || flowDirection === 'north' ? 3 : 1 + let intvVer = flowDirection === 'south' || flowDirection === 'north' ? 10 : 30 + let intvHor = flowDirection === 'south' || flowDirection === 'north' ? 30 : 10 - const trestleLeft = moduleSetupSurfaces[i].left - const trestleTop = moduleSetupSurfaces[i].top - const trestleRight = trestleLeft + moduleSetupSurfaces[i].width * moduleSetupSurfaces[i].scaleX - const trestleBottom = trestleTop + moduleSetupSurfaces[i].height * moduleSetupSurfaces[i].scaleY + const trestleLeft = toFixedWithoutRounding(moduleSetupSurfaces[i].left, 2) - toFixedWithoutRounding(moduleSetupSurfaces[i].width / 2, 2) + const trestleTop = toFixedWithoutRounding(moduleSetupSurfaces[i].top, 2) - toFixedWithoutRounding(moduleSetupSurfaces[i].height / 2, 2) + const trestleRight = + toFixedWithoutRounding(moduleSetupSurfaces[i].left, 2) + toFixedWithoutRounding(moduleSetupSurfaces[i].width / 2, 2) + const trestleBottom = + toFixedWithoutRounding(moduleSetupSurfaces[i].top, 2) + toFixedWithoutRounding(moduleSetupSurfaces[i].height / 2, 2) const bigCenterY = (trestleTop + trestleTop + moduleSetupSurfaces[i].height) / 2 - // 작은 폴리곤의 경계 좌표 계산 - const smallLeft = tempModule.left - const smallTop = tempModule.top - const smallRight = smallLeft + tempModule.width * tempModule.scaleX - const smallBottom = smallTop + tempModule.height * tempModule.scaleY - const smallCenterX = smallLeft + (tempModule.width * tempModule.scaleX) / 2 - const smallCenterY = smallTop + (tempModule.height * tempModule.scaleX) / 2 + // 이동하는 모듈의 경계 좌표 + const smallLeft = toFixedWithoutRounding(tempModule.left, 2) + const smallTop = toFixedWithoutRounding(tempModule.top, 2) + const smallRight = smallLeft + toFixedWithoutRounding(tempModule.width, 2) + const smallBottom = smallTop + toFixedWithoutRounding(tempModule.height, 2) + const smallCenterX = smallLeft + toFixedWithoutRounding(tempModule.width / 2, 2) + const smallCenterY = smallTop + toFixedWithoutRounding(tempModule.height / 2, 2) /** * 미리 깔아놓은 셀이 있을때 셀에 흡착됨 */ if (manualDrawModules) { manualDrawModules.forEach((cell) => { - const holdCellLeft = cell.left - const holdCellTop = cell.top - const holdCellRight = holdCellLeft + cell.width * cell.scaleX - const holdCellBottom = holdCellTop + cell.height * cell.scaleY - const holdCellCenterX = holdCellLeft + (cell.width * cell.scaleX) / 2 - const holdCellCenterY = holdCellTop + (cell.height * cell.scaleY) / 2 + const holdCellLeft = toFixedWithoutRounding(cell.left, 2) + const holdCellTop = toFixedWithoutRounding(cell.top, 2) + const holdCellRight = holdCellLeft + toFixedWithoutRounding(cell.width, 2) + const holdCellBottom = holdCellTop + toFixedWithoutRounding(cell.height, 2) + const holdCellCenterX = holdCellLeft + toFixedWithoutRounding(cell.width / 2, 2) + const holdCellCenterY = holdCellTop + toFixedWithoutRounding(cell.height / 2, 2) - //설치된 셀에 좌측에 스냅 - if (Math.abs(smallRight - holdCellLeft) < snapDistance) { - tempModule.left = holdCellLeft - width - intvHor - } + //흐름방향따라 달라야 한다. + if (flowDirection === 'south' || flowDirection === 'north') { + if (Math.abs(smallCenterX - holdCellCenterX) < snapDistance) { + //움직이는 모듈 가운데 -> 설치 모듈 가운데 + tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2) + } - //설치된 셀에 우측에 스냅 - if (Math.abs(smallLeft - holdCellRight) < snapDistance) { - tempModule.left = holdCellRight + intvHor - } + //설치된 셀에 좌측에 스냅 + if (Math.abs(smallRight - holdCellLeft) < snapDistance) { + // console.log('모듈 좌측 스냅') + tempModule.left = holdCellLeft - width - intvHor + } - //설치된 셀에 위쪽에 스냅 - if (Math.abs(smallBottom - holdCellTop) < snapDistance) { - tempModule.top = holdCellTop - height - intvVer - } + //설치된 셀에 우측에 스냅 + if (Math.abs(smallLeft - holdCellRight) < snapDistance) { + // console.log('모듈 우측 스냅') + tempModule.left = holdCellRight + intvHor + } + //설치된 셀에 위쪽에 스냅 + if (Math.abs(smallBottom - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop - height - intvVer + } - //설치된 셀에 밑쪽에 스냅 - if (Math.abs(smallTop - holdCellBottom) < snapDistance) { - tempModule.top = holdCellBottom + intvVer + //설치된 셀에 밑쪽에 스냅 + if (Math.abs(smallTop - holdCellBottom) < sideSnapDistance) { + tempModule.top = holdCellBottom + intvVer + } + + //설치된 셀에 윗쪽에 스냅 + if (Math.abs(smallTop - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop + } + } else { + //흐름방향 west, east + + //가운데 가운데 + if (Math.abs(smallCenterY - holdCellCenterY) < snapDistance) { + tempModule.top = holdCellCenterY - toFixedWithoutRounding(width / 2, 2) + } + + //위쪽 -> 가운데 + if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { + // console.log('holdCellCenterX', holdCellCenterX) + // console.log('smallLeft', smallLeft) + + // console.log('모듈 센터에 스냅') + tempModule.top = holdCellCenterY + intvHor / 2 + + // console.log('tempModule.left', tempModule.left) + } + // 밑 -> 가운데 + if (Math.abs(smallBottom - holdCellCenterY) < snapDistance) { + tempModule.top = holdCellCenterY - height - intvHor / 2 + } + + //설치된 셀에 좌측에 스냅 + if (Math.abs(smallRight - holdCellLeft) < snapDistance) { + // console.log('모듈 좌측 스냅') + tempModule.left = holdCellLeft - width - intvHor + } + + //설치된 셀에 우측에 스냅 + if (Math.abs(smallLeft - holdCellRight) < snapDistance) { + // console.log('모듈 우측 스냅') + tempModule.left = holdCellRight + intvHor + } + //설치된 셀에 위쪽에 스냅 + if (Math.abs(smallBottom - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop - height - intvVer + } + + //설치된 셀에 밑쪽에 스냅 + if (Math.abs(smallTop - holdCellBottom) < sideSnapDistance) { + tempModule.top = holdCellBottom + intvVer + } + + //설치된 셀에 윗쪽에 스냅 + if (Math.abs(smallTop - holdCellTop) < sideSnapDistance) { + tempModule.top = holdCellTop + } + + if (Math.abs(smallLeft - holdCellLeft) < snapDistance) { + tempModule.left = holdCellLeft + } } - //가운데 -> 가운데 - if (Math.abs(smallCenterX - holdCellCenterX) < cellSnapDistance) { - tempModule.left = holdCellCenterX - width / 2 - } - //왼쪽 -> 가운데 - if (Math.abs(smallLeft - holdCellCenterX) < cellSnapDistance) { - tempModule.left = holdCellCenterX - } - // 오른쪽 -> 가운데 - if (Math.abs(smallRight - holdCellCenterX) < cellSnapDistance) { - tempModule.left = holdCellCenterX - width - } - //세로 가운데 -> 가운데 - if (Math.abs(smallCenterY - holdCellCenterY) < cellSnapDistance) { - tempModule.top = holdCellCenterY - height / 2 - } - // //위쪽 -> 가운데 - // if (Math.abs(smallTop - holdCellCenterY) < cellSnapDistance) { - // tempModule.top = holdCellCenterY - // } - // //아랫쪽 -> 가운데 - // if (Math.abs(smallBottom - holdCellCenterY) < cellSnapDistance) { - // tempModule.top = holdCellCenterY - height - // } }) } // 위쪽 변에 스냅 - if (Math.abs(smallTop - trestleTop) < snapDistance) { - tempModule.top = trestleTop + if (Math.abs(smallTop - trestleTop) < trestleSnapDistance) { + tempModule.top = trestleTop + 1 } // 아래쪽 변에 스냅 - if (Math.abs(smallTop + tempModule.height * tempModule.scaleY - (trestleTop + moduleSetupSurfaces[i].height)) < snapDistance) { - tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height * tempModule.scaleY + if (Math.abs(smallBottom - trestleBottom) < trestleSnapDistance) { + tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height - 1 } // 왼쪽변에 스냅 - if (Math.abs(smallLeft - trestleLeft) < snapDistance) { - tempModule.left = trestleLeft + if (Math.abs(smallLeft - trestleLeft) < trestleSnapDistance) { + tempModule.left = trestleLeft + 1 } //오른쪽 변에 스냅 - if (Math.abs(smallRight - trestleRight) < snapDistance) { - tempModule.left = trestleRight - tempModule.width * tempModule.scaleX + if (Math.abs(smallRight - trestleRight) < trestleSnapDistance) { + tempModule.left = trestleRight - tempModule.width - 1 } if (flowDirection === 'south' || flowDirection === 'north') { - // 모듈왼쪽이 세로중앙선에 붙게 스냅 - if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) { - tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - } - // 모듈이 가운데가 세로중앙선에 붙게 스냅 - if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) { - tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - (tempModule.width * tempModule.scaleX) / 2 - } - - // 모듈오른쪽이 세로중앙선에 붙게 스냅 - if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) { - tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX + if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) { + tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width / 2 } } else { // 모듈이 가로중앙선에 스냅 - if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < snapDistance) { + if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < trestleSnapDistance) { tempModule.top = bigCenterY - tempModule.height / 2 } - - if (Math.abs(smallTop - (trestleTop + moduleSetupSurfaces[i].height / 2)) < snapDistance) { - tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2 - } - // 모듈 밑면이 가로중앙선에 스냅 - if (Math.abs(smallBottom - (trestleTop + moduleSetupSurfaces[i].height / 2)) < snapDistance) { - tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2 - tempModule.height * tempModule.scaleY - } } tempModule.setCoords() @@ -2326,6 +3242,7 @@ export function useModuleBasicSetting(tabNum) { targetRoof.setCoords() targetSurface.setCoords() moduleSetupSurfaces.push(targetSurface) + drawDirectionArrow(targetSurface) } canvas.remove(obj) }) @@ -2334,6 +3251,10 @@ export function useModuleBasicSetting(tabNum) { const targetRoof = canvas.getObjects().filter((roof) => roof.name === POLYGON_TYPE.ROOF && roof.id === surface.parentId)[0] if (targetRoof) targetRoof.angle = -compasDeg surface.angle = -compasDeg + + targetRoof.fire('modified') + surface.fire('modified') + drawDirectionArrow(surface) }) } canvas.renderAll() @@ -2416,8 +3337,6 @@ export function useModuleBasicSetting(tabNum) { return turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface) } - let moduleGroup = [] - const flatRoofDownFlowSetupModule = ( surfaceMaxLines, maxLengthLine, @@ -2689,11 +3608,13 @@ export function useModuleBasicSetting(tabNum) { selectedModules, makeModuleInstArea, manualModuleSetup, + manualModuleLayoutSetup, autoModuleSetup, restoreModuleInstArea, manualFlatroofModuleSetup, autoFlatroofModuleSetup, checkModuleDisjointObjects, makeModuleInitArea, + roofOutlineColor, } } diff --git a/src/hooks/module/useModuleSelection.js b/src/hooks/module/useModuleSelection.js index 8fa274a4..1373ea05 100644 --- a/src/hooks/module/useModuleSelection.js +++ b/src/hooks/module/useModuleSelection.js @@ -19,9 +19,9 @@ export function useModuleSelection(props) { const [moduleList, setModuleList] = useState([{}]) //모듈 목록 const [selectedSurfaceType, setSelectedSurfaceType] = useState({}) //선택된 면조도 - const [installHeight, setInstallHeight] = useState() //설치 높이 - const [standardWindSpeed, setStandardWindSpeed] = useState({}) //기준풍속 - const [verticalSnowCover, setVerticalSnowCover] = useState() //수직적설량 + const [installHeight, setInstallHeight] = useState(managementState?.installHeight) //설치 높이 + const [standardWindSpeed, setStandardWindSpeed] = useState() //기준풍속 + const [verticalSnowCover, setVerticalSnowCover] = useState(managementState?.verticalSnowCover) //수직적설량 const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //선택된 모듈 const [moduleSelectionInitParams, setModuleSelectionInitParams] = useRecoilState(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등 @@ -32,6 +32,7 @@ export function useModuleSelection(props) { const { restoreModuleInstArea } = useModuleBasicSetting() const bindInitData = () => { + console.log('bindInitData', managementState) setInstallHeight(managementState?.installHeight) setStandardWindSpeed(managementState?.standardWindSpeedId) setVerticalSnowCover(managementState?.verticalSnowCover) @@ -184,14 +185,6 @@ export function useModuleSelection(props) { }) } - useEffect(() => { - // console.log('installHeight', installHeight) - }, [installHeight]) - - useEffect(() => { - // console.log('verticalSnowCover', verticalSnowCover) - }, [verticalSnowCover]) - //TODO: 설치높이, 기준적설량 debounce 적용해서 추가해야됨 // useEffect(() => { @@ -226,11 +219,17 @@ export function useModuleSelection(props) { roughnessCodes, windSpeedCodes, managementState, + setManagementState, moduleList, + setSelectedModules, selectedSurfaceType, + setSelectedSurfaceType, installHeight, + setInstallHeight, standardWindSpeed, + setStandardWindSpeed, verticalSnowCover, + setVerticalSnowCover, handleChangeModule, handleChangeSurfaceType, handleChangeWindSpeed, diff --git a/src/hooks/module/useModuleTrestle.js b/src/hooks/module/useModuleTrestle.js new file mode 100644 index 00000000..178054ef --- /dev/null +++ b/src/hooks/module/useModuleTrestle.js @@ -0,0 +1,244 @@ +import { use, useContext, useEffect, useReducer, useState } from 'react' +import { useCommonCode } from '../common/useCommonCode' +import { useMasterController } from '../common/useMasterController' +import { selectedModuleState } from '@/store/selectedModuleOptions' +import { useRecoilValue } from 'recoil' +import { GlobalDataContext } from '@/app/GlobalDataProvider' + +const RAFT_BASE_CODE = '203800' + +const trestleReducer = (state, action) => { + console.log('🚀 ~ trestleReducer ~ state:', state) + console.log('🚀 ~ trestleReducer ~ action:', action) + switch (action.type) { + case 'SET_RAFT_BASE': + case 'SET_TRESTLE_MAKER': + case 'SET_CONST_MTHD': + case 'SET_ROOF_BASE': + case 'SET_CONSTRUCTION': + case 'SET_TRESTLE_DETAIL': + return { + ...action.roof, + } + case 'SET_INITIALIZE': + console.log('SET_INITIALIZE') + return { + moduleTpCd: action.roof.moduleTpCd ?? '', + roofMatlCd: action.roof.roofMatlCd ?? '', + raftBaseCd: action.roof.raftBaseCd ?? null, + trestleMkrCd: action.roof.trestleMkrCd ?? null, + constMthdCd: action.roof.constMthdCd ?? null, + constTp: action.roof.constTp ?? null, + roofBaseCd: action.roof.roofBaseCd ?? null, + workingWidth: action.roof.workingWidth ?? 0, + lengthBase: action.roof.length ?? 0, + illuminationTp: action.roof.illuminationTp ?? null, + instHt: action.roof.instHt ?? null, + stdWindSpeed: action.roof.stdWindSpeed ?? null, + stdSnowLd: action.roof.stdSnowLd ?? null, + inclCd: action.roof.inclCd ?? null, + roofPitch: action.roof.roofPchBase ?? 0, + eavesMargin: action.roof.eavesMargin ?? null, + ridgeMargin: action.roof.ridgeMargin ?? null, + kerabaMargin: action.roof.kerabaMargin ?? null, + } + default: + return state + } +} + +export function useModuleTrestle(props) { + const { selectedRoof } = props + const { findCommonCode } = useCommonCode() + const [raftBaseList, setRaftBaseList] = useState([]) + const [trestleList, setTrestleList] = useState([]) + const [constMthdList, setConstMthdList] = useState([]) + const [roofBaseList, setRoofBaseList] = useState([]) + const [constructionList, setConstructionList] = useState([]) + const { getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController() + const [cvrYn, setCvrYn] = useState('N') + const [cvrChecked, setCvrChecked] = useState(false) + const [snowGdPossYn, setSnowGdPossYn] = useState('N') + const [snowGdChecked, setSnowGdChecked] = useState(false) + const [eavesMargin, setEavesMargin] = useState(0) + const [ridgeMargin, setRidgeMargin] = useState(0) + const [kerabaMargin, setKerabaMargin] = useState(0) + const [trestleState, dispatch] = useReducer(trestleReducer, null) + const [trestleDetail, setTrestleDetail] = useState(null) + + useEffect(() => { + const raftCodeList = findCommonCode(RAFT_BASE_CODE) + + setRaftBaseList(raftCodeList) + setTrestleList([]) + setConstMthdList([]) + setRoofBaseList([]) + setConstructionList([]) + setEavesMargin(selectedRoof?.eavesMargin ?? 0) + setRidgeMargin(selectedRoof?.ridgeMargin ?? 0) + setKerabaMargin(selectedRoof?.kerabaMargin ?? 0) + setCvrYn(selectedRoof?.cvrYn ?? 'N') + setCvrChecked(selectedRoof?.cvrChecked ?? false) + setSnowGdPossYn(selectedRoof?.snowGdPossYn ?? 'N') + setSnowGdChecked(selectedRoof?.snowGdChecked ?? false) + }, [selectedRoof]) + + useEffect(() => { + if (trestleState) { + console.log('🚀 ~ useEffect ~ trestleState:', trestleState) + handleSetTrestleList() + if (!trestleState.trestleMkrCd) { + setConstMthdList([]) + setRoofBaseList([]) + setConstructionList([]) + setTrestleDetail(null) + return + } + + handleSetConstMthdList() + if (!trestleState.constMthdCd) { + setRoofBaseList([]) + setConstructionList([]) + setTrestleDetail(null) + return + } + + handleSetRoofBaseList() + if (!trestleState.roofBaseCd) { + setConstructionList([]) + setTrestleDetail(null) + return + } + + handleSetConstructionList() + if (!trestleState.constTp) { + setTrestleDetail(null) + return + } + + if (!trestleState.eavesMargin) { + handleSetTrestleDetailData() + } + } + }, [trestleState]) + + const handleSetTrestleList = () => { + getTrestleList({ + moduleTpCd: trestleState.moduleTpCd ?? '', + roofMatlCd: trestleState.roofMatlCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + }).then((res) => { + if (res?.data) setTrestleList(res.data) + }) + } + + const handleSetConstMthdList = () => { + getTrestleList({ + moduleTpCd: trestleState.moduleTpCd ?? '', + roofMatlCd: trestleState.roofMatlCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + trestleMkrCd: trestleState.trestleMkrCd ?? '', + }).then((res) => { + if (res?.data) setConstMthdList(res.data) + }) + } + + const handleSetRoofBaseList = () => { + getTrestleList({ + moduleTpCd: trestleState.moduleTpCd ?? '', + roofMatlCd: trestleState.roofMatlCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + trestleMkrCd: trestleState.trestleMkrCd ?? '', + constMthdCd: trestleState.constMthdCd ?? '', + }).then((res) => { + if (res?.data) setRoofBaseList(res.data) + }) + } + + const handleSetConstructionList = () => { + getConstructionList({ + moduleTpCd: trestleState.moduleTpCd ?? '', + roofMatlCd: trestleState.roofMatlCd ?? '', + trestleMkrCd: trestleState.trestleMkrCd ?? '', + constMthdCd: trestleState.constMthdCd ?? '', + roofBaseCd: trestleState.roofBaseCd ?? '', + illuminationTp: trestleState.illuminationTp ?? '', + instHt: trestleState.instHt ?? '', + stdWindSpeed: trestleState.stdWindSpeed ?? '', + stdSnowLd: trestleState.stdSnowLd ?? '', + inclCd: trestleState.inclCd ?? '', + raftBaseCd: trestleState.raftBaseCd ?? '', + roofPitch: trestleState.roofPitch ?? '', + }).then((res) => { + if (res?.data) setConstructionList(res.data) + }) + } + + const handleSetTrestleDetailData = () => { + getTrestleDetailList([ + { + moduleTpCd: trestleState.moduleTpCd ?? '', + roofMatlCd: trestleState.roofMatlCd ?? '', + trestleMkrCd: trestleState.trestleMkrCd ?? '', + constMthdCd: trestleState.constMthdCd ?? '', + roofBaseCd: trestleState.roofBaseCd ?? '', + illuminationTp: trestleState.illuminationTp ?? '', + instHt: trestleState.instHt ?? '', + stdWindSpeed: trestleState.stdWindSpeed ?? '', + stdSnowLd: trestleState.stdSnowLd ?? '', + inclCd: trestleState.inclCd ?? '', + constTp: trestleState.constTp ?? '', + mixMatlNo: trestleState.mixMatlNo ?? '', + roofPitch: trestleState.roofPitch ?? '', + workingWidth: trestleState.workingWidth ?? '', + }, + ]).then((res) => { + if (res.length > 0) { + if (!res[0].data) return + setEavesMargin(res[0].data.eaveIntvl) + setRidgeMargin(res[0].data.ridgeIntvl) + setKerabaMargin(res[0].data.kerabaIntvl) + setTrestleDetail(res[0].data) + // dispatch({ + // type: 'SET_TRESTLE_DETAIL', + // roof: { + // ...trestleState, + // eavesMargin: res[0].data.eaveIntvl, + // ridgeMargin: res[0].data.ridgeIntvl, + // kerabaMargin: res[0].data.kerabaIntvl, + // }, + // }) + } + }) + } + + return { + trestleState, + trestleDetail, + dispatch, + raftBaseList, + trestleList, + constMthdList, + roofBaseList, + constructionList, + handleSetTrestleList, + handleSetConstMthdList, + handleSetRoofBaseList, + handleSetConstructionList, + handleSetTrestleDetailData, + eavesMargin, + ridgeMargin, + kerabaMargin, + setEavesMargin, + setRidgeMargin, + setKerabaMargin, + cvrYn, + cvrChecked, + snowGdPossYn, + snowGdChecked, + setCvrYn, + setCvrChecked, + setSnowGdPossYn, + setSnowGdChecked, + } +} diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index 01e9ec8b..ecb8ee55 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -370,7 +370,20 @@ export const useTrestle = () => { rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp && rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) ) - } else { + } else if (leftRowsInfo.rowsInfo.length >= 2) { + //C1C2C3인 경우 + if (rack.value.moduleTpCd.length === 6) { + // 변환 C1C2만 있는경우 C3 0개로 추가해준다. + let newLeftRowsInfo = normalizeModules(rack.value.moduleTpCd, leftRowsInfo) + + return ( + rack.value.moduleTpCd === newLeftRowsInfo.moduleTotalTp && + rack.value.moduleRows === newLeftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && + Number(rack.value.moduleTpRows1) === newLeftRowsInfo.rowsInfo[0].count && + Number(rack.value.moduleTpRows2) === newLeftRowsInfo.rowsInfo[1].count && + Number(rack.value.moduleTpRows3) === newLeftRowsInfo.rowsInfo[2].count + ) + } return ( rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp && rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && @@ -387,7 +400,19 @@ export const useTrestle = () => { rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp && rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) ) - } else { + } else if (rightRowsInfo.rowsInfo.length === 2) { + if (rack.value.moduleTpCd.length === 6) { + // 변환 C1C2만 있는경우 C3 0개로 추가해준다. + let newRightRowsInfo = normalizeModules(rack.value.moduleTpCd, rightRowsInfo) + + return ( + rack.value.moduleTpCd === newRightRowsInfo.moduleTotalTp && + rack.value.moduleRows === newRightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && + Number(rack.value.moduleTpRows1) === newRightRowsInfo.rowsInfo[0].count && + Number(rack.value.moduleTpRows2) === newRightRowsInfo.rowsInfo[1].count && + Number(rack.value.moduleTpRows3) === newRightRowsInfo.rowsInfo[2].count + ) + } return ( rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp && rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && @@ -404,7 +429,19 @@ export const useTrestle = () => { rack.value.moduleTpCd === centerRowsInfo.moduleTotalTp && rack.value.moduleRows === centerRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) ) - } else { + } else if (centerRowsInfo.rowsInfo.length === 2) { + if (rack.value.moduleTpCd.length === 6) { + // 변환 C1C2만 있는경우 C3 0개로 추가해준다. + let newCenterRowsInfo = normalizeModules(rack.value.moduleTpCd, centerRowsInfo) + + return ( + rack.value.moduleTpCd === newCenterRowsInfo.moduleTotalTp && + rack.value.moduleRows === newCenterRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && + Number(rack.value.moduleTpRows1) === newCenterRowsInfo.rowsInfo[0].count && + Number(rack.value.moduleTpRows2) === newCenterRowsInfo.rowsInfo[1].count && + Number(rack.value.moduleTpRows3) === newCenterRowsInfo.rowsInfo[2].count + ) + } return ( rack.value.moduleTpCd === centerRowsInfo.moduleTotalTp && rack.value.moduleRows === centerRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && @@ -499,7 +536,19 @@ export const useTrestle = () => { rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp && rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) ) - } else { + } else if (leftRowsInfo.rowsInfo.length === 2) { + if (rack.value.moduleTpCd.length === 6) { + // 변환 C1C2만 있는경우 C3 0개로 추가해준다. + let newLeftRowsInfo = normalizeModules(rack.value.moduleTpCd, leftRowsInfo) + + return ( + rack.value.moduleTpCd === newLeftRowsInfo.moduleTotalTp && + rack.value.moduleRows === newLeftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && + Number(rack.value.moduleTpRows1) === newLeftRowsInfo.rowsInfo[0].count && + Number(rack.value.moduleTpRows2) === newLeftRowsInfo.rowsInfo[1].count && + Number(rack.value.moduleTpRows3) === newLeftRowsInfo.rowsInfo[2].count + ) + } return ( rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp && rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && @@ -575,7 +624,19 @@ export const useTrestle = () => { rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp && rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) ) - } else { + } else if (rightRowsInfo.rowsInfo.length === 2) { + if (rack.value.moduleTpCd.length === 6) { + // 변환 C1C2만 있는경우 C3 0개로 추가해준다. + let newRightRowsInfo = normalizeModules(rack.value.moduleTpCd, rightRowsInfo) + + return ( + rack.value.moduleTpCd === newRightRowsInfo.moduleTotalTp && + rack.value.moduleRows === newRightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && + Number(rack.value.moduleTpRows1) === newRightRowsInfo.rowsInfo[0].count && + Number(rack.value.moduleTpRows2) === newRightRowsInfo.rowsInfo[1].count && + Number(rack.value.moduleTpRows3) === newRightRowsInfo.rowsInfo[2].count + ) + } return ( rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp && rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) && @@ -635,6 +696,31 @@ export const useTrestle = () => { return { moduleTotalTp, rowsInfo } } + function normalizeModules(rackTpCd, data) { + // rackTpCd를 숫자를 기준으로 자른다. + const allModules = rackTpCd.match(/[A-Za-z]+\d+/g) || [] // 모든 모듈 유형 + + // 현재 존재하는 모듈 유형을 추출 + const existingModules = data.rowsInfo.map((row) => row.moduleTpCd) + + const result = { ...data, rowsInfo: [...data.rowsInfo] } + + // 없는 모듈을 추가 (count: 0) + allModules.forEach((module) => { + if (!existingModules.includes(module)) { + result.rowsInfo.push({ moduleTpCd: module, count: 0 }) + } + }) + + // rowsInfo를 C1, C2, C3 순서로 정렬 + result.rowsInfo.sort((a, b) => allModules.indexOf(a.moduleTpCd) - allModules.indexOf(b.moduleTpCd)) + + // moduleTotalTp를 C1C2C3로 설정 + result.moduleTotalTp = allModules.join('') + + return result + } + // itemList 조회 후 estimateParam에 저장 const getEstimateData = async () => { const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) diff --git a/src/locales/ja.json b/src/locales/ja.json index 1122d3d7..2bfc9da2 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -138,6 +138,7 @@ "modal.module.basic.setting.pitch.module.column.amount": "列数", "modal.module.basic.setting.pitch.module.column.margin": "左右間隔", "modal.module.basic.setting.prev": "前に戻る", + "modal.module.basic.setting.row.batch": "単数指定配置", "modal.module.basic.setting.passivity.placement": "手動配置", "modal.module.basic.setting.auto.placement": "自動配置", "plan.menu.module.circuit.setting.circuit.trestle.setting": "回路設定", @@ -603,7 +604,6 @@ "myinfo.message.password.error": "パスワードが間違っています。", "login": "ログイン", "login.auto.page.text": "自動ログイン中です。", - "login.fail": "アカウントが存在しないか、パスワードが間違っています。", "login.id.save": "ID保存", "login.id.placeholder": "IDを入力してください。", "login.password.placeholder": "パスワードを入力してください。", @@ -1046,6 +1046,7 @@ "outerLine.property.fix": "外壁線の属性設定 を完了しますか?", "outerLine.property.close": "外壁線の属性設定 を終了しますか?", "want.to.complete.auxiliary.creation": "補助線の作成を完了しますか?", + "module.layout.setup.has.zero.value": "モジュールの列、行を入力してください.", "modal.placement.initial.setting.plan.drawing.only.number": "(※数字は[半角]入力のみ可能です。)", "wall.line.not.found": "外壁がありません", "roof.line.not.found": "屋根形状がありません", @@ -1053,5 +1054,11 @@ "chidory.can.not.install": "千鳥配置できない工法です。", "module.layout.setup.max.count": "모듈의 최대 단수는 {0}, 최대 열수는 {1} 입니다. (JA)", "module.layout.setup.max.count.multiple": "모듈 {0}번의 최대 단수는 {1}, 최대 열수는 {2} 입니다. (JA)", - "roofAllocation.not.found": "할당할 지붕이 없습니다. (JA)" + "roofAllocation.not.found": "할당할 지붕이 없습니다. (JA)", + "modal.module.basic.setting.module.placement.max.size.check": "지붕재별 모듈의 최대 단수. 혼합 최대 단수를 확인하십시오. (JA)", + "modal.module.basic.setting.module.placement.max.row": "최대 단수 (JA)", + "modal.module.basic.setting.module.placement.max.rows.multiple": "혼합 단수 (JA)", + "modal.module.basic.setting.module.placement.mix.asg.yn.error": "혼합 설치 불가능한 모듈입니다. (JA)", + "modal.module.basic.setting.module.placement.mix.asg.yn": "ミックス. (JA)", + "modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)" } diff --git a/src/locales/ko.json b/src/locales/ko.json index abd8594b..ecd38036 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1047,6 +1047,7 @@ "outerLine.property.fix": "외벽선 속성 설정을 완료하시겠습니까?", "outerLine.property.close": "외벽선 속성 설정을 종료하시겠습니까?", "want.to.complete.auxiliary.creation": "보조선 작성을 완료하시겠습니까?", + "module.layout.setup.has.zero.value": "모듈의 열, 행을 입력해 주세요.", "modal.placement.initial.setting.plan.drawing.only.number": "(※ 숫자는 [반각]입력만 가능합니다.)", "wall.line.not.found": "외벽선이 없습니다.", "roof.line.not.found": "지붕형상이 없습니다.", @@ -1054,5 +1055,11 @@ "chidory.can.not.install": "치조 불가 공법입니다.", "module.layout.setup.max.count": "모듈의 최대 단수는 {0}, 최대 열수는 {1} 입니다.", "module.layout.setup.max.count.multiple": "모듈 {0}번의 최대 단수는 {1}, 최대 열수는 {2} 입니다.", - "roofAllocation.not.found": "할당할 지붕이 없습니다." + "roofAllocation.not.found": "할당할 지붕이 없습니다.", + "modal.module.basic.setting.module.placement.max.size.check": "지붕재별 모듈의 최대 단수. 혼합 최대 단수를 확인하십시오.", + "modal.module.basic.setting.module.placement.max.row": "최대 단수", + "modal.module.basic.setting.module.placement.max.rows.multiple": "혼합 단수", + "modal.module.basic.setting.module.placement.mix.asg.yn.error": "혼합 설치 불가능한 모듈입니다.", + "modal.module.basic.setting.module.placement.mix.asg.yn": "혼합", + "modal.module.basic.setting.layoutpassivity.placement": "레이아웃 배치" } diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index ddeed03d..c8bb1ad0 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -384,3 +384,27 @@ export const isManualModuleSetupState = atom({ key: 'isManualModuleSetupState', default: false, }) + +export const isManualModuleLayoutSetupState = atom({ + key: 'isManualModuleLayoutSetupState', + default: false, +}) + +export const moduleSetupOptionState = atom({ + key: 'moduleSetupOptionState', + default: { + isChidori: false, //치조 안함 + setupLocation: 'eaves', //처마 + }, +}) + +export const toggleManualSetupModeState = atom({ + key: 'toggleManualSetupModeState', + default: '', +}) + +export const moduleRowColArrayState = atom({ + key: 'moduleRowColArrayState', + default: [], + dangerouslyAllowMutability: true, +}) diff --git a/src/store/roofAtom.js b/src/store/roofAtom.js new file mode 100644 index 00000000..36f35b6c --- /dev/null +++ b/src/store/roofAtom.js @@ -0,0 +1,7 @@ +import { atom } from 'recoil' + +export const roofsState = atom({ + key: 'roofs', + default: null, + dangerouslyAllowMutability: true, +}) diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index fab3eb04..ac0d2f73 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -383,7 +383,7 @@ button{ } } &::-webkit-scrollbar { - width: 2px; + width: 5px; background-color: transparent; }