Merge branch 'dev' of https://git.hanasys.jp/qcast3/qcast-front into feature/skeleton-dev
This commit is contained in:
commit
8dfb7cb25a
@ -95,16 +95,11 @@ const resizeImage = async (image) => {
|
|||||||
const scaleY = targetImageHeight / image.bitmap.height
|
const scaleY = targetImageHeight / image.bitmap.height
|
||||||
let scale = Math.min(scaleX, scaleY) // 비율 유지하면서 최대한 크게
|
let scale = Math.min(scaleX, scaleY) // 비율 유지하면서 최대한 크게
|
||||||
|
|
||||||
// scale 저장 (나중에 전체 확대에 사용)
|
|
||||||
const originalScale = scale
|
|
||||||
|
|
||||||
let finalWidth = Math.round(image.bitmap.width * scale)
|
let finalWidth = Math.round(image.bitmap.width * scale)
|
||||||
let finalHeight = Math.round(image.bitmap.height * scale)
|
let finalHeight = Math.round(image.bitmap.height * scale)
|
||||||
|
|
||||||
if (scale >= 0.6) {
|
// 항상 리사이즈 실행 (scale >= 0.6 조건 제거)
|
||||||
// 실제 리사이즈 실행
|
image.resize({ w: finalWidth, h: finalHeight })
|
||||||
image.resize({ w: finalWidth, h: finalHeight })
|
|
||||||
}
|
|
||||||
|
|
||||||
//배경 이미지를 생성
|
//배경 이미지를 생성
|
||||||
const mixedImage = new Jimp({ width: convertStandardWidth, height: convertStandardHeight, color: 0xffffffff })
|
const mixedImage = new Jimp({ width: convertStandardWidth, height: convertStandardHeight, color: 0xffffffff })
|
||||||
@ -119,14 +114,7 @@ const resizeImage = async (image) => {
|
|||||||
opacityDest: 1,
|
opacityDest: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
// scale이 0.8 이하인 경우 완성된 이미지를 전체적으로 확대
|
// 1.5x 확대 로직 제거 - 이미지가 템플릿 크기를 초과하지 않도록 함
|
||||||
if (originalScale <= 0.8) {
|
|
||||||
const enlargeRatio = 1.5 // 50% 확대
|
|
||||||
const newWidth = Math.round(mixedImage.bitmap.width * enlargeRatio)
|
|
||||||
const newHeight = Math.round(mixedImage.bitmap.height * enlargeRatio)
|
|
||||||
|
|
||||||
mixedImage.resize({ w: newWidth, h: newHeight })
|
|
||||||
}
|
|
||||||
|
|
||||||
return mixedImage
|
return mixedImage
|
||||||
}
|
}
|
||||||
|
|||||||
@ -222,6 +222,9 @@ export const SAVE_KEY = [
|
|||||||
'skeletonLines',
|
'skeletonLines',
|
||||||
'skeleton',
|
'skeleton',
|
||||||
'viewportTransform',
|
'viewportTransform',
|
||||||
|
'outerLineFix',
|
||||||
|
'adjustRoofLines',
|
||||||
|
'northModuleYn',
|
||||||
]
|
]
|
||||||
|
|
||||||
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]
|
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]
|
||||||
|
|||||||
@ -18,8 +18,9 @@ import Config from '@/config/config.export'
|
|||||||
|
|
||||||
export default function MainPage() {
|
export default function MainPage() {
|
||||||
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
||||||
const [chagePasswordPopOpen, setChagePasswordPopOpen] = useState(false)
|
const [changePasswordPopOpen, setChangePasswordPopOpen] = useState(false)
|
||||||
|
// 데이터 확인 완료 여부 상태 추가
|
||||||
|
const [isSessionLoaded, setIsSessionLoaded] = useState(false)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
@ -52,6 +53,14 @@ export default function MainPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isObjectNotEmpty(sessionState)) {
|
||||||
|
if (sessionState?.pwdInitYn !== 'Y') {
|
||||||
|
setChangePasswordPopOpen(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [sessionState])
|
||||||
|
|
||||||
// 라디오 변경 이벤트
|
// 라디오 변경 이벤트
|
||||||
const handleOnChangeRadio = (e) => {
|
const handleOnChangeRadio = (e) => {
|
||||||
setSearchRadioType(e.target.value)
|
setSearchRadioType(e.target.value)
|
||||||
@ -77,7 +86,7 @@ export default function MainPage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isObjectNotEmpty(sessionState)) {
|
if (isObjectNotEmpty(sessionState)) {
|
||||||
if (sessionState?.pwdInitYn !== 'Y') {
|
if (sessionState?.pwdInitYn !== 'Y') {
|
||||||
setChagePasswordPopOpen(true)
|
setChangePasswordPopOpen(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [sessionState])
|
}, [sessionState])
|
||||||
@ -86,10 +95,25 @@ export default function MainPage() {
|
|||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [modalNoticeNo, setModalNoticeNo] = useState('')
|
const [modalNoticeNo, setModalNoticeNo] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isObjectNotEmpty(sessionState)) {
|
||||||
|
if (sessionState?.pwdInitYn !== 'Y') {
|
||||||
|
setChangePasswordPopOpen(true)
|
||||||
|
} else {
|
||||||
|
// pwdInitYn이 'Y'라면 팝업을 닫음 (false)
|
||||||
|
setChangePasswordPopOpen(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [sessionState])
|
||||||
|
|
||||||
|
//if (!isSessionLoaded) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{open && <BoardDetailModal noticeNo={modalNoticeNo} setOpen={setOpen} />}
|
{open && <BoardDetailModal noticeNo={modalNoticeNo} setOpen={setOpen} />}
|
||||||
{(!chagePasswordPopOpen && (
|
{changePasswordPopOpen ? (
|
||||||
|
<ChangePasswordPop setChangePasswordPopOpen={setChangePasswordPopOpen} />
|
||||||
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="background-bord"></div>
|
<div className="background-bord"></div>
|
||||||
<div className="main-contents">
|
<div className="main-contents">
|
||||||
@ -131,11 +155,8 @@ export default function MainPage() {
|
|||||||
<MainContents setFaqOpen={setOpen} setFaqModalNoticeNo={setModalNoticeNo} />
|
<MainContents setFaqOpen={setOpen} setFaqModalNoticeNo={setModalNoticeNo} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)) || (
|
|
||||||
<>
|
|
||||||
<ChangePasswordPop setChagePasswordPopOpen={setChagePasswordPopOpen} />
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,11 @@ export default function Join() {
|
|||||||
|
|
||||||
// 가입 신청 유효성 검사
|
// 가입 신청 유효성 검사
|
||||||
const joinValidation = (formData) => {
|
const joinValidation = (formData) => {
|
||||||
|
|
||||||
|
// 전화번호/FAX 정규식 (일본 형식: 0으로 시작, 하이픈 포함)
|
||||||
|
const telRegex = /^0\d{1,4}-\d{1,4}-\d{4}$/
|
||||||
|
|
||||||
|
|
||||||
// 판매대리점 정보 - 판매대리점명
|
// 판매대리점 정보 - 판매대리점명
|
||||||
const storeQcastNm = formData.get('storeQcastNm')
|
const storeQcastNm = formData.get('storeQcastNm')
|
||||||
if (!isObjectNotEmpty(storeQcastNm)) {
|
if (!isObjectNotEmpty(storeQcastNm)) {
|
||||||
@ -65,12 +70,34 @@ export default function Join() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 판매대리점 정보 - 전화번호
|
// 판매대리점 정보 - 전화번호
|
||||||
const telNo = formData.get('telNo')
|
const telNo = formData.get('telNo')
|
||||||
if (!isObjectNotEmpty(telNo)) {
|
if (!isObjectNotEmpty(telNo)) {
|
||||||
alert(getMessage('common.message.required.data', [getMessage('join.sub1.telNo')]))
|
alert(getMessage('common.message.required.data', [getMessage('join.sub1.telNo')]))
|
||||||
telNoRef.current.focus()
|
telNoRef.current.focus()
|
||||||
return false
|
return false
|
||||||
|
} else if (!telRegex.test(telNo)) {
|
||||||
|
alert(getMessage('join.validation.check1', [getMessage('join.sub1.telNo')]))
|
||||||
|
telNoRef.current.focus()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// // 판매대리점 정보 - 전화번호
|
||||||
|
// const telNo = formData.get('telNo')
|
||||||
|
// if (!isObjectNotEmpty(telNo)) {
|
||||||
|
// alert(getMessage('common.message.required.data', [getMessage('join.sub1.telNo')]))
|
||||||
|
// telNoRef.current.focus()
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 판매대리점 정보 - FAX 번호
|
||||||
|
const fax = formData.get('fax')
|
||||||
|
if (!isObjectNotEmpty(fax)) {
|
||||||
|
alert(getMessage('common.message.required.data', [getMessage('join.sub1.fax')]))
|
||||||
|
faxRef.current.focus()
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const bizNo = formData.get('bizNo')
|
const bizNo = formData.get('bizNo')
|
||||||
@ -122,16 +149,38 @@ export default function Join() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 담당자 정보 - 전화번호
|
// 담당자 정보 - 전화번호
|
||||||
|
// const userTelNo = formData.get('userTelNo')
|
||||||
|
// if (!isObjectNotEmpty(userTelNo)) {
|
||||||
|
// alert(getMessage('common.message.required.data', [getMessage('join.sub2.telNo')]))
|
||||||
|
// userTelNoRef.current.focus()
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
const userTelNo = formData.get('userTelNo')
|
const userTelNo = formData.get('userTelNo')
|
||||||
if (!isObjectNotEmpty(userTelNo)) {
|
if (!isObjectNotEmpty(userTelNo)) {
|
||||||
alert(getMessage('common.message.required.data', [getMessage('join.sub2.telNo')]))
|
alert(getMessage('common.message.required.data', [getMessage('join.sub1.telNo')]))
|
||||||
userTelNoRef.current.focus()
|
userTelNoRef.current.focus()
|
||||||
return false
|
return false
|
||||||
|
} else if (!telRegex.test(userTelNo)) {
|
||||||
|
alert(getMessage('join.validation.check1', [getMessage('join.sub1.telNo')]))
|
||||||
|
userTelNoRef.current.focus()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 담당자 정보 - FAX 번호
|
||||||
|
const userFax = formData.get('userFax')
|
||||||
|
if (!isObjectNotEmpty(userFax)) {
|
||||||
|
alert(getMessage('common.message.required.data', [getMessage('join.sub2.fax')]))
|
||||||
|
userFaxRef.current.focus()
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 가입 신청
|
// 가입 신청
|
||||||
const joinProcess = async (e) => {
|
const joinProcess = async (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@ -288,7 +337,8 @@ export default function Join() {
|
|||||||
name="telNo"
|
name="telNo"
|
||||||
className="input-light"
|
className="input-light"
|
||||||
maxLength={15}
|
maxLength={15}
|
||||||
onChange={inputNumberCheck}
|
placeholder={getMessage('join.sub1.telNo_placeholder')}
|
||||||
|
onChange={inputTelNumberCheck}
|
||||||
ref={telNoRef}
|
ref={telNoRef}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -296,7 +346,7 @@ export default function Join() {
|
|||||||
</tr>
|
</tr>
|
||||||
{/* FAX 번호 */}
|
{/* FAX 번호 */}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{getMessage('join.sub1.fax')}</th>
|
<th>{getMessage('join.sub1.fax')}<span className="important">*</span></th>
|
||||||
<td>
|
<td>
|
||||||
<div className="input-wrap" style={{ width: '200px' }}>
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
<input type="text" id="fax" name="fax" className="input-light" maxLength={15} onChange={inputNumberCheck} ref={faxRef} />
|
<input type="text" id="fax" name="fax" className="input-light" maxLength={15} onChange={inputNumberCheck} ref={faxRef} />
|
||||||
@ -381,7 +431,7 @@ export default function Join() {
|
|||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<div className="input-wrap" style={{ width: '200px' }}>
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
<input type="text" id="email" name="email" className="input-light" maxLength={30} ref={emailRef} />
|
<input type="text" id="email" name="email" className="input-light" maxLength={50} ref={emailRef} />
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -398,7 +448,8 @@ export default function Join() {
|
|||||||
name="userTelNo"
|
name="userTelNo"
|
||||||
className="input-light"
|
className="input-light"
|
||||||
maxLength={15}
|
maxLength={15}
|
||||||
onChange={inputNumberCheck}
|
placeholder={getMessage('join.sub1.telNo_placeholder')}
|
||||||
|
onChange={inputTelNumberCheck}
|
||||||
ref={userTelNoRef}
|
ref={userTelNoRef}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -406,7 +457,7 @@ export default function Join() {
|
|||||||
</tr>
|
</tr>
|
||||||
{/* FAX 번호 */}
|
{/* FAX 번호 */}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{getMessage('join.sub2.fax')}</th>
|
<th>{getMessage('join.sub2.fax')}<span className="important">*</span></th>
|
||||||
<td>
|
<td>
|
||||||
<div className="input-wrap" style={{ width: '200px' }}>
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useRef, useEffect, forwardRef } from 'react'
|
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from 'react'
|
||||||
import { createCalculator } from '@/util/calc-utils'
|
import { createCalculator } from '@/util/calc-utils'
|
||||||
import '@/styles/calc.scss'
|
import '@/styles/calc.scss'
|
||||||
|
|
||||||
@ -23,8 +23,23 @@ export const CalculatorInput = forwardRef(
|
|||||||
}, [ref])
|
}, [ref])
|
||||||
|
|
||||||
// Sync displayValue with value prop
|
// Sync displayValue with value prop
|
||||||
|
// useEffect(() => {
|
||||||
|
// setDisplayValue(value || '0')
|
||||||
|
// }, [value])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDisplayValue(value || '0')
|
const newValue = value || '0'
|
||||||
|
setDisplayValue(newValue)
|
||||||
|
|
||||||
|
// 외부에서 value가 변경될 때 계산기 내부 상태도 동기화
|
||||||
|
const calculator = calculatorRef.current
|
||||||
|
if (calculator) {
|
||||||
|
// 연산 중이 아닐 때 외부에서 값이 들어오면 현재 피연산자로 설정
|
||||||
|
calculator.currentOperand = newValue.toString()
|
||||||
|
calculator.previousOperand = ''
|
||||||
|
calculator.operation = undefined
|
||||||
|
setHasOperation(false)
|
||||||
|
}
|
||||||
}, [value])
|
}, [value])
|
||||||
|
|
||||||
// 클릭 외부 감지
|
// 클릭 외부 감지
|
||||||
@ -48,6 +63,33 @@ export const CalculatorInput = forwardRef(
|
|||||||
const calculator = calculatorRef.current
|
const calculator = calculatorRef.current
|
||||||
let newDisplayValue = ''
|
let newDisplayValue = ''
|
||||||
|
|
||||||
|
// 블록 지정(Selection) 확인 및 처리
|
||||||
|
if (inputRef.current) {
|
||||||
|
const { selectionStart, selectionEnd } = inputRef.current
|
||||||
|
// 텍스트 전체 또는 일부가 블록 지정된 경우
|
||||||
|
if (selectionStart !== null && selectionEnd !== null && selectionStart !== selectionEnd) {
|
||||||
|
// 연산 중이 아닐 때만 전체 초기화 후 입력 처리 (계산기 모드 유지를 위해)
|
||||||
|
if (!hasOperation) {
|
||||||
|
calculator.currentOperand = num.toString()
|
||||||
|
calculator.previousOperand = ''
|
||||||
|
calculator.operation = undefined
|
||||||
|
calculator.shouldResetDisplay = false
|
||||||
|
|
||||||
|
newDisplayValue = calculator.currentOperand
|
||||||
|
setDisplayValue(newDisplayValue)
|
||||||
|
onChange(newDisplayValue)
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.focus()
|
||||||
|
inputRef.current.setSelectionRange(newDisplayValue.length, newDisplayValue.length)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return // 블록 처리 로직 완료 후 종료
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// maxLength 체크
|
// maxLength 체크
|
||||||
if (maxLength > 0) {
|
if (maxLength > 0) {
|
||||||
const currentLength = (calculator.currentOperand || '').length + (calculator.previousOperand || '').length + (calculator.operation || '').length
|
const currentLength = (calculator.currentOperand || '').length + (calculator.previousOperand || '').length + (calculator.operation || '').length
|
||||||
@ -294,9 +336,11 @@ export const CalculatorInput = forwardRef(
|
|||||||
} else {
|
} else {
|
||||||
calculator.currentOperand = filteredValue
|
calculator.currentOperand = filteredValue
|
||||||
setHasOperation(false)
|
setHasOperation(false)
|
||||||
|
// 연산자가 없는 순수 숫자일 때만 부모 컴포넌트의 onChange 호출
|
||||||
|
onChange(filteredValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(filteredValue)
|
//onChange(filteredValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,13 +367,19 @@ export const CalculatorInput = forwardRef(
|
|||||||
|
|
||||||
// Tab 키는 계산기 숨기고 기본 동작 허용
|
// Tab 키는 계산기 숨기고 기본 동작 허용
|
||||||
if (e.key === 'Tab') {
|
if (e.key === 'Tab') {
|
||||||
|
if (hasOperation) {
|
||||||
|
handleCompute(true) // 계산 수행
|
||||||
|
}
|
||||||
setShowKeypad(false)
|
setShowKeypad(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 모든 방향키는 기본 동작 허용
|
// 모든 방향키는 기본 동작 허용
|
||||||
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight' || e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight' || e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
||||||
setShowKeypad(true)
|
if (hasOperation) {
|
||||||
|
handleCompute(true) // 계산 수행
|
||||||
|
}
|
||||||
|
setShowKeypad(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,6 +393,12 @@ export const CalculatorInput = forwardRef(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 여기서부터는 브라우저의 기본 입력을 막고 계산기 로직만 적용함 ---
|
||||||
|
if (e.key !== 'Process') { // 한글 입력 등 특수 상황 방지 (필요시)
|
||||||
|
// e.preventDefault() 호출 위치를 확인하세요.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const calculator = calculatorRef.current
|
const calculator = calculatorRef.current
|
||||||
const { allowDecimal } = options
|
const { allowDecimal } = options
|
||||||
|
|||||||
@ -96,7 +96,7 @@ export default function QSelectBox({
|
|||||||
title={tagTitle}
|
title={tagTitle}
|
||||||
>
|
>
|
||||||
<p>{selected}</p>
|
<p>{selected}</p>
|
||||||
<ul className="select-item-wrap">
|
<ul className="select-item-wrap" style={{ maxHeight: '200px' }}>
|
||||||
{options?.length > 0 &&
|
{options?.length > 0 &&
|
||||||
options?.map((option, index) => (
|
options?.map((option, index) => (
|
||||||
<li key={option.id + '_' + index} className="select-item" onClick={() => handleClickSelectOption(option)}>
|
<li key={option.id + '_' + index} className="select-item" onClick={() => handleClickSelectOption(option)}>
|
||||||
|
|||||||
@ -1465,19 +1465,19 @@ export default function Estimate({}) {
|
|||||||
: 'none',
|
: 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<input
|
{/*<input*/}
|
||||||
type="radio"
|
{/* type="radio"*/}
|
||||||
name="estimateType"
|
{/* name="estimateType"*/}
|
||||||
id="YJSS"
|
{/* id="YJSS"*/}
|
||||||
value={'YJSS'}
|
{/* value={'YJSS'}*/}
|
||||||
checked={estimateContextState?.estimateType === 'YJSS' ? true : false}
|
{/* checked={estimateContextState?.estimateType === 'YJSS' ? true : false}*/}
|
||||||
onChange={(e) => {
|
{/* onChange={(e) => {*/}
|
||||||
//주문분류
|
{/* //주문분류*/}
|
||||||
setHandlePricingFlag(true)
|
{/* setHandlePricingFlag(true)*/}
|
||||||
setEstimateContextState({ estimateType: e.target.value, setEstimateContextState })
|
{/* setEstimateContextState({ estimateType: e.target.value, setEstimateContextState })*/}
|
||||||
}}
|
{/* }}*/}
|
||||||
/>
|
{/*/>*/}
|
||||||
<label htmlFor="YJSS">{getMessage('estimate.detail.estimateType.yjss')}</label>
|
{/*<label htmlFor="YJSS">{getMessage('estimate.detail.estimateType.yjss')}</label>*/}
|
||||||
</div>
|
</div>
|
||||||
<div className="d-check-radio light">
|
<div className="d-check-radio light">
|
||||||
<input
|
<input
|
||||||
@ -2039,7 +2039,11 @@ export default function Estimate({}) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
menuPlacement={'auto'}
|
menuPlacement={'auto'}
|
||||||
getOptionLabel={(x) => x.itemName + ' (' + x.itemNo + ')'}
|
getOptionLabel={(x) => {
|
||||||
|
// 메뉴 리스트에 보이는 텍스트 디코딩
|
||||||
|
const doc = new DOMParser().parseFromString(x.itemName, 'text/html');
|
||||||
|
return (doc.documentElement.textContent || x.itemName) + ' (' + x.itemNo + ')';
|
||||||
|
}}
|
||||||
getOptionValue={(x) => x.itemNo}
|
getOptionValue={(x) => x.itemNo}
|
||||||
components={{
|
components={{
|
||||||
SingleValue: ({ children, ...props }) => {
|
SingleValue: ({ children, ...props }) => {
|
||||||
@ -2048,13 +2052,21 @@ export default function Estimate({}) {
|
|||||||
}}
|
}}
|
||||||
isClearable={false}
|
isClearable={false}
|
||||||
isDisabled={!!item?.paDispOrder}
|
isDisabled={!!item?.paDispOrder}
|
||||||
value={displayItemList.filter(function (option) {
|
value={(() => {
|
||||||
if (item.itemNo === '') {
|
const selectedOption = displayItemList.find((option) => {
|
||||||
return false
|
return item.itemNo !== '' && option.itemId === item.itemId;
|
||||||
} else {
|
});
|
||||||
return option.itemId === item.itemId
|
|
||||||
|
if (selectedOption) {
|
||||||
|
// 현재 선택된 값의 itemName을 실시간으로 디코딩하여 전달
|
||||||
|
const doc = new DOMParser().parseFromString(selectedOption.itemName, 'text/html');
|
||||||
|
return {
|
||||||
|
...selectedOption,
|
||||||
|
itemName: doc.documentElement.textContent || selectedOption.itemName
|
||||||
|
};
|
||||||
}
|
}
|
||||||
})}
|
return null;
|
||||||
|
})()}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { usePathname, useSearchParams } from 'next/navigation'
|
|||||||
import { QcastContext } from '@/app/QcastProvider'
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
import { sessionStore } from '@/store/commonAtom'
|
import { sessionStore } from '@/store/commonAtom'
|
||||||
|
|
||||||
export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDownPopLockFlg }) {
|
export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDownPopLockFlg, createStoreId = '' }) {
|
||||||
const { setIsGlobalLoading } = useContext(QcastContext)
|
const { setIsGlobalLoading } = useContext(QcastContext)
|
||||||
|
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
@ -70,6 +70,8 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDown
|
|||||||
pwrGnrSimType: 'D', //default 화면에 안보여줌
|
pwrGnrSimType: 'D', //default 화면에 안보여줌
|
||||||
userId: sessionState.userId ? sessionState.userId : "",
|
userId: sessionState.userId ? sessionState.userId : "",
|
||||||
saleStoreId: sessionState.storeId ? sessionState.storeId : "",
|
saleStoreId: sessionState.storeId ? sessionState.storeId : "",
|
||||||
|
storeLvl: sessionState.storeLvl,
|
||||||
|
createStoreId: createStoreId ? createStoreId : '',
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = { responseType: 'blob' }
|
const options = { responseType: 'blob' }
|
||||||
|
|||||||
@ -74,21 +74,28 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
|
|
||||||
setLength() {
|
setLength() {
|
||||||
// Ensure all required properties are valid numbers
|
// Ensure all required properties are valid numbers
|
||||||
const { x1, y1, x2, y2 } = this;
|
const { x1, y1, x2, y2 } = this
|
||||||
if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) {
|
if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) {
|
||||||
logger.error('Invalid coordinates in QLine:', { x1, y1, x2, y2 });
|
logger.error('Invalid coordinates in QLine:', { x1, y1, x2, y2 })
|
||||||
this.length = 0;
|
this.length = 0
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.length = calcLinePlaneSize({ x1, y1, x2, y2 }) / 10;
|
this.length = calcLinePlaneSize({ x1, y1, x2, y2 }) / 10
|
||||||
|
},
|
||||||
|
|
||||||
|
setLengthByValue(length) {
|
||||||
|
this.length = length / 10
|
||||||
},
|
},
|
||||||
|
|
||||||
addLengthText() {
|
addLengthText() {
|
||||||
const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
|
const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
|
||||||
|
|
||||||
if (this.textMode === 'none') {
|
if (thisText) {
|
||||||
if (thisText) {
|
if (this.attributes?.actualSize) {
|
||||||
this.canvas.remove(thisText)
|
thisText.set({ actualSize: this.attributes.actualSize })
|
||||||
|
}
|
||||||
|
if (this.attributes?.planeSize) {
|
||||||
|
thisText.set({ planeSize: this.attributes.planeSize })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.setLength()
|
this.setLength()
|
||||||
@ -99,11 +106,6 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
const x2 = this.left + this.width * scaleX
|
const x2 = this.left + this.width * scaleX
|
||||||
const y2 = this.top + this.height * scaleY
|
const y2 = this.top + this.height * scaleY
|
||||||
|
|
||||||
if (thisText) {
|
|
||||||
thisText.set({ text: this.getLength().toString(), left: (x1 + x2) / 2, top: (y1 + y2) / 2 })
|
|
||||||
this.text = thisText
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let left, top
|
let left, top
|
||||||
if (this.direction === 'left' || this.direction === 'right') {
|
if (this.direction === 'left' || this.direction === 'right') {
|
||||||
left = (x1 + x2) / 2
|
left = (x1 + x2) / 2
|
||||||
@ -120,6 +122,8 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
const degree = (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI
|
const degree = (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI
|
||||||
|
|
||||||
const text = new fabric.Textbox(this.getLength().toString(), {
|
const text = new fabric.Textbox(this.getLength().toString(), {
|
||||||
|
actualSize: this.attributes?.actualSize,
|
||||||
|
planeSize: this.attributes?.planeSize,
|
||||||
left: left,
|
left: left,
|
||||||
top: top,
|
top: top,
|
||||||
fontSize: this.fontSize,
|
fontSize: this.fontSize,
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
this.separatePolygon = []
|
this.separatePolygon = []
|
||||||
this.toFixed = options.toFixed ?? 1
|
this.toFixed = options.toFixed ?? 1
|
||||||
this.baseLines = []
|
this.baseLines = []
|
||||||
|
this.adjustRoofLines = []
|
||||||
// this.colorLines = []
|
// this.colorLines = []
|
||||||
|
|
||||||
// 소수점 전부 제거
|
// 소수점 전부 제거
|
||||||
@ -134,7 +135,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
this.setCoords()
|
this.setCoords()
|
||||||
})
|
})
|
||||||
|
|
||||||
this.on('modified', (e) => {
|
this.on('modified', () => {
|
||||||
this.initLines()
|
this.initLines()
|
||||||
this.addLengthText()
|
this.addLengthText()
|
||||||
this.setCoords()
|
this.setCoords()
|
||||||
@ -180,8 +181,27 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
return fabric.util.transformPoint(p, matrix)
|
return fabric.util.transformPoint(p, matrix)
|
||||||
})
|
})
|
||||||
this.points = transformedPoints
|
this.points = transformedPoints
|
||||||
const { left, top } = this.calcOriginCoords()
|
|
||||||
this.set('pathOffset', { x: left, y: top })
|
// 바운딩 박스 재계산 (width, height 업데이트 - fill 영역 수정)
|
||||||
|
const calcDim = this._calcDimensions({})
|
||||||
|
this.width = calcDim.width
|
||||||
|
this.height = calcDim.height
|
||||||
|
|
||||||
|
const newPathOffset = {
|
||||||
|
x: calcDim.left + this.width / 2,
|
||||||
|
y: calcDim.top + this.height / 2,
|
||||||
|
}
|
||||||
|
this.set('pathOffset', newPathOffset)
|
||||||
|
|
||||||
|
// 변환을 points에 적용했으므로 left, top, angle, scale 모두 리셋 (이중 변환 방지)
|
||||||
|
this.set({
|
||||||
|
left: newPathOffset.x,
|
||||||
|
top: newPathOffset.y,
|
||||||
|
angle: 0,
|
||||||
|
scaleX: 1,
|
||||||
|
scaleY: 1,
|
||||||
|
})
|
||||||
|
|
||||||
this.setCoords()
|
this.setCoords()
|
||||||
this.initLines()
|
this.initLines()
|
||||||
})
|
})
|
||||||
@ -223,7 +243,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
calculateDegree() {
|
calculateDegree() {
|
||||||
const degrees = []
|
const degrees = []
|
||||||
// polygon.lines를 순회하며 각도를 구해 출력
|
// polygon.lines를 순회하며 각도를 구해 출력
|
||||||
this.lines.forEach((line, idx) => {
|
this.lines.forEach((line) => {
|
||||||
const dx = line.x2 - line.x1
|
const dx = line.x2 - line.x1
|
||||||
const dy = line.y2 - line.y1
|
const dy = line.y2 - line.y1
|
||||||
const rad = Math.atan2(dy, dx)
|
const rad = Math.atan2(dy, dx)
|
||||||
@ -258,6 +278,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
)
|
)
|
||||||
.forEach((obj) => this.canvas.remove(obj))
|
.forEach((obj) => this.canvas.remove(obj))
|
||||||
this.innerLines = []
|
this.innerLines = []
|
||||||
|
this.adjustRoofLines = []
|
||||||
this.canvas.renderAll()
|
this.canvas.renderAll()
|
||||||
|
|
||||||
let textMode = 'plane'
|
let textMode = 'plane'
|
||||||
@ -339,18 +360,17 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
|
|
||||||
if (types.every((type) => type === LINE_TYPE.WALLLINE.EAVES)) {
|
if (types.every((type) => type === LINE_TYPE.WALLLINE.EAVES)) {
|
||||||
// 용마루 -- straight-skeleton
|
// 용마루 -- straight-skeleton
|
||||||
console.log('용마루 지붕')
|
// console.log('용마루 지붕')
|
||||||
///drawRidgeRoof(this.id, this.canvas, textMode)
|
|
||||||
drawSkeletonRidgeRoof(this.id, this.canvas, textMode)
|
drawSkeletonRidgeRoof(this.id, this.canvas, textMode)
|
||||||
} else if (isGableRoof(types)) {
|
} else if (isGableRoof(types)) {
|
||||||
// A형, B형 박공 지붕
|
// A형, B형 박공 지붕
|
||||||
console.log('패턴 지붕')
|
// console.log('패턴 지붕')
|
||||||
drawGableRoof(this.id, this.canvas, textMode)
|
drawGableRoof(this.id, this.canvas, textMode)
|
||||||
} else if (isShedRoof(types, this.lines)) {
|
} else if (isShedRoof(types, this.lines)) {
|
||||||
console.log('한쪽흐름 지붕')
|
// console.log('한쪽흐름 지붕')
|
||||||
drawShedRoof(this.id, this.canvas, textMode)
|
drawShedRoof(this.id, this.canvas, textMode)
|
||||||
} else {
|
} else {
|
||||||
console.log('변별로 설정')
|
// console.log('변별로 설정')
|
||||||
drawRoofByAttribute(this.id, this.canvas, textMode)
|
drawRoofByAttribute(this.id, this.canvas, textMode)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -404,7 +424,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
|
|
||||||
const degree = Big(Math.atan2(dy.toNumber(), dx.toNumber())).times(180).div(Math.PI).toNumber()
|
const degree = Big(Math.atan2(dy.toNumber(), dx.toNumber())).times(180).div(Math.PI).toNumber()
|
||||||
|
|
||||||
// Create new text object if it doesn't exist
|
// Create a new text object if it doesn't exist
|
||||||
const text = new fabric.Text(length.toString(), {
|
const text = new fabric.Text(length.toString(), {
|
||||||
left: midPoint.x,
|
left: midPoint.x,
|
||||||
top: midPoint.y,
|
top: midPoint.y,
|
||||||
|
|||||||
@ -452,7 +452,16 @@ export const Orientation = forwardRef((props, ref) => {
|
|||||||
className="input-origin block"
|
className="input-origin block"
|
||||||
value={inputCompasDeg}
|
value={inputCompasDeg}
|
||||||
readOnly={!hasAnglePassivity}
|
readOnly={!hasAnglePassivity}
|
||||||
onChange={(value) => setInputCompasDeg(value)}
|
onChange={(value) => {
|
||||||
|
// Convert to number and ensure it's within -180 to 180 range
|
||||||
|
const numValue = parseInt(value, 10);
|
||||||
|
if (!isNaN(numValue)) {
|
||||||
|
const clampedValue = Math.min(180, Math.max(-180, numValue));
|
||||||
|
setInputCompasDeg(String(clampedValue));
|
||||||
|
} else {
|
||||||
|
setInputCompasDeg(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
options={{
|
options={{
|
||||||
allowNegative: true,
|
allowNegative: true,
|
||||||
allowDecimal: false
|
allowDecimal: false
|
||||||
|
|||||||
@ -344,9 +344,9 @@ export default function CircuitTrestleSetting({ id }) {
|
|||||||
|
|
||||||
canvas.zoomToPoint(new fabric.Point(x, y), 0.4)
|
canvas.zoomToPoint(new fabric.Point(x, y), 0.4)
|
||||||
|
|
||||||
changeFontSize('lengthText', '28')
|
// changeFontSize('lengthText', '28')
|
||||||
changeFontSize('circuitNumber', '28')
|
// changeFontSize('circuitNumber', '28')
|
||||||
changeFontSize('flowText', '28')
|
// changeFontSize('flowText', '28')
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -649,12 +649,18 @@ export default function StepUp(props) {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{pcsItem.serQtyList.map((item, serQtyIdx) => {
|
{pcsItem?.serQtyList?.map((item, serQtyIdx) => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={`row-${serQtyIdx}`}
|
key={`row-${serQtyIdx}`}
|
||||||
className={`${item.selected ? 'on' : ''}`}
|
className={`${item.selected ? 'on' : ''}`}
|
||||||
style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }}
|
style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }}
|
||||||
|
onClick={() => {
|
||||||
|
if (stepUp?.pcsItemList.length !== 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleRowClick(idx, serQtyIdx, item.paralQty)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<td
|
<td
|
||||||
className="al-r"
|
className="al-r"
|
||||||
@ -667,33 +673,37 @@ export default function StepUp(props) {
|
|||||||
<td className="al-r">
|
<td className="al-r">
|
||||||
{/* 2025.12.04 select 추가 */}
|
{/* 2025.12.04 select 추가 */}
|
||||||
{idx === 0 ? (
|
{idx === 0 ? (
|
||||||
<select
|
stepUp?.pcsItemList.length !== 1 ? (
|
||||||
className="select-light dark table-select"
|
<select
|
||||||
defaultValue={item.paralQty}
|
className="select-light dark table-select"
|
||||||
name=""
|
defaultValue={item.paralQty}
|
||||||
id=""
|
name=""
|
||||||
onChange={(e) => {
|
id=""
|
||||||
handleChangeApplyParalQty(idx, serQtyIdx, e.target.value)
|
onChange={(e) => {
|
||||||
}}
|
handleChangeApplyParalQty(idx, serQtyIdx, e.target.value)
|
||||||
>
|
}}
|
||||||
{item.paralQty === 0 && (
|
>
|
||||||
<option key="0" value="0">
|
{item.paralQty === 0 && (
|
||||||
0
|
<option key="0" value="0">
|
||||||
</option>
|
0
|
||||||
)}
|
</option>
|
||||||
{Array.from(
|
)}
|
||||||
{
|
{Array.from(
|
||||||
length: originPcsVoltageStepUpList[index]
|
{
|
||||||
? originPcsVoltageStepUpList[index]?.pcsItemList[idx].serQtyList[serQtyIdx].paralQty
|
length: originPcsVoltageStepUpList[index]
|
||||||
: item.paralQty,
|
? originPcsVoltageStepUpList[index]?.pcsItemList[idx].serQtyList[serQtyIdx].paralQty
|
||||||
},
|
: item.paralQty,
|
||||||
(_, i) => i + 1,
|
},
|
||||||
).map((num) => (
|
(_, i) => i + 1,
|
||||||
<option key={num} value={num}>
|
).map((num) => (
|
||||||
{num}
|
<option key={num} value={num}>
|
||||||
</option>
|
{num}
|
||||||
))}
|
</option>
|
||||||
</select>
|
))}
|
||||||
|
</select>
|
||||||
|
) : (
|
||||||
|
<>{item.paralQty}</>
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<>{item.paralQty}</>
|
<>{item.paralQty}</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -122,21 +122,36 @@ export default function PassivityCircuitAllocation(props) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// targetModule중 북면 설치 여부가 Y인 것과 N인 것이 혼합이면 안됨.
|
||||||
|
const targetModuleGroup = [
|
||||||
|
...new Set(
|
||||||
|
canvas
|
||||||
|
.getObjects()
|
||||||
|
.filter((obj) => obj.name === POLYGON_TYPE.MODULE && targetModules.includes(obj.id))
|
||||||
|
.map((obj) => obj.moduleInfo.northModuleYn),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
if (targetModuleGroup.length > 1) {
|
||||||
|
swalFire({
|
||||||
|
text: getMessage('module.circuit.fix.not.same.roof.error'),
|
||||||
|
type: 'alert',
|
||||||
|
icon: 'warning',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch (pcsTpCd) {
|
switch (pcsTpCd) {
|
||||||
case 'INDFCS': {
|
case 'INDFCS': {
|
||||||
const originHaveThisPcsModules = canvas
|
const originHaveThisPcsModules = canvas
|
||||||
.getObjects()
|
.getObjects()
|
||||||
.filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.pcs && obj.pcs.id === selectedPcs.id)
|
.filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.pcs && obj.pcs.id === selectedPcs.id)
|
||||||
// 이미 해당 pcs로 설치된 모듈의 surface의 방향을 구한다.
|
// 1. 북면모듈, 북면외모듈 혼합 여부 체크
|
||||||
const originSurfaceList = canvas
|
const targetModuleInfos = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && targetModules.includes(obj.id))
|
||||||
.getObjects()
|
debugger
|
||||||
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && originHaveThisPcsModules.map((obj) => obj.surfaceId).includes(obj.id))
|
const newTargetModuleGroup = [...new Set(targetModuleInfos.concat(originHaveThisPcsModules).map((obj) => obj.moduleInfo.northModuleYn))]
|
||||||
|
|
||||||
originSurfaceList.concat(originSurfaceList).forEach((surface) => {
|
if (newTargetModuleGroup.length > 1) {
|
||||||
surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface
|
|
||||||
})
|
|
||||||
|
|
||||||
if (Object.keys(surfaceType).length > 1) {
|
|
||||||
swalFire({
|
swalFire({
|
||||||
text: getMessage('module.circuit.fix.not.same.roof.error'),
|
text: getMessage('module.circuit.fix.not.same.roof.error'),
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
@ -229,6 +244,7 @@ export default function PassivityCircuitAllocation(props) {
|
|||||||
roofSurface: surface.direction,
|
roofSurface: surface.direction,
|
||||||
roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
|
roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
|
||||||
roofSurfaceNorthYn: surface.direction === 'north' ? 'Y' : 'N',
|
roofSurfaceNorthYn: surface.direction === 'north' ? 'Y' : 'N',
|
||||||
|
roofSurfaceNorthModuleYn: surface.northModuleYn,
|
||||||
moduleList: surface.modules.map((module) => {
|
moduleList: surface.modules.map((module) => {
|
||||||
return {
|
return {
|
||||||
itemId: module.moduleInfo.itemId,
|
itemId: module.moduleInfo.itemId,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import Image from 'next/image'
|
|||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import { normalizeDecimalLimit, normalizeDigits } from '@/util/input-utils'
|
import { normalizeDecimalLimit, normalizeDigits } from '@/util/input-utils'
|
||||||
import { CalculatorInput } from '@/components/common/input/CalcInput'
|
import { CalculatorInput } from '@/components/common/input/CalcInput'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
export default function Angle({ props }) {
|
export default function Angle({ props }) {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
@ -31,11 +32,21 @@ export default function Angle({ props }) {
|
|||||||
className="input-origin block"
|
className="input-origin block"
|
||||||
value={angle1}
|
value={angle1}
|
||||||
ref={angle1Ref}
|
ref={angle1Ref}
|
||||||
onChange={(value) => setAngle1(value)}
|
onChange={(value) => {
|
||||||
|
// Calculate the final value first
|
||||||
|
let finalValue = value;
|
||||||
|
const numValue = parseInt(value, 10);
|
||||||
|
if (!isNaN(numValue)) {
|
||||||
|
const clampedValue = Math.min(180, Math.max(-180, numValue));
|
||||||
|
finalValue = String(clampedValue);
|
||||||
|
}
|
||||||
|
// Set state once with the final value
|
||||||
|
setAngle1(finalValue);
|
||||||
|
}}
|
||||||
placeholder="45"
|
placeholder="45"
|
||||||
onFocus={() => (angle1Ref.current.value = '')}
|
onFocus={() => (angle1Ref.current.value = '')}
|
||||||
options={{
|
options={{
|
||||||
allowNegative: false,
|
allowNegative: true,
|
||||||
allowDecimal: true
|
allowDecimal: true
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -26,17 +26,15 @@ export default function DoublePitch({ props }) {
|
|||||||
arrow2Ref,
|
arrow2Ref,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const getLength2 = () => {
|
const getLength2 = (angle1, angle2, length1) => {
|
||||||
const angle1Value = angle1Ref.current.value
|
const angle1Value = angle1 !== undefined ? angle1 : angle1Ref.current?.value
|
||||||
const angle2Value = angle2Ref.current.value
|
const angle2Value = angle2 !== undefined ? angle2 : angle2Ref.current?.value
|
||||||
const length1Value = length1Ref.current.value
|
const length1Value = length1 !== undefined ? length1 : length1Ref.current?.value
|
||||||
|
|
||||||
const arrow1Value = arrow1Ref.current
|
const arrow1Value = arrow1Ref.current
|
||||||
const arrow2Value = arrow2Ref.current
|
|
||||||
|
|
||||||
if (angle1Value !== 0 && length1Value !== 0 && angle2Value !== 0 && arrow1Value !== '') {
|
if (!isNaN(Number(angle1Value)) && !isNaN(Number(length1Value)) && !isNaN(Number(angle2Value)) && arrow1Value) {
|
||||||
const radian1 = (getDegreeByChon(angle1Value) * Math.PI) / 180
|
const radian1 = (getDegreeByChon(angle1Value) * Math.PI) / 180
|
||||||
|
|
||||||
const radian2 = (getDegreeByChon(angle2Value) * Math.PI) / 180
|
const radian2 = (getDegreeByChon(angle2Value) * Math.PI) / 180
|
||||||
return Math.floor((Math.tan(radian1) * length1Value) / Math.tan(radian2))
|
return Math.floor((Math.tan(radian1) * length1Value) / Math.tan(radian2))
|
||||||
}
|
}
|
||||||
@ -178,7 +176,7 @@ export default function DoublePitch({ props }) {
|
|||||||
ref={angle2Ref}
|
ref={angle2Ref}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setAngle2(value)
|
setAngle2(value)
|
||||||
setLength2(getLength2())
|
setLength2(getLength2(angle1Ref.current?.value, value, length1Ref.current?.value))
|
||||||
}}
|
}}
|
||||||
placeholder="45"
|
placeholder="45"
|
||||||
onFocus={() => (angle2Ref.current.value = '')}
|
onFocus={() => (angle2Ref.current.value = '')}
|
||||||
|
|||||||
@ -61,28 +61,40 @@ export default function RightAngle({ props }) {
|
|||||||
<div className="grid-direction">
|
<div className="grid-direction">
|
||||||
<button
|
<button
|
||||||
className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
|
className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
|
||||||
onClick={() => {
|
onMouseDown={(e) => {
|
||||||
|
e.preventDefault(); // 포커스가 input에서 버튼으로 옮겨가는 것을 원천 차단
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
setArrow1('↑')
|
setArrow1('↑')
|
||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
|
||||||
}}
|
}}
|
||||||
></button>
|
></button>
|
||||||
<button
|
<button
|
||||||
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
|
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
|
||||||
onClick={() => {
|
onMouseDown={(e) => {
|
||||||
|
e.preventDefault(); // 포커스가 input에서 버튼으로 옮겨가는 것을 원천 차단
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
setArrow1('↓')
|
setArrow1('↓')
|
||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
|
||||||
}}
|
}}
|
||||||
></button>
|
></button>
|
||||||
<button
|
<button
|
||||||
className={`direction left ${arrow1 === '←' ? 'act' : ''}`}
|
className={`direction left ${arrow1 === '←' ? 'act' : ''}`}
|
||||||
onClick={() => {
|
onMouseDown={(e) => {
|
||||||
|
e.preventDefault(); // 포커스가 input에서 버튼으로 옮겨가는 것을 원천 차단
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
setArrow1('←')
|
setArrow1('←')
|
||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
|
||||||
}}
|
}}
|
||||||
></button>
|
></button>
|
||||||
<button
|
<button
|
||||||
className={`direction right ${arrow1 === '→' ? 'act' : ''}`}
|
className={`direction right ${arrow1 === '→' ? 'act' : ''}`}
|
||||||
onClick={() => {
|
onMouseDown={(e) => {
|
||||||
|
e.preventDefault(); // 포커스가 input에서 버튼으로 옮겨가는 것을 원천 차단
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
setArrow1('→')
|
setArrow1('→')
|
||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -104,14 +104,16 @@ export default function PanelEdit(props) {
|
|||||||
<WithDraggable isShow={true} pos={pos} className="xm">
|
<WithDraggable isShow={true} pos={pos} className="xm">
|
||||||
<WithDraggable.Header
|
<WithDraggable.Header
|
||||||
title={getMessage(
|
title={getMessage(
|
||||||
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type) ? 'modal.move.setting' : 'modal.copy.setting',
|
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE, PANEL_EDIT_TYPE.ROW_MOVE].includes(type)
|
||||||
|
? 'modal.move.setting'
|
||||||
|
: 'modal.copy.setting',
|
||||||
)}
|
)}
|
||||||
onClose={() => closePopup(id)}
|
onClose={() => closePopup(id)}
|
||||||
/>
|
/>
|
||||||
<WithDraggable.Body>
|
<WithDraggable.Body>
|
||||||
<div className="grid-option-tit">
|
<div className="grid-option-tit">
|
||||||
{getMessage(
|
{getMessage(
|
||||||
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type)
|
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE, PANEL_EDIT_TYPE.ROW_MOVE].includes(type)
|
||||||
? 'modal.move.setting.info'
|
? 'modal.move.setting.info'
|
||||||
: 'modal.copy.setting.info',
|
: 'modal.copy.setting.info',
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -2,12 +2,13 @@ import { useContext } from 'react'
|
|||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { sessionStore } from '@/store/commonAtom'
|
import { sessionStore } from '@/store/commonAtom'
|
||||||
import { useRecoilValue, useRecoilState } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { useAxios } from '@/hooks/useAxios'
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
import { globalLocaleStore } from '@/store/localeAtom'
|
import { globalLocaleStore } from '@/store/localeAtom'
|
||||||
import { logout, setSession, login } from '@/lib/authActions'
|
import { login, logout, setSession } from '@/lib/authActions'
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { QcastContext } from '@/app/QcastProvider'
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
|
||||||
export default function ChangePasswordPop(props) {
|
export default function ChangePasswordPop(props) {
|
||||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||||
@ -18,6 +19,7 @@ export default function ChangePasswordPop(props) {
|
|||||||
const { patch } = useAxios(globalLocaleState)
|
const { patch } = useAxios(globalLocaleState)
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
||||||
|
const router = useRouter()
|
||||||
const formInitValue = {
|
const formInitValue = {
|
||||||
password1: '',
|
password1: '',
|
||||||
password2: '',
|
password2: '',
|
||||||
@ -114,7 +116,7 @@ export default function ChangePasswordPop(props) {
|
|||||||
const result = { ...sessionState, pwdInitYn: 'Y' }
|
const result = { ...sessionState, pwdInitYn: 'Y' }
|
||||||
setSession(result)
|
setSession(result)
|
||||||
setSessionState(result)
|
setSessionState(result)
|
||||||
props.setChagePasswordPopOpen(false)
|
props.setChangePasswordPopOpen(false)
|
||||||
await login()
|
await login()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -128,12 +130,14 @@ export default function ChangePasswordPop(props) {
|
|||||||
} else {
|
} else {
|
||||||
setIsGlobalLoading(false)
|
setIsGlobalLoading(false)
|
||||||
logout()
|
logout()
|
||||||
|
router.replace('/login', undefined, { shallow: true })
|
||||||
console.log('code not 200 error')
|
console.log('code not 200 error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setIsGlobalLoading(false)
|
setIsGlobalLoading(false)
|
||||||
logout()
|
logout()
|
||||||
|
router.replace('/login', undefined, { shallow: true })
|
||||||
console.log('catch::::::::', error)
|
console.log('catch::::::::', error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -207,6 +211,7 @@ export default function ChangePasswordPop(props) {
|
|||||||
className="btn-origin grey"
|
className="btn-origin grey"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
logout()
|
logout()
|
||||||
|
router.replace('/login', undefined, { shallow: true })
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{getMessage('main.popup.login.btn2')}
|
{getMessage('main.popup.login.btn2')}
|
||||||
|
|||||||
@ -54,6 +54,8 @@ export default function StuffDetail() {
|
|||||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||||
const ref = useRef()
|
const ref = useRef()
|
||||||
const { get, promiseGet, del, promisePost, promisePut } = useAxios(globalLocaleState)
|
const { get, promiseGet, del, promisePost, promisePut } = useAxios(globalLocaleState)
|
||||||
|
const [createSaleStoreId, setCreateSaleStoreId] = useState('')
|
||||||
|
|
||||||
//form
|
//form
|
||||||
const formInitValue = {
|
const formInitValue = {
|
||||||
// 물건번호 T...(임시) S...(진짜)
|
// 물건번호 T...(임시) S...(진짜)
|
||||||
@ -350,6 +352,9 @@ export default function StuffDetail() {
|
|||||||
promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
|
promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
|
||||||
setIsGlobalLoading(false)
|
setIsGlobalLoading(false)
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
|
|
||||||
|
setCreateSaleStoreId(res?.data?.createSaleStoreId);
|
||||||
|
|
||||||
if (res?.data?.createSaleStoreId === 'T01') {
|
if (res?.data?.createSaleStoreId === 'T01') {
|
||||||
if (session?.storeId !== 'T01') {
|
if (session?.storeId !== 'T01') {
|
||||||
setShowButton('none')
|
setShowButton('none')
|
||||||
@ -2936,7 +2941,7 @@ export default function StuffDetail() {
|
|||||||
<WindSelectPop setShowWindSpeedButtonValid={setShowWindSpeedButtonValid} prefName={form.watch('prefName')} windSpeedInfo={setWindSppedInfo} />
|
<WindSelectPop setShowWindSpeedButtonValid={setShowWindSpeedButtonValid} prefName={form.watch('prefName')} windSpeedInfo={setWindSppedInfo} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{estimatePopupOpen && <DocDownOptionPop planNo={popPlanNo} setEstimatePopupOpen={setEstimatePopupOpen} />}
|
{estimatePopupOpen && <DocDownOptionPop planNo={popPlanNo} setEstimatePopupOpen={setEstimatePopupOpen} createStoreId={createSaleStoreId}/>}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,19 @@
|
|||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { canvasState } from '@/store/canvasAtom'
|
import { canvasState } from '@/store/canvasAtom'
|
||||||
import { fontSelector } from '@/store/fontAtom'
|
import { fontSelector } from '@/store/fontAtom'
|
||||||
import { useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
|
|
||||||
|
/** 폰트 타입별 캔버스 오브젝트 이름 매핑 */
|
||||||
|
const FONT_TYPE_TO_OBJ_NAME = {
|
||||||
|
commonText: 'commonText',
|
||||||
|
dimensionLineText: 'dimensionLineText',
|
||||||
|
flowText: 'flowText',
|
||||||
|
lengthText: 'lengthText',
|
||||||
|
circuitNumberText: 'circuitNumber',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 캔버스 오브젝트 이름 → 폰트 타입 역매핑 */
|
||||||
|
const OBJ_NAME_TO_FONT_TYPE = Object.fromEntries(Object.entries(FONT_TYPE_TO_OBJ_NAME).map(([k, v]) => [v, k]))
|
||||||
|
|
||||||
export function useFont() {
|
export function useFont() {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
@ -11,85 +23,98 @@ export function useFont() {
|
|||||||
const lengthText = useRecoilValue(fontSelector('lengthText'))
|
const lengthText = useRecoilValue(fontSelector('lengthText'))
|
||||||
const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText'))
|
const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText'))
|
||||||
|
|
||||||
|
/** 폰트 타입별 설정 매핑 */
|
||||||
|
const fontSettings = {
|
||||||
|
commonText,
|
||||||
|
dimensionLineText,
|
||||||
|
flowText,
|
||||||
|
lengthText,
|
||||||
|
circuitNumberText,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 타입별 폰트 설정을 캔버스 오브젝트에 적용하는 공통 함수
|
||||||
|
* @param {string} type - 폰트 타입 (commonText, dimensionLineText, flowText, lengthText, circuitNumberText)
|
||||||
|
* @param {number} delay - 적용 지연 시간 (ms), 기본값 200
|
||||||
|
*/
|
||||||
|
const changeFontByType = useCallback(
|
||||||
|
(type, delay = 200) => {
|
||||||
|
const fontSetting = fontSettings[type]
|
||||||
|
const objName = FONT_TYPE_TO_OBJ_NAME[type]
|
||||||
|
|
||||||
|
if (!fontSetting || !objName) {
|
||||||
|
console.warn(`Invalid font type: ${type}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (canvas && fontSetting.fontWeight?.value) {
|
||||||
|
const textObjs = canvas.getObjects().filter((obj) => obj.name === objName)
|
||||||
|
textObjs.forEach((obj) => {
|
||||||
|
obj.set({
|
||||||
|
fontFamily: fontSetting.fontFamily.value,
|
||||||
|
fontWeight: fontSetting.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
||||||
|
fontStyle: fontSetting.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
||||||
|
fontSize: fontSetting.fontSize.value,
|
||||||
|
fill: fontSetting.fontColor.value,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
canvas.renderAll()
|
||||||
|
}
|
||||||
|
}, delay)
|
||||||
|
},
|
||||||
|
[canvas, fontSettings],
|
||||||
|
)
|
||||||
|
|
||||||
|
const changeAllFonts = () => {
|
||||||
|
changeFontByType('commonText')
|
||||||
|
changeFontByType('dimensionLineText')
|
||||||
|
changeFontByType('flowText')
|
||||||
|
changeFontByType('lengthText')
|
||||||
|
changeFontByType('circuitNumberText')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 각 폰트 타입별 useEffect */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (canvas && commonText.fontWeight.value) {
|
changeFontByType('commonText')
|
||||||
const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'commonText')
|
|
||||||
textObjs.forEach((obj) => {
|
|
||||||
obj.set({
|
|
||||||
fontFamily: commonText.fontFamily.value,
|
|
||||||
fontWeight: commonText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
|
||||||
fontStyle: commonText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
|
||||||
fontSize: commonText.fontSize.value,
|
|
||||||
fill: commonText.fontColor.value,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
canvas.renderAll()
|
|
||||||
}
|
|
||||||
}, [commonText])
|
}, [commonText])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (canvas && dimensionLineText.fontWeight.value) {
|
changeFontByType('dimensionLineText')
|
||||||
const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'dimensionLineText')
|
|
||||||
textObjs.forEach((obj) => {
|
|
||||||
obj.set({
|
|
||||||
fontFamily: dimensionLineText.fontFamily.value,
|
|
||||||
fontWeight: dimensionLineText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
|
||||||
fontStyle: dimensionLineText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
|
||||||
fontSize: dimensionLineText.fontSize.value,
|
|
||||||
fill: dimensionLineText.fontColor.value,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
canvas.renderAll()
|
|
||||||
}
|
|
||||||
}, [dimensionLineText])
|
}, [dimensionLineText])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (canvas && flowText.fontWeight.value) {
|
changeFontByType('flowText')
|
||||||
const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'flowText')
|
|
||||||
textObjs.forEach((obj) => {
|
|
||||||
obj.set({
|
|
||||||
fontFamily: flowText.fontFamily.value,
|
|
||||||
fontWeight: flowText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
|
||||||
fontStyle: flowText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
|
||||||
fontSize: flowText.fontSize.value,
|
|
||||||
fill: flowText.fontColor.value,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
canvas.renderAll()
|
|
||||||
}
|
|
||||||
}, [flowText])
|
}, [flowText])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (canvas && lengthText.fontWeight.value) {
|
changeFontByType('lengthText')
|
||||||
const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText')
|
|
||||||
textObjs.forEach((obj) => {
|
|
||||||
obj.set({
|
|
||||||
fontFamily: lengthText.fontFamily.value,
|
|
||||||
fontWeight: lengthText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
|
||||||
fontStyle: lengthText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
|
||||||
fontSize: lengthText.fontSize.value,
|
|
||||||
fill: lengthText.fontColor.value,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
canvas.renderAll()
|
|
||||||
}
|
|
||||||
}, [lengthText])
|
}, [lengthText])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (canvas && circuitNumberText.fontWeight.value) {
|
changeFontByType('circuitNumberText')
|
||||||
const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'circuitNumber')
|
|
||||||
textObjs.forEach((obj) => {
|
|
||||||
obj.set({
|
|
||||||
fontFamily: circuitNumberText.fontFamily.value,
|
|
||||||
fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
|
||||||
fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
|
||||||
fontSize: circuitNumberText.fontSize.value,
|
|
||||||
fill: circuitNumberText.fontColor.value,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
canvas.renderAll()
|
|
||||||
}
|
|
||||||
}, [circuitNumberText])
|
}, [circuitNumberText])
|
||||||
|
|
||||||
return {}
|
/** 캔버스에 텍스트 오브젝트 추가 시 자동으로 폰트 적용 */
|
||||||
|
useEffect(() => {
|
||||||
|
if (!canvas) return
|
||||||
|
|
||||||
|
const handleObjectAdded = (e) => {
|
||||||
|
const obj = e.target
|
||||||
|
if (!obj?.name) return
|
||||||
|
|
||||||
|
const fontType = OBJ_NAME_TO_FONT_TYPE[obj.name]
|
||||||
|
if (fontType) {
|
||||||
|
changeFontByType(fontType, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.on('object:added', handleObjectAdded)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvas.off('object:added', handleObjectAdded)
|
||||||
|
}
|
||||||
|
}, [canvas, changeFontByType])
|
||||||
|
|
||||||
|
return { changeFontByType, changeAllFonts }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,11 @@ import { useMessage } from '@/hooks/useMessage'
|
|||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { sessionStore } from '@/store/commonAtom'
|
import { sessionStore } from '@/store/commonAtom'
|
||||||
import { getQueryString } from '@/util/common-utils'
|
import { getQueryString } from '@/util/common-utils'
|
||||||
import { useRecoilValue } from 'recoil'
|
import { atom, useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
|
||||||
|
|
||||||
|
// API 요청을 저장할 모듈 레벨 변수 (Hook 외부)
|
||||||
|
let roofMaterialPromise = null;
|
||||||
/**
|
/**
|
||||||
* 마스터 컨트롤러 훅
|
* 마스터 컨트롤러 훅
|
||||||
* @returns
|
* @returns
|
||||||
@ -20,10 +23,23 @@ export function useMasterController() {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const getRoofMaterialList = async () => {
|
const getRoofMaterialList = async () => {
|
||||||
return await get({ url: '/api/v1/master/getRoofMaterialList' }).then((res) => {
|
// 1. 이미 진행 중이거나 완료된 Promise가 있으면 그것을 반환
|
||||||
// console.log('🚀🚀 ~ getRoofMaterialList ~ res:', res)
|
if (roofMaterialPromise) {
|
||||||
return res
|
return roofMaterialPromise;
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// 2. 처음 호출될 때 Promise를 생성하여 변수에 할당
|
||||||
|
roofMaterialPromise = get({ url: '/api/v1/master/getRoofMaterialList' })
|
||||||
|
.then((res) => {
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
// 에러 발생 시 다음 호출을 위해 초기화
|
||||||
|
roofMaterialPromise = null;
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
|
||||||
|
return roofMaterialPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -44,6 +44,9 @@ export const useTrestle = () => {
|
|||||||
// exposedBottomPoints는 노출 최하면 들의 centerPoint 배열.
|
// exposedBottomPoints는 노출 최하면 들의 centerPoint 배열.
|
||||||
|
|
||||||
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
||||||
|
surfaces.forEach((surface) => {
|
||||||
|
surface.set({ quotationParam: null })
|
||||||
|
})
|
||||||
// 기존 eaveBar를 삭제
|
// 기존 eaveBar를 삭제
|
||||||
canvas.getObjects().forEach((obj) => {
|
canvas.getObjects().forEach((obj) => {
|
||||||
if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack') {
|
if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack') {
|
||||||
@ -744,18 +747,17 @@ export const useTrestle = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//itemList = data
|
//itemList = data
|
||||||
// itemList에 northModuleYn 추가
|
// itemList에 northModuleYn 추가
|
||||||
itemList = data.map(item => {
|
itemList = data.map((item) => {
|
||||||
if (item.itemTpCd === "MODULE") {
|
if (item.itemTpCd === 'MODULE') {
|
||||||
const matchedModule = modules.find(module => module.moduleItemId === item.itemId);
|
const matchedModule = modules.find((module) => module.moduleItemId === item.itemId)
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
northModuleYn: matchedModule?.northModuleYn || 'N'
|
northModuleYn: matchedModule?.northModuleYn || 'N',
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
return item;
|
return item
|
||||||
});
|
})
|
||||||
|
|
||||||
|
|
||||||
//northArrangement 북면 설치 여부
|
//northArrangement 북면 설치 여부
|
||||||
const northArrangement = getNorthArrangement()
|
const northArrangement = getNorthArrangement()
|
||||||
@ -819,13 +821,18 @@ export const useTrestle = () => {
|
|||||||
|
|
||||||
// 발전 시뮬레이션 용 각도 재계산
|
// 발전 시뮬레이션 용 각도 재계산
|
||||||
const getAzimuth = (parent) => {
|
const getAzimuth = (parent) => {
|
||||||
const { moduleCompass, surfaceCompass, direction } = parent
|
if (typeof parent === 'string') {
|
||||||
|
console.warn('getAzimuth: parent is string, expected object', parent)
|
||||||
|
return 0 // 또는 적절한 기본값
|
||||||
|
}
|
||||||
|
|
||||||
|
const { moduleCompass, surfaceCompass, direction } = parent || {}
|
||||||
|
|
||||||
if (surfaceCompass) {
|
if (surfaceCompass) {
|
||||||
return -surfaceCompass
|
return -surfaceCompass
|
||||||
}
|
}
|
||||||
|
|
||||||
let resultAzimuth = moduleCompass
|
let resultAzimuth = parseInt(moduleCompass, 10)
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 'south': {
|
case 'south': {
|
||||||
@ -2598,7 +2605,7 @@ export const useTrestle = () => {
|
|||||||
return {
|
return {
|
||||||
moduleTpCd: module.moduleInfo.itemTp,
|
moduleTpCd: module.moduleInfo.itemTp,
|
||||||
moduleItemId: module.moduleInfo.itemId,
|
moduleItemId: module.moduleInfo.itemId,
|
||||||
northModuleYn: module?.moduleInfo?.northModuleYn || 'N' // 기본값 'N'
|
northModuleYn: module?.moduleInfo?.northModuleYn || 'N', // 기본값 'N'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -2610,7 +2617,7 @@ export const useTrestle = () => {
|
|||||||
moduleTpCd: cur.moduleTpCd,
|
moduleTpCd: cur.moduleTpCd,
|
||||||
moduleItemId: cur.moduleItemId,
|
moduleItemId: cur.moduleItemId,
|
||||||
cnt: 0,
|
cnt: 0,
|
||||||
northModuleYn: cur.northModuleYn
|
northModuleYn: cur.northModuleYn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
acc[key].cnt++
|
acc[key].cnt++
|
||||||
@ -2623,7 +2630,7 @@ export const useTrestle = () => {
|
|||||||
moduleTpCd: groupedParam.moduleTpCd,
|
moduleTpCd: groupedParam.moduleTpCd,
|
||||||
moduleItemId: groupedParam.moduleItemId,
|
moduleItemId: groupedParam.moduleItemId,
|
||||||
moduleCnt: groupedParam.cnt,
|
moduleCnt: groupedParam.cnt,
|
||||||
northModuleYn: groupedParam.northModuleYn
|
northModuleYn: groupedParam.northModuleYn,
|
||||||
// northModuleYn: params.find(p =>
|
// northModuleYn: params.find(p =>
|
||||||
// p.moduleTpCd === groupedParam.moduleTpCd &&
|
// p.moduleTpCd === groupedParam.moduleTpCd &&
|
||||||
// p.moduleItemId === groupedParam.moduleItemId
|
// p.moduleItemId === groupedParam.moduleItemId
|
||||||
@ -3087,7 +3094,7 @@ export const useTrestle = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (!halfBottomRightModule) {
|
if (!halfBottomRightModule) {
|
||||||
halfBottomRightPoint = { x: x + w, y: y - height / 2 }
|
halfBottomRightPoint = { x: x + w, y: y + height / 2 }
|
||||||
halfBottomRightModule = centerPoints.find(
|
halfBottomRightModule = centerPoints.find(
|
||||||
(centerPoint) => Math.abs(centerPoint.x - halfBottomRightPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomRightPoint.y) < maxY,
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomRightPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomRightPoint.y) < maxY,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -142,6 +142,15 @@ export function useMovementSetting(id) {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
|
if (roofs.length === 0) {
|
||||||
|
swalFire({ text: getMessage('roof.line.not.found') })
|
||||||
|
closePopup(id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
/** object 선택이 변경될 때 처리*/
|
/** object 선택이 변경될 때 처리*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (FOLLOW_LINE_REF.current != null) {
|
if (FOLLOW_LINE_REF.current != null) {
|
||||||
@ -186,7 +195,6 @@ export function useMovementSetting(id) {
|
|||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
}, [currentObject])
|
}, [currentObject])
|
||||||
|
|
||||||
|
|
||||||
const clearRef = () => {
|
const clearRef = () => {
|
||||||
if (type === TYPE.FLOW_LINE) {
|
if (type === TYPE.FLOW_LINE) {
|
||||||
// 안전한 ref 접근
|
// 안전한 ref 접근
|
||||||
@ -258,23 +266,25 @@ export function useMovementSetting(id) {
|
|||||||
let value = ''
|
let value = ''
|
||||||
let direction = ''
|
let direction = ''
|
||||||
|
|
||||||
if (Math.abs(target.y1 - target.y2) < 0.5) { // 수평 라인
|
if (Math.abs(target.y1 - target.y2) < 0.5) {
|
||||||
|
// 수평 라인
|
||||||
value = Big(targetTop).minus(currentY).times(10).round(0)
|
value = Big(targetTop).minus(currentY).times(10).round(0)
|
||||||
|
|
||||||
// 방향 감지
|
// 방향 감지
|
||||||
if (value.toNumber() > 0) {
|
if (value.toNumber() > 0) {
|
||||||
direction = 'up' // 마우스가 라인 위쪽에 있음 (위로 움직임)
|
direction = 'up' // 마우스가 라인 위쪽에 있음 (위로 움직임)
|
||||||
} else if (value.toNumber() < 0) {
|
} else if (value.toNumber() < 0) {
|
||||||
direction = 'down' // 마우스가 라인 아래쪽에 있음 (아래로 움직임)
|
direction = 'down' // 마우스가 라인 아래쪽에 있음 (아래로 움직임)
|
||||||
}
|
}
|
||||||
} else { // 수직 라인
|
} else {
|
||||||
|
// 수직 라인
|
||||||
value = Big(targetLeft).minus(currentX).times(10).round(0).neg()
|
value = Big(targetLeft).minus(currentX).times(10).round(0).neg()
|
||||||
|
|
||||||
// 방향 감지
|
// 방향 감지
|
||||||
if (value.toNumber() > 0) {
|
if (value.toNumber() > 0) {
|
||||||
direction = 'right' // 마우스가 라인 오른쪽에 있음 (오른쪽으로 움직임)
|
direction = 'right' // 마우스가 라인 오른쪽에 있음 (오른쪽으로 움직임)
|
||||||
} else if (value.toNumber() < 0) {
|
} else if (value.toNumber() < 0) {
|
||||||
direction = 'left' // 마우스가 라인 왼쪽에 있음 (왼쪽으로 움직임)
|
direction = 'left' // 마우스가 라인 왼쪽에 있음 (왼쪽으로 움직임)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,37 +322,35 @@ export function useMovementSetting(id) {
|
|||||||
const midY = Big(target.y1).plus(target.y2).div(2)
|
const midY = Big(target.y1).plus(target.y2).div(2)
|
||||||
const wall = canvas.getObjects().find((obj) => obj.id === target.attributes.wallId)
|
const wall = canvas.getObjects().find((obj) => obj.id === target.attributes.wallId)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const result = getSelectLinePosition(wall, target, {
|
const result = getSelectLinePosition(wall, target, {
|
||||||
testDistance: 5, // 테스트 거리
|
testDistance: 5, // 테스트 거리
|
||||||
debug: true // 디버깅 로그 출력
|
debug: true, // 디버깅 로그 출력
|
||||||
});
|
})
|
||||||
//console.log("1111litarget:::::", target);
|
//console.log("1111litarget:::::", target);
|
||||||
//console.log("1111linePosition:::::", result.position); // 'top', 'bottom', 'left', 'right'
|
//console.log("1111linePosition:::::", result.position); // 'top', 'bottom', 'left', 'right'
|
||||||
|
|
||||||
let linePosition = result.position;
|
let linePosition = result.position
|
||||||
//console.log("1111linePosition:::::", direction, linePosition);
|
//console.log("1111linePosition:::::", direction, linePosition);
|
||||||
|
|
||||||
if (target.y1 === target.y2) { //수평벽
|
if (target.y1 === target.y2) {
|
||||||
|
//수평벽
|
||||||
|
|
||||||
const setRadioStates = (isUp) => {
|
const setRadioStates = (isUp) => {
|
||||||
if (UP_DOWN_REF.UP_RADIO_REF.current) {
|
if (UP_DOWN_REF.UP_RADIO_REF.current) {
|
||||||
UP_DOWN_REF.UP_RADIO_REF.current.checked = isUp;
|
UP_DOWN_REF.UP_RADIO_REF.current.checked = isUp
|
||||||
}
|
}
|
||||||
if (UP_DOWN_REF.DOWN_RADIO_REF.current) {
|
if (UP_DOWN_REF.DOWN_RADIO_REF.current) {
|
||||||
UP_DOWN_REF.DOWN_RADIO_REF.current.checked = !isUp;
|
UP_DOWN_REF.DOWN_RADIO_REF.current.checked = !isUp
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (linePosition === 'top') {
|
|
||||||
setRadioStates(value.s !== -1);
|
|
||||||
} else if (linePosition === 'bottom') {
|
|
||||||
setRadioStates(value.s !== 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(direction === 'up') {
|
if (linePosition === 'top') {
|
||||||
|
setRadioStates(value.s !== -1)
|
||||||
|
} else if (linePosition === 'bottom') {
|
||||||
|
setRadioStates(value.s !== 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction === 'up') {
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
checkPoint = { x: midX.toNumber(), y: midY.plus(10).toNumber() }
|
checkPoint = { x: midX.toNumber(), y: midY.plus(10).toNumber() }
|
||||||
@ -367,20 +375,19 @@ export function useMovementSetting(id) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const setRadioStates = (isUp) => {
|
const setRadioStates = (isUp) => {
|
||||||
if (UP_DOWN_REF.UP_RADIO_REF.current) {
|
if (UP_DOWN_REF.UP_RADIO_REF.current) {
|
||||||
UP_DOWN_REF.UP_RADIO_REF.current.checked = isUp;
|
UP_DOWN_REF.UP_RADIO_REF.current.checked = isUp
|
||||||
}
|
}
|
||||||
if (UP_DOWN_REF.DOWN_RADIO_REF.current) {
|
if (UP_DOWN_REF.DOWN_RADIO_REF.current) {
|
||||||
UP_DOWN_REF.DOWN_RADIO_REF.current.checked = !isUp;
|
UP_DOWN_REF.DOWN_RADIO_REF.current.checked = !isUp
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if (linePosition === 'left') {
|
if (linePosition === 'left') {
|
||||||
setRadioStates(value.s !== 1);
|
setRadioStates(value.s !== 1)
|
||||||
} else if (linePosition === 'right') {
|
} else if (linePosition === 'right') {
|
||||||
setRadioStates(value.s !== -1);
|
setRadioStates(value.s !== -1)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
checkPoint = { x: midX.plus(10).toNumber(), y: midY.toNumber() }
|
checkPoint = { x: midX.plus(10).toNumber(), y: midY.toNumber() }
|
||||||
@ -407,11 +414,8 @@ export function useMovementSetting(id) {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const mouseDownEvent = (e) => {
|
const mouseDownEvent = (e) => {
|
||||||
canvas
|
canvas
|
||||||
.getObjects()
|
.getObjects()
|
||||||
@ -460,7 +464,6 @@ export function useMovementSetting(id) {
|
|||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const target = selectedObject.current !== null ? selectedObject.current : CONFIRM_LINE_REF.current?.target
|
const target = selectedObject.current !== null ? selectedObject.current : CONFIRM_LINE_REF.current?.target
|
||||||
if (!target) return
|
if (!target) return
|
||||||
|
|
||||||
@ -468,23 +471,23 @@ export function useMovementSetting(id) {
|
|||||||
const roof = canvas.getObjects().find((obj) => obj.id === roofId)
|
const roof = canvas.getObjects().find((obj) => obj.id === roofId)
|
||||||
|
|
||||||
// 현이동, 동이동 추가
|
// 현이동, 동이동 추가
|
||||||
let flPointValue = FLOW_LINE_REF.POINTER_INPUT_REF.current?.value ?? 0;
|
let flPointValue = FLOW_LINE_REF.POINTER_INPUT_REF.current?.value ?? 0
|
||||||
let flFilledValue = FLOW_LINE_REF.FILLED_INPUT_REF.current?.value ?? 0;
|
let flFilledValue = FLOW_LINE_REF.FILLED_INPUT_REF.current?.value ?? 0
|
||||||
flPointValue = (flFilledValue > 0 || flFilledValue < 0) ? flFilledValue : flPointValue;
|
flPointValue = flFilledValue > 0 || flFilledValue < 0 ? flFilledValue : flPointValue
|
||||||
const moveFlowLine = typeRef.current === TYPE.FLOW_LINE ? flPointValue : 0
|
const moveFlowLine = typeRef.current === TYPE.FLOW_LINE ? flPointValue : 0
|
||||||
|
|
||||||
let udPointValue = UP_DOWN_REF.POINTER_INPUT_REF.current?.value ?? 0;
|
let udPointValue = UP_DOWN_REF.POINTER_INPUT_REF.current?.value ?? 0
|
||||||
let udFilledValue = UP_DOWN_REF.FILLED_INPUT_REF.current?.value ?? 0;
|
let udFilledValue = UP_DOWN_REF.FILLED_INPUT_REF.current?.value ?? 0
|
||||||
udPointValue = udFilledValue > 0 ? udFilledValue : udPointValue;
|
udPointValue = udFilledValue > 0 ? udFilledValue : udPointValue
|
||||||
const moveUpDown = typeRef.current === TYPE.UP_DOWN ? udPointValue : 0
|
const moveUpDown = typeRef.current === TYPE.UP_DOWN ? udPointValue : 0
|
||||||
roof.moveFlowLine = parseInt(moveFlowLine, 10) || 0;
|
roof.moveFlowLine = parseInt(moveFlowLine, 10) || 0
|
||||||
roof.moveUpDown = parseInt(moveUpDown, 10) || 0;
|
roof.moveUpDown = parseInt(moveUpDown, 10) || 0
|
||||||
roof.moveDirect = "";
|
roof.moveDirect = ''
|
||||||
roof.moveSelectLine = target
|
roof.moveSelectLine = target
|
||||||
//console.log("target::::", target, roof.moveSelectLine)
|
//console.log("target::::", target, roof.moveSelectLine)
|
||||||
const wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes.roofId === roofId)
|
const wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes.roofId === roofId)
|
||||||
const baseLines = wall.baseLines
|
const baseLines = wall.baseLines
|
||||||
let centerPoint = wall.getCenterPoint();
|
let centerPoint = wall.getCenterPoint()
|
||||||
let targetBaseLines = []
|
let targetBaseLines = []
|
||||||
let isGableRoof
|
let isGableRoof
|
||||||
if (typeRef.current === TYPE.FLOW_LINE) {
|
if (typeRef.current === TYPE.FLOW_LINE) {
|
||||||
@ -522,9 +525,19 @@ export function useMovementSetting(id) {
|
|||||||
return minX <= line.x1 && line.x1 <= maxX && minX <= line.x2 && line.x2 <= maxX
|
return minX <= line.x1 && line.x1 <= maxX && minX <= line.x2 && line.x2 <= maxX
|
||||||
})
|
})
|
||||||
if (isGableRoof && currentBaseLines.length > 0) {
|
if (isGableRoof && currentBaseLines.length > 0) {
|
||||||
currentBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(line.y1).minus(target.y1).abs().toNumber() }))
|
currentBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(line.y1).minus(target.y1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
checkBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(target.y1).minus(line.y1).abs().toNumber() }))
|
checkBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(target.y1).minus(line.y1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
baseLines
|
baseLines
|
||||||
.filter((line) => line.y1 === line.y2 && line.y1 < target.y1)
|
.filter((line) => line.y1 === line.y2 && line.y1 < target.y1)
|
||||||
@ -538,9 +551,19 @@ export function useMovementSetting(id) {
|
|||||||
return minX <= line.x1 && line.x1 <= maxX && minX <= line.x2 && line.x2 <= maxX
|
return minX <= line.x1 && line.x1 <= maxX && minX <= line.x2 && line.x2 <= maxX
|
||||||
})
|
})
|
||||||
if (isGableRoof && currentBaseLines.length > 0) {
|
if (isGableRoof && currentBaseLines.length > 0) {
|
||||||
currentBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(line.y1).minus(target.y1).abs().toNumber() }))
|
currentBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(line.y1).minus(target.y1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
checkBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(line.y1).minus(target.y1).abs().toNumber() }))
|
checkBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(line.y1).minus(target.y1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'right':
|
case 'right':
|
||||||
@ -551,9 +574,19 @@ export function useMovementSetting(id) {
|
|||||||
return minY <= line.y1 && line.y1 <= maxY && minY <= line.y2 && line.y2 <= maxY
|
return minY <= line.y1 && line.y1 <= maxY && minY <= line.y2 && line.y2 <= maxY
|
||||||
})
|
})
|
||||||
if (isGableRoof && currentBaseLines.length > 0) {
|
if (isGableRoof && currentBaseLines.length > 0) {
|
||||||
currentBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(line.x1).minus(target.x1).abs().toNumber() }))
|
currentBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(line.x1).minus(target.x1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
checkBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(target.x1).minus(line.x1).abs().toNumber() }))
|
checkBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(target.x1).minus(line.x1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'left':
|
case 'left':
|
||||||
@ -564,9 +597,19 @@ export function useMovementSetting(id) {
|
|||||||
return minY <= line.y1 && line.y1 <= maxY && minY <= line.y2 && line.y2 <= maxY
|
return minY <= line.y1 && line.y1 <= maxY && minY <= line.y2 && line.y2 <= maxY
|
||||||
})
|
})
|
||||||
if (isGableRoof && currentBaseLines.length > 0) {
|
if (isGableRoof && currentBaseLines.length > 0) {
|
||||||
currentBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(line.x1).minus(target.x1).abs().toNumber() }))
|
currentBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(line.x1).minus(target.x1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
checkBaseLines.forEach((line) => targetBaseLines.push({ line, distance: Big(target.x1).minus(line.x1).abs().toNumber() }))
|
checkBaseLines.forEach((line) =>
|
||||||
|
targetBaseLines.push({
|
||||||
|
line,
|
||||||
|
distance: Big(target.x1).minus(line.x1).abs().toNumber(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -576,18 +619,18 @@ export function useMovementSetting(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicate lines
|
// Remove duplicate lines
|
||||||
const uniqueLines = new Map();
|
const uniqueLines = new Map()
|
||||||
targetBaseLines = targetBaseLines.filter(item => {
|
targetBaseLines = targetBaseLines.filter((item) => {
|
||||||
const key = `${item.line.x1},${item.line.y1},${item.line.x2},${item.line.y2}`;
|
const key = `${item.line.x1},${item.line.y1},${item.line.x2},${item.line.y2}`
|
||||||
if (!uniqueLines.has(key)) {
|
if (!uniqueLines.has(key)) {
|
||||||
uniqueLines.set(key, true);
|
uniqueLines.set(key, true)
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
});
|
})
|
||||||
|
|
||||||
// Sort by distance
|
// Sort by distance
|
||||||
targetBaseLines.sort((a, b) => a.distance - b.distance);
|
targetBaseLines.sort((a, b) => a.distance - b.distance)
|
||||||
targetBaseLines = targetBaseLines.filter((line) => line.distance === targetBaseLines[0].distance)
|
targetBaseLines = targetBaseLines.filter((line) => line.distance === targetBaseLines[0].distance)
|
||||||
|
|
||||||
if (isGableRoof) {
|
if (isGableRoof) {
|
||||||
@ -621,27 +664,22 @@ export function useMovementSetting(id) {
|
|||||||
let value
|
let value
|
||||||
if (typeRef.current === TYPE.FLOW_LINE) {
|
if (typeRef.current === TYPE.FLOW_LINE) {
|
||||||
value = (() => {
|
value = (() => {
|
||||||
const filledValue = FLOW_LINE_REF.FILLED_INPUT_REF.current?.value;
|
const filledValue = FLOW_LINE_REF.FILLED_INPUT_REF.current?.value
|
||||||
const pointerValue = FLOW_LINE_REF.POINTER_INPUT_REF.current?.value;
|
const pointerValue = FLOW_LINE_REF.POINTER_INPUT_REF.current?.value
|
||||||
|
|
||||||
if (filledValue && !isNaN(filledValue) && filledValue.trim() !== '') {
|
if (filledValue && !isNaN(filledValue) && filledValue.trim() !== '') {
|
||||||
return Big(filledValue).times(2);
|
return Big(filledValue).times(2)
|
||||||
} else if (pointerValue && !isNaN(pointerValue) && pointerValue.trim() !== '') {
|
} else if (pointerValue && !isNaN(pointerValue) && pointerValue.trim() !== '') {
|
||||||
return Big(pointerValue).times(2);
|
return Big(pointerValue).times(2)
|
||||||
}
|
}
|
||||||
return Big(0); // 기본값으로 0 반환 또는 다른 적절한 기본값
|
return Big(0) // 기본값으로 0 반환 또는 다른 적절한 기본값
|
||||||
})();
|
})()
|
||||||
if (Math.abs(target.y1 - target.y2) < 0.5) {
|
if (Math.abs(target.y1 - target.y2) < 0.5) {
|
||||||
value = value.neg()
|
value = value.neg()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("error::", UP_DOWN_REF.POINTER_INPUT_REF.current.value)
|
console.log('error::', UP_DOWN_REF.POINTER_INPUT_REF.current.value)
|
||||||
value = Big(
|
value = Big(UP_DOWN_REF?.FILLED_INPUT_REF?.current?.value?.trim() || UP_DOWN_REF?.POINTER_INPUT_REF?.current?.value?.trim() || '0')
|
||||||
(UP_DOWN_REF?.FILLED_INPUT_REF?.current?.value?.trim() ||
|
|
||||||
UP_DOWN_REF?.POINTER_INPUT_REF?.current?.value?.trim() ||
|
|
||||||
'0'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const midX = Big(target.x1).plus(target.x2).div(2)
|
const midX = Big(target.x1).plus(target.x2).div(2)
|
||||||
const midY = Big(target.y1).plus(target.y2).div(2)
|
const midY = Big(target.y1).plus(target.y2).div(2)
|
||||||
@ -665,17 +703,16 @@ export function useMovementSetting(id) {
|
|||||||
// console.log("2222저장된 moveSelectLine:", roof.moveSelectLine);
|
// console.log("2222저장된 moveSelectLine:", roof.moveSelectLine);
|
||||||
// console.log("222wall::::", wall.points)
|
// console.log("222wall::::", wall.points)
|
||||||
const result = getSelectLinePosition(wall, target, {
|
const result = getSelectLinePosition(wall, target, {
|
||||||
testDistance: 5, // 테스트 거리
|
testDistance: 5, // 테스트 거리
|
||||||
debug: true // 디버깅 로그 출력
|
debug: true, // 디버깅 로그 출력
|
||||||
});
|
})
|
||||||
|
|
||||||
//console.log("2222linePosition:::::", result.position);
|
//console.log("2222linePosition:::::", result.position);
|
||||||
//console.log("222moveDirect:::::", roof.moveDirect);
|
//console.log("222moveDirect:::::", roof.moveDirect);
|
||||||
|
|
||||||
|
// 디버깅용 분류 결과 확인
|
||||||
|
|
||||||
// 디버깅용 분류 결과 확인
|
let linePosition = result.position
|
||||||
|
|
||||||
let linePosition = result.position;
|
|
||||||
roof.movePosition = linePosition
|
roof.movePosition = linePosition
|
||||||
value = value.div(10)
|
value = value.div(10)
|
||||||
targetBaseLines
|
targetBaseLines
|
||||||
@ -684,15 +721,14 @@ export function useMovementSetting(id) {
|
|||||||
const currentLine = target.line
|
const currentLine = target.line
|
||||||
|
|
||||||
//console.log("linePosition::::::::::::::", linePosition)
|
//console.log("linePosition::::::::::::::", linePosition)
|
||||||
if (UP_DOWN_REF?.DOWN_RADIO_REF?.current?.checked ){
|
if (UP_DOWN_REF?.DOWN_RADIO_REF?.current?.checked) {
|
||||||
//position확인
|
//position확인
|
||||||
if(linePosition === 'bottom' || linePosition === 'right') {
|
if (linePosition === 'bottom' || linePosition === 'right') {
|
||||||
//console.log("1value::::::::::::::", value.toString())
|
//console.log("1value::::::::::::::", value.toString())
|
||||||
value = value.neg()
|
value = value.neg()
|
||||||
|
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
if(linePosition === 'top' || linePosition === 'left') {
|
if (linePosition === 'top' || linePosition === 'left') {
|
||||||
//console.log("1value::::::::::::::", value.toString())
|
//console.log("1value::::::::::::::", value.toString())
|
||||||
value = value.neg()
|
value = value.neg()
|
||||||
}
|
}
|
||||||
@ -753,7 +789,6 @@ export function useMovementSetting(id) {
|
|||||||
|
|
||||||
// javascript
|
// javascript
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
TYPE,
|
TYPE,
|
||||||
closePopup,
|
closePopup,
|
||||||
@ -765,4 +800,3 @@ export function useMovementSetting(id) {
|
|||||||
handleSave,
|
handleSave,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -251,6 +251,7 @@ export function useOuterLineWall(id, propertiesId) {
|
|||||||
removeAllDocumentEventListeners()
|
removeAllDocumentEventListeners()
|
||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
setOuterLineFix(true)
|
setOuterLineFix(true)
|
||||||
|
canvas.outerLineFix = true
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
ccwCheck()
|
ccwCheck()
|
||||||
addPopup(propertiesId, 1, <RoofShapeSetting id={propertiesId} pos={{ x: 50, y: 230 }} />)
|
addPopup(propertiesId, 1, <RoofShapeSetting id={propertiesId} pos={{ x: 50, y: 230 }} />)
|
||||||
@ -811,7 +812,7 @@ export function useOuterLineWall(id, propertiesId) {
|
|||||||
if (points.length === 0) {
|
if (points.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
enterCheck(e)
|
// enterCheck(e)
|
||||||
const key = e.key
|
const key = e.key
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'Enter': {
|
case 'Enter': {
|
||||||
|
|||||||
@ -30,7 +30,6 @@ import { QcastContext } from '@/app/QcastProvider'
|
|||||||
import { usePlan } from '@/hooks/usePlan'
|
import { usePlan } from '@/hooks/usePlan'
|
||||||
import { roofsState } from '@/store/roofAtom'
|
import { roofsState } from '@/store/roofAtom'
|
||||||
import { useText } from '@/hooks/useText'
|
import { useText } from '@/hooks/useText'
|
||||||
import { processEaveHelpLines } from '@/util/skeleton-utils'
|
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
|
|
||||||
export function useRoofAllocationSetting(id) {
|
export function useRoofAllocationSetting(id) {
|
||||||
@ -114,9 +113,9 @@ export function useRoofAllocationSetting(id) {
|
|||||||
*/
|
*/
|
||||||
const fetchBasicSettings = async (planNo) => {
|
const fetchBasicSettings = async (planNo) => {
|
||||||
try {
|
try {
|
||||||
const response = await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}` });
|
const response = await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}` })
|
||||||
|
|
||||||
let roofsArray = [];
|
let roofsArray = []
|
||||||
|
|
||||||
// API에서 데이터를 성공적으로 가져온 경우
|
// API에서 데이터를 성공적으로 가져온 경우
|
||||||
if (response && response.length > 0) {
|
if (response && response.length > 0) {
|
||||||
@ -133,15 +132,15 @@ export function useRoofAllocationSetting(id) {
|
|||||||
roofPitch: item.roofPitch,
|
roofPitch: item.roofPitch,
|
||||||
roofAngle: item.roofAngle,
|
roofAngle: item.roofAngle,
|
||||||
selected: index === 0, // 첫 번째 항목을 기본 선택으로 설정
|
selected: index === 0, // 첫 번째 항목을 기본 선택으로 설정
|
||||||
index: index
|
index: index,
|
||||||
}));
|
}))
|
||||||
}
|
}
|
||||||
// API에서 데이터가 없고 기존 roofList가 있는 경우
|
// API에서 데이터가 없고 기존 roofList가 있는 경우
|
||||||
else if (roofList && roofList.length > 0) {
|
else if (roofList && roofList.length > 0) {
|
||||||
roofsArray = roofList.map((roof, index) => ({
|
roofsArray = roofList.map((roof, index) => ({
|
||||||
...roof,
|
...roof,
|
||||||
selected: index === 0 // 첫 번째 항목을 기본 선택으로 설정
|
selected: index === 0, // 첫 번째 항목을 기본 선택으로 설정
|
||||||
}));
|
}))
|
||||||
}
|
}
|
||||||
// 둘 다 없는 경우 기본값 설정
|
// 둘 다 없는 경우 기본값 설정
|
||||||
else {
|
else {
|
||||||
@ -156,64 +155,62 @@ export function useRoofAllocationSetting(id) {
|
|||||||
roofHajebichi: 0,
|
roofHajebichi: 0,
|
||||||
roofGap: 'HEI_455',
|
roofGap: 'HEI_455',
|
||||||
roofLayout: 'P',
|
roofLayout: 'P',
|
||||||
roofPitch: 4,
|
roofPitch: 4,
|
||||||
roofAngle: 21.8,
|
roofAngle: 21.8,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 데이터 설정
|
||||||
|
*/
|
||||||
|
const selectRoofs = []
|
||||||
|
for (let i = 0; i < roofsArray.length; i++) {
|
||||||
|
roofMaterials?.map((material) => {
|
||||||
|
if (material.roofMatlCd === roofsArray[i].roofMatlCd) {
|
||||||
|
selectRoofs.push({
|
||||||
|
...material,
|
||||||
|
selected: roofsArray[i].roofApply,
|
||||||
|
index: roofsArray[i].roofSeq,
|
||||||
|
id: roofsArray[i].roofMatlCd,
|
||||||
|
width: roofsArray[i].roofWidth,
|
||||||
|
length: roofsArray[i].roofHeight,
|
||||||
|
hajebichi: roofsArray[i].roofHajebichi,
|
||||||
|
raft: roofsArray[i].roofGap,
|
||||||
|
layout: roofsArray[i].roofLayout,
|
||||||
|
pitch: roofsArray[i].roofPitch,
|
||||||
|
angle: roofsArray[i].roofAngle,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 데이터 설정
|
|
||||||
*/
|
|
||||||
const selectRoofs = []
|
|
||||||
for (let i = 0; i < roofsArray.length; i++) {
|
|
||||||
roofMaterials?.map((material) => {
|
|
||||||
if (material.roofMatlCd === roofsArray[i].roofMatlCd) {
|
|
||||||
selectRoofs.push({
|
|
||||||
...material,
|
|
||||||
selected: roofsArray[i].roofApply,
|
|
||||||
index: roofsArray[i].roofSeq,
|
|
||||||
id: roofsArray[i].roofMatlCd,
|
|
||||||
width: roofsArray[i].roofWidth,
|
|
||||||
length: roofsArray[i].roofHeight,
|
|
||||||
hajebichi: roofsArray[i].roofHajebichi,
|
|
||||||
raft: roofsArray[i].roofGap,
|
|
||||||
layout: roofsArray[i].roofLayout,
|
|
||||||
pitch: roofsArray[i].roofPitch,
|
|
||||||
angle: roofsArray[i].roofAngle,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstRes = Array.isArray(res) && res.length > 0 ? res[0] : null
|
|
||||||
|
|
||||||
setBasicSetting({
|
|
||||||
...basicSetting,
|
|
||||||
planNo: firstRes?.planNo ?? planNo,
|
|
||||||
roofSizeSet: firstRes?.roofSizeSet ?? 0,
|
|
||||||
roofAngleSet: firstRes?.roofAngleSet ?? 0,
|
|
||||||
roofsData: roofsArray,
|
|
||||||
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
setBasicInfo({
|
const firstRes = Array.isArray(response) && response.length > 0 ? response[0] : null
|
||||||
planNo: '' + (firstRes?.planNo ?? planNo),
|
|
||||||
roofSizeSet: '' + (firstRes?.roofSizeSet ?? 0),
|
|
||||||
roofAngleSet: '' + (firstRes?.roofAngleSet ?? 0),
|
|
||||||
})
|
|
||||||
// 데이터 동기화: 렌더링용 필드 기본값 보정
|
|
||||||
const normalizedRoofs = selectRoofs.map((roof) => ({
|
|
||||||
...roof,
|
|
||||||
width: roof.width ?? '',
|
|
||||||
length: roof.length ?? '',
|
|
||||||
hajebichi: roof.hajebichi ?? '',
|
|
||||||
pitch: roof.pitch ?? '',
|
|
||||||
angle: roof.angle ?? '',
|
|
||||||
}))
|
|
||||||
setCurrentRoofList(normalizedRoofs)
|
|
||||||
|
|
||||||
|
setBasicSetting({
|
||||||
|
...basicSetting,
|
||||||
|
planNo: firstRes?.planNo ?? planNo,
|
||||||
|
roofSizeSet: firstRes?.roofSizeSet ?? 0,
|
||||||
|
roofAngleSet: firstRes?.roofAngleSet ?? 0,
|
||||||
|
roofsData: roofsArray,
|
||||||
|
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
|
||||||
|
})
|
||||||
|
|
||||||
|
setBasicInfo({
|
||||||
|
planNo: '' + (firstRes?.planNo ?? planNo),
|
||||||
|
roofSizeSet: '' + (firstRes?.roofSizeSet ?? 0),
|
||||||
|
roofAngleSet: '' + (firstRes?.roofAngleSet ?? 0),
|
||||||
|
})
|
||||||
|
// 데이터 동기화: 렌더링용 필드 기본값 보정
|
||||||
|
const normalizedRoofs = selectRoofs.map((roof) => ({
|
||||||
|
...roof,
|
||||||
|
width: roof.width ?? '',
|
||||||
|
length: roof.length ?? '',
|
||||||
|
hajebichi: roof.hajebichi ?? '',
|
||||||
|
pitch: roof.pitch ?? '',
|
||||||
|
angle: roof.angle ?? '',
|
||||||
|
}))
|
||||||
|
setCurrentRoofList(normalizedRoofs)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Data fetching error:', error)
|
console.error('Data fetching error:', error)
|
||||||
}
|
}
|
||||||
@ -326,42 +323,19 @@ export function useRoofAllocationSetting(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const drawOriginRoofLine = () => {
|
const drawOriginRoofLine = () => {
|
||||||
// outerLinePoints 배열을 이용하여 빨간색 Line 객체들 생성
|
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
|
||||||
if (outerLinePoints && outerLinePoints.length > 1) {
|
/** 벽면 삭제 */
|
||||||
// 연속된 점들을 연결하여 라인 생성
|
wallLines.forEach((wallLine) => {
|
||||||
for (let i = 0; i < outerLinePoints.length - 1; i++) {
|
wallLine.set({
|
||||||
const point1 = outerLinePoints[i]
|
stroke: 'black',
|
||||||
const point2 = outerLinePoints[i + 1]
|
strokeDashArray: [5, 2],
|
||||||
|
strokeWidth: 1,
|
||||||
const line = new fabric.Line([point1.x, point1.y, point2.x, point2.y], {
|
selectable: false,
|
||||||
stroke: 'black',
|
name: 'originRoofOuterLine',
|
||||||
strokeDashArray: [5, 2],
|
visible: outlineDisplay,
|
||||||
strokeWidth: 1,
|
})
|
||||||
selectable: false,
|
})
|
||||||
name: 'originRoofOuterLine',
|
canvas.renderAll()
|
||||||
visible: outlineDisplay,
|
|
||||||
})
|
|
||||||
|
|
||||||
canvas.add(line)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 마지막 점과 첫 점을 연결하여 폐곡선 만들기
|
|
||||||
if (outerLinePoints.length > 2) {
|
|
||||||
const lastPoint = outerLinePoints[outerLinePoints.length - 1]
|
|
||||||
const firstPoint = outerLinePoints[0]
|
|
||||||
|
|
||||||
const closingLine = new fabric.Line([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], {
|
|
||||||
stroke: 'red',
|
|
||||||
strokeWidth: 2,
|
|
||||||
selectable: false,
|
|
||||||
name: 'originRoofOuterLine',
|
|
||||||
})
|
|
||||||
|
|
||||||
canvas.add(closingLine)
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.renderAll()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -467,7 +441,6 @@ export function useRoofAllocationSetting(id) {
|
|||||||
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
|
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
|
||||||
roofBases.forEach((roofBase) => {
|
roofBases.forEach((roofBase) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const roofEaveHelpLines = canvas.getObjects().filter((obj) => obj.lineName === 'eaveHelpLine' && obj.roofId === roofBase.id)
|
const roofEaveHelpLines = canvas.getObjects().filter((obj) => obj.lineName === 'eaveHelpLine' && obj.roofId === roofBase.id)
|
||||||
if (roofEaveHelpLines.length > 0) {
|
if (roofEaveHelpLines.length > 0) {
|
||||||
if (roofBase.lines) {
|
if (roofBase.lines) {
|
||||||
@ -536,6 +509,34 @@ export function useRoofAllocationSetting(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roofBase.adjustRoofLines.length > 0) {
|
||||||
|
const newRoofLines = []
|
||||||
|
let lineIndex = 1
|
||||||
|
roofBase.lines.forEach((line, idx) => {
|
||||||
|
const adjustLines = roofBase.adjustRoofLines.filter((adjustLine) => adjustLine.roofIdx === line.idx)
|
||||||
|
if (adjustLines.length === 0) {
|
||||||
|
line.idx = lineIndex
|
||||||
|
newRoofLines.push(line)
|
||||||
|
lineIndex++
|
||||||
|
} else {
|
||||||
|
adjustLines.forEach(({ point, roofIdx }) => {
|
||||||
|
const newLine = new QLine(point, {
|
||||||
|
idx: lineIndex,
|
||||||
|
selectable: false,
|
||||||
|
parentId: line.parentId,
|
||||||
|
parent: line.parent,
|
||||||
|
fontSize: line.fontSize,
|
||||||
|
stroke: line.stroke,
|
||||||
|
strokeWidth: line.strokeWidth,
|
||||||
|
attributes: line.attributes,
|
||||||
|
})
|
||||||
|
newRoofLines.push(newLine)
|
||||||
|
lineIndex++
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
roofBase.lines = newRoofLines
|
||||||
|
}
|
||||||
if (roofBase.separatePolygon.length > 0) {
|
if (roofBase.separatePolygon.length > 0) {
|
||||||
splitPolygonWithSeparate(roofBase.separatePolygon)
|
splitPolygonWithSeparate(roofBase.separatePolygon)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { useEvent } from '@/hooks/useEvent'
|
|||||||
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||||
import { useMode } from '@/hooks/useMode'
|
import { useMode } from '@/hooks/useMode'
|
||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
import { outerLineFixState } from '@/store/outerLineAtom'
|
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
import { getChonByDegree } from '@/util/canvas-util'
|
import { getChonByDegree } from '@/util/canvas-util'
|
||||||
@ -46,11 +45,9 @@ export function useRoofShapePassivitySetting(id) {
|
|||||||
{ id: 3, name: getMessage('windage'), type: TYPES.SHED },
|
{ id: 3, name: getMessage('windage'), type: TYPES.SHED },
|
||||||
]
|
]
|
||||||
|
|
||||||
const outerLineFix = useRecoilValue(outerLineFixState)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
if (!outerLineFix || outerLines.length === 0) {
|
if (!canvas.outerLineFix || outerLines.length === 0) {
|
||||||
swalFire({ text: getMessage('wall.line.not.found') })
|
swalFire({ text: getMessage('wall.line.not.found') })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -81,6 +81,12 @@ export function useRoofShapeSetting(id) {
|
|||||||
}, [jerkinHeadPitch])
|
}, [jerkinHeadPitch])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
|
if (!canvas.outerLineFix || outerLines.length === 0) {
|
||||||
|
swalFire({ text: getMessage('wall.line.not.found') })
|
||||||
|
closePopup(id)
|
||||||
|
return
|
||||||
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (!isFixRef.current) {
|
if (!isFixRef.current) {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -815,7 +815,7 @@ export function usePlacementShapeDrawing(id) {
|
|||||||
if (points.length === 0) {
|
if (points.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
enterCheck(e)
|
// enterCheck(e)
|
||||||
const key = e.key
|
const key = e.key
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'Enter': {
|
case 'Enter': {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useRecoilValue, useResetRecoilState } from 'recoil'
|
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
||||||
import {
|
import {
|
||||||
canvasSettingState,
|
canvasSettingState,
|
||||||
canvasState,
|
canvasState,
|
||||||
@ -50,7 +50,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
const { changeCorridorDimensionText } = useText()
|
const { changeCorridorDimensionText } = useText()
|
||||||
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
|
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
|
||||||
const { fetchSettings } = useCanvasSetting(false)
|
const { fetchSettings } = useCanvasSetting(false)
|
||||||
const currentObject = useRecoilValue(currentObjectState)
|
const [currentObject, setCurrentObject] = useRecoilState(currentObjectState)
|
||||||
const [popupId, setPopupId] = useState(uuidv4())
|
const [popupId, setPopupId] = useState(uuidv4())
|
||||||
|
|
||||||
const applySurfaceShape = (surfaceRefs, selectedType, id) => {
|
const applySurfaceShape = (surfaceRefs, selectedType, id) => {
|
||||||
@ -755,6 +755,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
confirmFn: () => {
|
confirmFn: () => {
|
||||||
canvas.clear()
|
canvas.clear()
|
||||||
|
delete canvas.outerLineFix
|
||||||
|
|
||||||
if (backgroundImage) {
|
if (backgroundImage) {
|
||||||
fabric.Image.fromURL(`${backgroundImage.path}`, function (img) {
|
fabric.Image.fromURL(`${backgroundImage.path}`, function (img) {
|
||||||
@ -1524,6 +1525,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
// 개별 객체들을 다시 캔버스에 추가하고 처리
|
// 개별 객체들을 다시 캔버스에 추가하고 처리
|
||||||
group.getObjects().forEach((obj) => {
|
group.getObjects().forEach((obj) => {
|
||||||
canvas.add(obj)
|
canvas.add(obj)
|
||||||
|
obj.dirty = true // 캐시 무효화
|
||||||
obj.setCoords()
|
obj.setCoords()
|
||||||
|
|
||||||
// currentObject인 경우 추가 처리
|
// currentObject인 경우 추가 처리
|
||||||
@ -1534,6 +1536,8 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
// QPolygon 내부 구조 재구성 (선이 깨지는 문제 해결)
|
// QPolygon 내부 구조 재구성 (선이 깨지는 문제 해결)
|
||||||
if (obj.type === 'QPolygon' && obj.lines) {
|
if (obj.type === 'QPolygon' && obj.lines) {
|
||||||
obj.initLines()
|
obj.initLines()
|
||||||
|
obj.dirty = true
|
||||||
|
obj.setCoords()
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.set({
|
obj.set({
|
||||||
@ -1544,6 +1548,8 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
// relatedObject인 경우에도 필요한 처리
|
// relatedObject인 경우에도 필요한 처리
|
||||||
if (obj.type === 'QPolygon' && obj.lines) {
|
if (obj.type === 'QPolygon' && obj.lines) {
|
||||||
obj.initLines()
|
obj.initLines()
|
||||||
|
obj.dirty = true
|
||||||
|
obj.setCoords()
|
||||||
}
|
}
|
||||||
if (obj.type === 'group') {
|
if (obj.type === 'group') {
|
||||||
// 회전 후의 points를 groupPoints로 업데이트
|
// 회전 후의 points를 groupPoints로 업데이트
|
||||||
@ -1551,24 +1557,30 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
|
|
||||||
obj.recalculateGroupPoints()
|
obj.recalculateGroupPoints()
|
||||||
|
|
||||||
obj._objects?.forEach((obj) => {
|
obj._objects?.forEach((innerObj) => {
|
||||||
obj.initLines()
|
innerObj.initLines()
|
||||||
obj.fire('modified')
|
innerObj.dirty = true
|
||||||
|
innerObj.setCoords()
|
||||||
|
innerObj.fire('modified')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
currentObject.dirty = true
|
||||||
|
currentObject.setCoords()
|
||||||
currentObject.fire('modified')
|
currentObject.fire('modified')
|
||||||
|
currentObject.fire('polygonMoved')
|
||||||
// 화살표와 선 다시 그리기
|
// 화살표와 선 다시 그리기
|
||||||
drawDirectionArrow(currentObject)
|
drawDirectionArrow(currentObject)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setPolygonLinesActualSize(currentObject)
|
setPolygonLinesActualSize(currentObject)
|
||||||
changeSurfaceLineType(currentObject)
|
changeSurfaceLineType(currentObject)
|
||||||
|
currentObject.dirty = true
|
||||||
|
currentObject.setCoords()
|
||||||
|
canvas.requestRenderAll()
|
||||||
|
setCurrentObject(currentObject)
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
// currentObject를 다시 선택 상태로 설정
|
|
||||||
canvas.setActiveObject(currentObject)
|
|
||||||
canvas.renderAll()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -99,6 +99,12 @@ export function useCircuitTrestle(executeEffect = false) {
|
|||||||
// 지붕면 목록
|
// 지붕면 목록
|
||||||
const getRoofSurfaceList = () => {
|
const getRoofSurfaceList = () => {
|
||||||
const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
||||||
|
|
||||||
|
roofSurfaceList.forEach((roofSurface) => {
|
||||||
|
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.surfaceId === roofSurface.id)
|
||||||
|
roofSurface.northModuleYn = modules.every((module) => module.moduleInfo.northModuleYn === 'Y') ? 'Y' : 'N'
|
||||||
|
})
|
||||||
|
|
||||||
roofSurfaceList.sort((a, b) => a.left - b.left || b.top - a.top)
|
roofSurfaceList.sort((a, b) => a.left - b.left || b.top - a.top)
|
||||||
|
|
||||||
const result = roofSurfaceList
|
const result = roofSurfaceList
|
||||||
@ -119,6 +125,7 @@ export function useCircuitTrestle(executeEffect = false) {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
roofSurfaceNorthYn: obj.direction === 'north' ? 'Y' : 'N',
|
roofSurfaceNorthYn: obj.direction === 'north' ? 'Y' : 'N',
|
||||||
|
roofSurfaceNorthModuleYn: obj.northModuleYn,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter((surface) => surface.moduleList.length > 0)
|
.filter((surface) => surface.moduleList.length > 0)
|
||||||
@ -139,11 +146,14 @@ export function useCircuitTrestle(executeEffect = false) {
|
|||||||
let remaining = [...arr]
|
let remaining = [...arr]
|
||||||
|
|
||||||
while (remaining.length > 0) {
|
while (remaining.length > 0) {
|
||||||
const { roofSurface, roofSurfaceIncl } = remaining[0]
|
const { roofSurface, roofSurfaceIncl, roofSurfaceNorthModuleYn } = remaining[0]
|
||||||
const key = `${roofSurface}|${roofSurfaceIncl}`
|
const key = `${roofSurface}|${roofSurfaceIncl}|${roofSurfaceNorthModuleYn}`
|
||||||
|
|
||||||
// 해당 그룹 추출
|
// 해당 그룹 추출
|
||||||
const group = remaining.filter((item) => item.roofSurface === roofSurface && item.roofSurfaceIncl === roofSurfaceIncl)
|
const group = remaining.filter(
|
||||||
|
(item) =>
|
||||||
|
item.roofSurface === roofSurface && item.roofSurfaceIncl === roofSurfaceIncl && item.roofSurfaceNorthModuleYn === roofSurfaceNorthModuleYn,
|
||||||
|
)
|
||||||
|
|
||||||
// 이미 처리했는지 체크 후 저장
|
// 이미 처리했는지 체크 후 저장
|
||||||
if (!seen.has(key)) {
|
if (!seen.has(key)) {
|
||||||
@ -152,7 +162,14 @@ export function useCircuitTrestle(executeEffect = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remaining에서 제거
|
// remaining에서 제거
|
||||||
remaining = remaining.filter((item) => !(item.roofSurface === roofSurface && item.roofSurfaceIncl === roofSurfaceIncl))
|
remaining = remaining.filter(
|
||||||
|
(item) =>
|
||||||
|
!(
|
||||||
|
item.roofSurface === roofSurface &&
|
||||||
|
item.roofSurfaceIncl === roofSurfaceIncl &&
|
||||||
|
item.roofSurfaceNorthModuleYn === roofSurfaceNorthModuleYn
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@ -10,9 +10,10 @@ import {
|
|||||||
} from '@/store/canvasAtom'
|
} from '@/store/canvasAtom'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { basicSettingState } from '@/store/settingAtom'
|
import { basicSettingState } from '@/store/settingAtom'
|
||||||
import { calcLineActualSize } from '@/util/qpolygon-utils'
|
import { calcLineActualSizeByLineLength, calcLinePlaneSize } from '@/util/qpolygon-utils'
|
||||||
import { getDegreeByChon } from '@/util/canvas-util'
|
import { getDegreeByChon } from '@/util/canvas-util'
|
||||||
import { useText } from '@/hooks/useText'
|
import { useText } from '@/hooks/useText'
|
||||||
|
import { fontSelector } from '@/store/fontAtom'
|
||||||
|
|
||||||
export const useLine = () => {
|
export const useLine = () => {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
@ -23,20 +24,22 @@ export const useLine = () => {
|
|||||||
const angleUnit = useRecoilValue(showAngleUnitSelector)
|
const angleUnit = useRecoilValue(showAngleUnitSelector)
|
||||||
const roofSizeSet = useRecoilValue(basicSettingState).roofSizeSet
|
const roofSizeSet = useRecoilValue(basicSettingState).roofSizeSet
|
||||||
const globalPitch = useRecoilValue(globalPitchState)
|
const globalPitch = useRecoilValue(globalPitchState)
|
||||||
|
const lengthText = useRecoilValue(fontSelector('lengthText'))
|
||||||
|
|
||||||
const { changeCorridorDimensionText } = useText()
|
const { changeCorridorDimensionText } = useText()
|
||||||
|
|
||||||
const addLine = (points = [], options) => {
|
const addLine = (points = [], options) => {
|
||||||
const line = new QLine(points, {
|
const line = new QLine(points, {
|
||||||
...options,
|
...options,
|
||||||
fontSize: fontSize,
|
attributes: {},
|
||||||
fontFamily: fontFamily,
|
fontSize: lengthText.fontSize.value,
|
||||||
|
fontFamily: lengthText.fontFamily.value,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (line.length < 1) {
|
if (line.length < 1) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
line.attributes.planeSize = calcLinePlaneSize(line)
|
||||||
canvas?.add(line)
|
canvas?.add(line)
|
||||||
return line
|
return line
|
||||||
}
|
}
|
||||||
@ -170,16 +173,16 @@ export const useLine = () => {
|
|||||||
const isHorizontal = y1 === y2
|
const isHorizontal = y1 === y2
|
||||||
const isVertical = x1 === x2
|
const isVertical = x1 === x2
|
||||||
const isDiagonal = !isHorizontal && !isVertical
|
const isDiagonal = !isHorizontal && !isVertical
|
||||||
const lineLength = line.getLength()
|
const lineLength = line.attributes.planeSize ?? line.getLength()
|
||||||
|
|
||||||
line.attributes = { ...line.attributes, planeSize: line.getLength(), actualSize: line.getLength() }
|
line.attributes = { ...line.attributes, planeSize: lineLength, actualSize: lineLength }
|
||||||
|
|
||||||
if (+roofSizeSet === 1) {
|
if (+roofSizeSet === 1) {
|
||||||
if (direction === 'south' || direction === 'north') {
|
if (direction === 'south' || direction === 'north') {
|
||||||
if (isVertical) {
|
if (isVertical) {
|
||||||
line.attributes = {
|
line.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
actualSize: calcLineActualSize(line, getDegreeByChon(pitch)),
|
actualSize: calcLineActualSizeByLineLength(lineLength, getDegreeByChon(pitch)),
|
||||||
}
|
}
|
||||||
} else if (isDiagonal) {
|
} else if (isDiagonal) {
|
||||||
const yLength = Math.abs(y2 - y1) * 10
|
const yLength = Math.abs(y2 - y1) * 10
|
||||||
@ -193,7 +196,7 @@ export const useLine = () => {
|
|||||||
if (isHorizontal) {
|
if (isHorizontal) {
|
||||||
line.attributes = {
|
line.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
actualSize: calcLineActualSize(line, getDegreeByChon(pitch)),
|
actualSize: calcLineActualSizeByLineLength(lineLength, getDegreeByChon(pitch)),
|
||||||
}
|
}
|
||||||
} else if (isDiagonal) {
|
} else if (isDiagonal) {
|
||||||
const xLength = Math.abs(x2 - x1) * 10
|
const xLength = Math.abs(x2 - x1) * 10
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, globalPitchState, pitchTextSelector } from '@/store/canvasAtom'
|
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, globalPitchState, pitchTextSelector } from '@/store/canvasAtom'
|
||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { calculateIntersection, findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, isPointOnLine } from '@/util/canvas-util'
|
import { calculateIntersection, findAndRemoveClosestPoint, getDegreeByChon, isPointOnLine } from '@/util/canvas-util'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
||||||
import { basicSettingState, flowDisplaySelector } from '@/store/settingAtom'
|
import { basicSettingState, flowDisplaySelector } from '@/store/settingAtom'
|
||||||
@ -344,6 +344,7 @@ export const usePolygon = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//arrow의 compass 값으로 방향 글자 설정 필요
|
//arrow의 compass 값으로 방향 글자 설정 필요
|
||||||
|
// moduleCompass 각도와 direction(지붕면 방향)에 따라 한자 방위 텍스트 매핑
|
||||||
const drawDirectionStringToArrow2 = (polygon, showDirectionText) => {
|
const drawDirectionStringToArrow2 = (polygon, showDirectionText) => {
|
||||||
let { direction, surfaceCompass, moduleCompass, arrow } = polygon
|
let { direction, surfaceCompass, moduleCompass, arrow } = polygon
|
||||||
if (moduleCompass === null || moduleCompass === undefined) {
|
if (moduleCompass === null || moduleCompass === undefined) {
|
||||||
@ -371,153 +372,114 @@ export const usePolygon = () => {
|
|||||||
|
|
||||||
let text = ''
|
let text = ''
|
||||||
|
|
||||||
let compassType = (375 + getDegreeInOrientation(moduleCompass)) / 15
|
// moduleCompass 각도와 direction에 따른 한자 방위 매핑
|
||||||
|
// direction: south(↓), west(←), north(↑), east(→)
|
||||||
|
// 각도 범위별 매핑 테이블 (사진 기준)
|
||||||
|
const getDirectionText = (angle, dir) => {
|
||||||
|
// 각도를 정규화 (-180 ~ 180 범위로)
|
||||||
|
let normalizedAngle = Number(angle)
|
||||||
|
while (normalizedAngle > 180) normalizedAngle -= 360
|
||||||
|
while (normalizedAngle < -180) normalizedAngle += 360
|
||||||
|
|
||||||
moduleCompass = -1 * moduleCompass
|
// 매핑 테이블: { south(↓), west(←), north(↑), east(→) }
|
||||||
|
// 각도 0: 남, 서, 북, 동
|
||||||
|
// 각도 45: 남서, 북서, 북동, 남동
|
||||||
|
// 각도 90: 서, 북, 동, 남
|
||||||
|
// 각도 135: 북서, 북동, 남동, 남서
|
||||||
|
// 각도 180: 북, 동, 남, 서
|
||||||
|
// 각도 -45: 남동, 남서, 북서, 북동
|
||||||
|
// 각도 -90: 동, 남, 서, 북
|
||||||
|
// 각도 -135: 북동, 남동, 남서, 북서
|
||||||
|
|
||||||
if (moduleCompass === 0 || (moduleCompass < 0 && moduleCompass >= -6)) {
|
let mapping
|
||||||
compassType = 1
|
// 정확한 각도 먼저 체크
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -21) {
|
if (normalizedAngle === 0) {
|
||||||
compassType = 2
|
mapping = { south: '南', west: '西', north: '北', east: '東' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -36) {
|
} else if (normalizedAngle === 45) {
|
||||||
compassType = 3
|
mapping = { south: '南西', west: '北西', north: '北東', east: '南東' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -51) {
|
} else if (normalizedAngle === 90) {
|
||||||
compassType = 4
|
mapping = { south: '西', west: '北', north: '東', east: '南' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -66) {
|
} else if (normalizedAngle === 135) {
|
||||||
compassType = 5
|
mapping = { south: '北西', west: '北東', north: '南東', east: '南西' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -81) {
|
} else if (normalizedAngle === 180 || normalizedAngle === -180) {
|
||||||
compassType = 6
|
mapping = { south: '北', west: '東', north: '南', east: '西' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -96) {
|
} else if (normalizedAngle === -45) {
|
||||||
compassType = 7
|
mapping = { south: '南東', west: '南西', north: '北西', east: '北東' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -111) {
|
} else if (normalizedAngle === -90) {
|
||||||
compassType = 8
|
mapping = { south: '東', west: '南', north: '西', east: '北' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -126) {
|
} else if (normalizedAngle === -135) {
|
||||||
compassType = 9
|
mapping = { south: '北東', west: '南東', north: '南西', east: '北西' }
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -141) {
|
}
|
||||||
compassType = 10
|
// 범위 각도 체크
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -156) {
|
else if (normalizedAngle >= 1 && normalizedAngle <= 44) {
|
||||||
compassType = 11
|
// 1~44: 남남서, 서북서, 북북동, 동남동
|
||||||
} else if (moduleCompass < 0 && moduleCompass >= -171) {
|
mapping = { south: '南南西', west: '西北西', north: '北北東', east: '東南東' }
|
||||||
compassType = 12
|
} else if (normalizedAngle >= 46 && normalizedAngle <= 89) {
|
||||||
} else if (Math.abs(moduleCompass) === 180) {
|
// 46~89: 서남서, 북북서, 동북동, 남남동
|
||||||
compassType = 13
|
mapping = { south: '西南西', west: '北北西', north: '東北東', east: '南南東' }
|
||||||
|
} else if (normalizedAngle >= 91 && normalizedAngle <= 134) {
|
||||||
|
// 91~134: 서북서, 북북동, 동남동, 남남서
|
||||||
|
mapping = { south: '西北西', west: '北北東', north: '東南東', east: '南南西' }
|
||||||
|
} else if (normalizedAngle >= 136 && normalizedAngle <= 179) {
|
||||||
|
// 136~179: 북북서, 동북동, 남남동, 서남서
|
||||||
|
mapping = { south: '北北西', west: '東北東', north: '南南東', east: '西南西' }
|
||||||
|
} else if (normalizedAngle >= -44 && normalizedAngle <= -1) {
|
||||||
|
// -1~-44: 남남동, 서남서, 북북서, 동북동
|
||||||
|
mapping = { south: '南南東', west: '西南西', north: '北北西', east: '東北東' }
|
||||||
|
} else if (normalizedAngle >= -89 && normalizedAngle <= -46) {
|
||||||
|
// -46~-89: 동남동, 남남서, 서북서, 북북동
|
||||||
|
mapping = { south: '東南東', west: '南南西', north: '西北西', east: '北北東' }
|
||||||
|
} else if (normalizedAngle >= -134 && normalizedAngle <= -91) {
|
||||||
|
// -91~-134: 동북동, 남남동, 서남서, 북북서
|
||||||
|
mapping = { south: '東北東', west: '南南東', north: '西南西', east: '北北西' }
|
||||||
|
} else if (normalizedAngle >= -179 && normalizedAngle <= -136) {
|
||||||
|
// -136~-179: 북북동, 동남동, 남남서, 서북서
|
||||||
|
mapping = { south: '北北東', west: '東南東', north: '南南西', east: '西北西' }
|
||||||
|
} else {
|
||||||
|
// 기본값: 0도
|
||||||
|
mapping = { south: '南', west: '西', north: '北', east: '東' }
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapping[dir] || '南'
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([1, 25].includes(compassType)) {
|
text = getDirectionText(moduleCompass, direction)
|
||||||
direction === 'north' ? (text = '北') : direction === 'south' ? (text = '南') : direction === 'west' ? (text = '西') : (text = '東')
|
|
||||||
} else if ([2, 3].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '北北東')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '南南西')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '西北西')
|
|
||||||
: (text = '東南東')
|
|
||||||
} else if ([4].includes(compassType)) {
|
|
||||||
direction === 'north' ? (text = '北東') : direction === 'south' ? (text = '南西') : direction === 'west' ? (text = '北西') : (text = '南東')
|
|
||||||
} else if ([5, 6].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '東北東')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '西南西')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '北北西')
|
|
||||||
: (text = '南南東')
|
|
||||||
} else if ([7].includes(compassType)) {
|
|
||||||
direction === 'north' ? (text = '東') : direction === 'south' ? (text = '西') : direction === 'west' ? (text = '北') : (text = '南')
|
|
||||||
} else if ([8, 9].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '東南東')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '西北西')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '北北東')
|
|
||||||
: (text = '南南西')
|
|
||||||
} else if ([10].includes(compassType)) {
|
|
||||||
direction === 'north' ? (text = '南東') : direction === 'south' ? (text = '北西') : direction === 'west' ? (text = '北東') : (text = '南西')
|
|
||||||
} else if ([11, 12].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '南南東')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '北北西')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '東北東')
|
|
||||||
: (text = '西南西')
|
|
||||||
} else if ([13].includes(compassType)) {
|
|
||||||
direction === 'north' ? (text = '南') : direction === 'south' ? (text = '北') : direction === 'west' ? (text = '東') : (text = '西')
|
|
||||||
} else if ([14, 15].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '南南西')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '北北東')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '東南東')
|
|
||||||
: (text = '西北西')
|
|
||||||
} else if ([16].includes(compassType)) {
|
|
||||||
direction === 'north' ? (text = '南西') : direction === 'south' ? (text = '北東') : direction === 'west' ? (text = '南東') : (text = '北西')
|
|
||||||
} else if ([17, 18].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '西南西')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '東北東')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '南南東')
|
|
||||||
: (text = '北北西')
|
|
||||||
} else if ([19].includes(compassType)) {
|
|
||||||
direction === 'north' ? (text = '西') : direction === 'south' ? (text = '東') : direction === 'west' ? (text = '南') : (text = '北')
|
|
||||||
} else if ([20, 21].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '西北西')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '東南東')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '南南西')
|
|
||||||
: (text = '北北東')
|
|
||||||
} else if ([22].includes(compassType)) {
|
|
||||||
direction === 'north' ? (text = '北西') : direction === 'south' ? (text = '南東') : direction === 'west' ? (text = '南西') : (text = '北東')
|
|
||||||
} else if ([23, 24].includes(compassType)) {
|
|
||||||
direction === 'north'
|
|
||||||
? (text = '北北西')
|
|
||||||
: direction === 'south'
|
|
||||||
? (text = '南南東')
|
|
||||||
: direction === 'west'
|
|
||||||
? (text = '西南西')
|
|
||||||
: (text = '東北東')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 東,西,南,北
|
// surfaceCompass가 있으면 text를 덮어쓰기 (기존 로직 유지)
|
||||||
if ([0].includes(surfaceCompass)) {
|
if (surfaceCompass !== null && surfaceCompass !== undefined) {
|
||||||
text = '南'
|
if ([0].includes(surfaceCompass)) {
|
||||||
} else if ([15, 30].includes(surfaceCompass)) {
|
text = '南'
|
||||||
text = '南南東'
|
} else if ([15, 30].includes(surfaceCompass)) {
|
||||||
} else if ([45].includes(surfaceCompass)) {
|
text = '南南東'
|
||||||
text = '南東'
|
} else if ([45].includes(surfaceCompass)) {
|
||||||
} else if ([60, 75].includes(surfaceCompass)) {
|
text = '南東'
|
||||||
text = '東南東'
|
} else if ([60, 75].includes(surfaceCompass)) {
|
||||||
} else if ([90].includes(surfaceCompass)) {
|
text = '東南東'
|
||||||
text = '東'
|
} else if ([90].includes(surfaceCompass)) {
|
||||||
} else if ([105, 120].includes(surfaceCompass)) {
|
text = '東'
|
||||||
text = '東北東'
|
} else if ([105, 120].includes(surfaceCompass)) {
|
||||||
} else if ([135].includes(surfaceCompass)) {
|
text = '東北東'
|
||||||
text = '北東'
|
} else if ([135].includes(surfaceCompass)) {
|
||||||
} else if ([150, 165].includes(surfaceCompass)) {
|
text = '北東'
|
||||||
text = '北北東'
|
} else if ([150, 165].includes(surfaceCompass)) {
|
||||||
} else if ([180].includes(surfaceCompass)) {
|
text = '北北東'
|
||||||
text = '北'
|
} else if ([180].includes(surfaceCompass)) {
|
||||||
} else if ([-165, -150].includes(surfaceCompass)) {
|
text = '北'
|
||||||
text = '北北西'
|
} else if ([-165, -150].includes(surfaceCompass)) {
|
||||||
} else if ([-135].includes(surfaceCompass)) {
|
text = '北北西'
|
||||||
text = '北西'
|
} else if ([-135].includes(surfaceCompass)) {
|
||||||
} else if ([-120, -105].includes(surfaceCompass)) {
|
text = '北西'
|
||||||
text = '西北西'
|
} else if ([-120, -105].includes(surfaceCompass)) {
|
||||||
} else if ([-90].includes(surfaceCompass)) {
|
text = '西北西'
|
||||||
text = '西'
|
} else if ([-90].includes(surfaceCompass)) {
|
||||||
} else if ([-75, -60].includes(surfaceCompass)) {
|
text = '西'
|
||||||
text = '西南西'
|
} else if ([-75, -60].includes(surfaceCompass)) {
|
||||||
} else if ([-45].includes(surfaceCompass)) {
|
text = '西南西'
|
||||||
text = '西南'
|
} else if ([-45].includes(surfaceCompass)) {
|
||||||
} else if ([-30, -15].includes(surfaceCompass)) {
|
text = '南西'
|
||||||
text = '西西南'
|
} else if ([-30, -15].includes(surfaceCompass)) {
|
||||||
|
text = '南南西'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sameDirectionCnt = canvas.getObjects().filter((obj) => {
|
const sameDirectionCnt = canvas.getObjects().filter((obj) => {
|
||||||
@ -1380,6 +1342,8 @@ export const usePolygon = () => {
|
|||||||
// 나눠서 중복 제거된 roof return
|
// 나눠서 중복 제거된 roof return
|
||||||
let newRoofs = getSplitRoofsPoints(allLines)
|
let newRoofs = getSplitRoofsPoints(allLines)
|
||||||
|
|
||||||
|
const createdRoofs = []
|
||||||
|
|
||||||
newRoofs = newRoofs.filter((roof) => roof.length !== 0)
|
newRoofs = newRoofs.filter((roof) => roof.length !== 0)
|
||||||
newRoofs.forEach((roofPoint, index) => {
|
newRoofs.forEach((roofPoint, index) => {
|
||||||
let defense, pitch
|
let defense, pitch
|
||||||
@ -1623,8 +1587,8 @@ export const usePolygon = () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
canvas.add(roof)
|
// canvas.add(roof)
|
||||||
addLengthText(roof)
|
createdRoofs.push(roof)
|
||||||
canvas.remove(polygon)
|
canvas.remove(polygon)
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
})
|
})
|
||||||
@ -1634,6 +1598,11 @@ export const usePolygon = () => {
|
|||||||
auxiliaryLines.forEach((line) => {
|
auxiliaryLines.forEach((line) => {
|
||||||
canvas.remove(line)
|
canvas.remove(line)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
createdRoofs.forEach((roof) => {
|
||||||
|
canvas.add(roof)
|
||||||
|
})
|
||||||
|
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
canvas.discardActiveObject()
|
canvas.discardActiveObject()
|
||||||
}
|
}
|
||||||
@ -1968,6 +1937,22 @@ export const usePolygon = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createdRoofs들의 모든 lines를 확인해서 length값이 1이하인 차이가 있으면 통일 시킨다.
|
||||||
|
const allRoofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
|
const allRoofLines = allRoofs.flatMap((roof) => roof.lines)
|
||||||
|
for (let i = 0; i < allRoofLines.length; i++) {
|
||||||
|
for (let j = i + 1; j < allRoofLines.length; j++) {
|
||||||
|
const line1 = allRoofLines[i]
|
||||||
|
const line2 = allRoofLines[j]
|
||||||
|
const diff = Math.abs(line1.length - line2.length)
|
||||||
|
if (diff > 0 && diff <= 2) {
|
||||||
|
const minLength = Math.min(line1.length, line2.length)
|
||||||
|
line1.setLengthByValue(minLength * 10)
|
||||||
|
line2.setLengthByValue(minLength * 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
polygon.lines.forEach((line) => {
|
polygon.lines.forEach((line) => {
|
||||||
setActualSize(line, polygon.direction, +polygon.roofMaterial?.pitch)
|
setActualSize(line, polygon.direction, +polygon.roofMaterial?.pitch)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -656,7 +656,7 @@
|
|||||||
"myinfo.message.password.error": "パスワードが間違っています。",
|
"myinfo.message.password.error": "パスワードが間違っています。",
|
||||||
"login": "ログイン",
|
"login": "ログイン",
|
||||||
"login.auto.page.text": "自動ログイン中です。",
|
"login.auto.page.text": "自動ログイン中です。",
|
||||||
"login.fail": "계정이 없거나 비밀번호가 잘못되었습니다.",
|
"login.fail": "アカウント未登録か、パスワードが正しくありません。",
|
||||||
"login.id.save": "ID保存",
|
"login.id.save": "ID保存",
|
||||||
"login.id.placeholder": "IDを入力してください。",
|
"login.id.placeholder": "IDを入力してください。",
|
||||||
"login.password.placeholder": "パスワードを入力してください。",
|
"login.password.placeholder": "パスワードを入力してください。",
|
||||||
@ -683,9 +683,9 @@
|
|||||||
"join.sub1.addr": "住所",
|
"join.sub1.addr": "住所",
|
||||||
"join.sub1.addr_placeholder": "全角50文字以内",
|
"join.sub1.addr_placeholder": "全角50文字以内",
|
||||||
"join.sub1.telNo": "電話番号",
|
"join.sub1.telNo": "電話番号",
|
||||||
"join.sub1.telNo_placeholder": "00 0000 0000",
|
"join.sub1.telNo_placeholder": "00-0000-0000",
|
||||||
"join.sub1.fax": "FAX番号",
|
"join.sub1.fax": "FAX番号",
|
||||||
"join.sub1.fax_placeholder": "00 0000 0000",
|
"join.sub1.fax_placeholder": "00-0000-0000",
|
||||||
"join.sub1.bizNo": "法人番号",
|
"join.sub1.bizNo": "法人番号",
|
||||||
"join.sub2.title": "担当者情報",
|
"join.sub2.title": "担当者情報",
|
||||||
"join.sub2.userNm": "担当者名",
|
"join.sub2.userNm": "担当者名",
|
||||||
|
|||||||
@ -683,7 +683,7 @@
|
|||||||
"join.sub1.addr": "주소",
|
"join.sub1.addr": "주소",
|
||||||
"join.sub1.addr_placeholder": "전각50자이내",
|
"join.sub1.addr_placeholder": "전각50자이내",
|
||||||
"join.sub1.telNo": "전화번호",
|
"join.sub1.telNo": "전화번호",
|
||||||
"join.sub1.telNo_placeholder": "00 0000 0000",
|
"join.sub1.telNo_placeholder": "000-0000-0000",
|
||||||
"join.sub1.fax": "FAX 번호",
|
"join.sub1.fax": "FAX 번호",
|
||||||
"join.sub1.fax_placeholder": "00 0000 0000",
|
"join.sub1.fax_placeholder": "00 0000 0000",
|
||||||
"join.sub1.bizNo": "법인번호",
|
"join.sub1.bizNo": "법인번호",
|
||||||
|
|||||||
@ -80,7 +80,7 @@ export const getCenterPoint = (point1, point2) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getDistance = (x1, y1, x2, y2) => {
|
export const getDistance = (x1, y1, x2, y2) => {
|
||||||
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)).toFixed(0)
|
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)).toFixed(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수
|
// polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -802,6 +802,10 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
const getAddLine = (p1, p2, stroke = '') => {
|
const getAddLine = (p1, p2, stroke = '') => {
|
||||||
movedLines.push({ index, p1, p2 })
|
movedLines.push({ index, p1, p2 })
|
||||||
|
|
||||||
|
const dx = Math.abs(p2.x - p1.x);
|
||||||
|
const dy = Math.abs(p2.y - p1.y);
|
||||||
|
const isDiagonal = dx > 0.5 && dy > 0.5; // x, y 변화가 모두 있으면 대각선
|
||||||
|
|
||||||
//console.log("mergeLines:::::::", mergeLines);
|
//console.log("mergeLines:::::::", mergeLines);
|
||||||
const line = new QLine([p1.x, p1.y, p2.x, p2.y], {
|
const line = new QLine([p1.x, p1.y, p2.x, p2.y], {
|
||||||
parentId: roof.id,
|
parentId: roof.id,
|
||||||
@ -818,6 +822,15 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
type: 'eaveHelpLine',
|
type: 'eaveHelpLine',
|
||||||
isStart: true,
|
isStart: true,
|
||||||
pitch: wallLine.attributes.pitch,
|
pitch: wallLine.attributes.pitch,
|
||||||
|
actualSize: (isDiagonal) ? calcLineActualSize(
|
||||||
|
{
|
||||||
|
x1: p1.x,
|
||||||
|
y1: p1.y,
|
||||||
|
x2: p2.x,
|
||||||
|
y2: p2.y
|
||||||
|
},
|
||||||
|
getDegreeByChon(wallLine.attributes.pitch)
|
||||||
|
) : calcLinePlaneSize({ x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y }),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user