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/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx
index 4a3337db..f6517960 100644
--- a/src/components/estimate/Estimate.jsx
+++ b/src/components/estimate/Estimate.jsx
@@ -23,6 +23,7 @@ import { usePopup } from '@/hooks/usePopup'
import { useSwal } from '@/hooks/useSwal'
import { QcastContext } from '@/app/QcastProvider'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
+import {normalizeDigits, normalizeDecimal} from '@/util/input-utils'
export default function Estimate({}) {
const [uniqueData, setUniqueData] = useState([])
const [handlePricingFlag, setHandlePricingFlag] = useState(false)
@@ -645,11 +646,14 @@ export default function Estimate({}) {
newValue = parts[0] + '.' + parts[1].substring(0, 2)
}
- let pkgAsp = newValue || '0'
+ let pkgAsp = normalizeDecimal(newValue || '0')
//현재 PKG용량값 가져오기
let totVolKw = estimateContextState.totVolKw * 1000
- let pkgTotPrice = parseFloat(pkgAsp?.replaceAll(',', '')) * totVolKw * 1000
+ // let pkgTotPrice = parseFloat(pkgAsp?.replaceAll(',', '')) * totVolKw * 1000
+
+ const pkgAspNumber = Number(normalizeDecimal(pkgAsp))
+ const pkgTotPrice = pkgAspNumber * totVolKw * 1000
setEstimateContextState({
pkgAsp: pkgAsp,
@@ -663,7 +667,7 @@ export default function Estimate({}) {
// 수량 변경
const onChangeAmount = (value, dispOrder, index) => {
//itemChangeFlg = 1, partAdd = 0 셋팅
- let amount = Number(value.replace(/[^0-9]/g, '').replaceAll(',', ''))
+ let amount = Number(normalizeDigits(value))
if (isNaN(amount)) {
amount = '0'
@@ -701,7 +705,8 @@ export default function Estimate({}) {
// 단가 변경
const onChangeSalePrice = (value, dispOrder, index) => {
//itemChangeFlg, partAdd 받아온 그대로
- let salePrice = Number(value.replace(/[^0-9]/g, '').replaceAll(',', ''))
+ let salePrice = Number(normalizeDecimal(value))
+
if (isNaN(salePrice)) {
salePrice = 0
} else {
@@ -940,7 +945,7 @@ export default function Estimate({}) {
delete item.showSalePrice
delete item.showSaleTotPrice
if (item.delFlg === '0') {
- let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
+ let amount = Number(normalizeDigits(item.amount)) || 0
let price
if (amount === 0) {
price = 0
@@ -975,7 +980,7 @@ export default function Estimate({}) {
makeUniqueSpecialNoteCd(itemList)
itemList.forEach((item) => {
if (item.delFlg === '0') {
- let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
+ let amount = Number(normalizeDigits(item.amount)) || 0
let salePrice
if (item.moduleFlg === '1') {
const volKw = (item.pnowW * amount) / 1000
@@ -1009,8 +1014,8 @@ export default function Estimate({}) {
}
}
})
- let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
-
+ //let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
+ const pkgAsp = Number(normalizeDecimal(estimateContextState.pkgAsp))
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
totals.supplyPrice = totals.addSupplyPrice + totals.pkgTotPrice
totals.vatPrice = totals.supplyPrice * 0.1
@@ -1069,7 +1074,7 @@ export default function Estimate({}) {
let dispCableFlgCnt = 0
estimateContextState.itemList.forEach((item) => {
if (item.delFlg === '0') {
- let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
+ let amount = Number(normalizeDigits(item.amount)) || 0
let salePrice
if (item.moduleFlg === '1') {
const volKw = (item.pnowW * amount) / 1000
@@ -1102,7 +1107,7 @@ export default function Estimate({}) {
item.showSaleTotPrice = '0'
}
- if (item.dispCableFlg === '1' ) {
+ if (item.dispCableFlg === '1') {
dispCableFlgCnt++
if(item.itemTpCd === 'M12' || item.itemTpCd === 'S13') {
setCableDbItem(item.itemId)
@@ -1118,9 +1123,10 @@ export default function Estimate({}) {
setCableDbItem('100037')
}
- let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
-
+ // let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
+ const pkgAsp = Number(normalizeDecimal(estimateContextState.pkgAsp))
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
+
totals.supplyPrice = totals.addSupplyPrice + totals.pkgTotPrice
totals.vatPrice = totals.supplyPrice * 0.1
totals.totPrice = totals.supplyPrice + totals.vatPrice
@@ -1150,7 +1156,7 @@ export default function Estimate({}) {
delete item.showSalePrice
delete item.showSaleTotPrice
if (item.delFlg === '0') {
- let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
+ let amount = Number(normalizeDigits(item.amount)) || 0
let price
if (amount === 0) {
price = 0
@@ -1176,10 +1182,6 @@ export default function Estimate({}) {
if (item.dispCableFlg === '1') {
dispCableFlgCnt++
- }
-
- if (item.dispCableFlg === '1'){
-
if(item.itemTpCd === 'M12' || item.itemTpCd === 'S13') {
setCableDbItem(item.itemId)
}else{
diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js
index af9dd7a4..7881712e 100644
--- a/src/components/fabric/QLine.js
+++ b/src/components/fabric/QLine.js
@@ -1,6 +1,7 @@
import { fabric } from 'fabric'
import { v4 as uuidv4 } from 'uuid'
import { getDirectionByPoint } from '@/util/canvas-util'
+import { calcLinePlaneSize } from '@/util/qpolygon-utils'
export const QLine = fabric.util.createClass(fabric.Line, {
type: 'QLine',
@@ -17,7 +18,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
initialize: function (points, options, length = 0) {
// 소수점 전부 제거
- points = points.map((point) => Number(point?.toFixed(1)))
+ points = points.map((point) => Number(Number(point)?.toFixed(1)))
this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? true })
if (options.id) {
@@ -31,14 +32,16 @@ export const QLine = fabric.util.createClass(fabric.Line, {
this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 })
this.textMode = options.textMode ?? 'plane' // plane:복시도, actual:실측, none:표시안함
this.textVisible = options.textVisible ?? true
- if (length !== 0) {
- this.length = length
- } else {
- this.setLength()
- }
this.startPoint = { x: this.x1, y: this.y1 }
this.endPoint = { x: this.x2, y: this.y2 }
+ try {
+ this.setLength()
+ } catch (e) {
+ setTimeout(() => {
+ this.setLength()
+ }, 100)
+ }
},
init: function () {
@@ -66,23 +69,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
},
setLength() {
- if (this.attributes?.actualSize !== undefined && this.attributes?.planeSize !== undefined) {
- if (this.textMode === 'plane') {
- this.length = this.attributes.planeSize / 10
- } else if (this.textMode === 'actual') {
- this.length = this.attributes.actualSize / 10
- }
- } else {
- const scaleX = this.scaleX
- const scaleY = this.scaleY
- const x1 = this.left
- const y1 = this.top
- const x2 = this.left + this.width * scaleX
- const y2 = this.top + this.height * scaleY
- const dx = x2 - x1
- const dy = y2 - y1
- this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1))
- }
+ this.length = calcLinePlaneSize(this) / 10
},
addLengthText() {
diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryEdit.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryEdit.jsx
index f10322ca..938b5244 100644
--- a/src/components/floor-plan/modal/auxiliary/AuxiliaryEdit.jsx
+++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryEdit.jsx
@@ -7,6 +7,7 @@ import { useState } from 'react'
import { currentObjectState } from '@/store/canvasAtom'
import { useAuxiliaryDrawing } from '@/hooks/roofcover/useAuxiliaryDrawing'
import { useSwal } from '@/hooks/useSwal'
+import { normalizeDigits } from '@/util/input-utils'
export default function AuxiliaryEdit(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
@@ -40,15 +41,15 @@ export default function AuxiliaryEdit(props) {
if (currentObject) {
copy(
currentObject,
- arrow2 ? (arrow2 === '←' ? Number(+horizonSize / 10) * -1 : Number(+horizonSize / 10)) : 0,
- arrow1 ? (arrow1 === '↑' ? Number(+verticalSize / 10) * -1 : Number(+verticalSize / 10)) : 0,
+ arrow2 ? (arrow2 === '←' ? (Number(normalizeDigits(horizonSize)) / 10) * -1 : Number(normalizeDigits(horizonSize)) / 10) : 0,
+ arrow1 ? (arrow1 === '↑' ? (Number(normalizeDigits(verticalSize)) / 10) * -1 : Number(normalizeDigits(verticalSize)) / 10) : 0,
)
}
} else {
move(
currentObject,
- arrow2 ? (arrow2 === '←' ? Number(+horizonSize / 10) * -1 : Number(+horizonSize / 10)) : 0,
- arrow1 ? (arrow1 === '↑' ? Number(+verticalSize / 10) * -1 : Number(+verticalSize / 10)) : 0,
+ arrow2 ? (arrow2 === '←' ? (Number(normalizeDigits(horizonSize)) / 10) * -1 : Number(normalizeDigits(horizonSize)) / 10) : 0,
+ arrow1 ? (arrow1 === '↑' ? (Number(normalizeDigits(verticalSize)) / 10) * -1 : Number(normalizeDigits(verticalSize)) / 10) : 0,
)
}
@@ -65,7 +66,7 @@ export default function AuxiliaryEdit(props) {
{getMessage('length')}
- setVerticalSize(e.target.value)} />
+ setVerticalSize(normalizeDigits(e.target.value))} />
mm
@@ -87,7 +88,7 @@ export default function AuxiliaryEdit(props) {
- setHorizonSize(e.target.value)} />
+ setHorizonSize(normalizeDigits(e.target.value))} />
mm
diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx
index 3bb94a4f..5a9cde6f 100644
--- a/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx
+++ b/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx
@@ -7,6 +7,7 @@ import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react'
import Big from 'big.js'
import { calcLineActualSize, calcLinePlaneSize } from '@/util/qpolygon-utils'
+import { normalizeDigits } from '@/util/input-utils'
export default function AuxiliarySize(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
@@ -42,7 +43,8 @@ export default function AuxiliarySize(props) {
if (checkedRadio === 2) setValue2(value)
setSize(0)
} else {
- value = Big(value.replace(/[^0-9]/g, ''))
+ //value = Big(value.replace(/[^0-9]/g, ''))
+ value = Big(normalizeDigits(value))
if (checkedRadio === 1) setValue1(value.toNumber())
if (checkedRadio === 2) setValue2(value.toNumber())
setSize(value.div(10).toNumber())
diff --git a/src/components/floor-plan/modal/basic/step/Module.jsx b/src/components/floor-plan/modal/basic/step/Module.jsx
index 8ab6f394..2402b3e0 100644
--- a/src/components/floor-plan/modal/basic/step/Module.jsx
+++ b/src/components/floor-plan/modal/basic/step/Module.jsx
@@ -10,6 +10,7 @@ import { useDebounceValue } from 'usehooks-ts'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { isObjectNotEmpty } from '@/util/common-utils'
+import { normalizeDecimal} from '@/util/input-utils'
export default function Module({ setTabNum }) {
const { getMessage } = useMessage()
@@ -188,7 +189,7 @@ export default function Module({ setTabNum }) {
type="text"
className="input-origin block"
value={inputInstallHeight}
- onChange={(e) => setInputInstallHeight(e.target.value)}
+ onChange={(e) => setInputInstallHeight(normalizeDecimal(e.target.value))}
/>
m
@@ -225,7 +226,7 @@ export default function Module({ setTabNum }) {
type="text"
className="input-origin block"
value={inputVerticalSnowCover}
- onChange={(e) => setInputVerticalSnowCover(e.target.value)}
+ onChange={(e) => setInputVerticalSnowCover(normalizeDecimal(e.target.value))}
/>
cm
diff --git a/src/components/floor-plan/modal/basic/step/Orientation.jsx b/src/components/floor-plan/modal/basic/step/Orientation.jsx
index 0b603aed..14618a20 100644
--- a/src/components/floor-plan/modal/basic/step/Orientation.jsx
+++ b/src/components/floor-plan/modal/basic/step/Orientation.jsx
@@ -8,6 +8,7 @@ import QSelectBox from '@/components/common/select/QSelectBox'
import { roofsState } from '@/store/roofAtom'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import Swal from 'sweetalert2'
+import { normalizeDecimal} from '@/util/input-utils'
export const Orientation = forwardRef((props, ref) => {
const { getMessage } = useMessage()
@@ -177,9 +178,10 @@ export const Orientation = forwardRef((props, ref) => {
setInputCompasDeg('-0')
return
}
- if (Number(e) >= -180 && Number(e) <= 180) {
- if (numberCheck(Number(e))) {
- setInputCompasDeg(Number(e))
+ const n = Number(normalizeDecimal(e))
+ if (n >= -180 && n <= 180) {
+ if (numberCheck(n)) {
+ setInputCompasDeg(n)
}
} else {
setInputCompasDeg(compasDeg)
@@ -398,7 +400,7 @@ export const Orientation = forwardRef((props, ref) => {
@@ -427,10 +429,10 @@ export const Orientation = forwardRef((props, ref) => {
{getMessage('modal.module.basic.setting.module.fitting.height')}
handleChangeInstallHeight(e.target.value)}
+ onChange={(e) => handleChangeInstallHeight(normalizeDecimal(e.target.value))}
/>
m
@@ -455,10 +457,10 @@ export const Orientation = forwardRef((props, ref) => {
{getMessage('modal.module.basic.setting.module.standard.snowfall.amount')}
handleChangeVerticalSnowCover(e.target.value)}
+ onChange={(e) => handleChangeVerticalSnowCover(normalizeDecimal(e.target.value))}
/>
cm
diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx
index 497d1307..e96cf5c0 100644
--- a/src/components/floor-plan/modal/basic/step/Placement.jsx
+++ b/src/components/floor-plan/modal/basic/step/Placement.jsx
@@ -12,6 +12,7 @@ import {
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty } from '@/util/common-utils'
+import { normalizeDigits } from '@/util/input-utils'
import Image from 'next/image'
const Placement = forwardRef((props, refs) => {
@@ -155,7 +156,7 @@ const Placement = forwardRef((props, refs) => {
newLayoutSetup[index] = {
...newLayoutSetup[index],
moduleId: itemId,
- [e.target.name]: Number(e.target.value),
+ [e.target.name]: Number(normalizeDigits(e.target.value)),
}
props.setLayoutSetup(newLayoutSetup)
}
diff --git a/src/components/floor-plan/modal/basic/step/Trestle.jsx b/src/components/floor-plan/modal/basic/step/Trestle.jsx
index e2e7bb78..c8b40ef3 100644
--- a/src/components/floor-plan/modal/basic/step/Trestle.jsx
+++ b/src/components/floor-plan/modal/basic/step/Trestle.jsx
@@ -9,6 +9,7 @@ import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedM
import { forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import Swal from 'sweetalert2'
+import { normalizeDigits } from '@/util/input-utils'
const Trestle = forwardRef((props, ref) => {
const { tabNum, setTabNum, trestleTrigger, roofs, setRoofs, moduleSelectionData, setModuleSelectionData, setRoofsStore } = props
@@ -58,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])
@@ -100,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) {
@@ -151,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: {
@@ -160,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: {
@@ -172,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) {
@@ -192,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: {
@@ -205,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 ?? '',
@@ -240,6 +352,11 @@ const Trestle = forwardRef((props, ref) => {
roofPitch: Math.round(hajebichi ?? 0),
},
})
+
+ // API 호출 완료 후 다음 단계(construction) 자동 선택 설정
+ setTimeout(() => {
+ setAutoSelectStep('construction')
+ }, 300)
}
const handleConstruction = (index) => {
@@ -558,7 +675,19 @@ const Trestle = forwardRef((props, ref) => {
type="text"
className="input-origin block"
value={lengthBase}
- onChange={(e) => onChangeLength(e.target.value)}
+ onChange={(e) => {
+ const v = e.target.value
+ if (v === '') {
+ onChangeLength('')
+ return
+ }
+ const n = Number(normalizeDigits(v))
+ if (Number.isNaN(n)) {
+ onChangeLength('')
+ } else {
+ onChangeLength(n)
+ }
+ }}
disabled={selectedRoof.lenAuth === 'R'}
/>
@@ -581,6 +710,8 @@ const Trestle = forwardRef((props, ref) => {
showKey={'clCodeNm'}
disabled={selectedRoof.raftAuth === 'R'}
onChange={(e) => onChangeRaftBase(e)}
+ showFirstOptionWhenEmpty={true}
+
/>
)}
@@ -598,7 +729,19 @@ const Trestle = forwardRef((props, ref) => {
type="text"
className="input-origin block"
disabled={selectedRoof.roofPchAuth === 'R'}
- onChange={(e) => onChangeHajebichi(e.target.value)}
+ onChange={(e) => {
+ const v = e.target.value
+ if (v === '') {
+ onChangeHajebichi('')
+ return
+ }
+ const n = Number(normalizeDigits(v))
+ if (Number.isNaN(n)) {
+ onChangeHajebichi('')
+ } else {
+ onChangeHajebichi(n)
+ }
+ }}
value={hajebichi}
/>
@@ -619,6 +762,7 @@ const Trestle = forwardRef((props, ref) => {
targetKey={'trestleMkrCd'}
showKey={'trestleMkrCdJp'}
onChange={(e) => onChangeTrestleMaker(e)}
+ showFirstOptionWhenEmpty={true}
/>
)}
@@ -637,6 +781,7 @@ const Trestle = forwardRef((props, ref) => {
targetKey={'constMthdCd'}
showKey={'constMthdCdJp'}
onChange={(e) => onChangeConstMthd(e)}
+ showFirstOptionWhenEmpty={true}
/>
)}
@@ -655,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/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx
index 44deb1a0..4c09868a 100644
--- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx
+++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx
@@ -120,7 +120,44 @@ export default function CircuitTrestleSetting({ id }) {
const beforeCapture = (type) => {
setCanvasZoom(100)
canvas.set({ zoom: 1 })
- canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
+
+ // roof 객체들을 찾아서 중앙점 계산
+ const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof')
+
+ if (roofs.length > 0) {
+ // 모든 roof의 x, y 좌표를 수집
+ const allPoints = []
+ roofs.forEach((roof) => {
+ if (roof.getCurrentPoints()) {
+ roof.getCurrentPoints().forEach((point) => {
+ allPoints.push({ x: point.x, y: point.y })
+ })
+ }
+ })
+
+ if (allPoints.length > 0) {
+ // 모든 점들의 중앙값 계산
+ const minX = Math.min(...allPoints.map((p) => p.x))
+ const maxX = Math.max(...allPoints.map((p) => p.x))
+ const minY = Math.min(...allPoints.map((p) => p.y))
+ const maxY = Math.max(...allPoints.map((p) => p.y))
+
+ const centerX = (minX + maxX) / 2
+ const centerY = (minY + maxY) / 2
+
+ // 캔버스 중앙으로 이동하기 위한 오프셋 계산
+ const canvasWidth = canvas.getWidth()
+ const canvasHeight = canvas.getHeight()
+ const offsetX = canvasWidth / 2 - centerX
+ const offsetY = canvasHeight / 2 - centerY
+
+ canvas.viewportTransform = [1, 0, 0, 1, offsetX, offsetY]
+ } else {
+ canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
+ }
+ } else {
+ canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
+ }
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
const circuitNumberTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
@@ -139,40 +176,9 @@ export default function CircuitTrestleSetting({ id }) {
// roof polygon들의 중간점 계산
const roofPolygons = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
let x, y
- x = 0 //canvas.width / 2
- y = 1000 //canvas.height / 2
-
- /*if (roofPolygons.length > 0) {
- let minX = Infinity,
- minY = Infinity,
- maxX = -Infinity,
- maxY = -Infinity
-
- roofPolygons.forEach((obj) => {
- const boundingRect = obj.getBoundingRect()
- minX = Math.min(minX, boundingRect.left)
- minY = Math.min(minY, boundingRect.top)
- maxX = Math.max(maxX, boundingRect.left + boundingRect.width)
- maxY = Math.max(maxY, boundingRect.top + boundingRect.height)
- })
-
- x = (minX + maxX) / 2
- y = (minY + maxY) / 2
- } else {
- // roof polygon이 없으면 기본 중앙점 사용
- x = canvas.width / 2
- y = canvas.height / 2
- }
-
- if (x > 1600) {
- x = 0
- y = 0
- }
- if (y > 1600) {
- x = 0
- y = 0
- }*/
-
+ x = canvas.width / 2
+ y = canvas.height / 2
+
canvas.zoomToPoint(new fabric.Point(x, y), 0.4)
changeFontSize('lengthText', '28')
changeFontSize('circuitNumber', '28')
diff --git a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx
index cf79634f..2009e63f 100644
--- a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx
+++ b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx
@@ -74,11 +74,9 @@ export default function PowerConditionalSelect(props) {
]
useEffect(() => {
- if (makers.length === 0) {
- getPcsMakerList().then((res) => {
- setMakers(res.data)
- })
- }
+ getPcsMakerList().then((res) => {
+ setMakers(res.data)
+ })
}, [])
const onCheckSeries = (data) => {
diff --git a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx
index 281ae5a8..8b880336 100644
--- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx
+++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx
@@ -12,6 +12,7 @@ import { selectedModuleState } from '@/store/selectedModuleOptions'
import { circuitNumDisplaySelector } from '@/store/settingAtom'
import { useContext, useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
+import { normalizeDigits } from '@/util/input-utils'
export default function PassivityCircuitAllocation(props) {
const {
@@ -580,7 +581,20 @@ export default function PassivityCircuitAllocation(props) {
value={circuitNumber}
min={1}
max={99}
- onChange={(e) => setCircuitNumber(e.target.value)}
+ onChange={(e) => {
+ const v = e.target.value
+ if (v === '') {
+ setCircuitNumber('')
+ return
+ }
+ const n = Number(normalizeDigits(v))
+ if (Number.isNaN(n)) {
+ setCircuitNumber('')
+ } else {
+ const clamped = Math.max(1, Math.min(99, n))
+ setCircuitNumber(clamped)
+ }
+ }}
/>