diff --git a/src/app/layout.js b/src/app/layout.js index fbe6c39a..3383aa10 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -55,6 +55,10 @@ export default async function RootLayout({ children }) { redirect('/login') } + if (headerPathname === '/login' && session.isLoggedIn) { + redirect('/') + } + return ( diff --git a/src/common/common.js b/src/common/common.js index 9bf6d367..e2e31889 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -159,6 +159,7 @@ export const SAVE_KEY = [ 'offset', 'arrow', 'surfaceCompass', + 'surfaceCompassType', 'moduleCompass', 'isFixed', 'modules', diff --git a/src/components/Main.jsx b/src/components/Main.jsx index 29d1305a..1a436582 100644 --- a/src/components/Main.jsx +++ b/src/components/Main.jsx @@ -13,14 +13,14 @@ import ChangePasswordPop from './main/ChangePasswordPop' import { searchState } from '@/store/boardAtom' import { SessionContext } from '@/app/SessionProvider' import { QcastContext } from '@/app/QcastProvider' +import { sessionStore } from '@/store/commonAtom' +import { isObjectNotEmpty } from '@/util/common-utils' -export default function MainPage() { +export default function MainPage(mainPageProps) { + const [sessionState, setSessionState] = useRecoilState(sessionStore) const [chagePasswordPopOpen, setChagePasswordPopOpen] = useState(false) const { session } = useContext(SessionContext) - const globalLocaleState = useRecoilValue(globalLocaleStore) - - const { promiseGet } = useAxios(globalLocaleState) const router = useRouter() const { getMessage } = useMessage() @@ -74,10 +74,12 @@ export default function MainPage() { } useEffect(() => { - if (session?.pwdInitYn !== 'Y') { - setChagePasswordPopOpen(true) + if (isObjectNotEmpty(sessionState)) { + if (sessionState?.pwdInitYn !== 'Y') { + setChagePasswordPopOpen(true) + } } - }, [session]) + }, [sessionState]) return ( <> diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index a908ba0f..e3d185ec 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -8,6 +8,7 @@ import { FaAnglesDown } from 'react-icons/fa6' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' +import { useMasterController } from '@/hooks/common/useMasterController' import { convertDwgToPng } from '@/lib/cadAction' import { cadFileNameState, googleMapFileNameState, useCadFileState, useGoogleMapFileState } from '@/store/canvasAtom' @@ -35,6 +36,7 @@ export default function Playground() { const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL const { getMessage } = useMessage() const { swalFire } = useSwal() + const { getRoofMaterialList, getModuleTypeItemList } = useMasterController() const [color, setColor] = useState('#ff0000') @@ -156,6 +158,24 @@ export default function Playground() { <>
이 영역은 테스트입니다.
+
+ + +
) })} @@ -1191,7 +1196,6 @@ export default function Estimate({ params }) { {originFiles.map((originFile) => { return (
  • - {/*
  • */}
    0 && specialNoteList.map((row) => { return ( - //
    diff --git a/src/components/estimate/EstimateFileUploader.jsx b/src/components/estimate/EstimateFileUploader.jsx index cda14e24..950ed6af 100644 --- a/src/components/estimate/EstimateFileUploader.jsx +++ b/src/components/estimate/EstimateFileUploader.jsx @@ -1,14 +1,12 @@ 'use client' -import { useContext, useRef } from 'react' +import { useRef } from 'react' import { v4 as uuidv4 } from 'uuid' import { useMessage } from '@/hooks/useMessage' -import { SessionContext } from '@/app/SessionProvider' export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { const fileInputRef = useRef(null) const { getMessage } = useMessage() - const { session } = useContext(SessionContext) const handleButtonClick = (e) => { e.preventDefault() @@ -20,13 +18,32 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { return } - const { files } = e.target - const file = files[0] - const fileType = file.type - if (!fileType.includes('image')) { - return alert(getMessage('estimate.detail.fileList.extCheck')) + const fileList = [] + let passFlag = true + Array.from(e.target.files).forEach((file) => { + let fileType = file.type + if (!fileType.includes('image')) { + passFlag = false + } else { + fileList.push({ data: file, id: uuidv4() }) + } + }) + + if (!passFlag) { + alert(getMessage('estimate.detail.fileList.extCheck')) } + // const { files } = e.target + // const file = files[0] + // const fileType = file.type + // if (!fileType.includes('image')) { + // return alert(getMessage('estimate.detail.fileList.extCheck')) + // } + + // setUploadFiles([...uploadFiles, { data: e.target.files[0], id: uuidv4() }]) + //다중으로 변경 + setUploadFiles([...uploadFiles, ...fileList]) + e.target.value = '' // const formData = new FormData() // formData.append('file', e.target.files[0]) // formData.append('objectNo', objectNo) // 받아와야 하는 값 @@ -37,8 +54,6 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { // await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => { // if (res.data > 0) setUploadFiles([...files, { name: e.target.files[0].name, id: uuidv4() }]) // }) - setUploadFiles([...uploadFiles, { data: e.target.files[0], id: uuidv4() }]) - e.target.value = '' } const deleteFile = (id) => { @@ -49,9 +64,21 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { e.preventDefault() e.stopPropagation() const fileList = [] + let passFlag = true + Array.from(e.dataTransfer.files).forEach((file) => { - fileList.push({ data: file, id: uuidv4() }) + let fileType = file.type + if (!fileType.includes('image')) { + passFlag = false + } else { + fileList.push({ data: file, id: uuidv4() }) + } }) + + if (!passFlag) { + alert(getMessage('estimate.detail.fileList.extCheck')) + } + setUploadFiles([...uploadFiles, ...fileList]) } @@ -76,7 +103,16 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { - onChangeFiles(e)} /> + onChangeFiles(e)} + />
    { setMenuNumber(menu.index) setCurrentMenu(menu.title) @@ -241,6 +245,16 @@ export default function CanvasMenu(props) { }) } + useEffect(() => { + if (isObjectNotEmpty(estimateRecoilState)) { + if (estimateRecoilState?.createUser === 'T01') { + if (sessionState.userId !== 'T01') { + setButtonStyle('none') + } + } + } + }, [estimateRecoilState]) + return (
    num === menuNumber) ? 'active' : ''}`}>
    @@ -320,11 +334,12 @@ export default function CanvasMenu(props) { {getMessage('plan.menu.estimate.docDown')} - )} - diff --git a/src/components/floor-plan/modal/basic/step/pitch/PitchPlacement.jsx b/src/components/floor-plan/modal/basic/step/pitch/PitchPlacement.jsx index 7b00478e..d14bf0cc 100644 --- a/src/components/floor-plan/modal/basic/step/pitch/PitchPlacement.jsx +++ b/src/components/floor-plan/modal/basic/step/pitch/PitchPlacement.jsx @@ -1,17 +1,17 @@ import { forwardRef, useState, useEffect } from 'react' import { useMessage } from '@/hooks/useMessage' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' -import { compasDegAtom } from '@/store/orientationAtom' import { canvasState } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' import { POLYGON_TYPE } from '@/common/common' +import { useEvent } from '@/hooks/useEvent' const PitchPlacement = forwardRef((props, refs) => { const { getMessage } = useMessage() const [setupLocation, setSetupLocation] = useState('south') const { makeModuleInstArea } = useModuleBasicSetting() - const compasDeg = useRecoilValue(compasDegAtom) const canvas = useRecoilValue(canvasState) + const { initEvent } = useEvent() useEffect(() => { makeModuleInstArea() @@ -45,6 +45,7 @@ const PitchPlacement = forwardRef((props, refs) => { } const handleSetupLocation = (e) => { + initEvent() refs.setupLocation.current = e.target setSetupLocation(e.target.value) } @@ -153,7 +154,7 @@ const PitchPlacement = forwardRef((props, refs) => { value={'south'} checked={setupLocation === 'south'} defaultChecked - onChange={handleSetupLocation} + onClick={handleSetupLocation} />
    @@ -164,7 +165,7 @@ const PitchPlacement = forwardRef((props, refs) => { id="ra02" value={'excreta'} checked={setupLocation === 'excreta'} - onChange={handleSetupLocation} + onClick={handleSetupLocation} />
    diff --git a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx index da49b07c..8e072e18 100644 --- a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx +++ b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx @@ -5,9 +5,14 @@ import { useRecoilValue } from 'recoil' import { contextPopupPositionState } from '@/store/popupAtom' import { useMessage } from '@/hooks/useMessage' import { usePopup } from '@/hooks/usePopup' -import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' -import { FLOW_DIRECTION_TYPE, useFlowDirectionSetting } from '@/hooks/contextpopup/useFlowDirectionSetting' import { canvasState } from '@/store/canvasAtom' +import { usePolygon } from '@/hooks/usePolygon' + +const FLOW_DIRECTION_TYPE = { + EIGHT_AZIMUTH: 'eightAzimuth', + TWENTY_FOUR_AZIMUTH: 'twentyFourAzimuth', +} + export default function FlowDirectionSetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, pos = contextPopupPosition, target } = props @@ -20,10 +25,9 @@ export default function FlowDirectionSetting(props) { } }, []) - const [compasDeg, setCompasDeg] = useState(null) + const [compasDeg, setCompasDeg] = useState(target.surfaceCompass ?? null) const [flowDirection, setFlowDirection] = useState(target.direction) const { closePopup } = usePopup() - const { changeSurfaceFlowDirection, type, setType } = useFlowDirectionSetting(id) const orientations = [ { name: `${getMessage('commons.none')}`, value: 0 }, @@ -36,7 +40,27 @@ export default function FlowDirectionSetting(props) { { name: `${getMessage('commons.north')}${getMessage('commons.west')}`, value: 135 }, { name: `${getMessage('commons.north')}`, value: 180 }, ] - const [selectedOrientation, setSelectedOrientation] = useState(orientations[0]) + + const { drawDirectionArrow } = usePolygon() + + const [type, setType] = useState(target.surfaceCompassType ?? FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH) + + const changeSurfaceFlowDirection = (roof, direction, orientation) => { + roof.set({ + direction: direction, + surfaceCompass: orientation, + surfaceCompassType: type, + }) + drawDirectionArrow(roof) + canvas?.renderAll() + closePopup(id) + } + + const [selectedOrientation, setSelectedOrientation] = useState( + target.surfaceCompassType !== null && target.surfaceCompassType === FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH + ? orientations.find((item) => item.value === target.surfaceCompass) + : orientations[0], + ) return ( @@ -84,9 +108,8 @@ export default function FlowDirectionSetting(props) {
    { setType(FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH) setSelectedOrientation(e) @@ -116,7 +139,7 @@ export default function FlowDirectionSetting(props) { {Array.from({ length: 180 / 15 + 1 }).map((dot, index) => (
    { setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH) setCompasDeg(15 * (12 + index)) @@ -126,7 +149,7 @@ export default function FlowDirectionSetting(props) { {Array.from({ length: 180 / 15 - 1 }).map((dot, index) => (
    { setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH) setCompasDeg(15 * (index + 1)) diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index 3928353c..9e402a71 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -1,6 +1,6 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { canvasState } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' @@ -17,27 +17,26 @@ const TYPE = { export default function DotLineGrid(props) { // const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state //const interval = useRecoilValue(dotLineIntervalSelector) - const { id, setIsShow, pos = { x: 840, y: -815 }, isConfig = false } = props + const { id, setIsShow, pos = { x: 840, y: -815 }, isConfig = false, settingsData, setSettingsData, settingsDataSave, setSettingsDataSave } = props const canvas = useRecoilValue(canvasState) const { getMessage } = useMessage() const { closePopup } = usePopup() const { swalFire } = useSwal() - const { - selectOption, - setSelectOption, - SelectOptions, - currentSetting, - setCurrentSetting, - dotLineGridSettingState, - setSettingModalGridOptions, - setDotLineGridSettingState, - } = useCanvasSetting() + const [selectOption, setSelectOption] = useState() + + const { SelectOptions, currentSetting, setCurrentSetting, dotLineGridSettingState, setSettingModalGridOptions, setDotLineGridSettingState } = + useCanvasSetting() // 데이터를 최초 한 번만 조회 useEffect(() => { console.log('DotLineGrid useEffect 실행') + setSettingsDataSave({ ...settingsData }) + + // dimension 값에 맞는 옵션을 선택 + const matchedOption = SelectOptions.find((option) => option.value == currentSetting.INTERVAL.dimension) + setSelectOption(matchedOption) return () => { setSettingModalGridOptions((prev) => { @@ -84,11 +83,23 @@ export default function DotLineGrid(props) { }, DOT: currentSetting.DOT, LINE: currentSetting.LINE, - flag: true, } //setDotLineGridSettingState({ ...currentSetting }) }) + setSettingsData({ + ...settingsData, + INTERVAL: { + type: currentSetting.INTERVAL.type, + horizontalInterval: currentSetting.INTERVAL.horizontalInterval, + verticalInterval: currentSetting.INTERVAL.verticalInterval, + ratioInterval: currentSetting.INTERVAL.ratioInterval, + dimension: currentSetting.INTERVAL.dimension, + }, + DOT: currentSetting.DOT, + LINE: currentSetting.LINE, + }) + setIsShow(false) closePopup(id, isConfig) } diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 1ce18a85..bc9fb401 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -8,68 +8,37 @@ import MaterialGuide from '@/components/floor-plan/modal/placementShape/Material import WithDraggable from '@/components/common/draggable/WithDraggable' import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' +import { useRecoilState, useRecoilValue } from 'recoil' +import { roofMaterialsAtom } from '@/store/settingAtom' +import { isObjectNotEmpty } from '@/util/common-utils' export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, setShowPlaceShapeModal }) { const [showSizeGuideModal, setShowSizeGuidModal] = useState(false) const [showMaterialGuideModal, setShowMaterialGuidModal] = useState(false) const { closePopup } = usePopup() const { getMessage } = useMessage() + const roofMaterials = useRecoilValue(roofMaterialsAtom) const { basicSetting, setBasicSettings, fetchBasicSettings, basicSettingSave } = useCanvasSetting() + const [currentRoofMaterial, setCurrentRoofMaterial] = useState( + isObjectNotEmpty(basicSetting.selectedRoofMaterial) ? basicSetting.selectedRoofMaterial : roofMaterials[0], + ) // 데이터를 최초 한 번만 조회 useEffect(() => { fetchBasicSettings() }, []) + useEffect(() => { + console.log(currentRoofMaterial) + }, [roofMaterials]) + // Function to update the roofType and corresponding values - const handleRoofTypeChange = (index, value) => { - const updatedRoofs = [...basicSetting.roofs] - const roofType = parseInt(value, 10) - - // Reset other values based on the selected roofType - if (roofType === 1) { - updatedRoofs[index] = { - ...updatedRoofs[index], - roofType: 1, - roofWidth: 265, - roofHeight: 235, - roofGap: 455, - roofHajebichi: 0, - } - } else if (roofType === 2) { - updatedRoofs[index] = { - ...updatedRoofs[index], - roofType: 2, - roofGap: 265, - roofHajebichi: 265, - roofWidth: 0, - roofHeight: 0, - } - } else if (roofType === 3) { - updatedRoofs[index] = { - ...updatedRoofs[index], - roofType: 3, - roofHajebichi: 265, - roofGap: 0, - roofWidth: 0, - roofHeight: 0, - } - } else if (roofType === 4) { - updatedRoofs[index] = { - ...updatedRoofs[index], - roofType: 4, - roofHeight: 265, - roofGap: 265, - roofHajebichi: 0, - roofWidth: 0, - } - } - - setBasicSettings({ - ...basicSetting, - roofs: updatedRoofs, - }) + const handleRoofTypeChange = (value) => { + const selectedRoofMaterial = roofMaterials.find((roof) => roof.roofMatlCd === value) + setCurrentRoofMaterial(selectedRoofMaterial) + /*const newBasicSetting = { ...basicSetting } + setBasicSettings({ ...newBasicSetting, selectedRoofMaterial: selectedRoofMaterial })*/ } return ( @@ -180,16 +149,19 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
    - {basicSetting.roofs[0].roofType === 1 ? ( + {['R', 'C'].includes(currentRoofMaterial.widAuth) && ( <>
    W @@ -197,204 +169,67 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set -
    -
    -
    - L -
    - -
    -
    -
    - {getMessage('modal.placement.initial.setting.rafter')} -
    -
    - ) : basicSetting.roofs[0].roofType === 2 ? ( - <> -
    - {getMessage('hajebichi')} -
    - -
    + )} + {['R', 'C'].includes(currentRoofMaterial.lenAuth) && ( +
    + L +
    +
    -
    - {getMessage('modal.placement.initial.setting.rafter')} -
    - -
    +
    + )} + {['C', 'R'].includes(currentRoofMaterial.raftAuth) && ( +
    + {getMessage('modal.placement.initial.setting.rafter')} +
    +
    - - ) : basicSetting.roofs[0].roofType === 3 ? ( - <> -
    - {getMessage('hajebichi')} -
    - -
    +
    + )} + {['C', 'R'].includes(currentRoofMaterial.roofPchAuth) && ( +
    + {getMessage('hajebichi')} +
    +
    - - ) : basicSetting.roofs[0].roofType === 4 ? ( - <> -
    - L -
    - -
    -
    -
    - {getMessage('modal.placement.initial.setting.rafter')} -
    - -
    -
    - - ) : ( - '' +
    )}
    diff --git a/src/components/floor-plan/modal/setting01/FirstOption.jsx b/src/components/floor-plan/modal/setting01/FirstOption.jsx index f3ef9b8b..a9532efb 100644 --- a/src/components/floor-plan/modal/setting01/FirstOption.jsx +++ b/src/components/floor-plan/modal/setting01/FirstOption.jsx @@ -8,21 +8,22 @@ import { useEvent } from '@/hooks/useEvent' export default function FirstOption(props) { const { getMessage } = useMessage() // const { canvas, settingModalFirstOptions, setSettingModalFirstOptions, settingsData, setSettingsData } = useCanvasSetting() - let { canvas, settingModalFirstOptions, setSettingModalFirstOptions, settingsData, setSettingsData } = props + let { canvas, settingModalFirstOptions, setSettingModalFirstOptions, settingsData, setSettingsData, settingsDataSave, setSettingsDataSave } = props const { option1, option2, dimensionDisplay } = settingModalFirstOptions const { initEvent } = useEvent() // 데이터를 최초 한 번만 조회 useEffect(() => { console.log('FirstOption useEffect 실행') + setSettingsDataSave({ ...settingsData }) }, []) const onClickOption = async (item) => { - //치수 표시(단 건 선택) let dimensionDisplay = settingModalFirstOptions?.dimensionDisplay let option1 = settingModalFirstOptions?.option1 let option2 = settingModalFirstOptions?.option2 + //치수 표시(단 건 선택) if (item.column === 'corridorDimension' || item.column === 'realDimension' || item.column === 'noneDimension') { dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.map((option) => { option.selected = option.id === item.id @@ -33,9 +34,9 @@ export default function FirstOption(props) { //화면 표시(단 건 선택) } else if (item.column === 'onlyBorder' || item.column === 'lineHatch' || item.column === 'allPainted') { - option2 = settingModalFirstOptions?.option2.map((option2) => { - option2.selected = option2.id === item.id - return option2 + option2 = settingModalFirstOptions?.option2.map((option) => { + option.selected = option.id === item.id + return option }) // setSettingModalFirstOptions({ ...settingModalFirstOptions, option2: [...options] }) @@ -47,11 +48,11 @@ export default function FirstOption(props) { }) //디스플레이 설정 표시(단 건 선택) } else { - option1 = settingModalFirstOptions?.option1.map((opt) => { - if (opt.id === item.id) { - opt.selected = !opt.selected + option1 = settingModalFirstOptions?.option1.map((option) => { + if (option.id === item.id) { + option.selected = !option.selected } - return opt + return option }) // setSettingModalFirstOptions({ ...settingModalFirstOptions, option1: [...options] }) diff --git a/src/components/floor-plan/modal/setting01/GridOption.jsx b/src/components/floor-plan/modal/setting01/GridOption.jsx index 1d40ddbc..b5b61acc 100644 --- a/src/components/floor-plan/modal/setting01/GridOption.jsx +++ b/src/components/floor-plan/modal/setting01/GridOption.jsx @@ -28,8 +28,13 @@ export default function GridOption(props) { const { initEvent } = useEvent() + const { SelectOptions, settingsData, setSettingsData, settingsDataSave, setSettingsDataSave } = useCanvasSetting() + useEffect(() => { console.log('GridOption useEffect 실행') + }, []) + + useEffect(() => { setGridColor(color.hex) }, [color]) @@ -96,7 +101,7 @@ export default function GridOption(props) { } useEffect(() => { - console.log('🚀 ~ useEffect ~ initEvent:') + //console.log('🚀 ~ useEffect ~ initEvent:') initEvent() }, [gridOptions]) @@ -108,10 +113,15 @@ export default function GridOption(props) { x: 845, y: 180, }, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, } const colorPickerProps = { id: colorId, + name: 'gridOptionColor', color: gridColor, setColor: setGridColor, isShow: showColorPickerModal, @@ -121,6 +131,10 @@ export default function GridOption(props) { x: 785, y: 180, }, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, } return ( diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index df60763d..941c2d3e 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -27,16 +27,6 @@ export default function SecondOption(props) { const { initEvent } = useEvent() - // const { - // fetchSettings, - // planSizeSettingMode, - // setPlanSizeSettingMode, - // settingModalSecondOptions, - // setSettingModalSecondOptions, - // adsorptionPointMode, - // setAdsorptionPointMode, - // setAdsorptionRange, - // } = useCanvasSetting() const { fetchSettings, planSizeSettingMode, @@ -46,12 +36,17 @@ export default function SecondOption(props) { adsorptionPointMode, setAdsorptionPointMode, setAdsorptionRange, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, } = props const { option3, option4 } = settingModalSecondOptions // 데이터를 최초 한 번만 조회 useEffect(() => { console.log('SecondOption useEffect 실행') + setSettingsDataSave({ ...settingsData }) }, []) const handlePopup = (type) => { @@ -142,18 +137,23 @@ export default function SecondOption(props) { return { ...prev, [fontProps.type]: { - // fontFamily: font.fontFamily.value, - // fontWeight: font.fontWeight.value, - // fontSize: font.fontSize.value, - // fontColor: font.fontColor.value, fontFamily: font.fontFamily, fontWeight: font.fontWeight, fontSize: font.fontSize, fontColor: font.fontColor, }, - fontFlag: true, } }) + + setSettingsData({ + ...settingsData, + [fontProps.type]: { + fontFamily: font.fontFamily, + fontWeight: font.fontWeight, + fontSize: font.fontSize, + fontColor: font.fontColor, + }, + }) } const fontProps = { @@ -168,6 +168,10 @@ export default function SecondOption(props) { id: dimensionId, isShow: showDimensionLineSettingModal, setIsShow: setShowDimensionLineSettingModal, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, } const planSizeProps = { @@ -177,9 +181,16 @@ export default function SecondOption(props) { isShow: showPlanSizeSettingModal, setIsShow: setShowPlanSizeSettingModal, pos: { x: 1025, y: 180 }, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, } const onClickOption = async (item) => { + let option4Data = settingModalSecondOptions?.option4 + let adsorpPointData = adsorptionPointMode.adsorptionPoint + //흡착범위 설정(단 건 선택) if ( item.column === 'adsorpRangeSmall' || @@ -189,21 +200,25 @@ export default function SecondOption(props) { ) { // option4에서 한 개만 선택 가능하도록 처리 //const updatedOption4 = option4.map((option) => (option.id === item.id ? { ...option, selected: true } : { ...option, selected: false })) - const options = settingModalSecondOptions?.option4.map((option4) => { - option4.selected = option4.id === item.id - return option4 + option4Data = settingModalSecondOptions?.option4.map((option) => { + option.selected = option.id === item.id + return option }) - setSettingModalSecondOptions({ ...settingModalSecondOptions, option3, option4, fontFlag: true }) + //흡착점 범위 + setAdsorptionRange(item.range) + + setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: adsorpPointData }) } else if (item === 'adsorpPoint') { - setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: !adsorptionPointMode.adsorptionPoint, fontFlag: true }) + setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: !adsorpPointData }) + adsorpPointData = !adsorpPointData } - //setAdsorptionRange(item.range) //사용여부 확인 필요 - setAdsorptionRange(50) + + setSettingsData({ ...settingsData, option4: [...option4Data], adsorptionPoint: adsorpPointData }) } useEffect(() => { - console.log('🚀 ~ useEffect ~ initEvent:') + //console.log('🚀 ~ useEffect ~ initEvent:') initEvent() }, [adsorptionPointMode]) diff --git a/src/components/floor-plan/modal/setting01/SettingModal01.jsx b/src/components/floor-plan/modal/setting01/SettingModal01.jsx index 73ce8fa2..f5e6e3ca 100644 --- a/src/components/floor-plan/modal/setting01/SettingModal01.jsx +++ b/src/components/floor-plan/modal/setting01/SettingModal01.jsx @@ -24,7 +24,11 @@ export default function SettingModal01(props) { setSettingModalFirstOptions, settingsData, setSettingsData, + settingsDataSave, + setSettingsDataSave, fetchSettings, + globalFont, + setGlobalFont, planSizeSettingMode, setPlanSizeSettingMode, settingModalSecondOptions, @@ -36,9 +40,19 @@ export default function SettingModal01(props) { setGridColor, color, } = useCanvasSetting() - const firstProps = { canvas, settingModalFirstOptions, setSettingModalFirstOptions, settingsData, setSettingsData } + const firstProps = { + canvas, + settingModalFirstOptions, + setSettingModalFirstOptions, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, + } const secondProps = { fetchSettings, + globalFont, + setGlobalFont, planSizeSettingMode, setPlanSizeSettingMode, settingModalSecondOptions, @@ -46,6 +60,10 @@ export default function SettingModal01(props) { adsorptionPointMode, setAdsorptionPointMode, setAdsorptionRange, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, } const gridProps = { gridColor, setGridColor, color } diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index 63581d5d..571741ed 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -33,7 +33,7 @@ const fontSizes = [ ] export default function DimensionLineSetting(props) { - const { isShow, setIsShow, id, pos = { x: 985, y: 180 } } = props + const { isShow, setIsShow, id, pos = { x: 985, y: 180 }, settingsData, setSettingsData, settingsDataSave, setSettingsDataSave } = props const { addPopup, closePopup, closePopups } = usePopup() const pixels = Array.from({ length: 5 }).map((_, index) => { return { id: index, name: index + 1, value: index + 1 } @@ -111,11 +111,16 @@ export default function DimensionLineSetting(props) { color: originColor, setColor: setOriginColor, id: colorModalId, + name: 'DimensionLineColor', isConfig: true, pos: { x: 495, y: 180, }, + settingsData, + setSettingsData, + settingsDataSave, + setSettingsDataSave, } const fontProps = { @@ -157,9 +162,9 @@ export default function DimensionLineSetting(props) { fontSize: originFontSize, fontColor: originFontColor, }, - fontFlag: true, } }) + setDimensionLineSettings((prev) => { return { ...prev, @@ -167,6 +172,19 @@ export default function DimensionLineSetting(props) { color: originColor, } }) + + setSettingsData({ + ...settingsData, + dimensionLineText: { + fontFamily: originFont, + fontWeight: originFontWeight, + fontSize: originFontSize, + fontColor: originFontColor, + }, + pixel: originPixel.name, + color: originColor, + }) + setIsShow(false) closePopups([fontModalId, colorModalId, id]) } diff --git a/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx b/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx index e65d28ca..0691046d 100644 --- a/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx +++ b/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx @@ -8,7 +8,7 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' import { onlyNumberInputChange } from '@/util/input-utils' export default function PlanSizeSetting(props) { - const { setIsShow, horizon, vertical, id, pos = { x: 985, y: 180 } } = props + const { setIsShow, horizon, vertical, id, pos = { x: 985, y: 180 }, settingsData, setSettingsData, settingsDataSave, setSettingsDataSave } = props const { closePopup } = usePopup() const { getMessage } = useMessage() @@ -26,10 +26,15 @@ export default function PlanSizeSetting(props) { ...prev, originHorizon: Number(planSizeSettingMode.originHorizon), originVertical: Number(planSizeSettingMode.originVertical), - flag: true, } }) + setSettingsData({ + ...settingsData, + originHorizon: Number(planSizeSettingMode.originHorizon), + originVertical: Number(planSizeSettingMode.originVertical), + }) + canvas.setWidth(planSizeSettingMode.originHorizon) canvas.setHeight(planSizeSettingMode.originVertical) canvas.renderAll() @@ -40,12 +45,11 @@ export default function PlanSizeSetting(props) { const changeInput = (value, e) => { const { name } = e.target - console.log('name', name, value) + setPlanSizeSettingMode((prev) => { return { ...prev, [name]: Number(value), - flag: false, } }) } diff --git a/src/components/main/ChangePasswordPop.jsx b/src/components/main/ChangePasswordPop.jsx index 2af060e7..4eb7164d 100644 --- a/src/components/main/ChangePasswordPop.jsx +++ b/src/components/main/ChangePasswordPop.jsx @@ -7,7 +7,7 @@ import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' import { useRouter } from 'next/navigation' import { setSession } from '@/lib/authActions' - +import { logout } from '@/lib/authActions' export default function ChangePasswordPop(props) { const globalLocaleState = useRecoilValue(globalLocaleStore) @@ -77,18 +77,21 @@ export default function ChangePasswordPop(props) { if (res?.result?.code === 200) { if (res?.result?.resultCode === 'S') { alert(getMessage('main.popup.login.success')) + logout() //로그인 화면으로 이동해서 다시 로그인해야되서 setSessionState필요없음 // setSessionState({ ...sessionState, pwdInitYn: 'Y' }) - props.setChagePasswordPopOpen(false) - router.push('/login') + //props.setChagePasswordPopOpen(false) + //router.push('/login') } else { alert(res?.result?.resultMsg) } } else { + logout() console.log('code not 200 error') } }) .catch((error) => { + logout() console.log('catch::::::::', error) }) } @@ -165,7 +168,8 @@ export default function ChangePasswordPop(props) { type="button" className="btn-origin grey" onClick={() => { - router.push('/login') + logout() + // router.push('/login') }} > {getMessage('main.popup.login.btn2')} diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index bba99266..95cb2fef 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -10,7 +10,7 @@ import { globalLocaleStore } from '@/store/localeAtom' import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' import { useMessage } from '@/hooks/useMessage' import { useForm } from 'react-hook-form' -import { useRecoilValue, useSetRecoilState, useResetRecoilState, useRecoilState } from 'recoil' +import { useRecoilValue, useSetRecoilState, useResetRecoilState } from 'recoil' import { SessionContext } from '@/app/SessionProvider' import FindAddressPop from './popup/FindAddressPop' import PlanRequestPop from './popup/PlanRequestPop' @@ -41,7 +41,6 @@ export default function StuffDetail() { const { session } = useContext(SessionContext) const router = useRouter() - const pathname = usePathname() const searchParams = useSearchParams() const { getMessage } = useMessage() const globalLocaleState = useRecoilValue(globalLocaleStore) diff --git a/src/components/management/StuffSubHeader.jsx b/src/components/management/StuffSubHeader.jsx index ab838335..27acf615 100644 --- a/src/components/management/StuffSubHeader.jsx +++ b/src/components/management/StuffSubHeader.jsx @@ -1,6 +1,6 @@ 'use client' -import { useContext, useEffect } from 'react' +import { useState, useContext, useEffect } from 'react' import Link from 'next/link' import Image from 'next/image' @@ -11,20 +11,37 @@ import { useSetRecoilState } from 'recoil' import { QcastContext } from '@/app/QcastProvider' import { useMessage } from '@/hooks/useMessage' import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' -import { queryStringFormatter } from '@/util/common-utils' +import { isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' + +import { ManagementContext } from '@/app/management/ManagementProvider' +import { SessionContext } from '@/app/SessionProvider' export default function StuffSubHeader({ type }) { const { getMessage } = useMessage() const router = useRouter() + const { session } = useContext(SessionContext) const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) const { isGlobalLoading } = useContext(QcastContext) + const { managementState } = useContext(ManagementContext) + + const [buttonStyle, setButtonStyle] = useState('') useEffect(() => { window.scrollTo(0, 0) }, []) + useEffect(() => { + if (isObjectNotEmpty(managementState)) { + if (managementState.createUser === 'T01') { + if (session.userId !== 'T01') { + setButtonStyle('none') + } + } + } + }, [managementState]) + const searchParams = useSearchParams() const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set @@ -98,7 +115,7 @@ export default function StuffSubHeader({ type }) { {getMessage('stuff.temp.subTitle')}
  • -
  • +
  • {getMessage('stuff.temp.subTitle2')} diff --git a/src/hooks/common/useMasterController.js b/src/hooks/common/useMasterController.js new file mode 100644 index 00000000..4f8bb799 --- /dev/null +++ b/src/hooks/common/useMasterController.js @@ -0,0 +1,88 @@ +import { useAxios } from '@/hooks/useAxios' +import { useMessage } from '@/hooks/useMessage' +import { useSwal } from '@/hooks/useSwal' +import { getQueryString } from '@/util/common-utils' +import axios from 'axios' + +/** + * 마스터 컨트롤러 훅 + * @returns + */ +export function useMasterController() { + const { get } = useAxios() + const { getMessage } = useMessage() + const { swalFire } = useSwal() + + /** + * 지붕재 목록 조회 + * @returns + */ + const getRoofMaterialList = async () => { + return await get({ url: '/api/v1/master/getRoofMaterialList' }).then((res) => { + console.log('🚀🚀 ~ getRoofMaterialList ~ res:', res) + return res + }) + } + + /** + * 모듈 타입별 아이템 목록 조회 + * @param {지붕재 코드} roofMatlCd + * @returns + */ + const getModuleTypeItemList = async (roofMatlCd) => { + if (!roofMatlCd || roofMatlCd.trim() === '') { + swalFire({ text: getMessage('master.moduletypeitem.message.error'), type: 'alert', icon: 'error' }) + return null + } + const param = { roofMatlCd: roofMatlCd } + const paramString = getQueryString(param) + return await get({ url: `/api/v1/master/getModuleTypeItemList${paramString}` }).then((res) => { + console.log('🚀🚀 ~ getModuleTypeItemList ~ res:', res) + return res + }) + } + + /** + * 가대 목록 조회 + * @param + * @returns + */ + const getTrestleList = async (params) => { + return await get({ url: `/api/v1/master/getTrestleList/${params}` }).then((res) => { + console.log('🚀🚀 ~ getTrestleList ~ res:', res) + return res + }) + } + + /** + * 모듈 시공법 목록 조회 + * @param + * @returns + */ + const getConstructionList = async (params) => { + return await get({ url: `/api/v1/master/getConstructionList/${params}` }).then((res) => { + console.log('🚀🚀 ~ getConstructionList ~ res:', res) + return res + }) + } + + /** + * 가대 상세 조회 + * @param + * @returns + */ + const getTrestleDetailList = async (params) => { + return await get({ url: `/api/v1/master/getTrestleDetailList/${params}` }).then((res) => { + console.log('🚀🚀 ~ getTrestleDetailList ~ res:', res) + return res + }) + } + + return { + getRoofMaterialList, + getModuleTypeItemList, + getTrestleList, + getConstructionList, + getTrestleDetailList, + } +} diff --git a/src/hooks/contextpopup/useFlowDirectionSetting.js b/src/hooks/contextpopup/useFlowDirectionSetting.js deleted file mode 100644 index 9e77aa4a..00000000 --- a/src/hooks/contextpopup/useFlowDirectionSetting.js +++ /dev/null @@ -1,30 +0,0 @@ -import { canvasState } from '@/store/canvasAtom' -import { useRecoilValue } from 'recoil' -import { usePolygon } from '@/hooks/usePolygon' -import { useState } from 'react' -import { usePopup } from '@/hooks/usePopup' - -export const FLOW_DIRECTION_TYPE = { - EIGHT_AZIMUTH: 'eightAzimuth', - TWENTY_FOUR_AZIMUTH: 'twentyFourAzimuth', -} - -export function useFlowDirectionSetting(id) { - const canvas = useRecoilValue(canvasState) - const { drawDirectionArrow } = usePolygon() - const { closePopup } = usePopup() - - const [type, setType] = useState(FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH) - - const changeSurfaceFlowDirection = (roof, direction, orientation) => { - roof.set({ - direction: direction, - surfaceCompass: orientation, - }) - drawDirectionArrow(roof) - canvas?.renderAll() - closePopup(id) - } - - return { changeSurfaceFlowDirection, type, setType } -} diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js index 762cf421..9008467f 100644 --- a/src/hooks/floorPlan/estimate/useEstimateController.js +++ b/src/hooks/floorPlan/estimate/useEstimateController.js @@ -1,13 +1,14 @@ import { useAxios } from '@/hooks/useAxios' -import { useContext, useEffect, useReducer, useState } from 'react' +import { useContext, useEffect, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { globalLocaleStore } from '@/store/localeAtom' import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' -import { isObjectNotEmpty, isEmptyArray, isNotEmptyArray } from '@/util/common-utils' +import { isObjectNotEmpty, isEmptyArray } from '@/util/common-utils' import { SessionContext } from '@/app/SessionProvider' import { useMessage } from '@/hooks/useMessage' import { useRouter } from 'next/navigation' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' +import { QcastContext } from '@/app/QcastProvider' // Constants const ESTIMATE_API_ENDPOINT = '/api/estimate' // API 엔드포인트 정의 @@ -19,7 +20,7 @@ const updateItemInList = (itemList, dispOrder, updates) => { export const useEstimateController = (planNo) => { const [fileList, setFileList] = useState([]) - const [deleteFileList, setDeleteFileList] = useState([]) + const { setIsGlobalLoading } = useContext(QcastContext) const router = useRouter() const { session } = useContext(SessionContext) @@ -52,6 +53,7 @@ export const useEstimateController = (planNo) => { const fetchSetting = async (objectNo, planNo) => { try { await promiseGet({ url: `/api/estimate/${objectNo}/${planNo}/detail` }).then((res) => { + setIsGlobalLoading(true) if (res.status === 200) { if (isObjectNotEmpty(res.data)) { if (res.data.itemList.length > 0) { @@ -72,9 +74,11 @@ export const useEstimateController = (planNo) => { } }) setIsLoading(true) + setIsGlobalLoading(false) } catch (error) { console.error('견적서 상세조회 Error: ', error) setIsLoading(true) + setIsGlobalLoading(false) } } @@ -354,15 +358,16 @@ export const useEstimateController = (planNo) => { // return try { await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => { + setIsGlobalLoading(true) if (res.status === 201) { estimateData.newFileList = [] - // estimateData.originFiles = [] alert(getMessage('estimate.detail.save.alertMsg')) //어디로 보낼지 fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo) } }) } catch (e) { + setIsGlobalLoading(false) console.log('error::::::::::::', e.response.data.message) } } diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index f51cf00f..e54b227f 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -12,6 +12,7 @@ import { v4 as uuidv4 } from 'uuid' import { useSwal } from '@/hooks/useSwal' import { canvasSettingState } from '@/store/canvasAtom' import { compasDegAtom } from '@/store/orientationAtom' +import { QLine } from '@/components/fabric/QLine' export function useModuleBasicSetting() { const canvas = useRecoilValue(canvasState) @@ -51,6 +52,7 @@ export function useModuleBasicSetting() { const makeModuleInstArea = () => { //지붕 객체 반환 const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof') + let offsetLength = canvasSetting.roofSizeSet === 3 ? -90 : -20 if (!roofs) { return @@ -63,13 +65,11 @@ export function useModuleBasicSetting() { } setSurfaceShapePattern(roof, roofDisplay.column, true) //패턴 변경 - const offsetPoints = offsetPolygon(roof.points, -20) //안쪽 offset + const offsetPoints = offsetPolygon(roof.points, offsetLength) //안쪽 offset //모듈설치영역?? 생성 const surfaceId = uuidv4() - console.log('roof.moduleCompass', roof.moduleCompass) - let setupSurface = new QPolygon(offsetPoints, { stroke: 'red', fill: 'transparent', @@ -88,7 +88,10 @@ export function useModuleBasicSetting() { flipX: roof.flipX, flipY: roof.flipY, surfaceId: surfaceId, + originX: 'center', + originY: 'center', modules: [], + // angle: -compasDeg, }) setupSurface.setViewLengthText(false) @@ -102,6 +105,7 @@ export function useModuleBasicSetting() { } setupSurface.set({ flowLines: flowLines }) + flatRoofMakeSurface(roof, setupSurface) //지붕면 선택 금지 roof.set({ @@ -656,7 +660,7 @@ export function useModuleBasicSetting() { } } - const leftFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, flowModuleLine, isCenter = false) => { + const leftFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, aaa, isCenter = false) => { let startPoint = flowModuleLine.left //중앙배치일 경우에는 계산한다 @@ -1206,9 +1210,10 @@ export function useModuleBasicSetting() { return turf.polygon([coordinates]) } - const polygonToTurfPolygon = (object) => { + const polygonToTurfPolygon = (object, current = false) => { let coordinates coordinates = object.points.map((point) => [point.x, point.y]) + if (current) coordinates = object.getCurrentPoints().map((point) => [point.x, point.y]) coordinates.push(coordinates[0]) return turf.polygon( [coordinates], @@ -1526,17 +1531,18 @@ export function useModuleBasicSetting() { let flatBatchType = placementFlatRef.setupLocation.current.value let excretaLinesAngle = [] - if (flatBatchType === 'south') { - applyAngle = compasDeg - } else { - const excretaLines = canvas.getObjects().filter((obj) => obj.name === 'flatExcretaLine' && obj.isSelected === true) + if (flatBatchType === 'excreta') { + const excretaLines = canvas.getObjects().filter((obj) => obj.name === 'flatExcretaLine') excretaLines.forEach((obj) => { - const points1 = { x: obj.x1, y: obj.y1 } - const points2 = { x: obj.x2, y: obj.y2 } - excretaLinesAngle.push({ - surfaceId: obj.surfaceId, - angle: calculateAngle(points1, points2), - }) + if (obj.isSelected) { + const points1 = { x: obj.x1, y: obj.y1 } + const points2 = { x: obj.x2, y: obj.y2 } + excretaLinesAngle.push({ + surfaceId: obj.surfaceId, + angle: calculateAngle(points1, points2), + }) + } + canvas.remove(obj) }) } @@ -1591,8 +1597,6 @@ export function useModuleBasicSetting() { return transformedCorners } - function getSelectedExcretaLine() {} - if (moduleSetupSurfaces.length !== 0) { let tempModule let manualDrawModules = [] @@ -1606,7 +1610,7 @@ export function useModuleBasicSetting() { const mousePoint = canvas.getPointer(e.e) for (let i = 0; i < moduleSetupSurfaces.length; i++) { - turfPolygon = polygonToTurfPolygon(moduleSetupSurfaces[i]) + turfPolygon = polygonToTurfPolygon(moduleSetupSurfaces[i], true) trestlePolygon = moduleSetupSurfaces[i] manualDrawModules = moduleSetupSurfaces[i].modules // 앞에서 자동으로 했을때 추가됨 flowDirection = moduleSetupSurfaces[i].flowDirection //도형의 방향 @@ -1616,18 +1620,11 @@ export function useModuleBasicSetting() { if (tempLine) { applyAngle = tempLine.angle } else { + //혹시나 두개의 지붕을 그리고 한쪽면만 선택했을때 한면은 그냥 기본 기울기를 준다 applyAngle = compasDeg } } - // const excretaLine = excretaLines.find((obj) => obj.isSelected === true && obj.surfaceId === trestlePolygon.surfaceId) - - // console.log('excretaLine', excretaLine.x1, excretaLine.y1, excretaLine.x2, excretaLine.y2) - - // applyAngle = calculateAngle(excretaLine.x1, excretaLine.y1, excretaLine.x2, excretaLine.y2) - - // console.log('applyAngle', applyAngle) - let width = flowDirection === 'south' || flowDirection === 'north' ? 172 : 113 let height = flowDirection === 'south' || flowDirection === 'north' ? 113 : 172 @@ -1667,123 +1664,125 @@ export function useModuleBasicSetting() { let snapDistance = 10 let cellSnapDistance = 20 - 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 bigCenterY = (trestleTop + trestleTop + moduleSetupSurfaces[i].height) / 2 + // if (applyAngle === 90 || applyAngle === 180 || applyAngle === 270 || applyAngle === 0) { + // 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 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 = 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 - 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 + // 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 - //설치된 셀에 좌측에 스냅 - if (Math.abs(smallRight - holdCellLeft) < snapDistance) { - tempModule.left = holdCellLeft - width - 0.5 - } + // //설치된 셀에 좌측에 스냅 + // if (Math.abs(smallRight - holdCellLeft) < snapDistance) { + // tempModule.left = holdCellLeft - width - 0.5 + // } - //설치된 셀에 우측에 스냅 - if (Math.abs(smallLeft - holdCellRight) < snapDistance) { - tempModule.left = holdCellRight + 0.5 - } + // //설치된 셀에 우측에 스냅 + // if (Math.abs(smallLeft - holdCellRight) < snapDistance) { + // tempModule.left = holdCellRight + 0.5 + // } - //설치된 셀에 위쪽에 스냅 - if (Math.abs(smallBottom - holdCellTop) < snapDistance) { - tempModule.top = holdCellTop - height - 0.5 - } + // //설치된 셀에 위쪽에 스냅 + // if (Math.abs(smallBottom - holdCellTop) < snapDistance) { + // tempModule.top = holdCellTop - height - 0.5 + // } - //설치된 셀에 밑쪽에 스냅 - if (Math.abs(smallTop - holdCellBottom) < snapDistance) { - tempModule.top = holdCellBottom + 0.5 - } - //가운데 -> 가운데 - 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 - holdCellBottom) < snapDistance) { + // tempModule.top = holdCellBottom + 0.5 + // } + // //가운데 -> 가운데 + // 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) < snapDistance) { + // tempModule.top = trestleTop + // } - // 아래쪽 변에 스냅 - 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(smallTop + tempModule.height * tempModule.scaleY - (trestleTop + moduleSetupSurfaces[i].height)) < snapDistance) { + // tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height * tempModule.scaleY + // } - // 왼쪽변에 스냅 - if (Math.abs(smallLeft - trestleLeft) < snapDistance) { - tempModule.left = trestleLeft - } - //오른쪽 변에 스냅 - if (Math.abs(smallRight - trestleRight) < snapDistance) { - tempModule.left = trestleRight - tempModule.width * tempModule.scaleX - } + // // 왼쪽변에 스냅 + // if (Math.abs(smallLeft - trestleLeft) < snapDistance) { + // tempModule.left = trestleLeft + // } + // //오른쪽 변에 스냅 + // if (Math.abs(smallRight - trestleRight) < snapDistance) { + // tempModule.left = trestleRight - tempModule.width * tempModule.scaleX + // } - if (flowDirection === 'south' || flowDirection === 'north') { - // 모듈왼쪽이 세로중앙선에 붙게 스냅 - if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) { - tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - } + // 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(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 - } - } else { - // 모듈이 가로중앙선에 스냅 - if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < snapDistance) { - tempModule.top = bigCenterY - tempModule.height / 2 - } + // // 모듈오른쪽이 세로중앙선에 붙게 스냅 + // if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) { + // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX + // } + // } else { + // // 모듈이 가로중앙선에 스냅 + // if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < snapDistance) { + // 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 - } - } + // 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 + // } + // } + // } inside = true break @@ -1833,8 +1832,6 @@ export function useModuleBasicSetting() { //마우스 클릭시 set으로 해당 위치에 셀을 넣음 const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 if (!isOverlap) { - console.log('tempModule.points', tempModule.points) - let manualModule = new QPolygon(tempModule.points, { ...moduleOptions }) canvas?.add(manualModule) manualDrawModules.push(tempModule) @@ -1849,7 +1846,411 @@ export function useModuleBasicSetting() { } } - const autoFlatroofModuleSetup = (placementFlatRef) => {} + const autoFlatroofModuleSetup = (placementFlatRef) => { + initEvent() //마우스 이벤트 초기화 + + let flatBatchType = placementFlatRef.setupLocation.current.value + const moduleSetupSurfaces = moduleSetupSurface //선택 설치면 + + const notSelectedTrestlePolygons = canvas + ?.getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && !moduleSetupSurfaces.includes(obj)) //설치면이 아닌것 + + const batchObjects = canvas + ?.getObjects() + .filter( + (obj) => + obj.name === BATCH_TYPE.OPENING || + obj.name === BATCH_TYPE.TRIANGLE_DORMER || + obj.name === BATCH_TYPE.PENTAGON_DORMER || + obj.name === BATCH_TYPE.SHADOW, + ) //도머s 객체 + + if (moduleSetupSurfaces.length === 0) { + alert('선택된 모듈 설치면이 없습니다.') + return + } + + //어짜피 자동으로 누르면 선택안된데도 다 날아간다 + canvas.getObjects().forEach((obj) => { + if (obj.name === 'module') { + canvas.remove(obj) + } + }) + + notSelectedTrestlePolygons.forEach((obj) => { + if (obj.modules) { + obj.modules.forEach((module) => { + canvas?.remove(module) + }) + obj.modules = [] + } + }) + + const moduleOptions = { + fill: '#BFFD9F', + stroke: 'black', + strokeWidth: 0.1, + selectable: false, // 선택 가능하게 설정 + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 + opacity: 0.8, + parentId: moduleSetupSurface.parentId, + name: 'module', + } + + let leftMargin, bottomMargin, square, chidoriLength + + //선택된 지붕안에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 포함되면 배열 반환 + const objectsIncludeSurface = (turfModuleSetupSurface) => { + let containsBatchObjects = [] + containsBatchObjects = batchObjects.filter((batchObject) => { + let convertBatchObject + + if (batchObject.type === 'group') { + //도머는 그룹형태임 + convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) + } else { + //개구, 그림자 + batchObject.set({ points: rectToPolygon(batchObject) }) + canvas?.renderAll() // set된걸 바로 적용하기 위해 + convertBatchObject = polygonToTurfPolygon(batchObject) //rect를 폴리곤으로 변환 -> turf 폴리곤으로 변환 + } + + // 폴리곤 안에 도머 폴리곤이 포함되어있는지 확인해서 반환하는 로직 + return turf.booleanContains(turfModuleSetupSurface, convertBatchObject) || turf.booleanWithin(convertBatchObject, turfModuleSetupSurface) + }) + + 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 + * @param {*} turfModuleSetupSurface + * @returns + */ + const checkModuleDisjointSurface = (squarePolygon, turfModuleSetupSurface) => { + return turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface) + } + + let moduleGroup = [] + + const flatRoofDownFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { + let startPoint = moduleSetupSurface.flowLines.bottom + + const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 + const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 + const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 + + let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1 + let totalTopEndPoint = maxTopEndPoint - startPoint.y1 + let totalWidth = Math.ceil(Math.abs(maxRightEndPoint - maxLeftEndPoint) / width) + let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width) + let diffTopEndPoint = Math.abs(totalTopEndPoint / height) + let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1) + let tempMaxWidth = width //최대배치인지 확인하려고 넣음 + + for (let j = 0; j < diffTopEndPoint; j++) { + bottomMargin = marginHeight * j + for (let i = 0; i <= totalWidth; i++) { + leftMargin = marginWidth * i + + square = [ + [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin], + [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - bottomMargin], + [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - height - bottomMargin], + [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - height - bottomMargin], + [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin], + ] + + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleGroup.push(tempModule) + } + } + } + + const flatRoofLeftFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { + let startPoint = moduleSetupSurface.flowLines.left + const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 + const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 + const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 + + let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌 + let diffTopEndPoint = Math.abs(totalTopEndPoint / height) + let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height) + let totalWidth = Math.abs(startPoint.x1 - maxRightEndPoint) / width + let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) + let tempMaxHeight = height //최대배치인지 확인하려고 넣음 + + for (let i = 0; i <= totalWidth; i++) { + bottomMargin = marginHeight * i + for (let j = 0; j < totalHeight; j++) { + leftMargin = marginWidth * j + + square = [ + [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin], + [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin], + [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin], + [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin], + [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin], + ] + + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + + // if (disjointFromTrestle && isDisjoint) { + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleGroup.push(tempModule) + } + } + } + + const flatRoofTopFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { + let startPoint = moduleSetupSurface.flowLines.top + + const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 + const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 + const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 + + let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1 + let totalRightEndPoint = maxLeftEndPoint - maxRightEndPoint + let totalBottomEndPoint = maxBottomEndPoint - startPoint.y1 + let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width) + let diffRightEndPoint = Math.ceil(Math.abs(totalRightEndPoint / width)) + let diffBottomEndPoint = Math.ceil(Math.abs(totalBottomEndPoint / height)) + let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1) + let tempMaxWidth = width //최대배치인지 확인하려고 넣음 + + for (let j = 0; j < diffBottomEndPoint; j++) { + bottomMargin = marginHeight * j + for (let i = 0; i < diffRightEndPoint; i++) { + leftMargin = marginWidth * i + + square = [ + [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 + height * j + bottomMargin], + [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 + height * j + height + bottomMargin], + [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 + height * j + height + bottomMargin], + [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 + height * j + bottomMargin], + [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 + height * j + bottomMargin], + ] + + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + + // if (disjointFromTrestle && isDisjoint) { + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleGroup.push(tempModule) + } + } + } + + const flatRoofRightFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { + let startPoint = moduleSetupSurface.flowLines.right + + const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 + const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 + const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 + + let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌 + let diffTopEndPoint = Math.abs(totalTopEndPoint / height) + let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height) + let totalWidth = Math.abs(startPoint.x1 - maxLeftEndPoint) / width + let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) - 3 // -3으로 위치살짝 보정 + let tempMaxHeight = height //최대배치인지 확인하려고 넣음 + + for (let i = 0; i <= totalWidth; i++) { + bottomMargin = marginHeight * i + for (let j = 0; j < totalHeight; j++) { + leftMargin = marginWidth * j + + square = [ + [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin], + [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin], + [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin], + [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin], + [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin], + ] + + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + + // if (disjointFromTrestle && isDisjoint) { + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleGroup.push(tempModule) + } + } + } + + moduleSetupSurfaces.forEach((moduleSetupSurface, index) => { + moduleSetupSurface.fire('mousedown') + const moduleSetupArray = [] + + let maxLengthLine = moduleSetupSurface.lines.reduce((acc, cur) => { + return acc.length > cur.length ? acc : cur + }) + + const turfModuleSetupSurface = polygonToTurfPolygon(moduleSetupSurface, true) //폴리곤을 turf 객체로 변환 + const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 + + let width = maxLengthLine.flowDirection === 'east' || maxLengthLine.flowDirection === 'west' ? 172.2 : 113.4 + let height = maxLengthLine.flowDirection === 'east' || maxLengthLine.flowDirection === 'west' ? 113.4 : 172.2 + + //배치면때는 방향쪽으로 패널이 넓게 누워져야함 + if (moduleSetupSurface.flowDirection !== undefined) { + width = moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' ? 172.2 : 113.4 + height = moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' ? 113.4 : 172.2 + } + + const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface) + const marginWidth = 0 + const marginHeight = 0 + + canvas.renderAll() + + if (compasDeg >= 0 && compasDeg < 90) { + flatRoofDownFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) + } else if (compasDeg >= 90 && compasDeg < 180) { + flatRoofLeftFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) + } else if (compasDeg >= 180 && compasDeg < 270) { + flatRoofRightFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) + } else { + flatRoofTopFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) + } + + 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() + + //나간애들 제외하고 설치된 애들로 겹친애들 삭제 하기 + // setupedModules.forEach((module, index) => { + // if (isMaxSetup && index > 0) { + // const isOverlap = turf.booleanOverlap(polygonToTurfPolygon(setupedModules[index - 1]), polygonToTurfPolygon(module)) + // //겹치는지 확인 + // if (isOverlap) { + // //겹쳐있으면 삭제 + // // canvas?.remove(module) + // module.set({ fill: 'rgba(72, 161, 250, 0.4)', stroke: 'black', strokeWidth: 0.1 }) + // canvas.renderAll() + // setupedModules.splice(index, 1) + // return false + // } + // } + // }) + + moduleSetupSurface.set({ modules: setupedModules }) + + // const moduleArray = [...moduleIsSetup] + // moduleArray.push({ + // surfaceId: moduleSetupSurface.surfaceId, + // moduleSetupArray: setupedModules, + // }) + // setModuleIsSetup(moduleArray) + }) + // console.log(calculateForApi()) + } + + const flatRoofMakeSurface = (roof, setupSurface) => { + setupSurface.angle = -compasDeg + roof.angle = -compasDeg + + const roofPoints = roof.getCurrentPoints() + const roofLines = roofPoints.map((point, index) => { + const nextIndex = (index + 1) % roofPoints.length + const nextPoint = roofPoints[nextIndex] + + return { + x1: point.x, + y1: point.y, + x2: nextPoint.x, + y2: nextPoint.y, + } + }) + roof.set({ lines: roofLines }) + roof.fire('modified') + + const surfacePoints = setupSurface.getCurrentPoints() + const surfaceLines = surfacePoints.map((point, index) => { + const nextIndex = (index + 1) % surfacePoints.length + const nextPoint = surfacePoints[nextIndex] + + return { + x1: point.x, + y1: point.y, + x2: nextPoint.x, + y2: nextPoint.y, + } + }) + setupSurface.set({ lines: surfaceLines }) + + const flowLines = { + bottom: bottomTopFlowLine(setupSurface).find((obj) => obj.target === 'bottom'), + top: bottomTopFlowLine(setupSurface).find((obj) => obj.target === 'top'), + left: leftRightFlowLine(setupSurface).find((obj) => obj.target === 'left'), + right: leftRightFlowLine(setupSurface).find((obj) => obj.target === 'right'), + } + setupSurface.set({ flowLines: flowLines }) + setupSurface.fire('modified') + } return { makeModuleInstArea, diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js index 77ff8bc3..7309d3d2 100644 --- a/src/hooks/option/useCanvasSetting.js +++ b/src/hooks/option/useCanvasSetting.js @@ -20,12 +20,14 @@ import { settingModalGridOptionsState, basicSettingState, settingsState, + roofMaterialsAtom, } from '@/store/settingAtom' import { POLYGON_TYPE } from '@/common/common' import { globalFontAtom } from '@/store/fontAtom' import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' import { gridColorState } from '@/store/gridAtom' import { useColor } from 'react-color-palette' +import { useMasterController } from '@/hooks/common/useMasterController' const defaultDotLineGridSetting = { INTERVAL: { @@ -48,28 +50,15 @@ export function useCanvasSetting() { const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) - // const [settingsData, setSettingsData] = useRecoilState(settingsState) - const [settingsData, setSettingsData] = useState({ ...settingModalFirstOptions, ...settingModalSecondOptions }) - const { option1, option2, dimensionDisplay } = settingModalFirstOptions - const { option4 } = settingModalSecondOptions - - const corridorDimension = useRecoilValue(corridorDimensionSelector) - - const globalLocaleState = useRecoilValue(globalLocaleStore) - const { get, post } = useAxios(globalLocaleState) - const { getMessage } = useMessage() - const { swalFire } = useSwal() - - const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState) - const [adsorptionRange, setAdsorptionRange] = useRecoilState(adsorptionRangeState) - const [planSizeSettingMode, setPlanSizeSettingMode] = useRecoilState(planSizeSettingState) - //const setAdsorptionRange = useSetRecoilState(adsorptionRangeState) - const [selectedFont, setSelectedFont] = useState() const [selectedFontWeight, setSelectedFontWeight] = useState() const [selectedFontSize, setSelectedFontSize] = useState() const [selectedFontColor, setSelectedFontColor] = useState() const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom) + + const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState) + const [adsorptionRange, setAdsorptionRange] = useRecoilState(adsorptionRangeState) + const [planSizeSettingMode, setPlanSizeSettingMode] = useRecoilState(planSizeSettingState) const [dimensionLineSettings, setDimensionLineSettings] = useRecoilState(dimensionLineSettingsState) const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) @@ -80,10 +69,31 @@ export function useCanvasSetting() { ) const [gridColor, setGridColor] = useRecoilState(gridColorState) const [color, setColor] = useColor(gridColor ?? '#FF0000') - const [colorTemp, setColorTemp] = useState() + + const [settingsData, setSettingsData] = useState({ + ...settingModalFirstOptions, + ...settingModalSecondOptions, + ...globalFont, + ...dotLineGridSetting, + ...planSizeSettingMode, + ...dimensionLineSettings, + ...color, + }) + const [settingsDataSave, setSettingsDataSave] = useState() + const { option1, option2, dimensionDisplay } = settingModalFirstOptions + const { option4 } = settingModalSecondOptions + + const corridorDimension = useRecoilValue(corridorDimensionSelector) + + const globalLocaleState = useRecoilValue(globalLocaleStore) + const { get, post } = useAxios(globalLocaleState) + const { getMessage } = useMessage() + const { swalFire } = useSwal() const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState) + const { getRoofMaterialList } = useMasterController() + const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom) const SelectOptions = [ { id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 }, @@ -91,7 +101,15 @@ export function useCanvasSetting() { { id: 3, name: '1/4', value: 1 / 4 }, { id: 4, name: '1/10', value: 1 / 10 }, ] - const [selectOption, setSelectOption] = useState(SelectOptions[0]) + + useEffect(() => { + addRoofMaterials() + }, []) + + const addRoofMaterials = async () => { + const { data } = await getRoofMaterialList() + setRoofMaterials(data) + } useEffect(() => { if (!canvas) { @@ -132,58 +150,10 @@ export function useCanvasSetting() { }, [canvasSetting]) useEffect(() => { - console.log('🚀 ~ useEffect ~ settingsData:', settingsData) + console.log('🚀 ~ useEffect ~ settingsDataSave:', settingsDataSave) + if (settingsDataSave !== undefined) onClickOption2() }, [settingsData]) - //흡착점 ON/OFF 변경 시 - // useEffect(() => { - // //console.log('useCanvasSetting 실행2', adsorptionPointMode.fontFlag, correntObjectNo) - // if (adsorptionPointMode.fontFlag) { - // onClickOption2() - // } - // }, [adsorptionPointMode]) - - // 1 과 2 변경 시 - // useEffect(() => { - // //console.log('useCanvasSetting 실행3', settingModalFirstOptions.fontFlag, settingModalSecondOptions.fontFlag, correntObjectNo) - // if (settingModalFirstOptions.fontFlag || settingModalSecondOptions.fontFlag) { - // onClickOption2() - // } - // }, [settingModalFirstOptions, settingModalSecondOptions]) - - // 글꼴 변경 시 - // useEffect(() => { - // //console.log('useCanvasSetting 실행4', globalFont.fontFlag, correntObjectNo) - // if (globalFont.fontFlag) { - // onClickOption2() - // } - // }, [globalFont]) - - // 도명크기 변경 시 - // useEffect(() => { - // //console.log('useCanvasSetting 실행5', planSizeSettingMode.flag, correntObjectNo) - // if (planSizeSettingMode.flag) { - // onClickOption2() - // } - // }, [planSizeSettingMode]) - - // 점/선 그리드 변경 시 - // useEffect(() => { - // //console.log('useCanvasSetting 실행6', dotLineGridSetting.flag) - // if (dotLineGridSetting.flag) { - // onClickOption2() - // } - // }, [dotLineGridSetting]) - - // 그리드 색 설정 변경 시 - // useEffect(() => { - // console.log('useCanvasSetting 실행7', colorTemp, gridColor) - // //colorTemp는 변경 전.. 값이 있고 변경된 컬러와 다를 때 실행 - // if (colorTemp !== undefined && colorTemp !== gridColor) { - // onClickOption2() - // } - // }, [color]) - const getFonts = (itemValue) => { if (!itemValue) return { id: 1, name: 'MS PGothic', value: 'MS PGothic' } const data = [ @@ -329,7 +299,7 @@ export function useCanvasSetting() { objectNo: correntObjectNo, roofSizeSet: basicSetting.roofSizeSet, roofAngleSet: basicSetting.roofAngleSet, - roofMaterialsAddList: basicSetting.roofs, + roofMaterialsAddList: basicSetting.roofs, // TODO : 선택된 roof로 변경해야함 } await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => { @@ -357,18 +327,13 @@ export function useCanvasSetting() { const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item })) //흡착점 ON/OFF - setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: res.adsorpPoint, fontFlag: false }) + setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: res.adsorpPoint }) //치수선 설정 setDimensionLineSettings({ ...dimensionLineSettings, pixel: res.originPixel, color: res.originColor }) //도면크기 설정 - setPlanSizeSettingMode({ - ...planSizeSettingMode, - originHorizon: res.originHorizon, - originVertical: res.originVertical, - flag: false, - }) + setPlanSizeSettingMode({ ...planSizeSettingMode, originHorizon: res.originHorizon, originVertical: res.originVertical }) // 데이터 설정 setSettingModalFirstOptions({ @@ -376,13 +341,11 @@ export function useCanvasSetting() { option1: optionData1, option2: optionData2, dimensionDisplay: optionData5, - fontFlag: false, }) setSettingModalSecondOptions({ ...settingModalSecondOptions, option3: optionData3, option4: optionData4, - fontFlag: false, }) const fontPatternData = { @@ -421,8 +384,6 @@ export function useCanvasSetting() { fontSize: getFontSizes(res.lengthFontSize), fontColor: getFontColors(res.lengthFontColor), }, - //글꼴 설정 Flag - fontFlag: false, } //조회된 글꼴 데이터 set @@ -439,55 +400,43 @@ export function useCanvasSetting() { }, DOT: res.dotGridDisplay, LINE: res.lineGridDisplay, - flag: false, } - const matchedOption = SelectOptions.find((option) => option.value == res.gridDimen) - - // dimension 값에 맞는 옵션을 선택 - setSelectOption(matchedOption) - setDotLineGridSettingState(patternData) //setCurrentSetting(patternData) //그리드 색 설정 setGridColor(res.gridColor) - setColorTemp(res.gridColor) } else { //조회된 글꼴 데이터가 없는 경우 //흡착점 ON/OFF - setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: false, fontFlag: false }) + setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: false }) //치수선 설정 setDimensionLineSettings({ ...dimensionLineSettings }) //도면크기 설정 - setPlanSizeSettingMode({ - ...planSizeSettingMode, - flag: false, - }) + setPlanSizeSettingMode({ ...planSizeSettingMode }) // 데이터 설정 setSettingModalFirstOptions({ ...settingModalFirstOptions, - fontFlag: false, }) setSettingModalSecondOptions({ ...settingModalSecondOptions, - fontFlag: false, }) - setGlobalFont({ ...globalFont, fontFlag: false }) + setGlobalFont({ ...globalFont }) //점/선 그리드 - setDotLineGridSettingState({ ...defaultDotLineGridSetting, flag: false }) + setDotLineGridSettingState({ ...defaultDotLineGridSetting }) //setCurrentSetting({ ...defaultDotLineGridSetting }) //그리드 색 설정 setGridColor('#FF0000') - setColorTemp('#FF0000') } + frontSettings() } catch (error) { console.error('Data fetching error:', error) @@ -513,9 +462,9 @@ export function useCanvasSetting() { secondOption2: option4.map((item) => ({ column: item.column, selected: item.selected, + range: item.range, })), } - // console.log('globalFont', globalFont) const patternData = { //견적서 번호 objectNo: correntObjectNo, @@ -543,6 +492,7 @@ export function useCanvasSetting() { adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, adsorpRangeMedium: dataToSend.secondOption2[2].selected, adsorpRangeLarge: dataToSend.secondOption2[3].selected, + //흡착점 ON/OFF adsorpPoint: adsorptionPointMode.adsorptionPoint, //??: adsorptionRange, 사용여부 확인 필요 @@ -594,14 +544,11 @@ export function useCanvasSetting() { gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10, gridDimen: dotLineGridSetting.INTERVAL.dimension, - //gridColor: gridColor.gridColor, gridColor: gridColor, } console.log('patternData ', patternData) - setColorTemp(gridColor) - // HTTP POST 요청 보내기 await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }) .then((res) => { @@ -719,15 +666,13 @@ export function useCanvasSetting() { setDimensionLineSettings, planSizeSettingMode, setPlanSizeSettingMode, - selectOption, - setSelectOption, SelectOptions, currentSetting, setCurrentSetting, dotLineGridSettingState, - setSettingModalGridOptions, setDotLineGridSettingState, resetDotLineGridSetting, + setSettingModalGridOptions, gridColor, setGridColor, color, @@ -740,5 +685,7 @@ export function useCanvasSetting() { basicSettingSave, settingsData, setSettingsData, + settingsDataSave, + setSettingsDataSave, } } diff --git a/src/locales/ja.json b/src/locales/ja.json index 8521c658..e0559649 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -840,7 +840,7 @@ "estimate.detail.fileFlg": "後日資料提出", "estimate.detail.header.fileList1": "ファイル添付", "estimate.detail.fileList.btn": "ファイル選択", - "estimate.detail.fileList.extCheck": "そのファイルはイメージファイルではありません", + "estimate.detail.fileList.extCheck": "画像ファイルのみ添付可能.", "estimate.detail.header.fileList2": "添付ファイル一覧", "estimate.detail.fileList2.btn.return": "復元", "estimate.detail.header.specialEstimate": "見積もりの具体的な", @@ -932,5 +932,6 @@ "simulator.table.sub8": "台", "simulator.table.sub9": "予測発電量 (kWh)", "simulator.notice.sub1": "Hanwha Japan 年間発電量", - "simulator.notice.sub2": "シミュレーション案内事項" + "simulator.notice.sub2": "シミュレーション案内事項", + "master.moduletypeitem.message.error": "지붕재 코드를 입력하세요." } diff --git a/src/locales/ko.json b/src/locales/ko.json index cc65bb7d..b4b745bc 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -850,7 +850,7 @@ "estimate.detail.fileFlg": "후일자료제출", "estimate.detail.header.fileList1": "파일첨부", "estimate.detail.fileList.btn": "파일선택", - "estimate.detail.fileList.extCheck": "해당 파일은 이미지 파일이 아닙니다", + "estimate.detail.fileList.extCheck": "이미지 파일만 첨부 가능합니다.", "estimate.detail.header.fileList2": "첨부파일 목록", "estimate.detail.fileList2.btn.return": "복원", "estimate.detail.header.specialEstimate": "견적특이사항", @@ -942,5 +942,6 @@ "simulator.table.sub8": "대", "simulator.table.sub9": "예측발전량 (kWh)", "simulator.notice.sub1": "Hanwha Japan 연간 발전량", - "simulator.notice.sub2": "시뮬레이션 안내사항" + "simulator.notice.sub2": "시뮬레이션 안내사항", + "master.moduletypeitem.message.error": "지붕재 코드를 입력하세요." } diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index 9e64d72f..7a07175b 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -203,21 +203,16 @@ export const basicSettingState = atom({ default: { roofSizeSet: 1, roofAngleSet: 'slope', - roofs: [ - { - roofApply: true, - roofSeq: 1, - roofType: 1, - roofWidth: 200, - roofHeight: 200, - roofHajebichi: 200, - roofGap: 0, - roofLayout: 'parallel', - }, - ], + selectedRoofMaterial: {}, }, }) +// db에 등록된 지붕재 목록 +export const roofMaterialsAtom = atom({ + key: 'roofMaterialState', + default: [], +}) + /** * 현재 선택된 물건 번호 */ diff --git a/src/util/common-utils.js b/src/util/common-utils.js index 06b96b60..95e6be87 100644 --- a/src/util/common-utils.js +++ b/src/util/common-utils.js @@ -117,3 +117,15 @@ export const calculateFlowDirection = (canvasAngle) => { right: -90 - canvasAngle < -180 ? -90 - canvasAngle + 360 : -90 - canvasAngle, } } + +/** + * 자바스크립트 객체로 쿼리스트링 생성 + * @param {javascript object} o 쿼리스트링 생성할 객체 + * @returns {string} 쿼리스트링 + */ +export const getQueryString = (o) => { + const queryString = Object.keys(o) + .map((key) => `${key}=${o[key]}`) + .join('&') + return `?${queryString}` +}