배치면 초기 설정 후 길이 계산 오류 수정, 배치면 복사 시 길이 이상 수정

This commit is contained in:
hyojun.choi 2026-02-10 11:44:34 +09:00
parent 67e62ee905
commit 256189fe40
3 changed files with 101 additions and 71 deletions

View File

@ -8,7 +8,7 @@ import MaterialGuide from '@/components/floor-plan/modal/placementShape/Material
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { addedRoofsState, roofDisplaySelector, roofMaterialsAtom } from '@/store/settingAtom' import { addedRoofsState, roofDisplaySelector, roofMaterialsAtom } from '@/store/settingAtom'
import { useCommonCode } from '@/hooks/common/useCommonCode' import { useCommonCode } from '@/hooks/common/useCommonCode'
import QSelectBox from '@/components/common/select/QSelectBox' import QSelectBox from '@/components/common/select/QSelectBox'
@ -16,11 +16,12 @@ import { globalLocaleStore } from '@/store/localeAtom'
import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util' import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
import { canvasState } from '@/store/canvasAtom' import { canvasState, currentMenuState } from '@/store/canvasAtom'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { MENU, POLYGON_TYPE } from '@/common/common'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { usePlan } from '@/hooks/usePlan' import { usePlan } from '@/hooks/usePlan'
import { normalizeDecimal, normalizeDigits } from '@/util/input-utils' import { normalizeDecimal } from '@/util/input-utils'
import { logger } from '@/util/logger'
import { CalculatorInput } from '@/components/common/input/CalcInput' import { CalculatorInput } from '@/components/common/input/CalcInput'
/** /**
@ -41,14 +42,21 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
const { basicSetting, setBasicSettings, fetchBasicSettings, basicSettingSave } = useCanvasSetting() const { basicSetting, setBasicSettings, fetchBasicSettings, basicSettingSave } = useCanvasSetting()
const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState) const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState)
const { findCommonCode } = useCommonCode() const { findCommonCode } = useCommonCode()
const [raftCodes, setRaftCodes] = useState([]) /** 서까래 정보 */ const [raftCodes, setRaftCodes] = useState([])
const [currentRoof, setCurrentRoof] = useState(null) /** 현재 선택된 지붕재 정보 */ /** 서까래 정보 */
const { closePopup } = usePopup() /** usePopup에서 closePopup 함수 가져오기 */ const [currentRoof, setCurrentRoof] = useState(null)
/** 현재 선택된 지붕재 정보 */
const { closePopup } = usePopup()
/** usePopup에서 closePopup 함수 가져오기 */
const { drawDirectionArrow } = usePolygon() const { drawDirectionArrow } = usePolygon()
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const roofDisplay = useRecoilValue(roofDisplaySelector) const roofDisplay = useRecoilValue(roofDisplaySelector)
const { setPolygonLinesActualSize } = usePolygon()
const { setSelectedMenu } = useCanvasMenu()
const setCurrentMenu = useSetRecoilState(currentMenuState)
const roofRef = { const roofRef = {
roofCd: useRef(null), roofCd: useRef(null),
width: useRef(null), width: useRef(null),
@ -121,7 +129,12 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
if (addedRoofs.length > 0) { if (addedRoofs.length > 0) {
const raftCodeList = findCommonCode('203800') const raftCodeList = findCommonCode('203800')
setRaftCodes(raftCodeList) setRaftCodes(raftCodeList)
setCurrentRoof({ ...addedRoofs[0], planNo: planNo, roofSizeSet: String(basicSetting.roofSizeSet), roofAngleSet: basicSetting.roofAngleSet }) setCurrentRoof({
...addedRoofs[0],
planNo: planNo,
roofSizeSet: String(basicSetting.roofSizeSet),
roofAngleSet: basicSetting.roofAngleSet,
})
} else { } else {
/** 데이터 설정 확인 후 데이터가 없으면 기본 데이터 설정 */ /** 데이터 설정 확인 후 데이터가 없으면 기본 데이터 설정 */
setCurrentRoof({ ...DEFAULT_ROOF_SETTINGS }) setCurrentRoof({ ...DEFAULT_ROOF_SETTINGS })
@ -209,7 +222,6 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
* 배치면초기설정 저장 버튼 클릭 * 배치면초기설정 저장 버튼 클릭
*/ */
const handleSaveBtn = async () => { const handleSaveBtn = async () => {
const roofInfo = { const roofInfo = {
...currentRoof, ...currentRoof,
planNo: basicSetting.planNo, planNo: basicSetting.planNo,
@ -227,7 +239,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
newAddedRoofs[0] = { ...roofInfo } newAddedRoofs[0] = { ...roofInfo }
setAddedRoofs(newAddedRoofs) setAddedRoofs(newAddedRoofs)
logger.debug('save Info', { console.log('save Info', {
...basicSetting, ...basicSetting,
selectedRoofMaterial: { selectedRoofMaterial: {
...newAddedRoofs[0], ...newAddedRoofs[0],
@ -235,7 +247,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
}) })
/** /**
* 배치면초기설정 저장 * 배치면초기설정 저장 (메뉴 변경/useEffect 트리거 없이)
*/ */
basicSettingSave({ basicSettingSave({
...basicSetting, ...basicSetting,
@ -245,7 +257,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
selectedRoofMaterial: { selectedRoofMaterial: {
...newAddedRoofs[0], ...newAddedRoofs[0],
}, },
}) }, { skipSideEffects: true })
const roofs = canvas.getObjects().filter((obj) => obj.roofMaterial?.index === 0) const roofs = canvas.getObjects().filter((obj) => obj.roofMaterial?.index === 0)
@ -254,7 +266,19 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
setSurfaceShapePattern(roof, roofDisplay.column, false, { ...roofInfo }) setSurfaceShapePattern(roof, roofDisplay.column, false, { ...roofInfo })
roof.roofMaterial = { ...roofInfo } roof.roofMaterial = { ...roofInfo }
drawDirectionArrow(roof) drawDirectionArrow(roof)
setPolygonLinesActualSize(roof, true)
}) })
canvas.renderAll()
/** 지붕면 존재 여부에 따라 메뉴 설정 */
const hasRoofs = canvas.getObjects().some((obj) => obj.name === POLYGON_TYPE.ROOF)
if (hasRoofs) {
setSelectedMenu('surface')
setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING)
} else {
setSelectedMenu('outline')
setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
}
/* 저장 후 화면 닫기 */ /* 저장 후 화면 닫기 */
closePopup(id) closePopup(id)
@ -353,26 +377,26 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
value={index === 0 ? (currentRoof?.pitch ?? basicSetting?.inclBase ?? '0') : (currentRoof?.angle ?? '0')} value={index === 0 ? (currentRoof?.pitch ?? basicSetting?.inclBase ?? '0') : (currentRoof?.angle ?? '0')}
onChange={(value) => { onChange={(value) => {
if (index === 0) { if (index === 0) {
const pitch = value === '' ? '' : Number(value); const pitch = value === '' ? '' : Number(value)
const angle = pitch === '' ? '' : getDegreeByChon(pitch); const angle = pitch === '' ? '' : getDegreeByChon(pitch)
setCurrentRoof(prev => ({ setCurrentRoof((prev) => ({
...prev, ...prev,
pitch, pitch,
angle angle,
})); }))
} else { } else {
const angle = value === '' ? '' : Number(value); const angle = value === '' ? '' : Number(value)
const pitch = angle === '' ? '' : getChonByDegree(angle); const pitch = angle === '' ? '' : getChonByDegree(angle)
setCurrentRoof(prev => ({ setCurrentRoof((prev) => ({
...prev, ...prev,
pitch, pitch,
angle angle,
})); }))
} }
}} }}
options={{ options={{
allowNegative: false, allowNegative: false,
allowDecimal: true allowDecimal: true,
}} }}
/> />
</div> </div>
@ -440,7 +464,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
disabled={currentRoof?.roofSizeSet === '3'} disabled={currentRoof?.roofSizeSet === '3'}
options={{ options={{
allowNegative: false, allowNegative: false,
allowDecimal: false //(index !== 0), allowDecimal: false, //(index !== 0),
}} }}
/> />
</div> </div>
@ -475,7 +499,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
disabled={currentRoof?.roofSizeSet === '3'} disabled={currentRoof?.roofSizeSet === '3'}
options={{ options={{
allowNegative: false, allowNegative: false,
allowDecimal: false //(index !== 0), allowDecimal: false, //(index !== 0),
}} }}
/> />
</div> </div>
@ -522,20 +546,19 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
ref={roofRef.hajebichi} ref={roofRef.hajebichi}
value={currentRoof?.hajebichi ?? basicSetting?.roofPchBase ?? '0'} value={currentRoof?.hajebichi ?? basicSetting?.roofPchBase ?? '0'}
onChange={(value) => { onChange={(value) => {
const hajebichi = value === '' ? '' : Number(value); const hajebichi = value === '' ? '' : Number(value)
setCurrentRoof(prev => ({ setCurrentRoof((prev) => ({
...prev, ...prev,
hajebichi hajebichi,
})); }))
}} }}
readOnly={currentRoof?.roofPchAuth === 'R'} readOnly={currentRoof?.roofPchAuth === 'R'}
disabled={currentRoof?.roofSizeSet === '3'} disabled={currentRoof?.roofSizeSet === '3'}
options={{ options={{
allowNegative: false, allowNegative: false,
allowDecimal: false //(index !== 0), allowDecimal: false, //(index !== 0),
}} }}
/> />
</div> </div>
</div> </div>
)} )}

View File

@ -633,9 +633,7 @@ export function useCommonUtils() {
// 원본 roof의 자식 오브젝트들 찾기 (개구, 그림자, 도머 등) // 원본 roof의 자식 오브젝트들 찾기 (개구, 그림자, 도머 등)
const childObjectTypes = [BATCH_TYPE.OPENING, BATCH_TYPE.SHADOW, BATCH_TYPE.TRIANGLE_DORMER, BATCH_TYPE.PENTAGON_DORMER] const childObjectTypes = [BATCH_TYPE.OPENING, BATCH_TYPE.SHADOW, BATCH_TYPE.TRIANGLE_DORMER, BATCH_TYPE.PENTAGON_DORMER]
const childObjects = canvas.getObjects().filter( const childObjects = canvas.getObjects().filter((o) => o.parentId === obj.id && childObjectTypes.includes(o.name))
(o) => o.parentId === obj.id && childObjectTypes.includes(o.name)
)
// 원본 roof 중심점 계산 // 원본 roof 중심점 계산
const originalPoints = obj.getCurrentPoints() const originalPoints = obj.getCurrentPoints()
@ -669,7 +667,9 @@ export function useCommonUtils() {
y: p.y + offsetY, y: p.y + offsetY,
})) }))
clonedObj = new QPolygon(newPoints, { clonedObj = new QPolygon(
newPoints,
{
fill: obj.fill || 'transparent', fill: obj.fill || 'transparent',
stroke: obj.stroke || 'black', stroke: obj.stroke || 'black',
strokeWidth: obj.strokeWidth || 1, strokeWidth: obj.strokeWidth || 1,
@ -685,8 +685,10 @@ export function useCommonUtils() {
originY: 'center', originY: 'center',
pitch: obj.pitch, pitch: obj.pitch,
surfaceId: obj.surfaceId, surfaceId: obj.surfaceId,
sort: false, // sort: false,
}, canvas) },
canvas,
)
canvas.add(clonedObj) canvas.add(clonedObj)

View File

@ -440,6 +440,7 @@ export function useCanvasSetting(executeEffect = true) {
}) })
setAddedRoofs(addRoofs) setAddedRoofs(addRoofs)
if (openPoint !== 'basicSettingSave') {
setCanvasSetting({ setCanvasSetting({
...basicSetting, ...basicSetting,
roofMaterials: addRoofs[0], roofMaterials: addRoofs[0],
@ -450,6 +451,7 @@ export function useCanvasSetting(executeEffect = true) {
selectedRoofMaterial: addRoofs.find((roof) => roof.selected), selectedRoofMaterial: addRoofs.find((roof) => roof.selected),
}) })
} }
}
}) })
} catch (error) { } catch (error) {
console.error('Data fetching error:', error) console.error('Data fetching error:', error)
@ -474,7 +476,8 @@ export function useCanvasSetting(executeEffect = true) {
/** /**
* 기본설정(PlacementShapeSetting) 저장 * 기본설정(PlacementShapeSetting) 저장
*/ */
const basicSettingSave = async (params) => { const basicSettingSave = async (params, options = {}) => {
const { skipSideEffects = false } = options
try { try {
const patternData = { const patternData = {
objectNo: correntObjectNo, objectNo: correntObjectNo,
@ -527,6 +530,7 @@ export function useCanvasSetting(executeEffect = true) {
setBasicSettings({ ...params }) setBasicSettings({ ...params })
}) })
if (!skipSideEffects) {
/** CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */ /** CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */
setCanvasSetting({ setCanvasSetting({
...basicSetting, ...basicSetting,
@ -535,6 +539,7 @@ export function useCanvasSetting(executeEffect = true) {
/** 메뉴 설정 */ /** 메뉴 설정 */
setMenuByRoofSize(params.roofSizeSet) setMenuByRoofSize(params.roofSizeSet)
}
/** 배치면초기설정 조회 */ /** 배치면초기설정 조회 */
fetchBasicSettings(params.planNo, 'basicSettingSave') fetchBasicSettings(params.planNo, 'basicSettingSave')