Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
50d92065c0
@ -2,8 +2,6 @@
|
||||
|
||||
import { correntObjectNoState } from '@/store/settingAtom'
|
||||
import { notFound, usePathname, useSearchParams } from 'next/navigation'
|
||||
// import { ErrorBoundary } from 'next/dist/client/components/error-boundary'
|
||||
// import ServerError from '../error'
|
||||
import { createContext, useReducer, useState } from 'react'
|
||||
import { useSetRecoilState } from 'recoil'
|
||||
|
||||
|
||||
@ -3,15 +3,23 @@
|
||||
import FloorPlanProvider from './FloorPlanProvider'
|
||||
import FloorPlan from '@/components/floor-plan/FloorPlan'
|
||||
import CanvasLayout from '@/components/floor-plan/CanvasLayout'
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
export default function FloorPlanLayout({ children }) {
|
||||
console.log('🚀 ~ FloorPlanLayout ~ FloorPlanLayout:')
|
||||
const pathname = usePathname()
|
||||
console.log('🚀 ~ FloorPlanLayout ~ pathname:', pathname)
|
||||
|
||||
return (
|
||||
<>
|
||||
<FloorPlanProvider>
|
||||
<FloorPlan>
|
||||
<CanvasLayout>{children}</CanvasLayout>
|
||||
{pathname.includes('estimate') || pathname.includes('simulator') ? (
|
||||
<div className="canvas-layout">{children}</div>
|
||||
) : (
|
||||
<CanvasLayout>{children}</CanvasLayout>
|
||||
)}
|
||||
{/* <CanvasLayout>{children}</CanvasLayout> */}
|
||||
</FloorPlan>
|
||||
</FloorPlanProvider>
|
||||
</>
|
||||
|
||||
18
src/app/management/stuff/tempReg/page.jsx
Normal file
18
src/app/management/stuff/tempReg/page.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import StuffSubHeader from '@/components/management/StuffSubHeader'
|
||||
import '@/styles/contents.scss'
|
||||
import StuffDetail from '@/components/management/StuffDetail'
|
||||
export default function ManagementStuffRegPage() {
|
||||
return (
|
||||
<>
|
||||
<StuffSubHeader type={'temp'} />
|
||||
<div className="sub-content">
|
||||
<div className="sub-content-inner">
|
||||
<div className="sub-content-box">
|
||||
<StuffDetail />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState, useContext } from 'react'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil'
|
||||
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||
@ -9,7 +9,7 @@ import SingleDatePicker from '../common/datepicker/SingleDatePicker'
|
||||
import EstimateFileUploader from './EstimateFileUploader'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { useCommonCode } from '@/hooks/common/useCommonCode'
|
||||
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
|
||||
@ -18,6 +18,8 @@ import Select, { components } from 'react-select'
|
||||
import { convertNumberToPriceDecimal, convertNumberToPriceDecimalToFixed } from '@/util/common-utils'
|
||||
import ProductFeaturesPop from './popup/ProductFeaturesPop'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { correntObjectNoState } from '@/store/settingAtom'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Estimate({ params }) {
|
||||
const [uniqueData, setUniqueData] = useState([])
|
||||
@ -74,6 +76,15 @@ export default function Estimate({ params }) {
|
||||
|
||||
const { setMenuNumber } = useCanvasMenu()
|
||||
|
||||
/**
|
||||
* objectNo 셋팅
|
||||
* url로 넘어온 objectNo을 리코일에 세팅
|
||||
*/
|
||||
const setCurrentObjectNo = useSetRecoilState(correntObjectNoState)
|
||||
const searchParams = useSearchParams()
|
||||
const currentObjectNo = searchParams.get('objectNo')
|
||||
setCurrentObjectNo(currentObjectNo)
|
||||
|
||||
//새로 추가한 첨부파일 props
|
||||
const fileUploadProps = {
|
||||
uploadFiles: files,
|
||||
@ -120,7 +131,6 @@ export default function Estimate({ params }) {
|
||||
let url = `/api/estimate/special-note-title-list`
|
||||
get({ url: url }).then((res) => {
|
||||
if (isNotEmptyArray(res)) {
|
||||
//디테일 ATTR001、ATTR002、ATTR003、ATTR007、ATTR009、ATTR010、ATTR015、ATTR019
|
||||
if (estimateContextState?.estimateOption) {
|
||||
res.map((row) => {
|
||||
let estimateOption = estimateContextState?.estimateOption?.split('、')
|
||||
@ -140,10 +150,10 @@ export default function Estimate({ params }) {
|
||||
//detail과 상관없이 디폴트 체크목록
|
||||
//ATTR003,ATTR007
|
||||
if (row.code === 'ATTR003') {
|
||||
row.check = true
|
||||
//row.check = true
|
||||
}
|
||||
if (row.code === 'ATTR007') {
|
||||
row.check = true
|
||||
//row.check = true
|
||||
}
|
||||
})
|
||||
|
||||
@ -191,9 +201,8 @@ export default function Estimate({ params }) {
|
||||
}, [specialNoteList])
|
||||
|
||||
// 견적특이사항 remark 보여주기
|
||||
const settingShowContent = (code, event) => {
|
||||
const settingShowContent = (code) => {
|
||||
setShowContentCode(code)
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
// 추가한 첨부파일 estimateContextState에 넣기
|
||||
@ -203,49 +212,62 @@ export default function Estimate({ params }) {
|
||||
files.map((row) => {
|
||||
fileList.push(row.data)
|
||||
setEstimateContextState({ fileList: row.data, newFileList: fileList })
|
||||
// setEstimateContextState({ fileList: row.data })
|
||||
})
|
||||
} else {
|
||||
setEstimateContextState({ fileList: [] })
|
||||
setEstimateContextState({ fileList: [], newFileList: [] })
|
||||
}
|
||||
}, [files])
|
||||
|
||||
useEffect(() => {
|
||||
if (originFiles.length > 0) {
|
||||
setEstimateContextState({
|
||||
originFiles: originFiles,
|
||||
})
|
||||
}
|
||||
}, [originFiles])
|
||||
|
||||
//상세에서 내려온 첨부파일 set 만들기
|
||||
useEffect(() => {
|
||||
if (isNotEmptyArray(estimateContextState.fileList)) {
|
||||
//드래그영역 비워주기
|
||||
setFiles([])
|
||||
setOriginFiles(estimateContextState.fileList)
|
||||
} else {
|
||||
if (originFiles.length > 0) {
|
||||
if (isEmptyArray(files)) {
|
||||
let file
|
||||
file = originFiles.filter((item) => item.delFlg === '0')
|
||||
setEstimateContextState({
|
||||
originFiles: file,
|
||||
})
|
||||
setOriginFiles(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [estimateContextState?.fileList])
|
||||
|
||||
// 삭제누른 첨부파일 복원
|
||||
const returnOriginFile = (no) => {
|
||||
originFiles.map((file) => {
|
||||
if (file.no === no) {
|
||||
file.delFlg = '0'
|
||||
}
|
||||
})
|
||||
setOriginFiles((prev) => {
|
||||
return [...prev]
|
||||
})
|
||||
setEstimateContextState({
|
||||
originFiles: originFiles,
|
||||
})
|
||||
}
|
||||
// 기존첨부파일 삭제 (플래그값 추가?) 저장할때 플래그값에 따라 진짜 삭제
|
||||
const deleteOriginFile = async (objectNo, no) => {
|
||||
const delParams = {
|
||||
userId: session.userId,
|
||||
objectNo: objectNo,
|
||||
no: no,
|
||||
}
|
||||
alert(getMessage('estimate.detail.alert.delFile'))
|
||||
// await promisePost({ url: 'api/file/fileDelete', data: delParams }).then((res) => {
|
||||
// if (res.status === 204) {
|
||||
// setOriginFiles(originFiles.filter((file) => file.objectNo === objectNo && file.no !== no))
|
||||
// setEstimateContextState({
|
||||
// fileList: originFiles.filter((file) => file.objectNo === objectNo && file.no !== no),
|
||||
// originFiles: originFiles.filter((file) => file.objectNo === objectNo && file.no !== no),
|
||||
// newFileList: originFiles.filter((file) => file.objectNo === objectNo && file.no !== no),
|
||||
// })
|
||||
const deleteOriginFile = (no) => {
|
||||
originFiles.map((file) => {
|
||||
if (file.no === no) {
|
||||
file.delFlg = '1'
|
||||
}
|
||||
})
|
||||
|
||||
// alert(getMessage('plan.message.delete'))
|
||||
// }
|
||||
// })
|
||||
setOriginFiles((prev) => {
|
||||
return [...prev]
|
||||
})
|
||||
setEstimateContextState({
|
||||
originFiles: originFiles,
|
||||
})
|
||||
alert(getMessage('estimate.detail.alert.delFile'))
|
||||
}
|
||||
|
||||
//가격표시 option 목록 최초세팅 && 주문분류 변경시
|
||||
@ -408,24 +430,26 @@ export default function Estimate({ params }) {
|
||||
if (isNotEmptyArray(data.data2)) {
|
||||
estimateContextState.itemList.map((item) => {
|
||||
let checkYn = false
|
||||
data.data2.map((item2) => {
|
||||
if (item2) {
|
||||
if (item2.itemId === item.itemId) {
|
||||
for (let i = 0; i < data.data2.length; i++) {
|
||||
if (data.data2[i]) {
|
||||
if (data.data2[i].itemId === item.itemId) {
|
||||
updateList.push({
|
||||
...item,
|
||||
openFlg: item2.unitPrice === '0.0' ? '1' : '0',
|
||||
salePrice: item2.unitPrice === null ? '0' : item2.unitPrice,
|
||||
saleTotPrice: (item.amount * item2.unitPrice).toString(),
|
||||
openFlg: data.data2[i].unitPrice === '0.0' ? '1' : '0',
|
||||
salePrice: data.data2[i].unitPrice === null ? '0' : data.data2[i].unitPrice,
|
||||
saleTotPrice: (item.amount * data.data2[i].unitPrice).toString(),
|
||||
})
|
||||
checkYn = true
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!checkYn) {
|
||||
updateList.push({ ...item, salePrice: '0', saleTotPrice: '0' })
|
||||
}
|
||||
})
|
||||
|
||||
setEstimateContextState({
|
||||
priceCd: showPriceCd,
|
||||
itemList: updateList,
|
||||
@ -472,7 +496,7 @@ export default function Estimate({ params }) {
|
||||
//주택PKG input 변경
|
||||
const onChangePkgAsp = (value) => {
|
||||
if (estimateContextState.estimateType === 'YJSS') {
|
||||
let pkgAsp = Number(value.replace(/[^0-9]/g, '').replaceAll(',', ''))
|
||||
let pkgAsp = Number(value.replace(/[^-\.0-9]/g, '').replaceAll(',', ''))
|
||||
if (isNaN(pkgAsp)) {
|
||||
pkgAsp = 0
|
||||
} else {
|
||||
@ -485,7 +509,7 @@ export default function Estimate({ params }) {
|
||||
|
||||
setEstimateContextState({
|
||||
pkgAsp: pkgAsp,
|
||||
pkgTotPrice: pkgTotPrice.toFixed(3),
|
||||
pkgTotPrice: pkgTotPrice.toFixed(2),
|
||||
})
|
||||
//아이템들 중 조건에 맞는애들 뽑아서 상단 공급가액 부가세 총액 수정
|
||||
setItemChangeYn(true)
|
||||
@ -496,6 +520,7 @@ export default function Estimate({ params }) {
|
||||
const onChangeAmount = (value, dispOrder, index) => {
|
||||
//itemChangeFlg = 1, partAdd = 0 셋팅
|
||||
let amount = Number(value.replace(/[^0-9]/g, '').replaceAll(',', ''))
|
||||
|
||||
if (isNaN(amount)) {
|
||||
amount = '0'
|
||||
} else {
|
||||
@ -584,14 +609,12 @@ export default function Estimate({ params }) {
|
||||
updates.pkgMaterialFlg = res.pkgMaterialFlg
|
||||
updates.pnowW = res.pnowW
|
||||
updates.salePrice = res.salePrice
|
||||
// updates.salePrice = ''
|
||||
updates.specification = res.specification
|
||||
updates.unit = res.unit
|
||||
updates.specialNoteCd = res.spnAttrCds
|
||||
updates.itemGroup = res.itemGroup
|
||||
updates.delFlg = '0' // 삭제플래그 0
|
||||
updates.saleTotPrice = (res.salePrice * estimateContextState.itemList[index].amount).toString()
|
||||
// updates.saleTotPrice = ''
|
||||
updates.amount = ''
|
||||
updates.openFlg = res.openFlg
|
||||
|
||||
@ -622,7 +645,6 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
}
|
||||
} else if (item.paDispOrder === dispOrder) {
|
||||
//봄제품을 바꿨을떄
|
||||
return { ...item, delFlg: '1' }
|
||||
} else {
|
||||
return item
|
||||
@ -639,12 +661,14 @@ export default function Estimate({ params }) {
|
||||
bomItem.salePrice = '0'
|
||||
bomItem.saleTotPrice = '0'
|
||||
bomItem.unitPrice = '0'
|
||||
bomItem.showSalePrice = '0'
|
||||
} else {
|
||||
bomItem.dispOrder = (index + 1 + Number(dispOrder)).toString()
|
||||
bomItem.paDispOrder = dispOrder
|
||||
bomItem.salePrice = '0'
|
||||
bomItem.saleTotPrice = '0'
|
||||
bomItem.unitPrice = '0'
|
||||
bomItem.showSalePrice = '0'
|
||||
}
|
||||
|
||||
bomItem.delFlg = '0'
|
||||
@ -653,6 +677,7 @@ export default function Estimate({ params }) {
|
||||
bomItem.addFlg = true //봄 추가시도 addFlg
|
||||
})
|
||||
|
||||
updateList = updateList.filter((item) => item.delFlg === '0')
|
||||
setEstimateContextState({
|
||||
itemList: [...updateList, ...bomList],
|
||||
})
|
||||
@ -729,15 +754,24 @@ export default function Estimate({ params }) {
|
||||
delete item.showSaleTotPrice
|
||||
if (item.delFlg === '0') {
|
||||
let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
|
||||
let price = Number(item.saleTotPrice?.replaceAll(',', '')) || 0
|
||||
let price
|
||||
if (amount === 0) {
|
||||
price = 0
|
||||
} else {
|
||||
price = Number(item.saleTotPrice?.replaceAll(',', '')) || 0
|
||||
}
|
||||
|
||||
if (item.moduleFlg === '1') {
|
||||
const volKw = (item.pnowW * amount) / 1000
|
||||
totals.totVolKw += volKw
|
||||
}
|
||||
totals.totAmount += amount
|
||||
totals.supplyPrice += price
|
||||
totals.totAmount += amount
|
||||
|
||||
if (item.paDispOrder) {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
if (item.openFlg === '1') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
@ -755,12 +789,16 @@ export default function Estimate({ params }) {
|
||||
itemList.forEach((item) => {
|
||||
if (item.delFlg === '0') {
|
||||
let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
|
||||
let salePrice = Number(item.salePrice?.replaceAll(',', '')) || 0
|
||||
|
||||
let salePrice
|
||||
if (item.moduleFlg === '1') {
|
||||
const volKw = (item.pnowW * amount) / 1000
|
||||
totals.totVolKw += volKw
|
||||
}
|
||||
if (amount === 0) {
|
||||
salePrice = 0
|
||||
} else {
|
||||
salePrice = Number(item.salePrice?.replaceAll(',', '')) || 0
|
||||
}
|
||||
|
||||
totals.totAmount += amount
|
||||
if (item.pkgMaterialFlg === '1') {
|
||||
@ -773,6 +811,14 @@ export default function Estimate({ params }) {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
} else {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
|
||||
if (item.openFlg === '1') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -782,25 +828,24 @@ export default function Estimate({ params }) {
|
||||
totals.vatPrice = totals.supplyPrice * 0.1
|
||||
totals.totPrice = totals.supplyPrice + totals.vatPrice
|
||||
}
|
||||
|
||||
if (estimateContextState.estimateType === 'YJOD') {
|
||||
calculateYJODTotals(estimateContextState.itemList)
|
||||
setEstimateContextState({
|
||||
totAmount: totals.totAmount,
|
||||
totVolKw: totals.totVolKw.toFixed(3),
|
||||
supplyPrice: totals.supplyPrice.toFixed(3),
|
||||
vatPrice: totals.vatPrice.toFixed(3),
|
||||
totPrice: totals.totPrice.toFixed(3),
|
||||
totVolKw: totals.totVolKw.toFixed(2),
|
||||
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
})
|
||||
} else if (estimateContextState.estimateType === 'YJSS') {
|
||||
calculateYJSSTotals(estimateContextState.itemList)
|
||||
setEstimateContextState({
|
||||
pkgTotPrice: totals.pkgTotPrice,
|
||||
totAmount: totals.totAmount,
|
||||
totVolKw: totals.totVolKw.toFixed(3),
|
||||
supplyPrice: totals.supplyPrice.toFixed(3),
|
||||
vatPrice: totals.vatPrice.toFixed(3),
|
||||
totPrice: totals.totPrice.toFixed(3),
|
||||
totVolKw: totals.totVolKw.toFixed(2),
|
||||
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
})
|
||||
}
|
||||
|
||||
@ -1014,16 +1059,14 @@ export default function Estimate({ params }) {
|
||||
let constructSpecificationMulti = estimateContextState?.constructSpecificationMulti?.split('、')
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`form-flex-wrap ${style}`} key={fixedKey}>
|
||||
<div className="input-wrap mr5" style={{ width: '610px' }} key={`roof${index}`}>
|
||||
<input type="text" className="input-light" value={roofList} readOnly />
|
||||
</div>
|
||||
<div className="input-wrap" style={{ width: '200px' }}>
|
||||
<input type="text" className="input-light" value={constructSpecificationMulti[index]} readOnly />
|
||||
</div>
|
||||
<div className={`form-flex-wrap ${style}`} key={`roof_${row}`}>
|
||||
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
||||
<input type="text" className="input-light" value={roofList} readOnly />
|
||||
</div>
|
||||
</>
|
||||
<div className="input-wrap" style={{ width: '200px' }}>
|
||||
<input type="text" className="input-light" value={constructSpecificationMulti[index]} readOnly />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</td>
|
||||
@ -1110,18 +1153,38 @@ export default function Estimate({ params }) {
|
||||
<ul className="file-list">
|
||||
{originFiles.map((originFile) => {
|
||||
return (
|
||||
<li className="file-item" key={uuidv4()}>
|
||||
<span onClick={() => handleEstimateFileDownload(originFile)}>
|
||||
{originFile.faileName}
|
||||
<button
|
||||
type="button"
|
||||
className="delete"
|
||||
onClick={(e) => {
|
||||
deleteOriginFile(originFile.objectNo, originFile.no)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
></button>
|
||||
</span>
|
||||
<li className="file-item" key={originFile.no}>
|
||||
{/* <li className="file-item" key={uuidv4()}> */}
|
||||
<div className="file-item-wrap">
|
||||
<span
|
||||
style={{ display: originFile.delFlg === '0' ? '' : 'none' }}
|
||||
onClick={() => handleEstimateFileDownload(originFile)}
|
||||
>
|
||||
{originFile.faileName}
|
||||
<button
|
||||
type="button"
|
||||
className="delete"
|
||||
onClick={(e) => {
|
||||
deleteOriginFile(originFile.no)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
></button>
|
||||
</span>
|
||||
<div className="return-wrap" style={{ display: originFile.delFlg !== '0' ? '' : 'none' }}>
|
||||
<span className="return">{originFile.faileName}</span>
|
||||
<button
|
||||
type="button"
|
||||
className="return-btn"
|
||||
onClick={(e) => {
|
||||
returnOriginFile(originFile.no)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<i className="return-ico"></i>
|
||||
{getMessage('estimate.detail.fileList2.btn.return')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
@ -1154,22 +1217,31 @@ export default function Estimate({ params }) {
|
||||
{specialNoteList.length > 0 &&
|
||||
specialNoteList.map((row) => {
|
||||
return (
|
||||
<div key={uuidv4()} className="special-note-check-item">
|
||||
<div className="d-check-box light">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={row.code}
|
||||
checked={!!row.check}
|
||||
disabled={row.code === 'ATTR001' ? true : false}
|
||||
onChange={(event) => {
|
||||
setSpecialNoteList((specialNote) =>
|
||||
specialNote.map((temp) => (temp.code === row.code ? { ...temp, check: !temp.check } : temp)),
|
||||
)
|
||||
|
||||
settingShowContent(row.code, event)
|
||||
// <div key={uuidv4()} className="special-note-check-item">
|
||||
<div key={row.code} className="special-note-check-item">
|
||||
<div className="special-note-check-box">
|
||||
<div className="d-check-box light">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={row.code}
|
||||
checked={!!row.check}
|
||||
disabled={row.code === 'ATTR001' || row.pkgYn === '1' ? true : false}
|
||||
onChange={() => {
|
||||
setSpecialNoteList((specialNote) =>
|
||||
specialNote.map((temp) => (temp.code === row.code ? { ...temp, check: !temp.check } : temp)),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={row.code}></label>
|
||||
</div>
|
||||
<span
|
||||
className="check-name"
|
||||
onClick={() => {
|
||||
settingShowContent(row.code)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={row.code}>{row.codeNm}</label>
|
||||
>
|
||||
{row.codeNm}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@ -1185,7 +1257,7 @@ export default function Estimate({ params }) {
|
||||
|
||||
if (isObjectNotEmpty(showcontent)) {
|
||||
return (
|
||||
<dl key={uuidv4()}>
|
||||
<dl key={row.code}>
|
||||
<dt>{showcontent.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: showcontent.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
@ -1200,12 +1272,23 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
})
|
||||
})
|
||||
return pushData.map((item) => (
|
||||
<dl key={uuidv4()}>
|
||||
<dt>{item.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
))
|
||||
//제품에 있는 특이사항만 보여주기 제품에 특이사항이 없으면 전부
|
||||
let filterData = pushData.filter((item) => uniqueData.includes(item.code))
|
||||
if (filterData.length > 0) {
|
||||
return filterData.map((item) => (
|
||||
<dl key={item.code}>
|
||||
<dt>{item.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
))
|
||||
} else {
|
||||
return pushData.map((item) => (
|
||||
<dl key={item.code}>
|
||||
<dt>{item.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
})}
|
||||
@ -1231,19 +1314,19 @@ export default function Estimate({ params }) {
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totVolKw')}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 3)}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}</div>
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.supplyPrice')}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimal(estimateContextState?.supplyPrice)}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.supplyPrice, 0)}</div>
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.vatPrice')}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimal(estimateContextState?.vatPrice)}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.vatPrice, 0)}</div>
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totPrice')}</div>
|
||||
<div className="estimate-name red">{convertNumberToPriceDecimal(estimateContextState?.totPrice)}</div>
|
||||
<div className="estimate-name red">{convertNumberToPriceDecimalToFixed(estimateContextState?.totPrice, 0)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1277,7 +1360,7 @@ export default function Estimate({ params }) {
|
||||
</div>
|
||||
</td>
|
||||
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgWeight')}</th>
|
||||
<td>{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 3)}</td>
|
||||
<td>{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}</td>
|
||||
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgPrice')}</th>
|
||||
<td>{convertNumberToPriceDecimal(estimateContextState?.pkgTotPrice)}</td>
|
||||
</tr>
|
||||
@ -1292,14 +1375,19 @@ export default function Estimate({ params }) {
|
||||
<div className="select-wrap">
|
||||
{session?.storeLvl === '1' ? (
|
||||
<select
|
||||
key={uuidv4()}
|
||||
// key={uuidv4()}
|
||||
className="select-light"
|
||||
onChange={(e) => {
|
||||
onChangeStorePriceList(e.target.value)
|
||||
}}
|
||||
value={showPriceCd}
|
||||
>
|
||||
{storePriceList.length > 0 && storePriceList.map((row) => <option value={row.priceCd}>{row.priceNm}</option>)}
|
||||
{storePriceList.length > 0 &&
|
||||
storePriceList.map((row) => (
|
||||
<option key={row.priceCd} value={row.priceCd}>
|
||||
{row.priceNm}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<select key={uuidv4()} className="select-light">
|
||||
@ -1409,7 +1497,7 @@ export default function Estimate({ params }) {
|
||||
<div className="form-flex-wrap">
|
||||
<div className="select-wrap mr5">
|
||||
<Select
|
||||
id="long-value-select1"
|
||||
name="long-value-select1"
|
||||
instanceId="long-value-select1"
|
||||
className="react-select-custom"
|
||||
classNamePrefix="custom"
|
||||
@ -1477,15 +1565,17 @@ export default function Estimate({ params }) {
|
||||
className="input-light al-r"
|
||||
value={convertNumberToPriceDecimal(item?.showSalePrice === '0' ? null : item?.salePrice?.replaceAll(',', ''))}
|
||||
disabled={
|
||||
estimateContextState?.estimateType === 'YJSS'
|
||||
? item?.paDispOrder
|
||||
? true
|
||||
: item.pkgMaterialFlg !== '1'
|
||||
: item.itemId === '' || !!item?.paDispOrder
|
||||
? true
|
||||
: item.openFlg === '1'
|
||||
item.openFlg === '1'
|
||||
? true
|
||||
: estimateContextState?.estimateType === 'YJSS'
|
||||
? item?.paDispOrder
|
||||
? true
|
||||
: false
|
||||
: item.pkgMaterialFlg !== '1'
|
||||
: item.itemId === '' || !!item?.paDispOrder
|
||||
? true
|
||||
: item.openFlg === '1'
|
||||
? true
|
||||
: false
|
||||
}
|
||||
onChange={(e) => {
|
||||
onChangeSalePrice(e.target.value, item.dispOrder, index)
|
||||
@ -1501,7 +1591,15 @@ export default function Estimate({ params }) {
|
||||
</div>
|
||||
</td>
|
||||
<td className="al-r">
|
||||
{convertNumberToPriceDecimal(item?.showSaleTotPrice === '0' ? null : item?.saleTotPrice?.replaceAll(',', ''))}
|
||||
{convertNumberToPriceDecimal(
|
||||
item?.showSaleTotPrice === '0'
|
||||
? null
|
||||
: item?.amount === ''
|
||||
? null
|
||||
: item?.saleTotPrice === '0'
|
||||
? null
|
||||
: item?.saleTotPrice?.replaceAll(',', ''),
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
|
||||
@ -40,9 +40,8 @@ export default function ProductFeaturesPop({ popShowSpecialNoteList, showProduct
|
||||
{showSpecialNoteList.length > 0 &&
|
||||
showSpecialNoteList.map((row) => {
|
||||
return (
|
||||
<dl>
|
||||
<dl key={row.code}>
|
||||
<dt>{row.codeNm}</dt>
|
||||
{/* <dd dangerouslySetInnerHTML={{ __html: row.remarks }}></dd> */}
|
||||
<dd dangerouslySetInnerHTML={{ __html: row.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
)
|
||||
|
||||
@ -318,11 +318,11 @@ export default function CanvasMenu(props) {
|
||||
<div className="ico-btn-from">
|
||||
<button className="btn-frame gray ico-flx" onClick={() => setEstimatePopupOpen(true)}>
|
||||
<span className="ico ico01"></span>
|
||||
<span>{getMessage('plan.menu.estimate.docDown')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.docDown')}</span>
|
||||
</button>
|
||||
<button className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
|
||||
<span className="ico ico02"></span>
|
||||
<span>{getMessage('plan.menu.estimate.save')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.save')}</span>
|
||||
</button>
|
||||
<button
|
||||
className="btn-frame gray ico-flx"
|
||||
@ -331,7 +331,7 @@ export default function CanvasMenu(props) {
|
||||
}}
|
||||
>
|
||||
<span className="ico ico03"></span>
|
||||
<span>{getMessage('plan.menu.estimate.reset')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.reset')}</span>
|
||||
</button>
|
||||
|
||||
{estimateRecoilState?.docNo !== null && (sessionState.storeId === 'T01' || sessionState.storeLvl === '1') && (
|
||||
@ -342,9 +342,13 @@ export default function CanvasMenu(props) {
|
||||
}}
|
||||
>
|
||||
<span className="ico ico04"></span>
|
||||
<span>{getMessage('plan.menu.estimate.copy')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.copy')}</span>
|
||||
</button>
|
||||
)}
|
||||
<button className="btn-frame gray ico-flx">
|
||||
<span className="ico ico05"></span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.unLock')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -20,7 +20,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
const orientationRef = useRef(null)
|
||||
const { initEvent } = useEvent()
|
||||
// const { initEvent } = useContext(EventContext)
|
||||
const { makeModuleInstArea, manualModuleSetup, autoModuleSetup } = useModuleBasicSetting()
|
||||
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting()
|
||||
const handleBtnNextStep = () => {
|
||||
if (tabNum === 1) {
|
||||
orientationRef.current.handleNextStep()
|
||||
@ -28,20 +28,16 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
setTabNum(tabNum + 1)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
makeModuleInstArea() //기붕 모듈설치면 생성
|
||||
|
||||
return () => {
|
||||
initEvent() //모듈설치면 선택 이벤트 삭제
|
||||
}
|
||||
}, [])
|
||||
|
||||
const placementRef = {
|
||||
isChidori: useRef('false'),
|
||||
setupLocation: useRef('center'),
|
||||
isMaxSetup: useRef('false'),
|
||||
}
|
||||
|
||||
const placementFlatRef = {
|
||||
setupLocation: useRef('south'),
|
||||
}
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={pos}>
|
||||
<div className={`modal-pop-wrap lx-2`}>
|
||||
@ -66,7 +62,9 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
|
||||
{/*배치면 초기설정 - 입력방법: 육지붕*/}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 2 && <PitchModule setTabNum={setTabNum} />}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 3 && <PitchPlacement setTabNum={setTabNum} />}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 3 && (
|
||||
<PitchPlacement setTabNum={setTabNum} ref={placementFlatRef} />
|
||||
)}
|
||||
|
||||
<div className="grid-btn-wrap">
|
||||
{tabNum !== 1 && (
|
||||
@ -80,14 +78,29 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
Next
|
||||
</button>
|
||||
)}
|
||||
|
||||
{tabNum === 3 && (
|
||||
<>
|
||||
<button className="btn-frame modal mr5" onClick={manualModuleSetup}>
|
||||
{getMessage('modal.module.basic.setting.passivity.placement')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
|
||||
{getMessage('modal.module.basic.setting.auto.placement')}
|
||||
</button>
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != 3 && (
|
||||
<>
|
||||
<button className="btn-frame modal mr5" onClick={manualModuleSetup}>
|
||||
{getMessage('modal.module.basic.setting.passivity.placement')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
|
||||
{getMessage('modal.module.basic.setting.auto.placement')}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet === 3 && (
|
||||
<>
|
||||
<button className="btn-frame modal mr5" onClick={() => manualFlatroofModuleSetup(placementFlatRef)}>
|
||||
{getMessage('modal.module.basic.setting.passivity.placement')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={() => autoFlatroofModuleSetup(placementFlatRef)}>
|
||||
{getMessage('modal.module.basic.setting.auto.placement')}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { forwardRef, useEffect, useState } from 'react'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { forwardRef, useState } from 'react'
|
||||
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
|
||||
|
||||
const Placement = forwardRef((props, refs) => {
|
||||
const { getMessage } = useMessage()
|
||||
@ -7,6 +8,12 @@ const Placement = forwardRef((props, refs) => {
|
||||
const [setupLocation, setSetupLocation] = useState('center')
|
||||
const [isMaxSetup, setIsMaxSetup] = useState('false')
|
||||
|
||||
const { makeModuleInstArea } = useModuleBasicSetting()
|
||||
|
||||
useEffect(() => {
|
||||
makeModuleInstArea()
|
||||
}, [])
|
||||
|
||||
const moduleData = {
|
||||
header: [
|
||||
{ type: 'check', name: '', prop: 'check', width: 70 },
|
||||
|
||||
@ -1,7 +1,26 @@
|
||||
import { forwardRef, useState, useEffect } from 'react'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
|
||||
import { compasDegAtom } from '@/store/orientationAtom'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { POLYGON_TYPE } from '@/common/common'
|
||||
|
||||
export default function PitchPlacement() {
|
||||
const PitchPlacement = forwardRef((props, refs) => {
|
||||
const { getMessage } = useMessage()
|
||||
const [setupLocation, setSetupLocation] = useState('south')
|
||||
const { makeModuleInstArea } = useModuleBasicSetting()
|
||||
const compasDeg = useRecoilValue(compasDegAtom)
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
useEffect(() => {
|
||||
makeModuleInstArea()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
handleChangeSetupLocation()
|
||||
}, [setupLocation])
|
||||
|
||||
const moduleData = {
|
||||
header: [
|
||||
{ type: 'check', name: '', prop: 'check', width: 70 },
|
||||
@ -24,6 +43,45 @@ export default function PitchPlacement() {
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const handleSetupLocation = (e) => {
|
||||
refs.setupLocation.current = e.target
|
||||
setSetupLocation(e.target.value)
|
||||
}
|
||||
|
||||
const handleChangeSetupLocation = () => {
|
||||
if (setupLocation === 'south') {
|
||||
canvas.getObjects().forEach((obj) => obj.name === 'flatExcretaLine' && canvas.remove(obj))
|
||||
return null
|
||||
} else {
|
||||
const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴
|
||||
moduleSetupSurfaces.forEach((surface, index) => {
|
||||
console.log(`surface ${index} : `, surface)
|
||||
|
||||
const excretaLine = surface.lines
|
||||
|
||||
excretaLine.forEach((line) => {
|
||||
line.set({
|
||||
stroke: '#642EFB',
|
||||
strokeWidth: 5,
|
||||
surfaceId: surface.surfaceId,
|
||||
name: 'flatExcretaLine',
|
||||
})
|
||||
canvas.add(line)
|
||||
|
||||
line.on('selected', () => {
|
||||
excretaLine.forEach((obj) => obj.set({ stroke: '#642EFB', isSelected: false }))
|
||||
if (!line.isSelected) {
|
||||
line.set({ stroke: 'red', isSelected: true })
|
||||
} else {
|
||||
line.set({ stroke: '#642EFB', isSelected: false })
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="module-table-box mb10">
|
||||
@ -88,11 +146,26 @@ export default function PitchPlacement() {
|
||||
<div className="hexagonal-item">
|
||||
<div className="pop-form-radio">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra01" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio01"
|
||||
id="ra01"
|
||||
value={'south'}
|
||||
checked={setupLocation === 'south'}
|
||||
defaultChecked
|
||||
onChange={handleSetupLocation}
|
||||
/>
|
||||
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.south')}</label>
|
||||
</div>
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra02" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio01"
|
||||
id="ra02"
|
||||
value={'excreta'}
|
||||
checked={setupLocation === 'excreta'}
|
||||
onChange={handleSetupLocation}
|
||||
/>
|
||||
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.select')}</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -102,4 +175,6 @@ export default function PitchPlacement() {
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default PitchPlacement
|
||||
|
||||
@ -1,113 +1,26 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
|
||||
import { canvasSettingState } from '@/store/canvasAtom'
|
||||
import { basicSettingState } from '@/store/settingAtom'
|
||||
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
|
||||
import SizeGuide from '@/components/floor-plan/modal/placementShape/SizeGuide'
|
||||
import MaterialGuide from '@/components/floor-plan/modal/placementShape/MaterialGuide'
|
||||
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||
|
||||
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
||||
|
||||
export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, setShowPlaceShapeModal }) {
|
||||
const [objectNo, setObjectNo] = useState('test123241008001') // 후에 삭제 필요
|
||||
const [showSizeGuideModal, setShowSizeGuidModal] = useState(false)
|
||||
const [showMaterialGuideModal, setShowMaterialGuidModal] = useState(false)
|
||||
const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(1)
|
||||
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
|
||||
const { closePopup } = usePopup()
|
||||
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const { get, post } = useAxios()
|
||||
const { swalFire } = useSwal()
|
||||
|
||||
const { basicSetting, setBasicSettings, fetchBasicSettings, basicSettingSave } = useCanvasSetting()
|
||||
|
||||
// 데이터를 최초 한 번만 조회
|
||||
useEffect(() => {
|
||||
console.log('PlacementShapeSetting useEffect 실행')
|
||||
|
||||
fetchSettings()
|
||||
}, [objectNo])
|
||||
|
||||
// PlacementShapeSetting 조회 및 초기화
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => {
|
||||
if (res.length == 0) return
|
||||
|
||||
// 'roofs' 배열을 생성하여 각 항목을 추가
|
||||
const roofsRow = res.map((item) => {
|
||||
return {
|
||||
roofSizeSet: item.roofSizeSet,
|
||||
roofAngleSet: item.roofAngleSet,
|
||||
}
|
||||
})
|
||||
|
||||
const roofsArray = res.some((item) => !item.roofSeq)
|
||||
? //최초 지붕재 추가 정보의 경우 roofsArray를 초기화 설정
|
||||
res.map(() => ({
|
||||
roofApply: true,
|
||||
roofSeq: 1,
|
||||
roofType: 1,
|
||||
roofWidth: 200,
|
||||
roofHeight: 200,
|
||||
roofHajebichi: 200,
|
||||
roofGap: 0,
|
||||
roofLayout: 'parallel',
|
||||
}))
|
||||
: res.map((item) => ({
|
||||
roofApply: item.roofApply === '' || item.roofApply === false ? false : true,
|
||||
roofSeq: item.roofSeq,
|
||||
roofType: item.roofType,
|
||||
roofWidth: item.roofWidth,
|
||||
roofHeight: item.roofHeight,
|
||||
roofHajebichi: item.roofHajebichi,
|
||||
roofGap: item.roofGap,
|
||||
roofLayout: item.roofLayout,
|
||||
}))
|
||||
console.log('roofsArray ', roofsArray)
|
||||
// 나머지 데이터와 함께 'roofs' 배열을 patternData에 넣음
|
||||
const patternData = {
|
||||
roofSizeSet: roofsRow[0].roofSizeSet, // 첫 번째 항목의 값을 사용
|
||||
roofAngleSet: roofsRow[0].roofAngleSet, // 첫 번째 항목의 값을 사용
|
||||
roofs: roofsArray, // 만들어진 roofs 배열
|
||||
}
|
||||
|
||||
// 데이터 설정
|
||||
setBasicSettings({ ...patternData })
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Data fetching error:', error)
|
||||
}
|
||||
|
||||
if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
|
||||
setBasicSettings({ ...canvasSetting })
|
||||
}
|
||||
}
|
||||
|
||||
const submitCanvasConfig = async () => {
|
||||
try {
|
||||
const patternData = {
|
||||
objectNo,
|
||||
roofSizeSet: basicSetting.roofSizeSet,
|
||||
roofAngleSet: basicSetting.roofAngleSet,
|
||||
roofMaterialsAddList: basicSetting.roofs,
|
||||
}
|
||||
|
||||
await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => {
|
||||
swalFire({ text: getMessage(res.returnMessage) })
|
||||
})
|
||||
|
||||
//Recoil 설정
|
||||
setCanvasSetting({ ...basicSetting })
|
||||
} catch (error) {
|
||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||
}
|
||||
}
|
||||
fetchBasicSettings()
|
||||
}, [])
|
||||
|
||||
// Function to update the roofType and corresponding values
|
||||
const handleRoofTypeChange = (index, value) => {
|
||||
@ -122,7 +35,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
|
||||
roofWidth: 265,
|
||||
roofHeight: 235,
|
||||
roofGap: 455,
|
||||
hajebichi: 0,
|
||||
roofHajebichi: 0,
|
||||
}
|
||||
} else if (roofType === 2) {
|
||||
updatedRoofs[index] = {
|
||||
@ -490,7 +403,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
|
||||
</table>
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame modal act" onClick={() => submitCanvasConfig()}>
|
||||
<button className="btn-frame modal act" onClick={() => basicSettingSave()}>
|
||||
{getMessage('modal.common.save')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -14,7 +14,7 @@ export default function SizeGuide({ setShowSizeGuidModal }) {
|
||||
<div className="placement-table light">
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style={{ width: '60px' }} />
|
||||
<col style={{ width: '65px' }} />
|
||||
<col />
|
||||
</colgroup>
|
||||
<tbody>
|
||||
|
||||
@ -96,7 +96,8 @@ export default function Header(props) {
|
||||
name: 'header.menus.management',
|
||||
url: '',
|
||||
children: [
|
||||
{ id: 3, name: 'header.menus.management.newStuff', url: '/management/stuff/tempdetail', children: [] },
|
||||
// { id: 3, name: 'header.menus.management.newStuff', url: '/management/stuff/tempdetail', children: [] },
|
||||
{ id: 3, name: 'header.menus.management.newStuff', url: '/management/stuff/tempReg', children: [] },
|
||||
{ id: 4, name: 'header.menus.management.stuffList', url: '/management/stuff', children: [] },
|
||||
],
|
||||
},
|
||||
@ -154,7 +155,9 @@ export default function Header(props) {
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={m.url}>{getMessage(m.name)}</Link>
|
||||
<Link scroll={false} href={m.url}>
|
||||
{getMessage(m.name)}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
|
||||
@ -128,9 +128,9 @@ export default function MainContents() {
|
||||
className="recently-item"
|
||||
onClick={() => {
|
||||
if (row.tempFlg === '0') {
|
||||
router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`)
|
||||
router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`, { scroll: false })
|
||||
} else {
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`)
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@ -75,7 +75,7 @@ export default function StuffDetail() {
|
||||
installHeight: '', //설치높이
|
||||
conType: '0', //계약조건(잉여 / 전량)
|
||||
remarks: '', //메모
|
||||
tempFlag: 'T', //임시저장(1) 저장(0)
|
||||
tempFlg: 'T', //임시저장(1) 저장(0)
|
||||
}
|
||||
const { register, setValue, getValues, handleSubmit, resetField, control, watch } = useForm({
|
||||
defaultValues: formInitValue,
|
||||
@ -108,7 +108,6 @@ export default function StuffDetail() {
|
||||
|
||||
const [editMode, setEditMode] = useState('NEW')
|
||||
const { managementState, setManagementState } = useContext(ManagementContext)
|
||||
|
||||
const [planGridProps, setPlanGridProps] = useState({
|
||||
planGridData: [],
|
||||
isPageable: false,
|
||||
@ -135,6 +134,7 @@ export default function StuffDetail() {
|
||||
field: 'moduleModel',
|
||||
headerName: getMessage('stuff.detail.planGridHeader.moduleModel'),
|
||||
flex: 1,
|
||||
wrapText: true,
|
||||
cellStyle: { justifyContent: 'flex-start' /* 좌측정렬*/ },
|
||||
},
|
||||
{
|
||||
@ -283,6 +283,7 @@ export default function StuffDetail() {
|
||||
{getMessage('stuff.detail.planGrid.btn1')}
|
||||
</button>
|
||||
<button
|
||||
style={buttonStyle}
|
||||
type="button"
|
||||
className="grid-btn"
|
||||
onClick={() => {
|
||||
@ -321,7 +322,7 @@ export default function StuffDetail() {
|
||||
} else {
|
||||
setManagementState({})
|
||||
alert(getMessage('stuff.detail.header.notExistObjectNo'))
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
}
|
||||
if (isNotEmptyArray(res.data.planList)) {
|
||||
setPlanGridProps({ ...planGridProps, planGridData: res.data.planList })
|
||||
@ -333,7 +334,7 @@ export default function StuffDetail() {
|
||||
setPlanGridProps({ ...planGridProps, planGridData: [] })
|
||||
|
||||
alert(getMessage('stuff.detail.header.notExistObjectNo'))
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@ -516,7 +517,6 @@ export default function StuffDetail() {
|
||||
firstList = res
|
||||
favList = res.filter((row) => row.priority !== 'B')
|
||||
otherList = res.filter((row) => row.firstAgentYn === 'N')
|
||||
|
||||
setSaleStoreList(firstList)
|
||||
setFavoriteStoreList(firstList)
|
||||
setShowSaleStoreList(firstList)
|
||||
@ -547,6 +547,9 @@ export default function StuffDetail() {
|
||||
form.setValue('otherSaleStoreLevel', managementState.saleStoreLevel)
|
||||
|
||||
form.setValue('saleStoreLevel', '1')
|
||||
|
||||
form.setValue('saleStoreId', managementState.firstAgentId)
|
||||
setSelOptions(managementState.firstAgentId)
|
||||
}
|
||||
|
||||
//설계의뢰No.
|
||||
@ -896,6 +899,8 @@ export default function StuffDetail() {
|
||||
|
||||
//팝업에서 넘어온 설계의뢰 정보로 바꾸기
|
||||
const setPlanReqInfo = (info) => {
|
||||
// console.log('session 정보:::::::', session)
|
||||
// console.log('설계의뢰에서 넘어온 정보:::::::', info)
|
||||
form.setValue('planReqNo', info.planReqNo)
|
||||
form.setValue('objectStatusId', info.building)
|
||||
setSelectObjectStatusId(info.building)
|
||||
@ -1376,7 +1381,7 @@ export default function StuffDetail() {
|
||||
} else {
|
||||
resetStuffRecoil()
|
||||
}
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -2032,8 +2037,8 @@ export default function StuffDetail() {
|
||||
onChange={onSelectionChange}
|
||||
getOptionLabel={(x) => x.saleStoreName}
|
||||
getOptionValue={(x) => x.saleStoreId}
|
||||
isClearable={managementState.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
isDisabled={managementState.tempFlg === '0' ? true : session?.storeLvl !== '1' ? true : false}
|
||||
isClearable={managementState?.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
isDisabled={managementState?.tempFlg === '0' ? true : session?.storeLvl !== '1' ? true : false}
|
||||
value={saleStoreList.filter(function (option) {
|
||||
return option.saleStoreId === selOptions
|
||||
})}
|
||||
@ -2066,7 +2071,7 @@ export default function StuffDetail() {
|
||||
getOptionValue={(x) => x.saleStoreId}
|
||||
isClearable={false}
|
||||
isDisabled={
|
||||
managementState.tempFlg === '0'
|
||||
managementState?.tempFlg === '0'
|
||||
? true
|
||||
: session?.storeLvl !== '1'
|
||||
? true
|
||||
@ -2151,9 +2156,13 @@ export default function StuffDetail() {
|
||||
getOptionLabel={(x) => x.saleStoreName}
|
||||
getOptionValue={(x) => x.saleStoreId}
|
||||
isDisabled={
|
||||
managementState.tempFlg === '0' ? true : session?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true
|
||||
managementState?.tempFlg === '0'
|
||||
? true
|
||||
: session?.storeLvl === '1' && form.watch('saleStoreId') != ''
|
||||
? false
|
||||
: true
|
||||
}
|
||||
isClearable={managementState.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
isClearable={managementState?.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
value={otherSaleStoreList.filter(function (option) {
|
||||
return option.saleStoreId === otherSelOptions
|
||||
})}
|
||||
|
||||
@ -564,7 +564,8 @@ export default function StuffSearchCondition() {
|
||||
<h3>{getMessage('stuff.search.title')}</h3>
|
||||
</div>
|
||||
<div className="left-unit-box">
|
||||
<Link href="/management/stuff/tempdetail" scroll={false}>
|
||||
<Link href="/management/stuff/tempReg" scroll={false}>
|
||||
{/* <Link href="/management/stuff/tempdetail" scroll={false}> */}
|
||||
<button type="button" className="btn-origin navy mr5">
|
||||
{getMessage('stuff.search.btn.register')}
|
||||
</button>
|
||||
|
||||
@ -3,7 +3,7 @@ import { useContext, useEffect, useReducer, useState } from 'react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||
import { isObjectNotEmpty, isEmptyArray, isNotEmptyArray } from '@/util/common-utils'
|
||||
import { SessionContext } from '@/app/SessionProvider'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useRouter } from 'next/navigation'
|
||||
@ -18,6 +18,9 @@ const updateItemInList = (itemList, dispOrder, updates) => {
|
||||
}
|
||||
|
||||
export const useEstimateController = (planNo) => {
|
||||
const [fileList, setFileList] = useState([])
|
||||
const [deleteFileList, setDeleteFileList] = useState([])
|
||||
|
||||
const router = useRouter()
|
||||
const { session } = useContext(SessionContext)
|
||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||
@ -39,6 +42,12 @@ export const useEstimateController = (planNo) => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (fileList.length > 0) {
|
||||
realSave(fileList)
|
||||
}
|
||||
}, [fileList])
|
||||
|
||||
// 상세 조회
|
||||
const fetchSetting = async (objectNo, planNo) => {
|
||||
try {
|
||||
@ -50,6 +59,7 @@ export const useEstimateController = (planNo) => {
|
||||
item.delFlg = '0'
|
||||
})
|
||||
}
|
||||
|
||||
setEstimateContextState(res.data)
|
||||
}
|
||||
}
|
||||
@ -146,19 +156,22 @@ export const useEstimateController = (planNo) => {
|
||||
return alert(getMessage('estimate.detail.save.requiredEstimateDate'))
|
||||
}
|
||||
|
||||
//첨부파일을 첨부안했는데
|
||||
//아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼
|
||||
console.log('새로추가첨부파일:::', estimateData.newFileList)
|
||||
console.log('기존첨부파일:::', estimateData.originFiles)
|
||||
|
||||
// return
|
||||
|
||||
//기존에 첨부된 파일이 있으면 파일첨부관련 통과
|
||||
if (estimateData?.originFiles?.length > 0) {
|
||||
originFileFlg = true
|
||||
let cnt = estimateData.originFiles.filter((file) => file.delFlg === '0').length
|
||||
|
||||
if (cnt == 0) {
|
||||
originFileFlg = false
|
||||
} else {
|
||||
originFileFlg = true
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
if (!originFileFlg) {
|
||||
if (estimateData.newFileList?.length < 1) {
|
||||
//기존에 첨부된 파일이 없으면
|
||||
if (isEmptyArray(estimateData.newFileList)) {
|
||||
//새로 첨부한 파일이 없으면
|
||||
if (estimateData.itemList.length > 1) {
|
||||
estimateData.itemList.map((row) => {
|
||||
if (row.delFlg === '0') {
|
||||
@ -181,9 +194,8 @@ export const useEstimateController = (planNo) => {
|
||||
estimateData.itemList.map((item) => {
|
||||
if (item.delFlg === '0') {
|
||||
item.amount = item.amount?.replaceAll(',', '')
|
||||
item.salePrice = parseFloat(item.salePrice?.replaceAll(',', '')).toFixed(2)
|
||||
item.saleTotPrice = parseFloat(item.saleTotPrice?.replaceAll(',', '')).toFixed(2)
|
||||
|
||||
item.salePrice = Number(item.salePrice?.replaceAll(',', '')).toFixed(2)
|
||||
item.saleTotPrice = Number(item.saleTotPrice?.replaceAll(',', '')).toFixed(2)
|
||||
if (!item.paDispOrder) {
|
||||
if (itemFlg) {
|
||||
if (isNaN(item.amount)) {
|
||||
@ -214,6 +226,17 @@ export const useEstimateController = (planNo) => {
|
||||
}
|
||||
}
|
||||
})
|
||||
estimateData.itemList = estimateData.itemList.filter((item) => item.delFlg === '0' || !item.addFlg)
|
||||
|
||||
let delCnt = 0
|
||||
estimateData.itemList.map((item) => {
|
||||
if (item.delFlg === '1') {
|
||||
delCnt++
|
||||
}
|
||||
})
|
||||
if (delCnt === estimateData.itemList.length) {
|
||||
return alert(getMessage('estimate.detail.save.requiredItem'))
|
||||
}
|
||||
}
|
||||
|
||||
if (flag && fileFlg && itemFlg) {
|
||||
@ -228,83 +251,93 @@ export const useEstimateController = (planNo) => {
|
||||
formData.append('category', '10')
|
||||
formData.append('userId', estimateData.userId)
|
||||
|
||||
await post({ url: '/api/file/fileUpload', data: formData })
|
||||
}
|
||||
|
||||
//첨부파일저장끝
|
||||
|
||||
//제품라인 추가했는데 아이템 안고르고 저장하면itemId=''은 날리고 나머지 저장하기
|
||||
// estimateData.itemList = estimateData.itemList.filter((item) => item.itemId !== '')
|
||||
estimateData.itemList = estimateData.itemList.filter((item) => item.delFlg === '0' || !item.addFlg)
|
||||
|
||||
let delCnt = 0
|
||||
estimateData.itemList.map((item) => {
|
||||
if (item.delFlg === '1') {
|
||||
delCnt++
|
||||
}
|
||||
})
|
||||
if (delCnt === estimateData.itemList.length) {
|
||||
return alert(getMessage('estimate.detail.save.requiredItem'))
|
||||
}
|
||||
|
||||
let option = []
|
||||
estimateData.itemList.forEach((item) => {
|
||||
if (item.specialNoteCd) {
|
||||
let split2 = item.specialNoteCd.split('、')
|
||||
option = option.concat(split2)
|
||||
}
|
||||
})
|
||||
|
||||
let estimateOptions = ''
|
||||
let estimateOptionsArray
|
||||
estimateData.specialNoteList.map((item) => {
|
||||
if (item.pkgYn === '0') {
|
||||
if (item.check) {
|
||||
if (estimateOptions === '') {
|
||||
estimateOptions = item.code
|
||||
} else {
|
||||
estimateOptions += '、' + item.code
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (item.check) {
|
||||
let flg = '0'
|
||||
for (let i = 0; i < estimateData.uniqueData.length; i++) {
|
||||
if (item.code.indexOf(estimateData.uniqueData[i]) > -1) {
|
||||
flg = '1'
|
||||
}
|
||||
if (flg === '1') {
|
||||
estimateOptions += '、' + estimateData.uniqueData[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
estimateOptionsArray = estimateOptions.split('、').sort()
|
||||
estimateOptionsArray = Array.from(new Set(estimateOptionsArray))
|
||||
|
||||
estimateOptions = estimateOptionsArray.join('、')
|
||||
|
||||
estimateData.estimateOption = estimateOptions
|
||||
console.log('최종아이템:::', estimateData.itemList)
|
||||
console.log('최종저장::', estimateData)
|
||||
//2. 상세데이터 저장
|
||||
// return
|
||||
try {
|
||||
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('estimate.detail.save.alertMsg'))
|
||||
//어디로 보낼지
|
||||
fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo)
|
||||
}
|
||||
await post({ url: '/api/file/fileUpload', data: formData }).then((res) => {
|
||||
setFileList(res)
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('error::::::::::::', e.response.data.message)
|
||||
} else {
|
||||
setFileList([])
|
||||
realSave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const realSave = async (fileList) => {
|
||||
//첨부파일저장끝
|
||||
|
||||
let option = []
|
||||
estimateData.itemList.forEach((item) => {
|
||||
if (item.specialNoteCd) {
|
||||
let split2 = item.specialNoteCd.split('、')
|
||||
option = option.concat(split2)
|
||||
}
|
||||
})
|
||||
|
||||
let estimateOptions = ''
|
||||
let estimateOptionsArray
|
||||
estimateData.specialNoteList.map((item) => {
|
||||
if (item.pkgYn === '0') {
|
||||
if (item.check) {
|
||||
if (estimateOptions === '') {
|
||||
estimateOptions = item.code
|
||||
} else {
|
||||
estimateOptions += '、' + item.code
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (item.check) {
|
||||
let flg = '0'
|
||||
for (let i = 0; i < estimateData.uniqueData.length; i++) {
|
||||
if (item.code.indexOf(estimateData.uniqueData[i]) > -1) {
|
||||
flg = '1'
|
||||
}
|
||||
if (flg === '1') {
|
||||
estimateOptions += '、' + estimateData.uniqueData[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
estimateOptionsArray = estimateOptions.split('、').sort()
|
||||
estimateOptionsArray = Array.from(new Set(estimateOptionsArray))
|
||||
|
||||
estimateOptions = estimateOptionsArray.join('、')
|
||||
|
||||
estimateData.estimateOption = estimateOptions
|
||||
// console.log('최종아이템:::', estimateData.itemList)
|
||||
if (fileList?.length > 0) {
|
||||
estimateData.fileList = fileList
|
||||
} else {
|
||||
estimateData.fileList = []
|
||||
}
|
||||
if (estimateData.originFiles?.length > 0) {
|
||||
estimateData.deleteFileList = estimateData.originFiles?.filter((item) => item.delFlg === '1')
|
||||
} else {
|
||||
estimateData.deleteFileList = []
|
||||
}
|
||||
|
||||
if (estimateData.estimateType === 'YJSS') {
|
||||
estimateData.pkgAsp = estimateData.pkgAsp.replaceAll(',', '')
|
||||
}
|
||||
|
||||
console.log('최종저장::', estimateData)
|
||||
//2. 상세데이터 저장
|
||||
// return
|
||||
try {
|
||||
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
|
||||
if (res.status === 201) {
|
||||
estimateData.newFileList = []
|
||||
// estimateData.originFiles = []
|
||||
alert(getMessage('estimate.detail.save.alertMsg'))
|
||||
//어디로 보낼지
|
||||
fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('error::::::::::::', e.response.data.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적서 복사버튼
|
||||
* (견적서 번호(estimateData.docNo)가 생성된 이후 버튼 활성화 )
|
||||
|
||||
@ -2,21 +2,27 @@ import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { rectToPolygon, setSurfaceShapePattern } from '@/util/canvas-util'
|
||||
import { roofDisplaySelector } from '@/store/settingAtom'
|
||||
import offsetPolygon from '@/util/qpolygon-utils'
|
||||
import offsetPolygon, { calculateAngle } from '@/util/qpolygon-utils'
|
||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
import { moduleSetupSurfaceState, moduleIsSetupState } from '@/store/canvasAtom'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { POLYGON_TYPE, BATCH_TYPE } from '@/common/common'
|
||||
import * as turf from '@turf/turf'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { canvasSettingState } from '@/store/canvasAtom'
|
||||
import { compasDegAtom } from '@/store/orientationAtom'
|
||||
|
||||
export function useModuleBasicSetting() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const roofDisplay = useRecoilValue(roofDisplaySelector)
|
||||
const [moduleSetupSurface, setModuleSetupSurface] = useRecoilState(moduleSetupSurfaceState)
|
||||
// const [moduleIsSetup, setModuleIsSetup] = useRecoilState(moduleIsSetupState)
|
||||
const [moduleIsSetup, setModuleIsSetup] = useRecoilState(moduleIsSetupState)
|
||||
const { addTargetMouseEventListener, addCanvasMouseEventListener, initEvent } = useEvent()
|
||||
const { swalFire } = useSwal()
|
||||
const canvasSetting = useRecoilValue(canvasSettingState)
|
||||
const compasDeg = useRecoilValue(compasDegAtom)
|
||||
|
||||
// const { addTargetMouseEventListener, addCanvasMouseEventListener, initEvent } = useContext(EventContext)
|
||||
let selectedModuleInstSurfaceArray = []
|
||||
|
||||
@ -62,6 +68,8 @@ export function useModuleBasicSetting() {
|
||||
|
||||
const surfaceId = uuidv4()
|
||||
|
||||
console.log('roof.moduleCompass', roof.moduleCompass)
|
||||
|
||||
let setupSurface = new QPolygon(offsetPoints, {
|
||||
stroke: 'red',
|
||||
fill: 'transparent',
|
||||
@ -440,6 +448,7 @@ export function useModuleBasicSetting() {
|
||||
|
||||
//자동 모듈 설치(그리드 방식)
|
||||
const autoModuleSetup = (placementRef) => {
|
||||
initEvent() //마우스 이벤트 초기화
|
||||
const isChidori = placementRef.isChidori.current === 'true' ? true : false
|
||||
const setupLocation = placementRef.setupLocation.current
|
||||
const isMaxSetup = placementRef.isMaxSetup.current === 'true' ? true : false
|
||||
@ -472,14 +481,20 @@ export function useModuleBasicSetting() {
|
||||
}
|
||||
})
|
||||
|
||||
moduleSetupSurfaces.forEach((obj) => {
|
||||
if (obj.modules) {
|
||||
obj.modules.forEach((module) => {
|
||||
canvas?.remove(module)
|
||||
})
|
||||
obj.modules = []
|
||||
}
|
||||
})
|
||||
// console.log('moduleIsSetup', moduleIsSetup)
|
||||
|
||||
// if (moduleIsSetup.length > 0) {
|
||||
// swalFire({ text: 'alert 아이콘 테스트입니다.', icon: 'error' })
|
||||
// }
|
||||
|
||||
// moduleSetupSurfaces.forEach((obj) => {
|
||||
// if (obj.modules) {
|
||||
// obj.modules.forEach((module) => {
|
||||
// canvas?.remove(module)
|
||||
// })
|
||||
// obj.modules = []
|
||||
// }
|
||||
// })
|
||||
|
||||
notSelectedTrestlePolygons.forEach((obj) => {
|
||||
if (obj.modules) {
|
||||
@ -614,20 +629,20 @@ export function useModuleBasicSetting() {
|
||||
if (isMaxSetup) totalWidth = totalWidth * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함
|
||||
|
||||
for (let j = 0; j < diffTopEndPoint; j++) {
|
||||
bottomMargin = j === 0 ? 1 : 0
|
||||
bottomMargin = j === 0 ? 1 : 2
|
||||
for (let i = 0; i <= totalWidth; i++) {
|
||||
leftMargin = i === 0 ? 1.1 : 0 //숫자가 0이면 0, 1이면 1로 바꾸기
|
||||
leftMargin = i === 0 ? 1 : 2
|
||||
chidoriLength = 0
|
||||
if (isChidori) {
|
||||
chidoriLength = j % 2 === 0 ? 0 : width / 2
|
||||
}
|
||||
|
||||
square = [
|
||||
[startColPoint + tempMaxWidth * i - chidoriLength, startPoint.y1 - height * j - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + width - chidoriLength, startPoint.y1 - height * j - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + width - chidoriLength, startPoint.y1 - height * j - height - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i - chidoriLength, startPoint.y1 - height * j - height - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i - chidoriLength, startPoint.y1 - height * j - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin],
|
||||
]
|
||||
|
||||
let squarePolygon = turf.polygon([square])
|
||||
@ -674,9 +689,9 @@ export function useModuleBasicSetting() {
|
||||
if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려서 반씩 검사
|
||||
|
||||
for (let i = 0; i <= totalWidth; i++) {
|
||||
bottomMargin = i === 0 ? 1 : 0.1
|
||||
bottomMargin = i === 0 ? 1 : 2
|
||||
for (let j = 0; j < totalHeight; j++) {
|
||||
leftMargin = i === 0 ? 0 : 0.5 * i
|
||||
leftMargin = i === 0 ? 1 : 2
|
||||
chidoriLength = 0
|
||||
if (isChidori) {
|
||||
chidoriLength = i % 2 === 0 ? 0 : height / 2
|
||||
@ -746,17 +761,19 @@ export function useModuleBasicSetting() {
|
||||
if (isMaxSetup) diffRightEndPoint = diffRightEndPoint * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함
|
||||
|
||||
for (let j = 0; j < diffBottomEndPoint; j++) {
|
||||
bottomMargin = j === 0 ? 1 : 2
|
||||
for (let i = 0; i < diffRightEndPoint; i++) {
|
||||
leftMargin = i === 0 ? 1 : 2
|
||||
chidoriLength = 0
|
||||
if (isChidori) {
|
||||
chidoriLength = j % 2 === 0 ? 0 : width / 2
|
||||
}
|
||||
square = [
|
||||
[startColPoint + tempMaxWidth * i + chidoriLength, startPoint.y1 + height * j + 1],
|
||||
[startColPoint + tempMaxWidth * i + chidoriLength, startPoint.y1 + height * j + height + 1],
|
||||
[startColPoint + tempMaxWidth * i + width + chidoriLength, startPoint.y1 + height * j + height + 1],
|
||||
[startColPoint + tempMaxWidth * i + width + chidoriLength, startPoint.y1 + height * j + 1],
|
||||
[startColPoint + tempMaxWidth * i + chidoriLength, startPoint.y1 + height * j + 1],
|
||||
[startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin],
|
||||
[startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin],
|
||||
]
|
||||
|
||||
let squarePolygon = turf.polygon([square])
|
||||
@ -804,9 +821,9 @@ export function useModuleBasicSetting() {
|
||||
if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려서 반씩 검사
|
||||
|
||||
for (let i = 0; i <= totalWidth; i++) {
|
||||
bottomMargin = i === 0 ? 1 : 2
|
||||
for (let j = 0; j < totalHeight; j++) {
|
||||
bottomMargin = j === 0 ? 0.5 : 0.5 * j
|
||||
leftMargin = i === 0 ? 0 : 0.5 * i
|
||||
leftMargin = j === 0 ? 1 : 2
|
||||
chidoriLength = 0
|
||||
if (isChidori) {
|
||||
chidoriLength = i % 2 === 0 ? 0 : height / 2
|
||||
@ -912,11 +929,12 @@ export function useModuleBasicSetting() {
|
||||
}
|
||||
})
|
||||
|
||||
canvas?.renderAll()
|
||||
|
||||
//나간애들 제외하고 설치된 애들로 겹친애들 삭제 하기
|
||||
setupedModules.forEach((module, index) => {
|
||||
if (isMaxSetup && index > 0) {
|
||||
const isOverlap = turf.booleanOverlap(polygonToTurfPolygon(setupedModules[index - 1]), polygonToTurfPolygon(module))
|
||||
|
||||
//겹치는지 확인
|
||||
if (isOverlap) {
|
||||
//겹쳐있으면 삭제
|
||||
@ -930,142 +948,231 @@ export function useModuleBasicSetting() {
|
||||
})
|
||||
|
||||
moduleSetupSurface.set({ modules: setupedModules })
|
||||
// setModuleIsSetup(moduleSetupArray)
|
||||
|
||||
// const moduleArray = [...moduleIsSetup]
|
||||
// moduleArray.push({
|
||||
// surfaceId: moduleSetupSurface.surfaceId,
|
||||
// moduleSetupArray: setupedModules,
|
||||
// })
|
||||
// setModuleIsSetup(moduleArray)
|
||||
})
|
||||
calculateForApi()
|
||||
}
|
||||
|
||||
const calculateForApi = (moduleSetupArray) => {
|
||||
// TODO : 현재는 남쪽기준. 동,서,북 분기처리 필요
|
||||
const centerPoints = []
|
||||
moduleSetupArray.forEach((module, index) => {
|
||||
module.tempIndex = index
|
||||
const { x, y } = module.getCenterPoint()
|
||||
const { width, height } = module
|
||||
centerPoints.push({ x, y, width, height, index })
|
||||
const circle = new fabric.Circle({
|
||||
radius: 5,
|
||||
fill: 'red',
|
||||
name: 'redCircle',
|
||||
left: x - 5,
|
||||
top: y - 5,
|
||||
index: index,
|
||||
selectable: false,
|
||||
const calculateForApi = () => {
|
||||
const moduleSufaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
||||
|
||||
const results = []
|
||||
|
||||
moduleSufaces.forEach((moduleSurface) => {
|
||||
const centerPoints = []
|
||||
const direction = moduleSurface.direction
|
||||
const modules = moduleSurface.modules
|
||||
|
||||
modules.forEach((module, index) => {
|
||||
module.tempIndex = index
|
||||
const { x, y } = module.getCenterPoint()
|
||||
const { width, height } = module
|
||||
centerPoints.push({ x, y, width: Math.floor(width), height: Math.floor(height), index })
|
||||
})
|
||||
|
||||
if (centerPoints.length === 0) return
|
||||
|
||||
//완전 노출 하면
|
||||
let exposedBottom = 0
|
||||
// 반 노출 하면
|
||||
let exposedHalfBottom = 0
|
||||
// 완전 노출 상면
|
||||
let exposedTop = 0
|
||||
//반 노출 상면
|
||||
let exposedHalfTop = 0
|
||||
// 완전 접면
|
||||
let touchDimension = 0
|
||||
//반접면
|
||||
let halfTouchDimension = 0
|
||||
// 노출하면 체크
|
||||
centerPoints.forEach((centerPoint, index) => {
|
||||
const { x, y, width, height } = centerPoint
|
||||
// centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인
|
||||
let bottomCell
|
||||
let bottomLeftPoint
|
||||
let bottomRightPoint
|
||||
let leftBottomCnt
|
||||
let rightBottomCnt
|
||||
|
||||
switch (direction) {
|
||||
case 'south':
|
||||
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y + height)) < 2)
|
||||
bottomLeftPoint = { x: x - width / 2, y: y + height }
|
||||
bottomRightPoint = { x: x + width / 2, y: y + height }
|
||||
break
|
||||
case 'north':
|
||||
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y - height)) < 2)
|
||||
bottomLeftPoint = { x: x + width / 2, y: y - height }
|
||||
bottomRightPoint = { x: x - width / 2, y: y - height }
|
||||
break
|
||||
case 'east':
|
||||
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x - width)) < 2 && Math.abs(centerPoint.y - y) < 2)
|
||||
bottomLeftPoint = { x: x + width, y: y + height / 2 }
|
||||
bottomRightPoint = { x: x + width, y: y - height / 2 }
|
||||
break
|
||||
case 'west':
|
||||
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x + width)) < 2 && Math.abs(centerPoint.y - y) < 2)
|
||||
bottomLeftPoint = { x: x - width, y: y - height / 2 }
|
||||
bottomRightPoint = { x: x - width, y: y + height / 2 }
|
||||
break
|
||||
}
|
||||
|
||||
if (bottomCell.length === 1) {
|
||||
return
|
||||
}
|
||||
|
||||
// 바로 아래에 셀이 없는 경우 물떼세 배치가 왼쪽 되어있는 셀을 찾는다.
|
||||
leftBottomCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < 2 && Math.abs(centerPoint.y - bottomLeftPoint.y) < 2,
|
||||
).length
|
||||
rightBottomCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < 2 && Math.abs(centerPoint.y - bottomRightPoint.y) < 2,
|
||||
).length
|
||||
|
||||
if (leftBottomCnt + rightBottomCnt === 1) {
|
||||
exposedHalfBottom++
|
||||
return
|
||||
}
|
||||
})
|
||||
// 노출상면 체크
|
||||
|
||||
centerPoints.forEach((centerPoint, index) => {
|
||||
const { x, y, width, height } = centerPoint
|
||||
|
||||
let topCell
|
||||
let topLeftPoint
|
||||
let topRightPoint
|
||||
let leftTopCnt
|
||||
let rightTopCnt
|
||||
|
||||
switch (direction) {
|
||||
case 'south':
|
||||
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y - height)) < 2)
|
||||
topLeftPoint = { x: x - width / 2, y: y - height }
|
||||
topRightPoint = { x: x + width / 2, y: y - height }
|
||||
break
|
||||
case 'north':
|
||||
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y + height)) < 2)
|
||||
topLeftPoint = { x: x + width / 2, y: y + height }
|
||||
topRightPoint = { x: x - width / 2, y: y + height }
|
||||
break
|
||||
case 'east':
|
||||
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x - width)) < 2 && Math.abs(centerPoint.y - y) < 2)
|
||||
topLeftPoint = { x: x - width, y: y + height / 2 }
|
||||
topRightPoint = { x: x - width, y: y - height / 2 }
|
||||
break
|
||||
case 'west':
|
||||
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x + width)) < 2 && Math.abs(centerPoint.y - y) < 2)
|
||||
topLeftPoint = { x: x + width, y: y - height / 2 }
|
||||
topRightPoint = { x: x + width, y: y + height / 2 }
|
||||
break
|
||||
}
|
||||
|
||||
if (topCell.length === 1) {
|
||||
touchDimension++
|
||||
return
|
||||
}
|
||||
|
||||
leftTopCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < 2 && Math.abs(centerPoint.y - topLeftPoint.y) < 2,
|
||||
).length
|
||||
rightTopCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < 2 && Math.abs(centerPoint.y - topRightPoint.y) < 2,
|
||||
).length
|
||||
|
||||
if (leftTopCnt + rightTopCnt === 2) {
|
||||
touchDimension++
|
||||
return
|
||||
}
|
||||
|
||||
if (leftTopCnt + rightTopCnt === 1) {
|
||||
exposedHalfTop++
|
||||
halfTouchDimension++
|
||||
return
|
||||
}
|
||||
if (leftTopCnt + rightTopCnt === 0) {
|
||||
exposedTop++
|
||||
}
|
||||
})
|
||||
// 완전 노출 하면 계산
|
||||
|
||||
/*const cells = canvas.getObjects().filter((obj) => polygon.id === obj.parentId)
|
||||
const points = cells.map((cell) => {
|
||||
return cell.getCenterPoint()
|
||||
})*/
|
||||
const groupPoints = groupCoordinates(centerPoints, modules[0], direction)
|
||||
|
||||
groupPoints.forEach((group) => {
|
||||
let maxY = group.reduce((acc, cur) => (acc.y > cur.y ? acc : cur)).y
|
||||
let minY = group.reduce((acc, cur) => (acc.y < cur.y ? acc : cur)).y
|
||||
let maxX = group.reduce((acc, cur) => (acc.x > cur.x ? acc : cur)).x
|
||||
let minX = group.reduce((acc, cur) => (acc.x < cur.x ? acc : cur)).x
|
||||
|
||||
let maxYCenterPoint = group.filter((centerPoint) => Math.abs(centerPoint.y - maxY) < 2)
|
||||
let minYCenterPoint = group.filter((centerPoint) => Math.abs(centerPoint.y - minY) < 2)
|
||||
let maxXCenterPoint = group.filter((centerPoint) => Math.abs(centerPoint.x - maxX) < 2)
|
||||
let minXCenterPoint = group.filter((centerPoint) => Math.abs(centerPoint.x - minX) < 2)
|
||||
|
||||
switch (direction) {
|
||||
case 'south':
|
||||
exposedBottom += maxYCenterPoint.length
|
||||
break
|
||||
case 'north':
|
||||
exposedBottom += minYCenterPoint.length
|
||||
break
|
||||
case 'east':
|
||||
exposedBottom += maxXCenterPoint.length
|
||||
break
|
||||
case 'west':
|
||||
exposedBottom += minXCenterPoint.length
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
results.push({
|
||||
exposedBottom,
|
||||
exposedHalfBottom,
|
||||
exposedTop,
|
||||
exposedHalfTop,
|
||||
touchDimension,
|
||||
halfTouchDimension,
|
||||
})
|
||||
console.log({
|
||||
direction,
|
||||
exposedBottom,
|
||||
exposedHalfBottom,
|
||||
exposedTop,
|
||||
exposedHalfTop,
|
||||
touchDimension,
|
||||
halfTouchDimension,
|
||||
})
|
||||
canvas.add(circle)
|
||||
})
|
||||
|
||||
//완전 노출 하면
|
||||
let exposedBottom = 0
|
||||
// 반 노출 하면
|
||||
let exposedHalfBottom = 0
|
||||
// 완전 노출 상면
|
||||
let exposedTop = 0
|
||||
//반 노출 상면
|
||||
let exposedHalfTop = 0
|
||||
// 완전 접면
|
||||
let touchDimension = 0
|
||||
//반접면
|
||||
let halfTouchDimension = 0
|
||||
// 노출하면 체크
|
||||
centerPoints.forEach((centerPoint, index) => {
|
||||
const { x, y, width, height } = centerPoint
|
||||
// centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인
|
||||
const bottomCell = centerPoints.filter((centerPoint) => centerPoint.x === x && Math.abs(centerPoint.y - (y + height)) < 2)
|
||||
if (bottomCell.length === 1) {
|
||||
touchDimension++
|
||||
return
|
||||
}
|
||||
|
||||
const bottomLeftPoint = { x: x - width / 2, y: y + height }
|
||||
const bottomRightPoint = { x: x + width / 2, y: y + height }
|
||||
|
||||
// 바로 아래에 셀이 없는 경우 물떼세 배치가 왼쪽 되어있는 셀을 찾는다.
|
||||
const leftBottomCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < 2 && Math.abs(centerPoint.y - bottomLeftPoint.y) < 2,
|
||||
).length
|
||||
const rightBottomCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < 2 && Math.abs(centerPoint.y - bottomRightPoint.y) < 2,
|
||||
).length
|
||||
if (leftBottomCnt + rightBottomCnt === 2) {
|
||||
touchDimension++
|
||||
return
|
||||
}
|
||||
if (leftBottomCnt + rightBottomCnt === 1) {
|
||||
halfTouchDimension++
|
||||
exposedHalfBottom++
|
||||
return
|
||||
}
|
||||
})
|
||||
// 노출상면 체크
|
||||
|
||||
centerPoints.forEach((centerPoint, index) => {
|
||||
const { x, y, width, height } = centerPoint
|
||||
const topCell = centerPoints.filter((centerPoint) => centerPoint.x === x && Math.abs(centerPoint.y - (y - height)) < 2)
|
||||
if (topCell.length === 1) {
|
||||
return
|
||||
}
|
||||
|
||||
const topLeftPoint = { x: x - width / 2, y: y - height }
|
||||
const topRightPoint = { x: x + width / 2, y: y - height }
|
||||
|
||||
const leftTopCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < 2 && Math.abs(centerPoint.y - topRightPoint.y) < 2,
|
||||
).length
|
||||
const rightTopCnt = centerPoints.filter(
|
||||
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < 2 && Math.abs(centerPoint.y - topRightPoint.y) < 2,
|
||||
).length
|
||||
|
||||
if (leftTopCnt + rightTopCnt === 1) {
|
||||
exposedHalfTop++
|
||||
return
|
||||
}
|
||||
if (leftTopCnt + rightTopCnt === 0) {
|
||||
exposedTop++
|
||||
return
|
||||
}
|
||||
})
|
||||
// 완전 노출 하면 계산
|
||||
|
||||
/*const cells = canvas.getObjects().filter((obj) => polygon.id === obj.parentId)
|
||||
const points = cells.map((cell) => {
|
||||
return cell.getCenterPoint()
|
||||
})*/
|
||||
const groupPoints = groupCoordinates(centerPoints)
|
||||
|
||||
groupPoints.forEach((group) => {
|
||||
// 각 그룹에서 y값이 큰 값을 찾는다.
|
||||
// 그리고 그 y값과 같은 값을 가지는 centerPoint를 찾는다.
|
||||
const maxY = group.reduce((acc, cur) => (acc.y > cur.y ? acc : cur)).y
|
||||
const maxYCenterPoint = group.filter((centerPoint) => Math.abs(centerPoint.y - maxY) < 2)
|
||||
exposedBottom += maxYCenterPoint.length
|
||||
})
|
||||
|
||||
return {
|
||||
exposedBottom,
|
||||
exposedHalfBottom,
|
||||
exposedTop,
|
||||
exposedHalfTop,
|
||||
touchDimension,
|
||||
halfTouchDimension,
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// polygon 내부 cell들의 centerPoint 배열을 그룹화 해서 반환
|
||||
const groupCoordinates = (points) => {
|
||||
const groupCoordinates = (points, moduleExample, direction) => {
|
||||
const groups = []
|
||||
const visited = new Set()
|
||||
const width = 100
|
||||
const height = 100
|
||||
const horizonPadding = 5 // 가로 패딩
|
||||
const verticalPadding = 3 // 세로 패딩
|
||||
const width = Math.floor(moduleExample.width)
|
||||
const height = Math.floor(moduleExample.height)
|
||||
const horizonPadding = 0 // 가로 패딩
|
||||
const verticalPadding = 0 // 세로 패딩
|
||||
|
||||
function isAdjacent(p1, p2) {
|
||||
const dx = Math.abs(p1.x - p2.x)
|
||||
const dy = Math.abs(p1.y - p2.y)
|
||||
return (
|
||||
(dx === width + horizonPadding && dy === 0) ||
|
||||
(dx === 0 && dy === height + verticalPadding) ||
|
||||
(dx === width / 2 + horizonPadding / 2 && dy === height + verticalPadding)
|
||||
(Math.abs(width + horizonPadding - dx) < 2 && dy < 2) ||
|
||||
(dx < 2 && Math.abs(dy - height + verticalPadding)) < 2 ||
|
||||
(Math.abs(dx - width / 2 + horizonPadding / 2) < 2 && Math.abs(dy - height + verticalPadding) < 2)
|
||||
)
|
||||
}
|
||||
|
||||
@ -1182,7 +1289,7 @@ export function useModuleBasicSetting() {
|
||||
const angle2 = Math.abs(Math.round(Math.atan(height2 / adjust2) * (180 / Math.PI) * 1000) / 1000)
|
||||
const angle3 = 180 - (angle1 + angle2)
|
||||
|
||||
const charlie = 173.3 + 3 // 평행선길이 약간 여유를 줌
|
||||
const charlie = 173.3 // 평행선길이 약간 여유를 줌
|
||||
const alpha = (charlie * Math.sin((angle1 * Math.PI) / 180)) / Math.sin((angle3 * Math.PI) / 180)
|
||||
const beta = Math.sqrt(alpha ** 2 + charlie ** 2 - 2 * alpha * charlie * Math.cos((angle2 * Math.PI) / 180))
|
||||
const h = beta * Math.sin((angle1 * Math.PI) / 180) // 높이
|
||||
@ -1297,7 +1404,7 @@ export function useModuleBasicSetting() {
|
||||
const angle2 = Math.abs(Math.round(Math.atan(adjust2 / height2) * (180 / Math.PI) * 1000) / 1000)
|
||||
const angle3 = 180 - (angle1 + angle2)
|
||||
|
||||
const charlie = 173.3 + 3 // 평행선길이 약간 여유를줌
|
||||
const charlie = 173.3 // 평행선길이 약간 여유를줌
|
||||
const alpha = (charlie * Math.sin((angle1 * Math.PI) / 180)) / Math.sin((angle3 * Math.PI) / 180)
|
||||
const beta = Math.sqrt(alpha ** 2 + charlie ** 2 - 2 * alpha * charlie * Math.cos((angle2 * Math.PI) / 180))
|
||||
|
||||
@ -1413,10 +1520,343 @@ export function useModuleBasicSetting() {
|
||||
return obj
|
||||
}
|
||||
|
||||
const manualFlatroofModuleSetup = (placementFlatRef) => {
|
||||
const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴
|
||||
let applyAngle
|
||||
let flatBatchType = placementFlatRef.setupLocation.current.value
|
||||
let excretaLinesAngle = []
|
||||
|
||||
if (flatBatchType === 'south') {
|
||||
applyAngle = compasDeg
|
||||
} else {
|
||||
const excretaLines = canvas.getObjects().filter((obj) => obj.name === 'flatExcretaLine' && obj.isSelected === true)
|
||||
excretaLines.forEach((obj) => {
|
||||
const points1 = { x: obj.x1, y: obj.y1 }
|
||||
const points2 = { x: obj.x2, y: obj.y2 }
|
||||
excretaLinesAngle.push({
|
||||
surfaceId: obj.surfaceId,
|
||||
angle: calculateAngle(points1, points2),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//calculateAngle
|
||||
|
||||
const batchObjects = canvas
|
||||
?.getObjects()
|
||||
.filter(
|
||||
(obj) =>
|
||||
obj.name === BATCH_TYPE.OPENING ||
|
||||
obj.name === BATCH_TYPE.TRIANGLE_DORMER ||
|
||||
obj.name === BATCH_TYPE.PENTAGON_DORMER ||
|
||||
obj.name === BATCH_TYPE.SHADOW,
|
||||
) //도머s 객체
|
||||
|
||||
const moduleOptions = {
|
||||
fill: '#BFFD9F',
|
||||
stroke: 'black',
|
||||
strokeWidth: 0.1,
|
||||
selectable: false, // 선택 가능하게 설정
|
||||
lockMovementX: true, // X 축 이동 잠금
|
||||
lockMovementY: true, // Y 축 이동 잠금
|
||||
lockRotation: true, // 회전 잠금
|
||||
lockScalingX: true, // X 축 크기 조정 잠금
|
||||
lockScalingY: true, // Y 축 크기 조정 잠금
|
||||
opacity: 0.8,
|
||||
parentId: moduleSetupSurface.parentId,
|
||||
name: 'module',
|
||||
}
|
||||
|
||||
function getRotatedCorners(rect) {
|
||||
// 사각형의 중심점
|
||||
const center = rect.getCenterPoint()
|
||||
|
||||
// 사각형의 원래 꼭짓점 좌표 (로컬 좌표 기준)
|
||||
const halfWidth = (rect.width / 2) * rect.scaleX
|
||||
const halfHeight = (rect.height / 2) * rect.scaleY
|
||||
|
||||
const corners = [
|
||||
{ x: -halfWidth, y: -halfHeight }, // 좌상단
|
||||
{ x: halfWidth, y: -halfHeight }, // 우상단
|
||||
{ x: halfWidth, y: halfHeight }, // 우하단
|
||||
{ x: -halfWidth, y: halfHeight }, // 좌하단
|
||||
]
|
||||
|
||||
// 각 꼭짓점 좌표를 캔버스 좌표로 변환
|
||||
const transformedCorners = corners.map((corner) => {
|
||||
const point = new fabric.Point(corner.x, corner.y)
|
||||
return fabric.util.transformPoint(point, rect.calcTransformMatrix())
|
||||
})
|
||||
|
||||
return transformedCorners
|
||||
}
|
||||
|
||||
function getSelectedExcretaLine() {}
|
||||
|
||||
if (moduleSetupSurfaces.length !== 0) {
|
||||
let tempModule
|
||||
let manualDrawModules = []
|
||||
let inside = false
|
||||
let turfPolygon
|
||||
let flowDirection
|
||||
let trestlePolygon
|
||||
|
||||
addCanvasMouseEventListener('mouse:move', (e) => {
|
||||
//마우스 이벤트 삭제 후 재추가
|
||||
const mousePoint = canvas.getPointer(e.e)
|
||||
|
||||
for (let i = 0; i < moduleSetupSurfaces.length; i++) {
|
||||
turfPolygon = polygonToTurfPolygon(moduleSetupSurfaces[i])
|
||||
trestlePolygon = moduleSetupSurfaces[i]
|
||||
manualDrawModules = moduleSetupSurfaces[i].modules // 앞에서 자동으로 했을때 추가됨
|
||||
flowDirection = moduleSetupSurfaces[i].flowDirection //도형의 방향
|
||||
|
||||
if (flatBatchType === 'excreta') {
|
||||
const tempLine = excretaLinesAngle.find((obj) => obj.surfaceId === trestlePolygon.surfaceId)
|
||||
if (tempLine) {
|
||||
applyAngle = tempLine.angle
|
||||
} else {
|
||||
applyAngle = compasDeg
|
||||
}
|
||||
}
|
||||
|
||||
// const excretaLine = excretaLines.find((obj) => obj.isSelected === true && obj.surfaceId === trestlePolygon.surfaceId)
|
||||
|
||||
// console.log('excretaLine', excretaLine.x1, excretaLine.y1, excretaLine.x2, excretaLine.y2)
|
||||
|
||||
// applyAngle = calculateAngle(excretaLine.x1, excretaLine.y1, excretaLine.x2, excretaLine.y2)
|
||||
|
||||
// console.log('applyAngle', applyAngle)
|
||||
|
||||
let width = flowDirection === 'south' || flowDirection === 'north' ? 172 : 113
|
||||
let height = flowDirection === 'south' || flowDirection === 'north' ? 113 : 172
|
||||
|
||||
const angledModule = new fabric.Rect({
|
||||
width: width,
|
||||
height: height,
|
||||
left: mousePoint.x - width / 2,
|
||||
top: mousePoint.y - height / 2,
|
||||
})
|
||||
|
||||
const center = angledModule.getCenterPoint()
|
||||
angledModule.set('angle', applyAngle)
|
||||
angledModule.setPositionByOrigin(center, 'center', 'center')
|
||||
|
||||
const points = getRotatedCorners(angledModule) //
|
||||
const turfPoints = coordToTurfPolygon(points)
|
||||
|
||||
if (turf.booleanWithin(turfPoints, turfPolygon)) {
|
||||
let isDrawing = false
|
||||
|
||||
if (isDrawing) return
|
||||
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임
|
||||
|
||||
tempModule = new QPolygon(points, {
|
||||
fill: 'white',
|
||||
stroke: 'black',
|
||||
strokeWidth: 0.3,
|
||||
name: 'tempModule',
|
||||
})
|
||||
|
||||
canvas?.add(tempModule) //움직여가면서 추가됨
|
||||
canvas?.renderAll()
|
||||
|
||||
/**
|
||||
* 스냅기능
|
||||
*/
|
||||
let snapDistance = 10
|
||||
let cellSnapDistance = 20
|
||||
|
||||
const trestleLeft = moduleSetupSurfaces[i].left
|
||||
const trestleTop = moduleSetupSurfaces[i].top
|
||||
const trestleRight = trestleLeft + moduleSetupSurfaces[i].width * moduleSetupSurfaces[i].scaleX
|
||||
const trestleBottom = trestleTop + moduleSetupSurfaces[i].height * moduleSetupSurfaces[i].scaleY
|
||||
const bigCenterY = (trestleTop + trestleTop + moduleSetupSurfaces[i].height) / 2
|
||||
|
||||
// 작은 폴리곤의 경계 좌표 계산
|
||||
const smallLeft = tempModule.left
|
||||
const smallTop = tempModule.top
|
||||
const smallRight = smallLeft + tempModule.width * tempModule.scaleX
|
||||
const smallBottom = smallTop + tempModule.height * tempModule.scaleY
|
||||
const smallCenterX = smallLeft + (tempModule.width * tempModule.scaleX) / 2
|
||||
const smallCenterY = smallTop + (tempModule.height * tempModule.scaleX) / 2
|
||||
|
||||
if (manualDrawModules) {
|
||||
manualDrawModules.forEach((cell) => {
|
||||
const holdCellLeft = cell.left
|
||||
const holdCellTop = cell.top
|
||||
const holdCellRight = holdCellLeft + cell.width * cell.scaleX
|
||||
const holdCellBottom = holdCellTop + cell.height * cell.scaleY
|
||||
const holdCellCenterX = holdCellLeft + (cell.width * cell.scaleX) / 2
|
||||
const holdCellCenterY = holdCellTop + (cell.height * cell.scaleY) / 2
|
||||
|
||||
//설치된 셀에 좌측에 스냅
|
||||
if (Math.abs(smallRight - holdCellLeft) < snapDistance) {
|
||||
tempModule.left = holdCellLeft - width - 0.5
|
||||
}
|
||||
|
||||
//설치된 셀에 우측에 스냅
|
||||
if (Math.abs(smallLeft - holdCellRight) < snapDistance) {
|
||||
tempModule.left = holdCellRight + 0.5
|
||||
}
|
||||
|
||||
//설치된 셀에 위쪽에 스냅
|
||||
if (Math.abs(smallBottom - holdCellTop) < snapDistance) {
|
||||
tempModule.top = holdCellTop - height - 0.5
|
||||
}
|
||||
|
||||
//설치된 셀에 밑쪽에 스냅
|
||||
if (Math.abs(smallTop - holdCellBottom) < snapDistance) {
|
||||
tempModule.top = holdCellBottom + 0.5
|
||||
}
|
||||
//가운데 -> 가운데
|
||||
if (Math.abs(smallCenterX - holdCellCenterX) < cellSnapDistance) {
|
||||
tempModule.left = holdCellCenterX - width / 2
|
||||
}
|
||||
//왼쪽 -> 가운데
|
||||
if (Math.abs(smallLeft - holdCellCenterX) < cellSnapDistance) {
|
||||
tempModule.left = holdCellCenterX
|
||||
}
|
||||
// 오른쪽 -> 가운데
|
||||
if (Math.abs(smallRight - holdCellCenterX) < cellSnapDistance) {
|
||||
tempModule.left = holdCellCenterX - width
|
||||
}
|
||||
//세로 가운데 -> 가운데
|
||||
if (Math.abs(smallCenterY - holdCellCenterY) < cellSnapDistance) {
|
||||
tempModule.top = holdCellCenterY - height / 2
|
||||
}
|
||||
//위쪽 -> 가운데
|
||||
if (Math.abs(smallTop - holdCellCenterY) < cellSnapDistance) {
|
||||
tempModule.top = holdCellCenterY
|
||||
}
|
||||
//아랫쪽 -> 가운데
|
||||
if (Math.abs(smallBottom - holdCellCenterY) < cellSnapDistance) {
|
||||
tempModule.top = holdCellCenterY - height
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 위쪽 변에 스냅
|
||||
if (Math.abs(smallTop - trestleTop) < snapDistance) {
|
||||
tempModule.top = trestleTop
|
||||
}
|
||||
|
||||
// 아래쪽 변에 스냅
|
||||
if (Math.abs(smallTop + tempModule.height * tempModule.scaleY - (trestleTop + moduleSetupSurfaces[i].height)) < snapDistance) {
|
||||
tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height * tempModule.scaleY
|
||||
}
|
||||
|
||||
// 왼쪽변에 스냅
|
||||
if (Math.abs(smallLeft - trestleLeft) < snapDistance) {
|
||||
tempModule.left = trestleLeft
|
||||
}
|
||||
//오른쪽 변에 스냅
|
||||
if (Math.abs(smallRight - trestleRight) < snapDistance) {
|
||||
tempModule.left = trestleRight - tempModule.width * tempModule.scaleX
|
||||
}
|
||||
|
||||
if (flowDirection === 'south' || flowDirection === 'north') {
|
||||
// 모듈왼쪽이 세로중앙선에 붙게 스냅
|
||||
if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
|
||||
tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2
|
||||
}
|
||||
|
||||
// 모듈이 가운데가 세로중앙선에 붙게 스냅
|
||||
if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
|
||||
tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - (tempModule.width * tempModule.scaleX) / 2
|
||||
}
|
||||
|
||||
// 모듈오른쪽이 세로중앙선에 붙게 스냅
|
||||
if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
|
||||
tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX
|
||||
}
|
||||
} else {
|
||||
// 모듈이 가로중앙선에 스냅
|
||||
if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < snapDistance) {
|
||||
tempModule.top = bigCenterY - tempModule.height / 2
|
||||
}
|
||||
|
||||
if (Math.abs(smallTop - (trestleTop + moduleSetupSurfaces[i].height / 2)) < snapDistance) {
|
||||
tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2
|
||||
}
|
||||
// 모듈 밑면이 가로중앙선에 스냅
|
||||
if (Math.abs(smallBottom - (trestleTop + moduleSetupSurfaces[i].height / 2)) < snapDistance) {
|
||||
tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2 - tempModule.height * tempModule.scaleY
|
||||
}
|
||||
}
|
||||
|
||||
inside = true
|
||||
break
|
||||
} else {
|
||||
inside = false
|
||||
}
|
||||
}
|
||||
|
||||
if (!inside) {
|
||||
// tempModule.set({ fill: 'red' })
|
||||
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule'))
|
||||
canvas?.renderAll()
|
||||
}
|
||||
})
|
||||
|
||||
addCanvasMouseEventListener('mouse:up', (e) => {
|
||||
let isIntersection = true
|
||||
if (!inside) return
|
||||
if (tempModule) {
|
||||
const tempTurfModule = polygonToTurfPolygon(tempModule)
|
||||
|
||||
//도머 객체를 가져옴
|
||||
if (batchObjects) {
|
||||
batchObjects.forEach((object) => {
|
||||
let dormerTurfPolygon
|
||||
|
||||
if (object.type === 'group') {
|
||||
//도머는 그룹형태임
|
||||
dormerTurfPolygon = batchObjectGroupToTurfPolygon(object)
|
||||
} else {
|
||||
//개구, 그림자
|
||||
dormerTurfPolygon = polygonToTurfPolygon(rectToPolygon(object))
|
||||
}
|
||||
|
||||
const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인
|
||||
//겹치면 안됨
|
||||
if (intersection) {
|
||||
alert('도머위에 모듈을 올릴 수 없습니다.')
|
||||
isIntersection = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!isIntersection) return
|
||||
|
||||
if (turf.booleanWithin(tempTurfModule, turfPolygon)) {
|
||||
//마우스 클릭시 set으로 해당 위치에 셀을 넣음
|
||||
const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인
|
||||
if (!isOverlap) {
|
||||
console.log('tempModule.points', tempModule.points)
|
||||
|
||||
let manualModule = new QPolygon(tempModule.points, { ...moduleOptions })
|
||||
canvas?.add(manualModule)
|
||||
manualDrawModules.push(tempModule)
|
||||
} else {
|
||||
alert('셀끼리 겹치면 안되죠?')
|
||||
}
|
||||
} else {
|
||||
alert('나갔죠?!!')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const autoFlatroofModuleSetup = (placementFlatRef) => {}
|
||||
|
||||
return {
|
||||
makeModuleInstArea,
|
||||
manualModuleSetup,
|
||||
autoModuleSetup,
|
||||
restoreModuleInstArea,
|
||||
manualFlatroofModuleSetup,
|
||||
autoFlatroofModuleSetup,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
|
||||
import { adsorptionPointModeState, adsorptionRangeState, canvasState, planSizeSettingState, dotLineGridSettingState } from '@/store/canvasAtom'
|
||||
import {
|
||||
adsorptionPointModeState,
|
||||
adsorptionRangeState,
|
||||
canvasState,
|
||||
planSizeSettingState,
|
||||
dotLineGridSettingState,
|
||||
canvasSettingState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
@ -11,6 +18,7 @@ import {
|
||||
settingModalFirstOptionsState,
|
||||
settingModalSecondOptionsState,
|
||||
settingModalGridOptionsState,
|
||||
basicSettingState,
|
||||
} from '@/store/settingAtom'
|
||||
import { POLYGON_TYPE } from '@/common/common'
|
||||
import { globalFontAtom } from '@/store/fontAtom'
|
||||
@ -70,6 +78,9 @@ export function useCanvasSetting() {
|
||||
const [color, setColor] = useColor(gridColor ?? '#FF0000')
|
||||
const [colorTemp, setColorTemp] = useState()
|
||||
|
||||
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
|
||||
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
|
||||
|
||||
const SelectOptions = [
|
||||
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 },
|
||||
{ id: 2, name: '1/2', value: 1 / 2 },
|
||||
@ -112,6 +123,14 @@ export function useCanvasSetting() {
|
||||
console.log('useCanvasSetting 실행1', correntObjectNo)
|
||||
}, [])
|
||||
|
||||
// 배치면 초기설정 변경 시
|
||||
useEffect(() => {
|
||||
//console.log('useCanvasSetting canvasSetting 실행', canvasSetting)
|
||||
if (canvasSetting.flag) {
|
||||
basicSettingSave()
|
||||
}
|
||||
}, [canvasSetting])
|
||||
|
||||
//흡착점 ON/OFF 변경 시
|
||||
useEffect(() => {
|
||||
//console.log('useCanvasSetting 실행2', adsorptionPointMode.fontFlag, correntObjectNo)
|
||||
@ -232,6 +251,95 @@ export function useCanvasSetting() {
|
||||
}
|
||||
}
|
||||
|
||||
// 기본설정(PlacementShapeSetting) 조회 및 초기화
|
||||
const fetchBasicSettings = async () => {
|
||||
try {
|
||||
await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}` }).then((res) => {
|
||||
console.log('fetchBasicSettings res ', res)
|
||||
if (res.length == 0) return
|
||||
|
||||
// 'roofs' 배열을 생성하여 각 항목을 추가
|
||||
const roofsRow = res.map((item) => {
|
||||
return {
|
||||
roofSizeSet: item.roofSizeSet,
|
||||
roofAngleSet: item.roofAngleSet,
|
||||
}
|
||||
})
|
||||
|
||||
const roofsArray = res.some((item) => !item.roofSeq)
|
||||
? //최초 지붕재 추가 정보의 경우 roofsArray를 초기화 설정
|
||||
res.map(() => ({
|
||||
flag: false,
|
||||
roofApply: true,
|
||||
roofSeq: 1,
|
||||
roofType: 1,
|
||||
roofWidth: 265,
|
||||
roofHeight: 235,
|
||||
roofHajebichi: 0,
|
||||
roofGap: 455,
|
||||
// roofType: 1,
|
||||
// roofWidth: 200,
|
||||
// roofHeight: 200,
|
||||
// roofHajebichi: 200,
|
||||
// roofGap: 0,
|
||||
roofLayout: 'parallel',
|
||||
}))
|
||||
: res.map((item) => ({
|
||||
flag: false,
|
||||
roofApply: item.roofApply === '' || item.roofApply === false ? false : true,
|
||||
roofSeq: item.roofSeq,
|
||||
roofType: item.roofType,
|
||||
roofWidth: item.roofWidth,
|
||||
roofHeight: item.roofHeight,
|
||||
roofHajebichi: item.roofHajebichi,
|
||||
roofGap: item.roofGap,
|
||||
roofLayout: item.roofLayout,
|
||||
}))
|
||||
console.log('roofsArray ', roofsArray)
|
||||
// 나머지 데이터와 함께 'roofs' 배열을 patternData에 넣음
|
||||
const patternData = {
|
||||
roofSizeSet: roofsRow[0].roofSizeSet, // 첫 번째 항목의 값을 사용
|
||||
roofAngleSet: roofsRow[0].roofAngleSet, // 첫 번째 항목의 값을 사용
|
||||
roofs: roofsArray, // 만들어진 roofs 배열
|
||||
}
|
||||
|
||||
//console.error('patternData', patternData)
|
||||
|
||||
// 데이터 설정
|
||||
setBasicSettings({ ...patternData })
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Data fetching error:', error)
|
||||
}
|
||||
|
||||
if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
|
||||
setBasicSettings({ ...canvasSetting })
|
||||
}
|
||||
//setCanvasSetting({ ...basicSetting })
|
||||
}
|
||||
|
||||
// 기본설정(PlacementShapeSetting) 저장
|
||||
const basicSettingSave = async () => {
|
||||
try {
|
||||
const patternData = {
|
||||
objectNo: correntObjectNo,
|
||||
roofSizeSet: basicSetting.roofSizeSet,
|
||||
roofAngleSet: basicSetting.roofAngleSet,
|
||||
roofMaterialsAddList: basicSetting.roofs,
|
||||
}
|
||||
|
||||
await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => {
|
||||
swalFire({ text: getMessage(res.returnMessage) })
|
||||
})
|
||||
|
||||
//Recoil 설정
|
||||
setCanvasSetting({ ...basicSetting, flag: false })
|
||||
} catch (error) {
|
||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||
}
|
||||
}
|
||||
|
||||
// CanvasSetting 조회 및 초기화
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${correntObjectNo}` })
|
||||
@ -382,7 +490,7 @@ export function useCanvasSetting() {
|
||||
}
|
||||
}
|
||||
|
||||
// 옵션 클릭 후 저장
|
||||
// CanvasSetting 옵션 클릭 후 저장
|
||||
const onClickOption2 = useCallback(async () => {
|
||||
// 서버에 전송할 데이터
|
||||
const dataToSend = {
|
||||
@ -592,7 +700,6 @@ export function useCanvasSetting() {
|
||||
adsorptionRange,
|
||||
setAdsorptionRange,
|
||||
fetchSettings,
|
||||
//onClickOption,
|
||||
frontSettings,
|
||||
globalFont,
|
||||
setGlobalFont,
|
||||
@ -621,5 +728,11 @@ export function useCanvasSetting() {
|
||||
setGridColor,
|
||||
color,
|
||||
setColor,
|
||||
canvasSetting,
|
||||
setCanvasSetting,
|
||||
basicSetting,
|
||||
setBasicSettings,
|
||||
fetchBasicSettings,
|
||||
basicSettingSave,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { v4 as uuidv4, validate as isValidUUID } from 'uuid'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { canvasState, currentCanvasPlanState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
@ -179,7 +179,7 @@ export function usePlan() {
|
||||
* objectNo에 해당하는 canvas 목록을 조회
|
||||
*/
|
||||
const getCanvasByObjectNo = async (userId, objectNo) => {
|
||||
return get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) =>
|
||||
return await get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) =>
|
||||
res.map((item, index) => ({
|
||||
id: item.id,
|
||||
userId: item.userId,
|
||||
@ -237,15 +237,15 @@ export function usePlan() {
|
||||
/**
|
||||
* id에 해당하는 canvas 데이터를 삭제
|
||||
*/
|
||||
const delCanvasById = (id) => {
|
||||
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` })
|
||||
const delCanvasById = async (id) => {
|
||||
return await promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` })
|
||||
}
|
||||
|
||||
/**
|
||||
* objectNo에 해당하는 canvas 데이터들을 삭제
|
||||
*/
|
||||
const delCanvasByObjectNo = (objectNo) => {
|
||||
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` })
|
||||
const delCanvasByObjectNo = async (objectNo) => {
|
||||
return await promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,19 +282,19 @@ export function usePlan() {
|
||||
* 새로운 plan 생성
|
||||
* 현재 plan의 데이터가 있을 경우 복제 여부를 확인
|
||||
*/
|
||||
const handleAddPlan = (userId, objectNo) => {
|
||||
const handleAddPlan = async (userId, objectNo) => {
|
||||
JSON.parse(currentCanvasData()).objects.length > 0
|
||||
? swalFire({
|
||||
text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.copy'),
|
||||
type: 'confirm',
|
||||
confirmFn: () => {
|
||||
postCanvasStatus(userId, objectNo, currentCanvasData())
|
||||
confirmFn: async () => {
|
||||
await postCanvasStatus(userId, objectNo, currentCanvasData())
|
||||
},
|
||||
denyFn: () => {
|
||||
postCanvasStatus(userId, objectNo, '')
|
||||
denyFn: async () => {
|
||||
await postCanvasStatus(userId, objectNo, '')
|
||||
},
|
||||
})
|
||||
: postCanvasStatus(userId, objectNo, '')
|
||||
: await postCanvasStatus(userId, objectNo, '')
|
||||
}
|
||||
|
||||
/**
|
||||
@ -317,10 +317,10 @@ export function usePlan() {
|
||||
/**
|
||||
* plan 삭제
|
||||
*/
|
||||
const handleDeletePlan = (e, id) => {
|
||||
const handleDeletePlan = async (e, id) => {
|
||||
e.stopPropagation() // 이벤트 버블링 방지
|
||||
|
||||
delCanvasById(id)
|
||||
await delCanvasById(id)
|
||||
.then((res) => {
|
||||
setPlans((plans) => plans.filter((plan) => plan.id !== id))
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
@ -344,8 +344,8 @@ export function usePlan() {
|
||||
/**
|
||||
* plan 조회
|
||||
*/
|
||||
const loadCanvasPlanData = (userId, objectNo, pid) => {
|
||||
getCanvasByObjectNo(userId, objectNo).then((res) => {
|
||||
const loadCanvasPlanData = async (userId, objectNo, pid) => {
|
||||
await getCanvasByObjectNo(userId, objectNo).then((res) => {
|
||||
// console.log('canvas 목록 ', res)
|
||||
if (res.length > 0) {
|
||||
setPlans(res)
|
||||
|
||||
@ -3,8 +3,8 @@ export const defaultSession = {}
|
||||
export const sessionOptions = {
|
||||
password: process.env.SESSION_SECRET,
|
||||
cookieName: 'lama-session',
|
||||
cookieOptions: {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
},
|
||||
// cookieOptions: {
|
||||
// httpOnly: true,
|
||||
// secure: process.env.NODE_ENV === 'production',
|
||||
// },
|
||||
}
|
||||
|
||||
@ -164,6 +164,7 @@
|
||||
"plan.menu.estimate.save": "保存",
|
||||
"plan.menu.estimate.reset": "初期化",
|
||||
"plan.menu.estimate.copy": "見積書のコピー",
|
||||
"plan.menu.estimate.unLock": "ロック解除",
|
||||
"plan.menu.simulation": "発展シミュレーション",
|
||||
"plan.menu.simulation.excel": "Excel",
|
||||
"plan.menu.simulation.pdf": "PDF",
|
||||
@ -841,6 +842,7 @@
|
||||
"estimate.detail.fileList.btn": "ファイル選択",
|
||||
"estimate.detail.fileList.extCheck": "そのファイルはイメージファイルではありません",
|
||||
"estimate.detail.header.fileList2": "添付ファイル一覧",
|
||||
"estimate.detail.fileList2.btn.return": "復元",
|
||||
"estimate.detail.header.specialEstimate": "見積もりの具体的な",
|
||||
"estimate.detail.header.specialEstimateProductInfo": "製品情報",
|
||||
"estimate.detail.sepcialEstimateProductInfo.totAmount": "数量 (PCS)",
|
||||
|
||||
@ -168,6 +168,7 @@
|
||||
"plan.menu.estimate.save": "저장",
|
||||
"plan.menu.estimate.reset": "초기화",
|
||||
"plan.menu.estimate.copy": "견적서 복사",
|
||||
"plan.menu.estimate.unLock": "잠금 해제",
|
||||
"plan.menu.simulation": "발전 시뮬레이션",
|
||||
"plan.menu.simulation.excel": "Excel",
|
||||
"plan.menu.simulation.pdf": "PDF",
|
||||
@ -851,6 +852,7 @@
|
||||
"estimate.detail.fileList.btn": "파일선택",
|
||||
"estimate.detail.fileList.extCheck": "해당 파일은 이미지 파일이 아닙니다",
|
||||
"estimate.detail.header.fileList2": "첨부파일 목록",
|
||||
"estimate.detail.fileList2.btn.return": "복원",
|
||||
"estimate.detail.header.specialEstimate": "견적특이사항",
|
||||
"estimate.detail.header.specialEstimateProductInfo": "제품정보",
|
||||
"estimate.detail.sepcialEstimateProductInfo.totAmount": "수량 (PCS)",
|
||||
|
||||
@ -113,7 +113,7 @@ export const calculateFlowDirection = (canvasAngle) => {
|
||||
return {
|
||||
down: -canvasAngle,
|
||||
up: 180 - canvasAngle,
|
||||
left: 90 - canvasAngle,
|
||||
right: -90 - canvasAngle,
|
||||
left: 90 - canvasAngle < 180 ? 90 - canvasAngle : 90 - canvasAngle - 360,
|
||||
right: -90 - canvasAngle < -180 ? -90 - canvasAngle + 360 : -90 - canvasAngle,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user