Merge branch 'dev' into dev-yj

# Conflicts:
#	src/hooks/common/useCanvasPopupStatusController.js
This commit is contained in:
yjnoh 2025-02-08 17:09:30 +09:00
commit 94ed3585eb
9 changed files with 152 additions and 73 deletions

View File

@ -25,6 +25,7 @@ import {
selectedModelsState, selectedModelsState,
seriesState, seriesState,
} from '@/store/circuitTrestleAtom' } from '@/store/circuitTrestleAtom'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
export default function CanvasFrame() { export default function CanvasFrame() {
const canvasRef = useRef(null) const canvasRef = useRef(null)
@ -43,6 +44,7 @@ export default function CanvasFrame() {
const resetModelsState = useResetRecoilState(modelsState) const resetModelsState = useResetRecoilState(modelsState)
const resetSelectedModelsState = useResetRecoilState(selectedModelsState) const resetSelectedModelsState = useResetRecoilState(selectedModelsState)
const resetPcsCheckState = useResetRecoilState(pcsCheckState) const resetPcsCheckState = useResetRecoilState(pcsCheckState)
const { handleModuleSelectionTotal } = useCanvasPopupStatusController()
const loadCanvas = () => { const loadCanvas = () => {
if (canvas) { if (canvas) {
canvas?.clear() // . canvas?.clear() // .
@ -62,6 +64,7 @@ export default function CanvasFrame() {
useEffect(() => { useEffect(() => {
loadCanvas() loadCanvas()
resetRecoilData() resetRecoilData()
Object.keys(currentCanvasPlan).length > 0 && handleModuleSelectionTotal()
}, [currentCanvasPlan, canvas]) }, [currentCanvasPlan, canvas])
useEffect(() => { useEffect(() => {

View File

@ -199,9 +199,10 @@ export default function ContextRoofAllocationSetting(props) {
type="text" type="text"
className="input-origin block" className="input-origin block"
onChange={(e) => { onChange={(e) => {
handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index) // handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index)
handleChangePitch(e, index) handleChangePitch(e, index)
}} }}
value={currentAngleType === 'slope' ? roof.pitch : roof.angle}
defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle} defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
/> />
</div> </div>

View File

@ -201,6 +201,7 @@ export default function RoofAllocationSetting(props) {
onChange={(e) => { onChange={(e) => {
handleChangePitch(e, index) handleChangePitch(e, index)
}} }}
value={currentAngleType === 'slope' ? roof.pitch : roof.angle}
defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle} defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
/> />
</div> </div>

View File

@ -1,81 +1,108 @@
'use client' 'use client'
import { useEffect } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import useSWR from 'swr' import useSWR from 'swr'
import useSWRMutation from 'swr/mutation' import useSWRMutation from 'swr/mutation'
import { useAxios } from '../useAxios' import { useAxios } from '../useAxios'
import { unescapeString } from '@/util/common-utils' import { unescapeString } from '@/util/common-utils'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState, moduleSelectionTotalState } from '@/store/selectedModuleOptions'
import { compasDegAtom } from '@/store/orientationAtom' import { compasDegAtom } from '@/store/orientationAtom'
import { currentCanvasPlanState } from '@/store/canvasAtom' import { currentCanvasPlanState } from '@/store/canvasAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
export function useCanvasPopupStatusController(param = 1) { export function useCanvasPopupStatusController(param = 1) {
const popupType = parseInt(param) const popupType = parseInt(param)
const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom) const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom)
const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState) const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState)
const { getFetcher, postFetcher } = useAxios() const { get, getFetcher, postFetcher } = useAxios()
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
// console.log('🚀 ~ Orientation ~ currentCanvasPlan:', currentCanvasPlan) // console.log('🚀 ~ Orientation ~ currentCanvasPlan:', currentCanvasPlan)
const { /**
data: popupStatus, * 팝업 상태 조회
error, * @param {number} popupTypeParam
isLoading, * @returns
} = useSWR( */
popupType ? `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}` : null, const getModuleSelection = async (popupTypeParam) => {
getFetcher, // const {
) // data: popupStatus,
// error,
// isLoading,
// } = useSWR(
// `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupTypeParam}`,
// getFetcher,
// )
useEffect(() => { const res = await get({
// console.log('🚀 ~ useEffect ~ popupStatus:', popupStatus) url: `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupTypeParam}`,
if (popupStatus) { })
switch (parseInt(popupStatus?.popupType)) {
case 1: return res
setCompasDeg(popupStatus.popupStatus) }
break
case 2: /**
isObjectNotEmpty(popupStatus.popupStatus) * 전체 팝업 상태 조회
? setModuleSelectionDataStore(JSON.parse(unescapeString(popupStatus.popupStatus))) * 조회 전체 데이터 recoil에 저장
: setModuleSelectionDataStore({}) */
break const handleModuleSelectionTotal = async () => {
case 3: for (let i = 1; i < 3; i++) {
break const result = await getModuleSelection(i)
case 4: // setModuleSelectionTotal((prev) => ({ ...prev, [i]: JSON.parse(unescapeString(result.popupStatus)) }))
break if (i === 1) {
case 5: setCompasDeg(result.popupStatus)
break } else if (i === 2) {
case 6: setModuleSelectionDataStore(JSON.parse(unescapeString(result.popupStatus)))
break
default:
}
} else {
switch (popupType) {
case 1:
setCompasDeg(0)
break
case 2:
setModuleSelectionDataStore({
common: {},
roofConstructions: [],
})
break
case 3:
break
case 4:
break
case 5:
break
case 6:
break
default:
} }
} }
}, [popupStatus]) }
// useEffect(() => {
// if (popupStatus) {
// switch (parseInt(popupStatus?.popupType)) {
// case 1:
// setCompasDeg(popupStatus.popupStatus)
// break
// case 2:
// setModuleSelectionDataStore(JSON.parse(unescapeString(popupStatus.popupStatus)))
// break
// case 3:
// break
// case 4:
// break
// case 5:
// break
// case 6:
// break
// default:
// }
// } else {
// switch (popupType) {
// case 1:
// setCompasDeg(0)
// break
// case 2:
// setModuleSelectionDataStore({
// common: {},
// roofConstructions: [],
// })
// break
// case 3:
// break
// case 4:
// break
// case 5:
// break
// case 6:
// break
// default:
// }
// }
// }, [popupStatus])
/**
* 팝업 상태 저장
*/
const { trigger, isMutating } = useSWRMutation( const { trigger, isMutating } = useSWRMutation(
`/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}`, `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}`,
(url, { arg }) => { (url, { arg }) => {
@ -89,5 +116,5 @@ export function useCanvasPopupStatusController(param = 1) {
}, },
) )
return { trigger } return { handleModuleSelectionTotal, trigger }
} }

View File

@ -1,10 +1,11 @@
import { useRecoilValue } from 'recoil' import { useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { selectedRoofMaterialSelector } from '@/store/settingAtom' import { selectedRoofMaterialSelector } from '@/store/settingAtom'
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { useLine } from '@/hooks/useLine' import { useLine } from '@/hooks/useLine'
import { outerLinePointsState } from '@/store/outerLineAtom'
const ROOF_COLOR = { const ROOF_COLOR = {
0: 'rgb(199,240,213)', 0: 'rgb(199,240,213)',
@ -17,6 +18,7 @@ export function useRoofFn() {
const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
const currentObject = useRecoilValue(currentObjectState) const currentObject = useRecoilValue(currentObjectState)
const { addCanvasMouseEventListener, initEvent } = useEvent() const { addCanvasMouseEventListener, initEvent } = useEvent()
const resetPoints = useResetRecoilState(outerLinePointsState)
const { addPitchText } = useLine() const { addPitchText } = useLine()
//면형상 선택 클릭시 지붕 패턴 입히기 //면형상 선택 클릭시 지붕 패턴 입히기
@ -307,5 +309,33 @@ export function useRoofFn() {
return area.points.map((p) => fabric.util.transformPoint({ x: p.x - area.pathOffset.x, y: p.y - area.pathOffset.y }, area.calcTransformMatrix())) return area.points.map((p) => fabric.util.transformPoint({ x: p.x - area.pathOffset.x, y: p.y - area.pathOffset.y }, area.calcTransformMatrix()))
} }
return { setSurfaceShapePattern, removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial } const removeOuterLines = (currentMousePos) => {
const roofBase = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.ROOF)
.filter((roof) => roof.inPolygon(currentMousePos))
if (roofBase.length === 0) {
return
}
const roof = roofBase[0]
const wall = roof.wall
canvas.remove(roof)
canvas.remove(wall)
const allRoofObject = canvas
.getObjects()
.filter((obj) => /*obj !== roof && obj !== wall &&*/ obj.attributes?.roofId === roof.id || obj.parentId === roof.id || obj.parentId === wall.id)
allRoofObject.forEach((obj) => {
canvas.remove(obj)
})
canvas.renderAll()
resetPoints()
}
return { setSurfaceShapePattern, removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial, removeOuterLines }
} }

View File

@ -7,6 +7,9 @@ import { usePolygon } from '@/hooks/usePolygon'
import { useLine } from '@/hooks/useLine' import { useLine } from '@/hooks/useLine'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting'
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
// 외벽선 속성 설정 // 외벽선 속성 설정
export function usePropertiesSetting(id) { export function usePropertiesSetting(id) {
@ -19,7 +22,7 @@ export function usePropertiesSetting(id) {
const { addPolygonByLines } = usePolygon() const { addPolygonByLines } = usePolygon()
const { removeLine, hideLine } = useLine() const { removeLine, hideLine } = useLine()
const { closePopup } = usePopup() const { addPopup, closePopup } = usePopup()
useEffect(() => { useEffect(() => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
@ -134,7 +137,8 @@ export function usePropertiesSetting(id) {
}) })
}) })
canvas.discardActiveObject() canvas.discardActiveObject()
closePopup(id) // closePopup(id)
addPopup(id, 1, <RoofShapeSetting id={id} pos={{ x: 50, y: 230 }} />)
return return
} }
@ -157,10 +161,7 @@ export function usePropertiesSetting(id) {
setPoints([]) setPoints([])
canvas.renderAll() canvas.renderAll()
roof.drawHelpLine() roof.drawHelpLine()
addPopup(id, 1, <RoofAllocationSetting id={id} pos={{ x: 50, y: 230 }} />)
closePopup(id)
return
} else {
return return
} }
} }

View File

@ -1,4 +1,4 @@
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
@ -26,6 +26,7 @@ import { globalLocaleStore } from '@/store/localeAtom'
import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util' import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { outerLinePointsState } from '@/store/outerLineAtom'
// 지붕면 할당 // 지붕면 할당
export function useRoofAllocationSetting(id) { export function useRoofAllocationSetting(id) {
@ -55,6 +56,7 @@ export function useRoofAllocationSetting(id) {
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const resetPoints = useResetRecoilState(outerLinePointsState)
useEffect(() => { useEffect(() => {
setCurrentRoofList(roofList) setCurrentRoofList(roofList)
@ -256,6 +258,7 @@ export function useRoofAllocationSetting(id) {
addPopup(popupId, 1, <ActualSizeSetting id={popupId} />) addPopup(popupId, 1, <ActualSizeSetting id={popupId} />)
} else { } else {
apply() apply()
resetPoints()
} }
} }
@ -495,7 +498,12 @@ export function useRoofAllocationSetting(id) {
} }
const handleChangePitch = (e, index) => { const handleChangePitch = (e, index) => {
const value = e.target.value let value = e.target.value
const reg = /^[0-9]+(\.[0-9]{0,1})?$/
if (!reg.test(value)) {
value = value.substring(0, value.length - 1)
}
const newRoofList = currentRoofList.map((roof, idx) => { const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) { if (idx === index) {
const result = const result =

View File

@ -10,6 +10,7 @@ import { outerLineFixState } from '@/store/outerLineAtom'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { getChonByDegree } from '@/util/canvas-util' import { getChonByDegree } from '@/util/canvas-util'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
// 지붕형상 설정 // 지붕형상 설정
export function useRoofShapeSetting(id) { export function useRoofShapeSetting(id) {
@ -46,7 +47,7 @@ export function useRoofShapeSetting(id) {
const jerkinHeadPitchRef = useRef(null) const jerkinHeadPitchRef = useRef(null)
const history = useRef([]) const history = useRef([])
const { closePopup } = usePopup() const { closePopup, addPopup } = usePopup()
useEffect(() => { useEffect(() => {
pitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch) pitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch)
@ -436,7 +437,7 @@ export function useRoofShapeSetting(id) {
canvas?.renderAll() canvas?.renderAll()
roof.drawHelpLine() roof.drawHelpLine()
isFixRef.current = true isFixRef.current = true
closePopup(id) addPopup(id, 1, <RoofAllocationSetting id={id} pos={{ x: 50, y: 230 }} />)
} }
const initLineSetting = () => { const initLineSetting = () => {
@ -568,6 +569,7 @@ export function useRoofShapeSetting(id) {
pitch: pitchRef.current, pitch: pitchRef.current,
offset: eavesOffset / 10, offset: eavesOffset / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#45CD7D' }) selectedLine.set({ stroke: '#45CD7D' })
@ -579,6 +581,7 @@ export function useRoofShapeSetting(id) {
type: LINE_TYPE.WALLLINE.GABLE, type: LINE_TYPE.WALLLINE.GABLE,
offset: gableOffset / 10, offset: gableOffset / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#3FBAE6' }) selectedLine.set({ stroke: '#3FBAE6' })
break break
@ -590,6 +593,7 @@ export function useRoofShapeSetting(id) {
width: hasSleeve === '0' ? 0 : sleeveOffset / 10, width: hasSleeve === '0' ? 0 : sleeveOffset / 10,
sleeve: hasSleeve === '1', sleeve: hasSleeve === '1',
} }
selectedLine.attributes = { ...attributes, isFixed: true }
break break
} }
case 4: { case 4: {
@ -600,6 +604,7 @@ export function useRoofShapeSetting(id) {
offset: eavesOffset / 10, offset: eavesOffset / 10,
width: hipAndGableWidth / 10, width: hipAndGableWidth / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#45CD7D' }) selectedLine.set({ stroke: '#45CD7D' })
@ -613,6 +618,7 @@ export function useRoofShapeSetting(id) {
width: jerkinHeadWidth / 10, width: jerkinHeadWidth / 10,
pitch: jerkinHeadPitchRef.current, pitch: jerkinHeadPitchRef.current,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#3FBAE6' }) selectedLine.set({ stroke: '#3FBAE6' })
@ -625,13 +631,13 @@ export function useRoofShapeSetting(id) {
pitch: shedPitchRef.current, pitch: shedPitchRef.current,
width: shedWidth / 10, width: shedWidth / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#000000' }) selectedLine.set({ stroke: '#000000' })
break break
} }
} }
selectedLine.attributes = { ...attributes, isFixed: true }
canvas.renderAll() canvas.renderAll()
nextLineFocus(selectedLine) nextLineFocus(selectedLine)
@ -643,7 +649,7 @@ export function useRoofShapeSetting(id) {
const index = lines.findIndex((line) => line.idx === selectedLine.idx) const index = lines.findIndex((line) => line.idx === selectedLine.idx)
const nextLine = lines[index + 1] || lines[0] const nextLine = lines[index + 1] || lines[0]
if (nextLine.attributes.isFixed) { if (nextLine.attributes?.isFixed) {
canvas.discardActiveObject() canvas.discardActiveObject()
return return
} }

View File

@ -68,7 +68,7 @@ export function useContextMenu() {
const { settingsData, setSettingsDataSave } = useCanvasSetting() const { settingsData, setSettingsDataSave } = useCanvasSetting()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { alignModule, modulesRemove, moduleRoofRemove } = useModule() const { alignModule, modulesRemove, moduleRoofRemove } = useModule()
const { removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial } = useRoofFn() const { removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial, removeOuterLines } = useRoofFn()
const currentMenuSetting = () => { const currentMenuSetting = () => {
switch (currentMenu) { switch (currentMenu) {
@ -150,7 +150,9 @@ export function useContextMenu() {
{ {
id: 'wallLineRemove', id: 'wallLineRemove',
name: getMessage('contextmenu.wallline.remove'), name: getMessage('contextmenu.wallline.remove'),
fn: () => deleteOuterLineObject(), fn: (currentMousePos) => {
removeOuterLines(currentMousePos)
},
}, },
], ],
[ [