qcast-front/src/hooks/roofcover/useRoofAllocationSetting.js

618 lines
20 KiB
JavaScript

import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, currentAngleTypeSelector, currentObjectState } from '@/store/canvasAtom'
import { useContext, useEffect, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal'
import { usePolygon } from '@/hooks/usePolygon'
import {
addedRoofsState,
basicSettingState,
correntObjectNoState,
corridorDimensionSelector,
roofDisplaySelector,
roofMaterialsSelector,
selectedRoofMaterialSelector,
} from '@/store/settingAtom'
import { usePopup } from '@/hooks/usePopup'
import { POLYGON_TYPE } from '@/common/common'
import { v4 as uuidv4 } from 'uuid'
import ActualSizeSetting from '@/components/floor-plan/modal/roofAllocation/ActualSizeSetting'
import { useMessage } from '@/hooks/useMessage'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { globalLocaleStore } from '@/store/localeAtom'
import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { QcastContext } from '@/app/QcastProvider'
import { usePlan } from '@/hooks/usePlan'
import { roofsState } from '@/store/roofAtom'
export function useRoofAllocationSetting(id) {
const canvas = useRecoilValue(canvasState)
const [correntObjectNo, setCorrentObjectNo] = useRecoilState(correntObjectNoState)
const roofDisplay = useRecoilValue(roofDisplaySelector)
const { drawDirectionArrow, addLengthText, splitPolygonWithLines, splitPolygonWithSeparate } = usePolygon()
const [popupId, setPopupId] = useState(uuidv4())
const { addPopup, closePopup, closeAll } = usePopup()
const currentObject = useRecoilValue(currentObjectState)
const { setSelectedMenu } = useCanvasMenu()
const roofMaterials = useRecoilValue(roofMaterialsSelector)
const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
const [basicSetting, setBasicSetting] = useRecoilState(basicSettingState)
const [currentRoofMaterial, setCurrentRoofMaterial] = useState(roofMaterials[0])
/** 팝업 내 기준 지붕재 */
const [roofList, setRoofList] = useRecoilState(addedRoofsState)
/** 배치면 초기설정에서 선택한 지붕재 배열 */
const [editingLines, setEditingLines] = useState([])
const [currentRoofList, setCurrentRoofList] = useState([])
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const [basicInfo, setBasicInfo] = useState(null)
const { get, post } = useAxios(globalLocaleState)
const { getMessage } = useMessage()
const { swalFire } = useSwal()
const { setIsGlobalLoading } = useContext(QcastContext)
const { setSurfaceShapePattern } = useRoofFn()
const { saveCanvas } = usePlan()
const [roofsStore, setRoofsStore] = useRecoilState(roofsState)
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const resetPoints = useResetRecoilState(outerLinePointsState)
const [corridorDimension, setCorridorDimension] = useRecoilState(corridorDimensionSelector)
useEffect(() => {
/** 배치면 초기설정에서 선택한 지붕재 배열 설정 */
setCurrentRoofList(roofList)
}, [])
useEffect(() => {
/** 지붕면 조회 */
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) /** roofPolygon.innerLines */
roofBases.forEach((roof) => {
roof.innerLines.forEach((line) => {
/** 실측값이 없는 경우 라인 두께 4로 설정 */
if (!line.attributes.actualSize || line.attributes?.actualSize === 0) {
line.set({ strokeWidth: 4, stroke: 'black', selectable: true })
}
/** 현재 선택된 라인인 경우 라인 두께 2로 설정 */
if (editingLines.includes(line)) {
line.set({ strokeWidth: 2, stroke: 'black', selectable: true })
}
})
})
/** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
if (currentObject && currentObject.name && ['auxiliaryLine', 'ridge', 'hip'].includes(currentObject.name)) {
currentObject.set({ strokeWidth: 4, stroke: '#EA10AC' })
}
}, [currentObject])
useEffect(() => {
/** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
if (roofBases.length === 0) {
swalFire({ text: getMessage('roofAllocation.not.found'), icon: 'warning' })
closePopup(id)
}
/** 배치면 초기설정 조회 */
fetchBasicSettings(basicSetting.planNo)
}, [])
/**
* 배치면 초기설정 조회
*/
const fetchBasicSettings = async (planNo) => {
try {
await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}` }).then((res) => {
let roofsArray = {}
if (res.length > 0) {
roofsArray = res.map((item) => {
return {
planNo: item.planNo,
roofApply: item.roofApply,
roofSeq: item.roofSeq,
roofMatlCd: item.roofMatlCd,
roofWidth: item.roofWidth,
roofHeight: item.roofHeight,
roofHajebichi: item.roofHajebichi,
roofGap: item.roofGap,
roofLayout: item.roofLayout,
roofPitch: item.roofPitch,
roofAngle: item.roofAngle,
}
})
} else {
roofsArray = [
{
planNo: planNo,
roofApply: true,
roofSeq: 0,
roofMatlCd: 'ROOF_ID_WA_53A',
roofWidth: 265,
roofHeight: 235,
roofHajebichi: 0,
roofGap: 'HEI_455',
roofLayout: 'P',
roofPitch: 4,
roofAngle: 21.8,
},
]
}
/**
* 데이터 설정
*/
const selectRoofs = []
for (let i = 0; i < roofsArray.length; i++) {
roofMaterials?.map((material) => {
if (material.roofMatlCd === roofsArray[i].roofMatlCd) {
selectRoofs.push({
...material,
selected: roofsArray[i].roofApply,
index: roofsArray[i].roofSeq,
id: roofsArray[i].roofMatlCd,
width: roofsArray[i].roofWidth,
length: roofsArray[i].roofHeight,
hajebichi: roofsArray[i].roofHajebichi,
raft: roofsArray[i].roofGap,
layout: roofsArray[i].roofLayout,
pitch: roofsArray[i].roofPitch,
angle: roofsArray[i].roofAngle,
})
}
})
}
setBasicSetting({
...basicSetting,
planNo: res[0].planNo,
roofSizeSet: res[0].roofSizeSet,
roofAngleSet: res[0].roofAngleSet,
roofsData: roofsArray,
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
})
setBasicInfo({
planNo: '' + res[0].planNo,
roofSizeSet: '' + res[0].roofSizeSet,
roofAngleSet: '' + res[0].roofAngleSet,
})
})
} catch (error) {
console.error('Data fetching error:', error)
}
}
/**
* 지붕면 할당 저장
*/
const basicSettingSave = async () => {
try {
setIsGlobalLoading(true)
const patternData = {
objectNo: correntObjectNo,
planNo: Number(basicSetting.planNo),
roofSizeSet: Number(basicSetting.roofSizeSet),
roofAngleSet: basicSetting.roofAngleSet,
roofAllocationList: currentRoofList.map((item, index) => ({
planNo: Number(basicSetting.planNo),
roofApply: item.selected,
roofSeq: index,
roofMatlCd: item.roofMatlCd === null || item.roofMatlCd === undefined ? 'ROOF_ID_WA_53A' : item.roofMatlCd,
roofWidth: item.width === null || item.width === undefined ? 0 : Number(item.width),
roofHeight: item.length === null || item.length === undefined ? 0 : Number(item.length),
roofHajebichi: item.hajebichi === null || item.hajebichi === undefined ? 0 : Number(item.hajebichi),
roofGap: !item.raft ? item.raftBaseCd : item.raft,
roofLayout: item.layout === null || item.layout === undefined ? 'P' : item.layout,
roofPitch: item.pitch === null || item.pitch === undefined ? 4 : Number(item.pitch),
roofAngle: item.angle === null || item.angle === undefined ? 21.8 : Number(item.angle),
})),
}
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData }).then((res) => {
setIsGlobalLoading(false)
})
//Recoil 설정
//setCanvasSetting({ ...basicSetting })
/** 배치면 초기설정 조회 */
fetchBasicSettings(basicSetting.planNo)
} catch (error) {
swalFire({ text: error.message, icon: 'error' })
}
}
/**
* 지붕재 추가
*/
const onAddRoofMaterial = () => {
if (currentRoofList.length >= 4) {
swalFire({ type: 'alert', icon: 'error', text: getMessage('roof.exceed.count') })
return
}
const originCurrentRoofList = currentRoofList.map((roof) => {
return { ...roof, selected: false }
})
originCurrentRoofList.push({
...currentRoofMaterial,
selected: true,
id: currentRoofMaterial.roofMatlCd,
name: currentRoofMaterial.roofMatlNm,
index: currentRoofList.length,
})
setCurrentRoofList(originCurrentRoofList)
}
/**
* 지붕재 삭제
*/
const onDeleteRoofMaterial = (idx) => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
for (let i = 0; i < roofs.length; i++) {
if (roofs[i].roofMaterial?.index === idx) {
swalFire({ type: 'alert', icon: 'error', text: getMessage('roof.material.can.not.delete') })
return
}
}
const isSelected = currentRoofList[idx].selected
const newRoofList = JSON.parse(JSON.stringify(currentRoofList)).filter((_, index) => index !== idx)
if (isSelected) {
newRoofList[0].selected = true
}
setCurrentRoofList(newRoofList)
setRoofsStore(newRoofList)
setModuleSelectionData({ ...moduleSelectionData, roofConstructions: newRoofList })
}
/**
* 선택한 지붕재로 할당
*/
const handleSave = () => {
/**
* 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정
*/
if (checkInnerLines()) {
addPopup(popupId, 1, <ActualSizeSetting id={popupId} />)
} else {
apply()
resetPoints()
basicSettingSave()
}
}
/**
* 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우
*/
const handleSaveContext = () => {
const newRoofList = currentRoofList.map((roof, idx) => {
if (roof.index !== idx) {
// 기존 저장된 지붕재의 index 수정
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF && obj.roofMaterial?.index === roof.index)
roofs.forEach((roof) => {
setSurfaceShapePattern(roof, roofDisplay.column, false, { ...roof, index: idx }, true)
})
}
return { ...roof, index: idx, raft: roof.raft ? roof.raft : roof.raftBaseCd }
})
setBasicSetting((prev) => {
return { ...prev, selectedRoofMaterial: newRoofList.find((roof) => roof.selected) }
})
setRoofList(newRoofList)
setRoofMaterials(newRoofList)
setRoofsStore(newRoofList)
const selectedRoofMaterial = newRoofList.find((roof) => roof.selected)
setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial, true)
drawDirectionArrow(currentObject)
modifyModuleSelectionData()
// closeAll()
closePopup(id)
basicSettingSave()
setModuleSelectionData({ ...moduleSelectionData, roofConstructions: newRoofList })
}
/**
* 기존 세팅된 지붕에 지붕재 내용을 바뀐 내용으로 수정
* @param newRoofMaterials
*/
const setRoofMaterials = (newRoofMaterials) => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
newRoofMaterials.forEach((roofMaterial) => {
const index = roofMaterial.index
const tempRoofs = roofs.filter((roof) => roof.roofMaterial?.index === index)
tempRoofs.forEach((roof) => {
setSurfaceShapePattern(roof, roofDisplay.column, false, roofMaterial)
})
})
}
/**
* 지붕면 할당
*/
const handleAlloc = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // roofPolygon.innerLines
roofBases.forEach((roof) => {
if (roof.separatePolygon.length === 0) {
roof.innerLines.forEach((line) => {
if ((!line.attributes.actualSize || line.attributes?.actualSize === 0) && line.length > 1) {
line.set({ attributes: { ...line.attributes, actualSize: line.attributes.planeSize } })
}
})
}
})
apply()
}
/**
* 실측값 없는 경우 체크
*/
const checkInnerLines = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // roofPolygon.innerLines
let result = false
roofBases.forEach((roof) => {
const auxiliaryLines = canvas
.getObjects()
.filter((obj) => obj.name === 'auxiliaryLine' && roof.inPolygonImproved(obj.startPoint) && roof.inPolygonImproved(obj.endPoint))
auxiliaryLines.forEach((auxiliaryLine) => {
roof.innerLines.push(auxiliaryLine)
})
if (roof.separatePolygon.length === 0) {
roof.innerLines.forEach((line) => {
if ((!line.attributes.actualSize || line.attributes?.actualSize === 0) && line.length > 1) {
line.set({ strokeWidth: 4, stroke: 'black', selectable: true })
result = true
}
})
}
})
if (result) canvas?.renderAll()
return result
}
/**
* 지붕면 할당
*/
const apply = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF && !obj.roofMaterial)
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
roofBases.forEach((roofBase) => {
try {
if (roofBase.separatePolygon.length > 0) {
splitPolygonWithSeparate(roofBase.separatePolygon)
} else {
splitPolygonWithLines(roofBase)
}
} catch (e) {
console.log(e)
canvas.discardActiveObject()
return
}
/** 라인 삭제 */
roofBase.innerLines.forEach((line) => {
canvas.remove(line)
})
canvas.remove(roofBase)
})
/** 벽면 삭제 */
wallLines.forEach((wallLine) => {
canvas.remove(wallLine)
})
/** 데이터 설정 */
const newRoofList = currentRoofList.map((roof, idx) => {
return { ...roof, index: idx, ...basicInfo, raft: roof.raft ? roof.raft : roof.raftBaseCd }
})
setBasicSetting((prev) => {
return { ...prev, selectedRoofMaterial: newRoofList.find((roof) => roof.selected) }
})
setRoofList(newRoofList)
const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof')
roofs.forEach((roof) => {
if (roof.isFixed) return
roof.set({ isFixed: true })
/** 모양 패턴 설정 */
setSurfaceShapePattern(
roof,
roofDisplay.column,
false,
currentRoofList.find((roof) => roof.selected),
)
drawDirectionArrow(roof)
})
setRoofMaterials(newRoofList)
setRoofsStore(newRoofList)
/** 외곽선 삭제 */
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine' || obj.name === 'pitchText')
removeTargets.forEach((obj) => {
canvas.remove(obj)
})
setEditingLines([])
closeAll()
setSelectedMenu('surface')
//지붕면 완성 후 실측치 로 보이도록 수정
setCorridorDimension(1)
/** 모듈 선택 데이터 초기화 */
// modifyModuleSelectionData()
setModuleSelectionData({ ...moduleSelectionData, roofConstructions: newRoofList })
}
/**
* 라인 사이즈 설정
*/
const setLineSize = (id, size) => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofBases.forEach((roof) => {
roof.innerLines.forEach((line) => {
if (id === line.id) {
setEditingLines([...editingLines.filter((editLine) => editLine.id !== line.id), line])
line.attributes.actualSize = size
line.set({ strokeWidth: 2, stroke: 'black' })
}
})
})
canvas?.renderAll()
}
/**
* 지붕재 변경
*/
const handleChangeRoofMaterial = (value, index) => {
const selectedRoofMaterial = roofMaterials.find((roof) => roof.roofMatlCd === value.id)
const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) {
return { ...selectedRoofMaterial, selected: roof.selected, index }
}
return roof
})
setCurrentRoofList(newRoofList)
}
/**
* 기본 지붕재 radio값 변경
*/
const handleDefaultRoofMaterial = (index) => {
const newRoofList = currentRoofList.map((roof, idx) => {
return { ...roof, selected: idx === index }
})
setCurrentRoofList(newRoofList)
}
/**
* 서까래 변경
*/
const handleChangeRaft = (e, index) => {
const raftValue = e.clCode
const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) {
return { ...roof, raft: raftValue }
}
return roof
})
setCurrentRoofList(newRoofList)
}
/**
* 레이아웃 변경
*/
const handleChangeLayout = (layoutValue, index) => {
const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) {
return { ...roof, layout: layoutValue }
}
return roof
})
setCurrentRoofList(newRoofList)
}
/**
* 치수 입력방법(복시도입력/실측값입력/육지붕)
*/
const handleChangeInput = (e, type = '', index) => {
const value = e.target.value
const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) {
return { ...roof, [type]: value }
}
return roof
})
setCurrentRoofList(newRoofList)
}
/**
* 피치 변경
*/
const handleChangePitch = (e, index) => {
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) => {
if (idx === index) {
const result =
currentAngleType === 'slope'
? {
pitch: value,
angle: getDegreeByChon(value),
}
: { pitch: getChonByDegree(value), angle: value }
return { ...roof, ...result }
}
return roof
})
setCurrentRoofList(newRoofList)
}
/**
* 모듈 선택에서 선택한 데이터 초기화
*/
const modifyModuleSelectionData = () => {
if (moduleSelectionData.roofConstructions?.length > 0) {
setModuleSelectionData({ ...moduleSelectionData, roofConstructions: [] })
moduleSelectedDataTrigger({ ...moduleSelectionData, roofConstructions: [] })
}
}
/**
* 모듈 선택 데이터 트리거
*/
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
return {
handleSave,
onAddRoofMaterial,
onDeleteRoofMaterial,
handleAlloc,
setLineSize,
roofMaterials,
selectedRoofMaterial,
basicSetting,
setBasicSetting,
currentRoofMaterial,
setCurrentRoofMaterial,
handleDefaultRoofMaterial,
handleChangeRoofMaterial,
handleChangeRaft,
handleChangeLayout,
handleSaveContext,
currentRoofList,
handleChangeInput,
handleChangePitch,
}
}