From 21634a7a8a0b0b703f60ce7d6c9f7a073367d042 Mon Sep 17 00:00:00 2001 From: ysCha Date: Mon, 25 Aug 2025 17:39:06 +0900 Subject: [PATCH] =?UTF-8?q?[1237]=EB=AA=A8=EB=93=88=EC=84=A4=EC=A0=95,=20?= =?UTF-8?q?=EA=B3=B5=EB=B2=95=EC=84=A4=EC=A0=95=EC=8B=9C=EC=97=90=20?= =?UTF-8?q?=EB=AF=B8=EB=A6=AC=20=EA=B7=9C=EC=A0=95=EC=9D=98=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=EC=9D=B4=20=EC=9E=85=EB=A0=A5,=20=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=EC=A7=80=EB=B6=95=EC=84=A4=EC=A0=95=20<=3D>=20=EA=B0=9C?= =?UTF-8?q?=EB=B1=94=EC=A7=80=EB=B6=95=EC=84=A4=EC=A0=95[0]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/select/QSelectBox.jsx | 14 +- .../floor-plan/modal/basic/step/Trestle.jsx | 159 +++++++++++++++--- .../placementShape/PlacementShapeSetting.jsx | 7 +- .../common/useCanvasPopupStatusController.js | 2 +- 4 files changed, 156 insertions(+), 26 deletions(-) diff --git a/src/components/common/select/QSelectBox.jsx b/src/components/common/select/QSelectBox.jsx index 495f3ae6..dbb3c285 100644 --- a/src/components/common/select/QSelectBox.jsx +++ b/src/components/common/select/QSelectBox.jsx @@ -14,6 +14,7 @@ import { useMessage } from '@/hooks/useMessage' * @param {string} targetKey - value에 있는 키 * @param {string} showKey - options 있는 키중 보여줄 키 * @param {object} params - 추가 파라미터 + * @param {boolean} showFirstOptionWhenEmpty - value가 빈값일 때 첫 번째 옵션을 보여줄지 여부 * @returns */ export default function QSelectBox({ @@ -27,6 +28,7 @@ export default function QSelectBox({ showKey = '', params = {}, tagTitle = '', + showFirstOptionWhenEmpty = false, }) { const { getMessage } = useMessage() @@ -39,7 +41,9 @@ export default function QSelectBox({ if (options.length === 0) return title !== '' ? title : getMessage('selectbox.title') if (showKey !== '' && !value) { //value가 없으면 showKey가 있으면 우선 보여준다 - // return options[0][showKey] + if (showFirstOptionWhenEmpty && options.length > 0) { + return options[0][showKey] + } return title !== '' ? title : getMessage('selectbox.title') } else if (showKey !== '' && value) { //value가 있으면 sourceKey와 targetKey를 비교하여 보여준다 @@ -48,12 +52,18 @@ export default function QSelectBox({ return option[sourceKey] === value[targetKey] }) if (!option) { + if (showFirstOptionWhenEmpty && options.length > 0) { + return options[0][showKey] + } return title !== '' ? title : getMessage('selectbox.title') } else { return option[showKey] } } else { //일치하는 조건이 없으면 기본값을 보여준다. + if (showFirstOptionWhenEmpty && options.length > 0) { + return showKey !== '' ? options[0][showKey] : options[0].name + } return title !== '' ? title : getMessage('selectbox.title') } } @@ -74,7 +84,7 @@ export default function QSelectBox({ useEffect(() => { // value && handleClickSelectOption(value) setSelected(handleInitState()) - }, [options, value, sourceKey, targetKey, showKey]) + }, [options, value, sourceKey, targetKey, showKey, showFirstOptionWhenEmpty]) useOnClickOutside(ref, handleClose) diff --git a/src/components/floor-plan/modal/basic/step/Trestle.jsx b/src/components/floor-plan/modal/basic/step/Trestle.jsx index d017803a..c8b40ef3 100644 --- a/src/components/floor-plan/modal/basic/step/Trestle.jsx +++ b/src/components/floor-plan/modal/basic/step/Trestle.jsx @@ -59,12 +59,21 @@ const Trestle = forwardRef((props, ref) => { const { restoreModuleInstArea } = useModuleBasicSetting() const [flag, setFlag] = useState(false) const tempModuleSelectionData = useRef(null) + const [autoSelectStep, setAutoSelectStep] = useState(null) // 'raftBase', 'trestle', 'constMthd', 'roofBase', 'construction' + useEffect(() => { if (roofs && !selectedRoof) { + console.log("roofs:::::", roofs.length) + setLengthBase(roofs[0].length); setSelectedRoof(roofs[0]) } - + if (selectedRoof && selectedRoof.lenAuth === "C") { + onChangeLength(selectedRoof.length); + } + if (selectedRoof && ["C", "R"].includes(selectedRoof.raftAuth)) { + onChangeRaftBase(roofs[0]); + } //모듈 설치 영역 복구 restoreModuleInstArea() }, [roofs]) @@ -101,41 +110,86 @@ const Trestle = forwardRef((props, ref) => { useEffect(() => { if (trestleList.length > 0) { - setSelectedTrestle(trestleList.find((trestle) => trestle.trestleMkrCd === trestleState?.trestleMkrCd) ?? null) + const existingTrestle = trestleList.find( + (trestle) => trestle.trestleMkrCd === trestleState?.trestleMkrCd + ); + if (existingTrestle) { + setSelectedTrestle(existingTrestle) + } else if (autoSelectStep === 'trestle') { + // 자동 선택: 첫 번째 가대메이커 선택 + console.log('Auto selecting first trestle:', trestleList[0]) + const firstTrestle = trestleList[0] + onChangeTrestleMaker(firstTrestle) + // setAutoSelectStep은 onChangeTrestleMaker 내부에서 처리됨 + } } else { setSelectedTrestle(null) } - }, [trestleList]) - - useEffect(() => { - if (roofBaseList.length > 0) { - setSelectedRoofBase(roofBaseList.find((roofBase) => roofBase.roofBaseCd === trestleState?.roofBaseCd) ?? null) - } else { - setSelectedRoofBase(null) - } - }, [roofBaseList]) + }, [trestleList, autoSelectStep]) useEffect(() => { if (constMthdList.length > 0) { - setSelectedConstMthd(constMthdList.find((constMthd) => constMthd.constMthdCd === trestleState?.constMthdCd) ?? null) + const existingConstMthd = constMthdList.find((constMthd) => constMthd.constMthdCd === trestleState?.constMthdCd) + if (existingConstMthd) { + setSelectedConstMthd(existingConstMthd) + } else if (autoSelectStep === 'constMthd') { + // 자동 선택: 첫 번째 공법 선택 + const firstConstMthd = constMthdList[0] + onChangeConstMthd(firstConstMthd) + setAutoSelectStep('roofBase') // 다음 단계로 설정 + } } else { setSelectedConstMthd(null) } - }, [constMthdList]) + }, [constMthdList, autoSelectStep]) + + useEffect(() => { + if (roofBaseList.length > 0) { + const existingRoofBase = roofBaseList.find((roofBase) => roofBase.roofBaseCd === trestleState?.roofBaseCd) + if (existingRoofBase) { + setSelectedRoofBase(existingRoofBase) + } else if (autoSelectStep === 'roofBase') { + // 자동 선택: 첫 번째 지붕밑바탕 선택 + const firstRoofBase = roofBaseList[0] + onChangeRoofBase(firstRoofBase) + setAutoSelectStep('construction') // 다음 단계로 설정 + } + } else { + setSelectedRoofBase(null) + } + }, [roofBaseList, autoSelectStep]) useEffect(() => { if (constructionList.length > 0) { - setSelectedConstruction(constructionList.find((construction) => construction.constTp === trestleState?.construction?.constTp) ?? null) + const existingConstruction = constructionList.find((construction) => construction.constTp === trestleState?.construction?.constTp) + if (existingConstruction) { + setSelectedConstruction(existingConstruction) + } else if (autoSelectStep === 'construction') { + // 자동 선택: 첫 번째 가능한 construction 선택 + const availableConstructions = constructionList.filter((construction) => construction.constPossYn === 'Y') + if (availableConstructions.length > 0) { + const firstConstruction = availableConstructions[0] + const firstIndex = constructionList.findIndex((construction) => construction.constTp === firstConstruction.constTp) + handleConstruction(firstIndex) + setAutoSelectStep(null) // 자동 선택 완료 + } else { + Swal.fire({ + title: getMessage('modal.module.basic.settting.module.error4', [selectedRoof?.nameJp]), + icon: 'warning', + }) + } + } + if (constructionList.filter((construction) => construction.constPossYn === 'Y').length === 0) { Swal.fire({ - title: getMessage('modal.module.basic.settting.module.error4', [selectedRoof?.nameJp]), // 시공법법을 선택해주세요. + title: getMessage('modal.module.basic.settting.module.error4', [selectedRoof?.nameJp]), icon: 'warning', }) } } else { setSelectedConstruction(null) } - }, [constructionList]) + }, [constructionList, autoSelectStep]) const getConstructionState = (index) => { if (constructionList && constructionList.length > 0) { @@ -152,6 +206,13 @@ const Trestle = forwardRef((props, ref) => { const onChangeLength = (e) => { setLengthBase(e) + // 다음 단계들 초기화 + setSelectedRaftBase(null) + setSelectedTrestle(null) + setSelectedConstMthd(null) + setSelectedRoofBase(null) + setSelectedConstruction(null) + dispatch({ type: 'SET_LENGTH', roof: { @@ -161,10 +222,24 @@ const Trestle = forwardRef((props, ref) => { raft: selectedRaftBase?.clCode, }, }) + + // 자동으로 첫 번째 서까래 간격 선택 + if (raftBaseList.length > 0) { + + const inx = raftBaseList.findIndex((raft) => raft.clCode === selectedRoof?.raft) ?? 0 + const firstRaftBase = raftBaseList[inx] + onChangeRaftBase(firstRaftBase) + } } const onChangeRaftBase = (e) => { setSelectedRaftBase(e) + // 다음 단계들 초기화 + setSelectedTrestle(null) + setSelectedConstMthd(null) + setSelectedRoofBase(null) + setSelectedConstruction(null) + dispatch({ type: 'SET_RAFT_BASE', roof: { @@ -173,10 +248,20 @@ const Trestle = forwardRef((props, ref) => { raft: e.clCode, }, }) + + // 다음 단계(가대메이커) 자동 선택 설정 - 지연 실행 + setTimeout(() => { + setAutoSelectStep('trestle') + }, 500) // API 호출 완료를 위한 더 긴 지연 } const onChangeHajebichi = (e) => { setHajebichi(e) + // 다음 단계들 초기화 + setSelectedTrestle(null) + setSelectedConstMthd(null) + setSelectedRoofBase(null) + setSelectedConstruction(null) // roofs 배열에서 selectedRoof.index와 같은 인덱스의 지붕 객체 업데이트 if (selectedRoof && selectedRoof.index !== undefined) { @@ -193,10 +278,20 @@ const Trestle = forwardRef((props, ref) => { hajebichi: e, }, }) + + // 다음 단계(가대메이커) 자동 선택 설정 - 지연 실행 + setTimeout(() => { + setAutoSelectStep('trestle') + }, 500) } const onChangeTrestleMaker = (e) => { setSelectedTrestle(e) + // 다음 단계들 초기화 + setSelectedConstMthd(null) + setSelectedRoofBase(null) + setSelectedConstruction(null) + dispatch({ type: 'SET_TRESTLE_MAKER', roof: { @@ -206,32 +301,48 @@ const Trestle = forwardRef((props, ref) => { trestleMkrCd: e.trestleMkrCd, }, }) + + // API 호출 완료 후 다음 단계(공법) 자동 선택 설정 + setTimeout(() => { + setAutoSelectStep('constMthd') + }, 300) } const onChangeConstMthd = (e) => { setSelectedConstMthd(e) + // 다음 단계 초기화 + setSelectedRoofBase(null) + setSelectedConstruction(null) + dispatch({ type: 'SET_CONST_MTHD', roof: { moduleTpCd: selectedModules.itemTp ?? '', roofMatlCd: selectedRoof?.roofMatlCd ?? '', raft: selectedRaftBase?.clCode, - trestleMkrCd: selectedTrestle.trestleMkrCd, + trestleMkrCd: selectedTrestle?.trestleMkrCd, constMthdCd: e.constMthdCd, }, }) + + // API 호출 완료 후 다음 단계(지붕밑바탕) 자동 선택 설정 + setTimeout(() => { + setAutoSelectStep('roofBase') + }, 300) } const onChangeRoofBase = (e) => { setSelectedRoofBase(e) + setSelectedConstruction(null) + dispatch({ type: 'SET_ROOF_BASE', roof: { moduleTpCd: selectedModules.itemTp ?? '', roofMatlCd: selectedRoof?.roofMatlCd ?? '', raft: selectedRaftBase?.clCode, - trestleMkrCd: selectedTrestle.trestleMkrCd, - constMthdCd: selectedConstMthd.constMthdCd, + trestleMkrCd: selectedTrestle?.trestleMkrCd, + constMthdCd: selectedConstMthd?.constMthdCd, roofBaseCd: e.roofBaseCd, illuminationTp: managementState?.surfaceTypeValue ?? '', instHt: managementState?.installHeight ?? '', @@ -241,6 +352,11 @@ const Trestle = forwardRef((props, ref) => { roofPitch: Math.round(hajebichi ?? 0), }, }) + + // API 호출 완료 후 다음 단계(construction) 자동 선택 설정 + setTimeout(() => { + setAutoSelectStep('construction') + }, 300) } const handleConstruction = (index) => { @@ -594,6 +710,8 @@ const Trestle = forwardRef((props, ref) => { showKey={'clCodeNm'} disabled={selectedRoof.raftAuth === 'R'} onChange={(e) => onChangeRaftBase(e)} + showFirstOptionWhenEmpty={true} + /> )} @@ -644,6 +762,7 @@ const Trestle = forwardRef((props, ref) => { targetKey={'trestleMkrCd'} showKey={'trestleMkrCdJp'} onChange={(e) => onChangeTrestleMaker(e)} + showFirstOptionWhenEmpty={true} /> )} @@ -662,6 +781,7 @@ const Trestle = forwardRef((props, ref) => { targetKey={'constMthdCd'} showKey={'constMthdCdJp'} onChange={(e) => onChangeConstMthd(e)} + showFirstOptionWhenEmpty={true} /> )} @@ -680,6 +800,7 @@ const Trestle = forwardRef((props, ref) => { showKey={'roofBaseCdJp'} value={selectedRoofBase} onChange={(e) => onChangeRoofBase(e)} + showFirstOptionWhenEmpty={true} /> )} diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 15b485d9..2ab64736 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -214,7 +214,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla width: roofRef.width.current?.value, length: roofRef.length.current?.value, hajebichi: roofRef.hajebichi.current?.value, - raft: roofRef.rafter.current?.value, + //raft: roofRef.rafter.current?.value, selected: true, layout: currentRoof.layout, index: 0, @@ -419,10 +419,9 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla r.clCode === (currentRoof?.raft === undefined ? currentRoof?.raftBaseCd : currentRoof?.raft)) - .clCodeNm + raftCodes?.find((r) => r.clCode === ( currentRoof.raft?? currentRoof?.raftBaseCd))?.clCodeNm } - value={currentRoof?.raft === undefined ? currentRoof?.raftBaseCd : currentRoof?.raft} + value={currentRoof?.raft??currentRoof?.raftBaseCd} onChange={(e) => handleRafterChange(e.clCode)} sourceKey="clCode" targetKey={currentRoof?.raft ? 'raft' : 'raftBaseCd'} diff --git a/src/hooks/common/useCanvasPopupStatusController.js b/src/hooks/common/useCanvasPopupStatusController.js index 437bf41f..a59b6e38 100644 --- a/src/hooks/common/useCanvasPopupStatusController.js +++ b/src/hooks/common/useCanvasPopupStatusController.js @@ -101,7 +101,7 @@ export function useCanvasPopupStatusController(param = 1) { popupType: popupType.toString(), // popupStatus: popupType === 1 ? arg : JSON.stringify(arg).replace(/"/g, '\"'), popupStatus: JSON.stringify(arg).replace(/"/g, '\"'), - hajebichi: arg.roofConstructions?.[0]?.addRoof?.hajebichi || '', + //hajebichi: arg.roofConstructions?.[0]?.addRoof?.hajebichi || '', } postFetcher(`/api/v1/canvas-popup-status`, params) },