From 6fdb0df00cb1d95094524b051106404a81023292 Mon Sep 17 00:00:00 2001 From: ysCha Date: Mon, 22 Dec 2025 17:31:45 +0900 Subject: [PATCH 01/22] =?UTF-8?q?0.=EC=9D=B4=ED=95=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/input/CalcInput.jsx | 45 ++++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/components/common/input/CalcInput.jsx b/src/components/common/input/CalcInput.jsx index 17af010e..14118b87 100644 --- a/src/components/common/input/CalcInput.jsx +++ b/src/components/common/input/CalcInput.jsx @@ -50,26 +50,42 @@ export const CalculatorInput = forwardRef( // 소수점 이하 2자리 제한 로직 추가 const shouldPreventInput = (value) => { - const decimalParts = (value || '').split('.') + if (!value) return false + const decimalParts = value.toString().split('.') return decimalParts.length > 1 && decimalParts[1].length >= 2 } + // 숫자 추가 함수 + const appendNumber = (current, num) => { + // 현재 값이 0이고 소수점이 없을 때 0이 아닌 숫자를 입력하면 대체 + if (current === '0' && num !== '.' && !current.includes('.')) { + return num.toString() + } + // 0. 다음에 0을 입력하는 경우 허용 + if (current === '0' && num === '0') { + return '0.' + } + return current + num + } + if (hasOperation) { // 연산자 이후 숫자 입력 시 - if (calculator.currentOperand === '0' || calculator.shouldResetDisplay) { + if (calculator.shouldResetDisplay) { calculator.currentOperand = num.toString() calculator.shouldResetDisplay = false - }else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리 - calculator.currentOperand = (calculator.currentOperand || '') + num + } else if (num === '.') { + if (!calculator.currentOperand.includes('.')) { + calculator.currentOperand = calculator.currentOperand || '0' + '.' + } + } else if (!shouldPreventInput(calculator.currentOperand)) { + calculator.currentOperand = appendNumber(calculator.currentOperand || '0', num) } - // else { - // calculator.currentOperand = (calculator.currentOperand || '') + num - // } + newDisplayValue = calculator.previousOperand + calculator.operation + calculator.currentOperand setDisplayValue(newDisplayValue) } else { // 첫 번째 숫자 입력 시 - if (displayValue === '0' || calculator.shouldResetDisplay) { + if (calculator.shouldResetDisplay) { calculator.currentOperand = num.toString() calculator.shouldResetDisplay = false newDisplayValue = calculator.currentOperand @@ -77,8 +93,17 @@ export const CalculatorInput = forwardRef( if (!hasOperation) { onChange(calculator.currentOperand) } - } else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리 - calculator.currentOperand = (calculator.currentOperand || '') + num + } else if (num === '.') { + if (!calculator.currentOperand.includes('.')) { + calculator.currentOperand = (calculator.currentOperand || '0') + '.' + newDisplayValue = calculator.currentOperand + setDisplayValue(newDisplayValue) + if (!hasOperation) { + onChange(newDisplayValue) + } + } + } else if (!shouldPreventInput(calculator.currentOperand)) { + calculator.currentOperand = appendNumber(calculator.currentOperand || '0', num) newDisplayValue = calculator.currentOperand setDisplayValue(newDisplayValue) if (!hasOperation) { From 54ac757ced04478d02bbbdb864cc20887a80c6a0 Mon Sep 17 00:00:00 2001 From: ysCha Date: Mon, 22 Dec 2025 17:54:07 +0900 Subject: [PATCH 02/22] =?UTF-8?q?=EA=B3=84=EC=82=B0=EA=B8=B0=20=ED=88=AC?= =?UTF-8?q?=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/basic/step/Module.jsx | 18 +++++++++++++++--- .../modal/basic/step/Orientation.jsx | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/components/floor-plan/modal/basic/step/Module.jsx b/src/components/floor-plan/modal/basic/step/Module.jsx index 426724eb..a708f749 100644 --- a/src/components/floor-plan/modal/basic/step/Module.jsx +++ b/src/components/floor-plan/modal/basic/step/Module.jsx @@ -235,11 +235,23 @@ export default function Module({ setTabNum }) {
- setInputVerticalSnowCover(normalizeDecimal(e.target.value))}*/} + {/*/>*/} + setInputVerticalSnowCover(normalizeDecimal(e.target.value))} + onChange={(value) => setInputVerticalSnowCover(value)} + options={{ + allowNegative: false, + allowDecimal: false + }} />
cm diff --git a/src/components/floor-plan/modal/basic/step/Orientation.jsx b/src/components/floor-plan/modal/basic/step/Orientation.jsx index fdf599be..4feeb41b 100644 --- a/src/components/floor-plan/modal/basic/step/Orientation.jsx +++ b/src/components/floor-plan/modal/basic/step/Orientation.jsx @@ -638,7 +638,7 @@ export const Orientation = forwardRef((props, ref) => { name="" label="" className="input-origin block" - value={inputInstallHeight} + value={inputVerticalSnowCover} onChange={(value) => handleChangeVerticalSnowCover(value)} options={{ allowNegative: false, From f8cc93d54e0419009222e242ec4d454c14186164 Mon Sep 17 00:00:00 2001 From: ysCha Date: Mon, 22 Dec 2025 18:20:54 +0900 Subject: [PATCH 03/22] =?UTF-8?q?=ED=95=A0=EB=8B=B9=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useRoofAllocationSetting.js | 15 ++++++++++++++- src/util/skeleton-utils.js | 16 ++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index f93e230d..3ebaa56c 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -473,7 +473,20 @@ export function useRoofAllocationSetting(id) { // Filter out any eaveHelpLines that are already in lines to avoid duplicates const existingEaveLineIds = new Set(roofBase.lines.map((line) => line.id)) const newEaveLines = roofEaveHelpLines.filter((line) => !existingEaveLineIds.has(line.id)) - roofBase.lines = [...newEaveLines] + // Filter out lines from roofBase.lines that share any points with newEaveLines + const linesToKeep = roofBase.lines.filter(roofLine => { + return !newEaveLines.some(eaveLine => { + // Check if any endpoint of roofLine matches any endpoint of eaveLine + return ( + // Check if any endpoint of roofLine matches any endpoint of eaveLine + (Math.abs(roofLine.x1 - eaveLine.x1) < 0.1 && Math.abs(roofLine.y1 - eaveLine.y1) < 0.1) || // p1 matches p1 + (Math.abs(roofLine.x2 - eaveLine.x2) < 0.1 && Math.abs(roofLine.y2 - eaveLine.y2) < 0.1) // p2 matches p2 + ); + }); + }); + +// Combine remaining lines with newEaveLines + roofBase.lines = [...linesToKeep, ...newEaveLines]; } else { roofBase.lines = [...roofEaveHelpLines] } diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 1599bd84..185cc653 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -844,7 +844,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length const nextIndex = (index + 1) % sortRoofLines.length - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) { if (inLine) { @@ -898,7 +898,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) { @@ -1014,7 +1014,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length const nextIndex = (index + 1) % sortRoofLines.length - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) { if (inLine) { @@ -1068,7 +1068,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (inLine) { if (inLine.x2 < inLine.x1) { @@ -1203,7 +1203,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) { if (inLine) { @@ -1255,7 +1255,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) { if (inLine) { @@ -1365,7 +1365,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) { if (inLine) { @@ -1419,7 +1419,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) { if (inLine) { From b02faafb3eb09113c1114e893695a4867dc3ad98 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 23 Dec 2025 10:17:58 +0900 Subject: [PATCH 04/22] =?UTF-8?q?=EB=8F=84=EB=A8=B8,=20=EA=B7=B8=EB=A6=BC?= =?UTF-8?q?=EC=9E=90,=20=EA=B0=9C=EA=B5=AC=20=EC=9D=B4=EA=B2=A9=2030?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModuleBasicSetting.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index a0392407..d72d66fc 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -267,14 +267,14 @@ export function useModuleBasicSetting(tabNum) { //도머일때 if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) { const groupPoints = obj.getCurrentPoints() - const offsetObjects = offsetPolygon(groupPoints, 10) + const offsetObjects = offsetPolygon(groupPoints, 30) const dormerOffset = new QPolygon(offsetObjects, batchObjectOptions) dormerOffset.setViewLengthText(false) canvas.add(dormerOffset) //모듈설치면 만들기 } else { //개구, 그림자일때 const points = obj.getCurrentPoints() - const offsetObjects = offsetPolygon(points, 10) + const offsetObjects = offsetPolygon(points, 30) const offset = new QPolygon(offsetObjects, batchObjectOptions) offset.setViewLengthText(false) canvas.add(offset) //모듈설치면 만들기 From 3f9bc960b353900aafd3764defa608272485f495 Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 23 Dec 2025 13:31:38 +0900 Subject: [PATCH 05/22] =?UTF-8?q?=EC=A2=8C=ED=91=9C=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/skeleton-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 185cc653..d1019c66 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -729,7 +729,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { }, }) - coordinateText(line) + //coordinateText(line) canvas.add(line) line.bringToFront() canvas.renderAll() From 0ee7f6c59048e9c96c54e8ed266e2da32f3daf9b Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 23 Dec 2025 14:19:35 +0900 Subject: [PATCH 06/22] =?UTF-8?q?=EA=B3=84=EC=82=B0=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/estimate/Estimate.jsx | 66 ++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 4cdffbed..a8f5f148 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -24,6 +24,7 @@ import { useSwal } from '@/hooks/useSwal' import { QcastContext } from '@/app/QcastProvider' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import {normalizeDigits, normalizeDecimal} from '@/util/input-utils' +import { CalculatorInput } from '@/components/common/input/CalcInput' export default function Estimate({}) { const [uniqueData, setUniqueData] = useState([]) const [handlePricingFlag, setHandlePricingFlag] = useState(false) @@ -2106,25 +2107,60 @@ export default function Estimate({}) {
- {*/} + {/* onChangeAmount(e.target.value, item.dispOrder, index)*/} + {/* }}*/} + {/* maxLength={6}*/} + {/*/>*/} + { - onChangeAmount(e.target.value, item.dispOrder, index) + onChange={(value) =>{ + onChangeAmount(value, item.dispOrder, index) }} - maxLength={6} - /> + options={{ + allowNegative: false, + allowDecimal: false + }} + />
{item.unit}
- {*/} + {/* onChangeSalePrice(e.target.value, item.dispOrder, index)*/} + {/* }}*/} + {/* maxLength={12}*/} + {/*/>*/} + { - onChangeSalePrice(e.target.value, item.dispOrder, index) + onChange={(value) =>{ + onChangeSalePrice(value, item.dispOrder, index) }} maxLength={12} + options={{ + allowNegative: false, + allowDecimal: false + }} />
{item.openFlg === '1' && ( From 59b65df1d6b2156c8537a3ce11c2f1b5d4bfcd5e Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 23 Dec 2025 15:21:29 +0900 Subject: [PATCH 07/22] =?UTF-8?q?abs()=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/skeleton-utils.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index d1019c66..943f1f38 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -871,7 +871,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPStart.y = wallLine.y1; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber() - newPStart.y = Big(wallBaseLine.y1).minus(rLineM).abs().toNumber() + newPStart.y = Big(wallBaseLine.y1).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -927,7 +927,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber() - newPEnd.y = Big(wallBaseLine.y2).plus(rLineM).abs().toNumber() + newPEnd.y = Big(wallBaseLine.y2).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -1041,7 +1041,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPStart.y = wallLine.y1; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x1).minus(roofLine.x1).abs().toNumber() - newPStart.y = Big(wallBaseLine.y1).plus(rLineM).abs().toNumber() + newPStart.y = Big(wallBaseLine.y1).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -1096,7 +1096,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber() - newPEnd.y = Big(wallBaseLine.y2).minus(rLineM).abs().toNumber() + newPEnd.y = Big(wallBaseLine.y2).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -1229,7 +1229,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { } else { //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber() - newPStart.x = Big(wallBaseLine.x1).plus(rLineM).abs().toNumber() + newPStart.x = Big(wallBaseLine.x1).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.y2 > inLine.y1) { @@ -1282,7 +1282,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPEnd.x = wallLine.x2; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber() - newPEnd.x = Big(wallBaseLine.x2).minus(rLineM).abs().toNumber() + newPEnd.x = Big(wallBaseLine.x2).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.y1 > inLine.y2) { @@ -1392,7 +1392,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPStart.x = wallLine.x1; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber() - newPStart.x = Big(wallBaseLine.x1).minus(rLineM).abs().toNumber() + newPStart.x = Big(wallBaseLine.x1).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.y2 > inLine.y1) { @@ -1446,7 +1446,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPEnd.x = wallLine.x2; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber() - newPEnd.x = Big(wallBaseLine.x2).plus(rLineM).abs().toNumber() + newPEnd.x = Big(wallBaseLine.x2).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.y1 > inLine.y2) { From dc080a873784491cd621f669d5abd56d37fcd1ad Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 23 Dec 2025 15:30:27 +0900 Subject: [PATCH 08/22] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=EC=97=90=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=EA=B8=B0=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/input/CalcInput.jsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/common/input/CalcInput.jsx b/src/components/common/input/CalcInput.jsx index 14118b87..d386bd7d 100644 --- a/src/components/common/input/CalcInput.jsx +++ b/src/components/common/input/CalcInput.jsx @@ -3,7 +3,7 @@ import { createCalculator } from '@/util/calc-utils' import '@/styles/calc.scss' export const CalculatorInput = forwardRef( - ({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false, placeholder, name='', disabled = false }, ref) => { + ({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false, placeholder, name='', disabled = false, maxLength = 6 }, ref) => { const [showKeypad, setShowKeypad] = useState(false) const [displayValue, setDisplayValue] = useState(value || '0') const [hasOperation, setHasOperation] = useState(false) @@ -48,6 +48,14 @@ export const CalculatorInput = forwardRef( const calculator = calculatorRef.current let newDisplayValue = '' + // maxLength 체크 + if (maxLength > 0) { + const currentLength = (calculator.currentOperand || '').length + (calculator.previousOperand || '').length + (calculator.operation || '').length + if (currentLength >= maxLength) { + return + } + } + // 소수점 이하 2자리 제한 로직 추가 const shouldPreventInput = (value) => { if (!value) return false @@ -57,6 +65,10 @@ export const CalculatorInput = forwardRef( // 숫자 추가 함수 const appendNumber = (current, num) => { + // maxLength 체크 + if (maxLength > 0 && (current + num).length > maxLength) { + return current + } // 현재 값이 0이고 소수점이 없을 때 0이 아닌 숫자를 입력하면 대체 if (current === '0' && num !== '.' && !current.includes('.')) { return num.toString() @@ -407,6 +419,7 @@ export const CalculatorInput = forwardRef( placeholder={placeholder} autoComplete={'off'} disabled={disabled} + maxLength={maxLength} /> {showKeypad && !readOnly && ( From ae1ae05d0936cb378e6c0e91fce6449d54eb1752 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 24 Dec 2025 09:50:47 +0900 Subject: [PATCH 09/22] =?UTF-8?q?=ED=9A=8C=EB=A1=9C=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/circuitTrestle/step/StepUp.jsx | 62 ++++++++++++++----- src/hooks/useCanvasEvent.js | 4 ++ 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 5b956cc2..78b645ce 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -1,13 +1,10 @@ -import { GlobalDataContext } from '@/app/GlobalDataProvider' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' import { canvasState } from '@/store/canvasAtom' -import { modelState, pcsCheckState } from '@/store/circuitTrestleAtom' +import { pcsCheckState } from '@/store/circuitTrestleAtom' import { selectedModuleState } from '@/store/selectedModuleOptions' -import { useContext, useEffect, useState } from 'react' +import { useEffect, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' -import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' -import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' import { useMasterController } from '@/hooks/common/useMasterController' import { v4 as uuidv4 } from 'uuid' import { globalLocaleStore } from '@/store/localeAtom' @@ -15,7 +12,6 @@ import { POLYGON_TYPE } from '@/common/common' import { useSwal } from '@/hooks/useSwal' import { circuitNumDisplaySelector } from '@/store/settingAtom' import { fontSelector } from '@/store/fontAtom' -import { PCS_MKR_MULTI_TYPE } from './PowerConditionalSelect' export default function StepUp(props) { const { @@ -109,7 +105,7 @@ export default function StepUp(props) { /** 캔버스에 회로 정보 적용 */ // 병설일때 pcs 있으면 setSubOpsions, 없으면 setMainOptions console.log('stepUpListData', stepUpListData) - let mChk = 0; + let mChk = 0 stepUpListData[0].pcsItemList.forEach((pcsItem, index) => { const optionList = formatOptionCodes(pcsItem.optionList) if (isMultiOptions()) { @@ -166,7 +162,7 @@ export default function StepUp(props) { targetModule.circuitNumber = module.circuit canvas.add(moduleCircuitText) } else { - mChk++; + mChk++ } }) }) @@ -399,10 +395,14 @@ export default function StepUp(props) { })) } + const handleChangeApplyParalQty = (mainIdx, subIdx, applyParalQty) => { + handleRowClick(mainIdx, subIdx, applyParalQty) + } + /** * 행 선택 핸들러 함수 추가 */ - const handleRowClick = (mainIdx, subIdx) => { + const handleRowClick = (mainIdx, subIdx, applyParalQty = null) => { /** 자동 승압 설정인 경우만 실행 */ if (allocationType !== 'auto') return @@ -434,7 +434,13 @@ export default function StepUp(props) { /** 선택된 serQty 찾기 */ const selectedSerQty = matchingPcsItem?.serQtyList.find((serQty) => serQty.selected)?.serQty || 0 - + if (index === 0) { + return { + ...pcsItem, + applySerQty: selectedSerQty, + applyParalQty: +applyParalQty, + } + } return { ...pcsItem, applySerQty: selectedSerQty, @@ -474,7 +480,7 @@ export default function StepUp(props) { module.pcsItemId = null }) - /** 선택된 모듈 목록 추가 */ + /** 선택된 모듈 목록 추가 */ selectedData.roofSurfaceList.forEach((roofSurface) => { const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0] const moduleIds = targetSurface.modules.map((module) => { @@ -523,7 +529,7 @@ export default function StepUp(props) { canvas.renderAll() setModuleStatisticsData() - } + } /** * 현재 선택된 값들을 가져오는 함수 추가 @@ -645,15 +651,39 @@ export default function StepUp(props) { handleRowClick(idx, serQtyIdx)} + onClick={() => { + if (idx === 0) return + handleRowClick(idx, serQtyIdx) + }} style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }} > {item.serQty} {/* 2025.12.04 select 추가 */} - + {idx === 0 ? ( + + ) : ( + <>{item.paralQty} + )} {/* {item.paralQty} */} diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index cc4ac608..7808bb5f 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -50,6 +50,10 @@ export function useCanvasEvent() { if (target) { // settleDown(target) + // roof 이동 후 좌표 재계산 + if (target.name === POLYGON_TYPE.ROOF && target.type === 'QPolygon') { + target.fire('polygonMoved') + } } }, addEvent: (e) => { From 92a3b15d403f9c425f1ed4a18493f064f1727283 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 24 Dec 2025 13:26:55 +0900 Subject: [PATCH 10/22] =?UTF-8?q?onClick=20event=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/circuitTrestle/step/StepUp.jsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 78b645ce..76ef3e93 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -651,13 +651,16 @@ export default function StepUp(props) { { - if (idx === 0) return - handleRowClick(idx, serQtyIdx) - }} style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }} > - {item.serQty} + { + handleRowClick(idx, serQtyIdx) + }} + > + {item.serQty} + {/* 2025.12.04 select 추가 */} {idx === 0 ? ( From c8ad779c58d0f0b9d08a4bc867c82d251e64d84b Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 24 Dec 2025 14:05:09 +0900 Subject: [PATCH 11/22] =?UTF-8?q?=EC=B5=9C=EC=B4=88=20pcs=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B0=B8=EC=A1=B0?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/circuitTrestle/step/StepUp.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 76ef3e93..a9b5029a 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -38,6 +38,7 @@ export default function StepUp(props) { const [arrayLength, setArrayLength] = useState(3) //module-table-inner의 반복 개수 const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) const { getPcsVoltageStepUpList, getPcsAutoRecommendList, getPcsVoltageChk, getPcsConnOptionItemList } = useMasterController() + const [originPcsVoltageStepUpList, setOriginPcsVoltageStepUpList] = useState([]) const canvas = useRecoilValue(canvasState) const selectedModules = useRecoilValue(selectedModuleState) const [optCodes, setOptCodes] = useState([]) @@ -96,6 +97,9 @@ export default function StepUp(props) { /** PCS 승압설정 정보 SET */ setStepUpListData(stepUpListData) + if (originPcsVoltageStepUpList.length === 0) { + setOriginPcsVoltageStepUpList(stepUpListData) + } /** PCS 옵션 조회 */ // const formattedOptCodes = formatOptionCodes(res.data.optionList) @@ -104,7 +108,6 @@ export default function StepUp(props) { /** 캔버스에 회로 정보 적용 */ // 병설일때 pcs 있으면 setSubOpsions, 없으면 setMainOptions - console.log('stepUpListData', stepUpListData) let mChk = 0 stepUpListData[0].pcsItemList.forEach((pcsItem, index) => { const optionList = formatOptionCodes(pcsItem.optionList) @@ -631,7 +634,7 @@ export default function StepUp(props) {
{/* 3개일때 className = by-max */} - {stepUpListData.map((stepUp, index) => ( + {originPcsVoltageStepUpList.map((stepUp, index) => (
{stepUp?.pcsItemList.map((pcsItem, idx) => (
From 456ec7643e6e4a2befb2e0e9a4cc2af005e3c1a2 Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 24 Dec 2025 14:13:30 +0900 Subject: [PATCH 12/22] =?UTF-8?q?=EC=A0=84=EC=B2=B4=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useContextMenu.js | 6 ++++++ src/util/skeleton-utils.js | 25 +++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index a863fd01..1f6a33b0 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -355,6 +355,12 @@ export function useContextMenu() { canvas.remove(line) }) + //동이동현이동 + const eaveHelpLines = canvas.getObjects().filter((obj) => obj.name === 'eaveHelpLine' && obj.parentId === currentObject.attributes.roofId) + eaveHelpLines.forEach((line) => { + canvas.remove(line) + }) + canvas.renderAll() }, }, diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 943f1f38..da15751c 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -677,8 +677,9 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { // 조건에 맞는 라인들만 필터링 const validWallLines = [...wallLines].sort((a, b) => a.idx - b.idx).filter((wallLine, index) => wallLine.idx - 1 === index) - console.log('', sortRoofLines, sortWallLines, sortWallBaseLines) - sortWallLines.length > 3 && + console.log('', sortRoofLines, sortWallLines, sortWallBaseLines); + + (sortWallLines.length === sortWallBaseLines.length && sortWallBaseLines.length > 3) && sortWallLines.forEach((wallLine, index) => { const roofLine = sortRoofLines[index] @@ -1056,8 +1057,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { if (isStartEnd.end) { const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber() - const aStartY = Big(roofLine.y2).minus(moveDist).abs().toNumber() - const bStartY = Big(wallLine.y2).minus(moveDist).abs().toNumber() + const aStartY = Big(roofLine.y2).minus(moveDist).toNumber() + const bStartY = Big(wallLine.y2).minus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 }) console.log('startLines:::::::', inLine) const eLineY = Big(bStartY).minus(wallLine.y2).abs().toNumber() @@ -1167,7 +1168,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const newPointY = Big(roofLine.y1).plus(moveDist).toNumber() const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber() - const pLineX = Big(roofLine.x2).minus(0).abs().toNumber() + const pLineX = Big(roofLine.x2).minus(0).toNumber() // let idx = sortRoofLines.length < index + 1 ? 0 : index // const pLineY = sortRoofLines[idx + 1].y2 @@ -1243,11 +1244,11 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { } if (isStartEnd.end) { const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() - const aStartX = Big(roofLine.x2).minus(moveDist).abs().toNumber() - const bStartX = Big(wallLine.x2).minus(moveDist).abs().toNumber() + const aStartX = Big(roofLine.x2).minus(moveDist).toNumber() + const bStartX = Big(wallLine.x2).minus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: newPEnd.y }) console.log('startLines:::::::', inLine) - const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber() + const eLineX = Big(bStartX).minus(wallLine.x2).toNumber() newPStart.x = roofLine.x1 //Big(newPStart.x).minus(eLineX).abs().toNumber() newPEnd.x = aStartX // let idx = sortRoofLines.length < index + 1 ? 0 : index @@ -1303,7 +1304,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const newPointY = Big(roofLine.y2).minus(moveDist).toNumber() const pDist = Big(wallLine.y2).minus(roofLine.y2).abs().toNumber() - const pLineX = Big(roofLine.x1).minus(0).abs().toNumber() + const pLineX = Big(roofLine.x1).minus(0).toNumber() // let idx = 0 > index - 1 ? sortRoofLines.length : index // const pLineY = sortRoofLines[idx - 1].y1 @@ -1330,7 +1331,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const newPointY = Big(roofLine.y1).minus(moveDist).toNumber() const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber() - const pLineX = Big(roofLine.x2).minus(0).abs().toNumber() + const pLineX = Big(roofLine.x2).minus(0).toNumber() // let idx = sortRoofLines.length < index + 1 ? 0 : index // const pLineY = sortRoofLines[idx + 1].y2 @@ -1353,8 +1354,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { console.log('bottom_out isStartEnd:::::::', isStartEnd) if (isStartEnd.start) { const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() - const aStartX = Big(roofLine.x1).minus(moveDist).abs().toNumber() - const bStartX = Big(wallLine.x1).minus(moveDist).abs().toNumber() + const aStartX = Big(roofLine.x1).minus(moveDist).toNumber() + const bStartX = Big(wallLine.x1).minus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: roofLine.y1 }) console.log('startLines:::::::', inLine) const eLineX = Big(bStartX).minus(wallLine.x1).abs().toNumber() From a6dff928c0b044d6e7568ab303c590f209eca4a8 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 24 Dec 2025 14:20:22 +0900 Subject: [PATCH 13/22] =?UTF-8?q?pcs=EC=B5=9C=EC=B4=88=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=B0=B8=EC=A1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/circuitTrestle/step/StepUp.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index a9b5029a..77cdf7b4 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -634,7 +634,7 @@ export default function StepUp(props) {
{/* 3개일때 className = by-max */} - {originPcsVoltageStepUpList.map((stepUp, index) => ( + {stepUpListData.map((stepUp, index) => (
{stepUp?.pcsItemList.map((pcsItem, idx) => (
@@ -681,7 +681,10 @@ export default function StepUp(props) { 0 )} - {Array.from({ length: item.paralQty }, (_, i) => i + 1).map((num) => ( + {Array.from( + { length: originPcsVoltageStepUpList[index].pcsItemList[idx].serQtyList[serQtyIdx].paralQty }, + (_, i) => i + 1, + ).map((num) => ( From 15d94bab537d599126f21a42aa5f91c2bf315721 Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 24 Dec 2025 14:24:30 +0900 Subject: [PATCH 14/22] =?UTF-8?q?abs=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/skeleton-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index da15751c..c92cea69 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -1003,8 +1003,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { if (isStartEnd.start) { //x1 inside const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber() - const aStartY = Big(roofLine.y1).plus(moveDist).abs().toNumber() - const bStartY = Big(wallLine.y1).plus(moveDist).abs().toNumber() + const aStartY = Big(roofLine.y1).plus(moveDist).toNumber() + const bStartY = Big(wallLine.y1).plus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 }) console.log('startLines:::::::', inLine) const eLineY = Big(bStartY).minus(wallLine.y1).abs().toNumber() From c1e4fe5b10eb969ae9d0a915560c5a80c047a5f5 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 24 Dec 2025 15:00:15 +0900 Subject: [PATCH 15/22] =?UTF-8?q?row=20=EC=84=A0=ED=83=9D=20=EC=8B=9C=20?= =?UTF-8?q?=EB=B3=91=EB=A0=AC=20=EC=88=98=200=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EA=B0=80=EB=8A=94=20=ED=98=84=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/circuitTrestle/step/StepUp.jsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 77cdf7b4..b0b9a1e5 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -659,7 +659,7 @@ export default function StepUp(props) { { - handleRowClick(idx, serQtyIdx) + handleRowClick(idx, serQtyIdx, item.paralQty) }} > {item.serQty} @@ -682,7 +682,11 @@ export default function StepUp(props) { )} {Array.from( - { length: originPcsVoltageStepUpList[index].pcsItemList[idx].serQtyList[serQtyIdx].paralQty }, + { + length: originPcsVoltageStepUpList[index] + ? originPcsVoltageStepUpList[index]?.pcsItemList[idx].serQtyList[serQtyIdx].paralQty + : item.paralQty, + }, (_, i) => i + 1, ).map((num) => (