Merge branch 'dev' into feature/jaeyoung

# Conflicts:
#	src/hooks/useContextMenu.js
This commit is contained in:
Jaeyoung Lee 2025-02-03 10:35:09 +09:00
commit 5ef8ccfc40
117 changed files with 5880 additions and 2201 deletions

View File

@ -3,17 +3,32 @@
import { createContext, useEffect, useState } from 'react'
import { useLocalStorage } from 'usehooks-ts'
export const GlobalDataContext = createContext({
managementState: {},
setManagementState: () => {},
managementStateLoaded: null,
})
// export const GlobalDataContext = createContext({
// managementState: {},
// setManagementState: () => {},
// managementStateLoaded: null,
// })
export const GlobalDataContext = createContext(null)
const GlobalDataProvider = ({ children }) => {
const [managementState, setManagementState] = useState(null)
// TODO: 임시 조치이며 개발 완료시 삭제 예정 -> 잊지말기...
const [managementStateLoaded, setManagementStateLoaded] = useLocalStorage('managementStateLoaded', null)
// const pathname = usePathname()
// const setCorrentObjectNo = useSetRecoilState(correntObjectNoState)
// const searchParams = useSearchParams()
// const objectNo = searchParams.get('objectNo')
// const pid = searchParams.get('pid')
// useEffect(() => {
// if (pathname === '/floor-plan') {
// if (pid === undefined || pid === '' || pid === null || objectNo === undefined || objectNo === '' || objectNo === null) {
// notFound()
// }
// setCorrentObjectNo(objectNo)
// }
// }, [pathname])
useEffect(() => {
if (managementState !== null) {
setManagementStateLoaded(managementState)

View File

@ -0,0 +1,11 @@
'use client'
import { useContext } from 'react'
import { QcastContext } from './QcastProvider'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
export default function GlobalLoadingProvider() {
const { isGlobalLoading } = useContext(QcastContext)
return <>{isGlobalLoading && <GlobalSpinner />}</>
}

View File

@ -6,7 +6,6 @@ import { useCommonCode } from '@/hooks/common/useCommonCode'
import ServerError from './error'
import '@/styles/common.scss'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
export const QcastContext = createContext({
qcastState: {},
@ -17,7 +16,7 @@ export const QcastContext = createContext({
export const QcastProvider = ({ children }) => {
const [planSave, setPlanSave] = useState(false)
const [isGlobalLoading, setIsGlobalLoading] = useState(false)
const [isGlobalLoading, setIsGlobalLoading] = useState(true)
const { commonCode, findCommonCode } = useCommonCode()
const [qcastState, setQcastState] = useState({
@ -35,11 +34,6 @@ export const QcastProvider = ({ children }) => {
return (
<>
{isGlobalLoading && (
<div className="fixed inset-0 bg-white z-50 flex items-center justify-center">
<GlobalSpinner />
</div>
)}
<QcastContext.Provider value={{ qcastState, setQcastState, isGlobalLoading, setIsGlobalLoading }}>
<ErrorBoundary fallback={<ServerError />}>{children}</ErrorBoundary>
</QcastContext.Provider>

View File

@ -1,9 +1,9 @@
'ues client'
import { correntObjectNoState } from '@/store/settingAtom'
// import { correntObjectNoState } from '@/store/settingAtom'
import { notFound, usePathname, useSearchParams } from 'next/navigation'
import { createContext, useReducer, useState, useEffect } from 'react'
import { useSetRecoilState } from 'recoil'
// import { useSetRecoilState } from 'recoil'
const reducer = (prevState, nextState) => {
return { ...prevState, ...nextState }
@ -27,12 +27,12 @@ const defaultEstimateData = {
* 모듈,회로 구성 상태 데이터
* 설정 팝업 상태를 저장하는 데이터
*/
const defaultProcessStep = {
gnbStep: 0,
processStep: 0,
moduleCofigureData: {},
pcsConfigureData: {},
}
// const defaultProcessStep = {
// gnbStep: 0,
// processStep: 0,
// moduleCofigureData: {},
// pcsConfigureData: {},
// }
export const FloorPlanContext = createContext({
floorPlanState: {},
@ -42,20 +42,29 @@ export const FloorPlanContext = createContext({
})
const FloorPlanProvider = ({ children }) => {
const pathname = usePathname()
const setCurrentObjectNo = useSetRecoilState(correntObjectNoState)
// const pathname = usePathname()
// const setCorrentObjectNo = useSetRecoilState(correntObjectNoState)
const searchParams = useSearchParams()
const objectNo = searchParams.get('objectNo')
const pid = searchParams.get('pid')
// useEffect(() => {
// console.log('🚀 ~ useEffect ~ objectNo:')
// if (pathname === '/floor-plan') {
// if (pid === undefined || pid === '' || pid === null || objectNo === undefined || objectNo === '' || objectNo === null) {
// notFound()
// }
// setCorrentObjectNo(objectNo)
// }
// }, [])
useEffect(() => { // 오류 발생으로 useEffect 사용
if (pathname === '/floor-plan') {
if (pid === undefined || pid === '' || pid === null || objectNo === undefined || objectNo === '' || objectNo === null) {
notFound()
}
setCurrentObjectNo(objectNo)
}
}, [pid, objectNo])
//useEffect(() => { // 오류 발생으로 useEffect 사용
// if (pathname === '/floor-plan') {
// if (pid === undefined || pid === '' || pid === null || objectNo === undefined || objectNo === '' || objectNo === null) {
// notFound()
// }
// setCurrentObjectNo(objectNo)
// }
//}, [pid, objectNo])
const [floorPlanState, setFloorPlanState] = useState({
// 플랜 파일 업로드 모달 오픈 제어
@ -70,12 +79,10 @@ const FloorPlanProvider = ({ children }) => {
const [estimateContextState, setEstimateContextState] = useReducer(reducer, defaultEstimateData)
const [processStepState, setProcessStepState] = useReducer(reducer, defaultProcessStep)
// const [processStepState, setProcessStepState] = useReducer(reducer, defaultProcessStep)
return (
<FloorPlanContext.Provider
value={{ floorPlanState, setFloorPlanState, estimateContextState, setEstimateContextState, processStepState, setProcessStepState }}
>
<FloorPlanContext.Provider value={{ floorPlanState, setFloorPlanState, estimateContextState, setEstimateContextState }}>
{children}
</FloorPlanContext.Provider>
)

View File

@ -1,31 +1,22 @@
'use client'
import { usePathname } from 'next/navigation'
import FloorPlanProvider from './FloorPlanProvider'
import FloorPlan from '@/components/floor-plan/FloorPlan'
import CanvasLayout from '@/components/floor-plan/CanvasLayout'
import { Suspense } from 'react'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
export default function FloorPlanLayout({ children }) {
console.log('🚀 ~ FloorPlanLayout ~ FloorPlanLayout:')
const pathname = usePathname()
console.log('🚀 ~ FloorPlanLayout ~ pathname:', pathname)
return (
<>
<Suspense fallback={<GlobalSpinner />}>
<FloorPlanProvider>
<FloorPlan>
{/* {pathname.includes('estimate') || pathname.includes('simulator') ? (
<FloorPlanProvider>
<FloorPlan>
{/* {pathname.includes('estimate') || pathname.includes('simulator') ? (
<div className="canvas-layout">{children}</div>
) : (
<CanvasLayout>{children}</CanvasLayout>
)} */}
<CanvasLayout>{children}</CanvasLayout>
</FloorPlan>
</FloorPlanProvider>
</Suspense>
<CanvasLayout>{children}</CanvasLayout>
</FloorPlan>
</FloorPlanProvider>
</>
)
}

View File

@ -8,15 +8,13 @@ import SessionProvider from './SessionProvider'
import GlobalDataProvider from './GlobalDataProvider'
import Header from '@/components/header/Header'
import QModal from '@/components/common/modal/QModal'
import Dimmed from '@/components/ui/Dimmed'
import PopupManager from '@/components/common/popupManager/PopupManager'
import './globals.css'
import '../styles/style.scss'
import '../styles/contents.scss'
import Footer from '@/components/footer/Footer'
import { Suspense } from 'react'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
import GlobalLoadingProvider from './GlobalLoadingProvider'
export const metadata = {
title: 'Create Next App',
@ -66,24 +64,22 @@ export default async function RootLayout({ children }) {
<GlobalDataProvider>
<html lang="en">
<body>
<Suspense fallback={<GlobalSpinner />}>
{headerPathname === '/login' || headerPathname === '/join' ? (
<QcastProvider>{children}</QcastProvider>
) : (
<QcastProvider>
<div className="wrap">
<Header userSession={sessionProps} />
<div className="content">
<Dimmed />
<SessionProvider useSession={sessionProps}>{children}</SessionProvider>
</div>
<Footer />
{headerPathname === '/login' || headerPathname === '/join' ? (
<QcastProvider>{children}</QcastProvider>
) : (
<QcastProvider>
<GlobalLoadingProvider />
<div className="wrap">
<Header userSession={sessionProps} />
<div className="content">
<SessionProvider useSession={sessionProps}>{children}</SessionProvider>
</div>
</QcastProvider>
)}
<QModal />
<PopupManager />
</Suspense>
<Footer />
</div>
</QcastProvider>
)}
<QModal />
<PopupManager />
</body>
</html>
</GlobalDataProvider>

View File

@ -12,7 +12,8 @@ const ManagementProvider = ({ children }) => {
// }, [managementState])
// return <ManagementContext.Provider value={{ managementState, setManagementState }}>{children}</ManagementContext.Provider>
return <ManagementContext.Provider>{children}</ManagementContext.Provider>
// return <ManagementContext.Provider>{children}</ManagementContext.Provider>
return <>{children}</>
}
export default ManagementProvider

View File

@ -113,6 +113,7 @@ export const POLYGON_TYPE = {
TRESTLE: 'trestle',
MODULE_SETUP_SURFACE: 'moduleSetupSurface',
MODULE: 'module',
OBJECT_SURFACE: 'objectOffset',
}
export const SAVE_KEY = [
@ -170,6 +171,12 @@ export const SAVE_KEY = [
'supFitIntvlPct',
'rackLen',
'trestleDetail',
'turfPoints',
'tempIndex',
'surfaceId',
'moduleRowsTotCnt',
'seq',
'smartRackId',
]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]

View File

@ -27,6 +27,7 @@ import useSWR from 'swr'
import useSWRMutation from 'swr/mutation'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
import { moduleSelectionDataPlanListState } from '@/store/selectedModuleOptions'
export default function Playground() {
const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState)
@ -256,25 +257,25 @@ export default function Playground() {
})
}
const [callFlag, setCallFlag] = useState(false)
// const [callFlag, setCallFlag] = useState(false)
// const { data: tutoData, error, isLoading } = useSWR('http://localhost:8080/api/tutorial', getFetcher)
const { data: tutoData, error, isLoading } = useSWR(callFlag ? 'http://localhost:8080/api/tutorial' : null, getFetcher)
const { trigger, isMutating } = useSWRMutation('http://localhost:8080/api/tutorial', postFetcher)
// const { data: tutoData, error, isLoading } = useSWR(callFlag ? 'http://localhost:8080/api/tutorial' : null, getFetcher)
// const { trigger, isMutating } = useSWRMutation('http://localhost:8080/api/tutorial', postFetcher)
if (isLoading) {
return <div>Loading...</div>
}
// if (isLoading) {
// return <div>Loading...</div>
// }
if (error) {
return <div>Error...</div>
}
// if (error) {
// return <div>Error...</div>
// }
useCanvasPopupStatusController(1)
// const [moduleSelectionDataPlanListStore, setModuleSelectionDataPlanListStore] = useRecoilState(moduleSelectionDataPlanListState)
// useEffect(() => {
// console.log('🚀 ~ Playground ~ moduleSelectionDataPlanListStore:', moduleSelectionDataPlanListStore)
// }, [moduleSelectionDataPlanListStore])
// const { trigger: canvasPopupStatusTrigger } = useCanvasPopupStatusController({ objectNo: 'R201T01241120001', planNo: 2, popupType: 2 })
const [canvasPopupStatusState, setCanvasPopupStatusState] = useRecoilState(canvasPopupStatusStore)
useEffect(() => {
console.log('🚀 ~ Playground ~ canvasPopupStatusState:', canvasPopupStatusState)
}, [canvasPopupStatusState])
return (
<>
<div className="container mx-auto p-4 m-4 border">
@ -579,7 +580,7 @@ export default function Playground() {
Sweetalert - alert
</Button>
</div>
<div className="my-2">
{/* <div className="my-2">
{tutoData &&
tutoData.map((item) => (
<div key={item.id}>
@ -594,6 +595,301 @@ export default function Playground() {
<Button disabled={isMutating} onClick={() => trigger({ id: 3, name: 'seulda kim', email: 'seulda.kim@interplug.co.kr' })}>
insert data
</Button>
</div> */}
<div className="my-2">
<Button
onClick={() => {
canvasPopupStatusTrigger({
common: {
illuminationTp: '3',
instHt: '10',
stdWindSpeed: 'WL_32',
stdSnowLd: '5',
moduleTpCd: 'A1',
moduleItemId: '106796',
},
roofConstructions: [
{
roofIndex: 0,
addRoof: {
roofMatlCd: 'ROOF_ID_WA_53A',
roofMatlNm: '일본기와 A',
roofMatlNmJp: '和瓦A',
widAuth: 'R',
widBase: '265.000',
lenAuth: 'R',
lenBase: '235.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_WA_53A',
name: '일본기와 A',
selected: true,
index: 0,
nameJp: '和瓦A',
length: 235,
width: 265,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 7,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_WA_53A',
roofMatlCdNm: '일본기와 A',
roofMatlCdJp: '和瓦A',
trestleMkrCd: 'ROOF_TECHRI',
trestleMkrCdNm: '지붕 기술 연구소',
trestleMkrCdJp: '屋根技術研究所',
constMthdCd: 'CST026',
constMthdCdNm: 'YG 앵커 랙 있음',
constMthdCdJp: 'YGアンカー ラック有り',
roofBaseCd: 'RFB001',
roofBaseCdNm: '구조용 합판 9mm 이상',
roofBaseCdJp: '構造用合板9mm以上',
rackYn: null,
priority: 1,
},
construction: {
constTp: 'WORK_LV_ID_1',
constTpNm: '표준 시공',
constTpJp: '標準施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 0,
setupCover: true,
setupSnowCover: true,
selectedIndex: 1,
},
},
{
roofIndex: 1,
addRoof: {
roofMatlCd: 'ROOF_ID_WA_53B',
roofMatlNm: '일본기와 B',
roofMatlNmJp: '和瓦B',
widAuth: 'R',
widBase: '275.000',
lenAuth: 'R',
lenBase: '225.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_WA_53B',
name: '일본기와 B',
selected: true,
index: 1,
nameJp: '和瓦B',
length: 225,
width: 275,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 5,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_WA_53B',
roofMatlCdNm: '일본기와 B',
roofMatlCdJp: '和瓦B',
trestleMkrCd: 'DAIDO HUNT',
trestleMkrCdNm: '다이도 헌트',
trestleMkrCdJp: 'ダイドーハント',
constMthdCd: 'CST016',
constMthdCdNm: '지지 기와Ⅱ-B 랙 있음',
constMthdCdJp: '支持瓦Ⅱ-B ラック有り',
roofBaseCd: 'RFB002',
roofBaseCdNm: 'OSB12mm 이상',
roofBaseCdJp: 'OSB12mm以上',
rackYn: null,
priority: 95,
},
construction: {
constTp: 'WORK_LV_ID_1',
constTpNm: '표준 시공',
constTpJp: '標準施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 1,
setupCover: false,
setupSnowCover: true,
selectedIndex: 1,
},
},
{
roofIndex: 2,
addRoof: {
roofMatlCd: 'ROOF_ID_HIRA_C',
roofMatlNm: '평판기와 C',
roofMatlNmJp: '平板瓦C',
widAuth: 'R',
widBase: '305.000',
lenAuth: 'R',
lenBase: '280.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_HIRA_C',
name: '평판기와 C',
selected: true,
index: 2,
nameJp: '平板瓦C',
length: 280,
width: 305,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 4,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_HIRA_C',
roofMatlCdNm: '평판기와 C',
roofMatlCdJp: '平板瓦C',
trestleMkrCd: 'ROOF_TECHRI',
trestleMkrCdNm: '지붕 기술 연구소',
trestleMkrCdJp: '屋根技術研究所',
constMthdCd: 'CST034',
constMthdCdNm: '지지 기와 C 랙 있음',
constMthdCdJp: '支持瓦C ラック有り',
roofBaseCd: 'RFB001',
roofBaseCdNm: '구조용 합판 9mm 이상',
roofBaseCdJp: '構造用合板9mm以上',
rackYn: null,
priority: 122,
},
construction: {
constTp: 'WORK_LV_ID_1',
constTpNm: '표준 시공',
constTpJp: '標準施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 2,
setupCover: false,
setupSnowCover: false,
selectedIndex: 1,
},
},
{
roofIndex: 3,
addRoof: {
roofMatlCd: 'ROOF_ID_HIRA_D',
roofMatlNm: '평판기와 D',
roofMatlNmJp: '平板瓦D',
widAuth: 'R',
widBase: '305.000',
lenAuth: 'R',
lenBase: '280.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_HIRA_D',
name: '평판기와 D',
selected: true,
index: 3,
nameJp: '平板瓦D',
length: 280,
width: 305,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 8,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_HIRA_D',
roofMatlCdNm: '평판기와 D',
roofMatlCdJp: '平板瓦D',
trestleMkrCd: 'DAIDO HUNT',
trestleMkrCdNm: '다이도 헌트',
trestleMkrCdJp: 'ダイドーハント',
constMthdCd: 'CST018',
constMthdCdNm: '지지 기와Ⅱ-D 랙 있음',
constMthdCdJp: '支持瓦Ⅱ-D ラック有り',
roofBaseCd: 'RFB002',
roofBaseCdNm: 'OSB12mm 이상',
roofBaseCdJp: 'OSB12mm以上',
rackYn: null,
priority: 203,
},
construction: {
constTp: 'WORK_LV_ID_3',
constTpNm: '강화 시공',
constTpJp: '強化施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 3,
setupCover: false,
setupSnowCover: false,
selectedIndex: 2,
},
},
],
module: {
itemId: '106796',
itemNm: 'Q.TRON M-G2.4+ 430',
goodsNo: 'Q.TRON M-G2.4+ 430',
itemTp: 'A1',
mixMatlNo: null,
mixItemTpYn: 'N',
itemList: [
{
itemId: '106796',
itemNm: 'Q.TRON M-G2.4+ 430',
goodsNo: 'Q.TRON M-G2.4+ 430',
itemTp: 'A1',
color: '#BEF781',
longAxis: '1722.000',
shortAxis: '1134.000',
thickness: '30.000',
wpOut: '430',
mixMatlNo: null,
},
],
name: 'Q.TRON M-G2.4+ 430',
},
})
}}
>
Test Data insert
</Button>
</div>
</div>
</>

View File

@ -1,6 +1,6 @@
'use client'
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { useRouter } from 'next/navigation'
import { useMessage } from '@/hooks/useMessage'
@ -8,7 +8,11 @@ import Cookies from 'js-cookie'
import { isObjectNotEmpty, inputTelNumberCheck, inputNumberCheck } from '@/util/common-utils'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
export default function Join() {
const [isLoading, setIsLoading] = useState(false)
const { getMessage } = useMessage()
const { promisePost } = useAxios()
const router = useRouter()
@ -152,6 +156,8 @@ export default function Join() {
},
}
setIsLoading(true)
await promisePost({ url: '/api/login/v1.0/user/join', data: param })
.then((res) => {
if (res) {
@ -162,8 +168,10 @@ export default function Join() {
alert(res.data.result.resultMsg)
}
}
setIsLoading(false)
})
.catch((error) => {
setIsLoading(false)
alert(error.response.data.message)
})
}
@ -171,277 +179,280 @@ export default function Join() {
}
return (
<div className="center-page-wrap">
<div className="center-page-inner">
<form onSubmit={joinProcess}>
<div className="center-page-tit">{getMessage('join.title')}</div>
<div className="sub-table-box signup">
<div className="table-box-title-wrap">
<div className="title-wrap">
<h3>
{getMessage('join.sub1.title')} <span className="important">(*{getMessage('common.require')})</span>
</h3>
<span className="option">{getMessage('join.sub1.comment')}</span>
<>
{isLoading && <GlobalSpinner />}
<div className="center-page-wrap">
<div className="center-page-inner">
<form onSubmit={joinProcess}>
<div className="center-page-tit">{getMessage('join.title')}</div>
<div className="sub-table-box signup">
<div className="table-box-title-wrap">
<div className="title-wrap">
<h3>
{getMessage('join.sub1.title')} <span className="important">(*{getMessage('common.require')})</span>
</h3>
<span className="option">{getMessage('join.sub1.comment')}</span>
</div>
</div>
</div>
<div className="common-table">
<table>
<colgroup>
<col style={{ width: '180px' }} />
<col />
</colgroup>
<tbody>
{/* 판매대리점명 */}
<tr>
<th>
{getMessage('join.sub1.storeQcastNm')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '700px' }}>
<input
type="text"
id="storeQcastNm"
name="storeQcastNm"
alt={getMessage('join.sub1.storeQcastNm')}
className="input-light"
placeholder={getMessage('join.sub1.storeQcastNm_placeholder')}
maxLength={30}
ref={storeQcastNmRef}
/>
</div>
</td>
</tr>
{/* 판매대리점명 후리가나 */}
<tr>
<th>
{getMessage('join.sub1.storeQcastNmKana')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '700px' }}>
<input
type="text"
id="storeQcastNmKana"
name="storeQcastNmKana"
className="input-light"
placeholder={getMessage('join.sub1.storeQcastNmKana_placeholder')}
maxLength={30}
ref={storeQcastNmKanaRef}
/>
</div>
</td>
</tr>
{/* 우편번호/주소 */}
<tr>
<th>
{getMessage('join.sub1.postCd')}/{getMessage('join.sub1.addr')} <span className="important">*</span>
</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<div className="common-table">
<table>
<colgroup>
<col style={{ width: '180px' }} />
<col />
</colgroup>
<tbody>
{/* 판매대리점명 */}
<tr>
<th>
{getMessage('join.sub1.storeQcastNm')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '700px' }}>
<input
type="text"
id="postCd"
name="postCd"
id="storeQcastNm"
name="storeQcastNm"
alt={getMessage('join.sub1.storeQcastNm')}
className="input-light"
placeholder={getMessage('join.sub1.postCd_placeholder')}
onChange={inputNumberCheck}
maxLength={7}
ref={postCdRef}
placeholder={getMessage('join.sub1.storeQcastNm_placeholder')}
maxLength={30}
ref={storeQcastNmRef}
/>
</div>
<div className="input-wrap" style={{ width: '495px' }}>
</td>
</tr>
{/* 판매대리점명 후리가나 */}
<tr>
<th>
{getMessage('join.sub1.storeQcastNmKana')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '700px' }}>
<input
type="text"
id="addr"
name="addr"
id="storeQcastNmKana"
name="storeQcastNmKana"
className="input-light"
placeholder={getMessage('join.sub1.addr_placeholder')}
maxLength={50}
ref={addrRef}
placeholder={getMessage('join.sub1.storeQcastNmKana_placeholder')}
maxLength={30}
ref={storeQcastNmKanaRef}
/>
</div>
</div>
</td>
</tr>
{/* 전화번호 */}
<tr>
<th>
{getMessage('join.sub1.telNo')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="telNo"
name="telNo"
className="input-light"
placeholder={getMessage('join.sub1.telNo_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={telNoRef}
/>
</div>
</td>
</tr>
{/* FAX 번호 */}
<tr>
<th>
{getMessage('join.sub1.fax')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="fax"
name="fax"
className="input-light"
placeholder={getMessage('join.sub1.fax_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={faxRef}
/>
</div>
</td>
</tr>
{/* 법인번호 */}
<tr>
<th>{getMessage('join.sub1.bizNo')}</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="bizNo" name="bizNo" className="input-light" maxLength={15} onChange={inputTelNumberCheck} />
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="sub-table-box signup">
<div className="table-box-title-wrap">
<div className="title-wrap">
<h3>
{getMessage('join.sub2.title')} <span className="important">(*{getMessage('common.require')})</span>
</h3>
</td>
</tr>
{/* 우편번호/주소 */}
<tr>
<th>
{getMessage('join.sub1.postCd')}/{getMessage('join.sub1.addr')} <span className="important">*</span>
</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input
type="text"
id="postCd"
name="postCd"
className="input-light"
placeholder={getMessage('join.sub1.postCd_placeholder')}
onChange={inputNumberCheck}
maxLength={7}
ref={postCdRef}
/>
</div>
<div className="input-wrap" style={{ width: '495px' }}>
<input
type="text"
id="addr"
name="addr"
className="input-light"
placeholder={getMessage('join.sub1.addr_placeholder')}
maxLength={50}
ref={addrRef}
/>
</div>
</div>
</td>
</tr>
{/* 전화번호 */}
<tr>
<th>
{getMessage('join.sub1.telNo')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="telNo"
name="telNo"
className="input-light"
placeholder={getMessage('join.sub1.telNo_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={telNoRef}
/>
</div>
</td>
</tr>
{/* FAX 번호 */}
<tr>
<th>
{getMessage('join.sub1.fax')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="fax"
name="fax"
className="input-light"
placeholder={getMessage('join.sub1.fax_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={faxRef}
/>
</div>
</td>
</tr>
{/* 법인번호 */}
<tr>
<th>{getMessage('join.sub1.bizNo')}</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="bizNo" name="bizNo" className="input-light" maxLength={15} onChange={inputTelNumberCheck} />
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="common-table">
<table>
<colgroup>
<col style={{ width: '180px' }} />
<col />
</colgroup>
<tbody>
{/* 담당자명 */}
<tr>
<th>
{getMessage('join.sub2.userNm')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="userNm" name="userNm" className="input-light" maxLength={20} ref={userNmRef} />
</div>
</td>
</tr>
{/* 담당자명 후리가나 */}
<tr>
<th>{getMessage('join.sub2.userNmKana')}</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="userNmKana" name="userNmKana" maxLength={20} className="input-light" />
</div>
</td>
</tr>
{/* 신청 ID */}
<tr>
<th>
{getMessage('join.sub2.userId')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="userId" name="userId" className="input-light" maxLength={20} ref={userIdRef} />
</div>
</td>
</tr>
{/* 이메일 주소 */}
<tr>
<th>
{getMessage('join.sub2.email')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="email" name="email" className="input-light" maxLength={30} ref={emailRef} />
</div>
</td>
</tr>
{/* 전화번호 */}
<tr>
<th>
{getMessage('join.sub2.telNo')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="userTelNo"
name="userTelNo"
className="input-light"
placeholder={getMessage('join.sub2.telNo_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={userTelNoRef}
/>
</div>
</td>
</tr>
{/* FAX 번호 */}
<tr>
<th>
{getMessage('join.sub2.fax')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="userFax"
name="userFax"
className="input-light"
placeholder={getMessage('join.sub1.fax_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={userFaxRef}
/>
</div>
</td>
</tr>
{/* 부서명 */}
<tr>
<th>{getMessage('join.sub2.category')}</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="category" name="category" className="input-light" maxLength={20} />
</div>
</td>
</tr>
</tbody>
</table>
<div className="sub-table-box signup">
<div className="table-box-title-wrap">
<div className="title-wrap">
<h3>
{getMessage('join.sub2.title')} <span className="important">(*{getMessage('common.require')})</span>
</h3>
</div>
</div>
<div className="common-table">
<table>
<colgroup>
<col style={{ width: '180px' }} />
<col />
</colgroup>
<tbody>
{/* 담당자명 */}
<tr>
<th>
{getMessage('join.sub2.userNm')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="userNm" name="userNm" className="input-light" maxLength={20} ref={userNmRef} />
</div>
</td>
</tr>
{/* 담당자명 후리가나 */}
<tr>
<th>{getMessage('join.sub2.userNmKana')}</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="userNmKana" name="userNmKana" maxLength={20} className="input-light" />
</div>
</td>
</tr>
{/* 신청 ID */}
<tr>
<th>
{getMessage('join.sub2.userId')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="userId" name="userId" className="input-light" maxLength={20} ref={userIdRef} />
</div>
</td>
</tr>
{/* 이메일 주소 */}
<tr>
<th>
{getMessage('join.sub2.email')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="email" name="email" className="input-light" maxLength={30} ref={emailRef} />
</div>
</td>
</tr>
{/* 전화번호 */}
<tr>
<th>
{getMessage('join.sub2.telNo')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="userTelNo"
name="userTelNo"
className="input-light"
placeholder={getMessage('join.sub2.telNo_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={userTelNoRef}
/>
</div>
</td>
</tr>
{/* FAX 번호 */}
<tr>
<th>
{getMessage('join.sub2.fax')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input
type="text"
id="userFax"
name="userFax"
className="input-light"
placeholder={getMessage('join.sub1.fax_placeholder')}
maxLength={15}
onChange={inputTelNumberCheck}
ref={userFaxRef}
/>
</div>
</td>
</tr>
{/* 부서명 */}
<tr>
<th>{getMessage('join.sub2.category')}</th>
<td>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" id="category" name="category" className="input-light" maxLength={20} />
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div className="sign-up-btn-wrap">
<button
type="button"
className="btn-origin grey mr5"
onClick={() => {
router.push('/login')
}}
>
{getMessage('join.btn.login_page')}
</button>
<button type="submit" className="btn-origin navy">
{getMessage('join.btn.approval_request')}
</button>
</div>
</form>
<div className="sign-up-btn-wrap">
<button
type="button"
className="btn-origin grey mr5"
onClick={() => {
router.push('/login')
}}
>
{getMessage('join.btn.login_page')}
</button>
<button type="submit" className="btn-origin navy">
{getMessage('join.btn.approval_request')}
</button>
</div>
</form>
</div>
</div>
</div>
</>
)
}

View File

@ -33,9 +33,9 @@ export default function ColorPickerModal(props) {
}, [isShow])
return (
<WithDraggable isShow={true} pos={pos ?? ''}>
<WithDraggable isShow={true} pos={pos ?? ''} handle=".modal-handle">
<div className={`modal-pop-wrap lr mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.color.picker.title')}</h1>
<button
className="modal-close"
@ -78,6 +78,7 @@ export default function ColorPickerModal(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -20,7 +20,7 @@ export default function WithDraggable({ isShow, children, pos = { x: 0, y: 0 },
<Draggable
position={{ x: position.x, y: position.y }}
onDrag={(e, data) => handleOnDrag(e, data)}
handle={handle === '' ? '.modal-head' : handle}
handle={handle === '' ? '.modal-handle' : handle}
>
{children}
</Draggable>

View File

@ -67,9 +67,9 @@ export default function FontSetting(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<WithDraggable isShow={true} pos={pos} handle=".modal-handle">
<div className={`modal-pop-wrap lrr mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.font')}</h1>
<button
className="modal-close"
@ -133,6 +133,7 @@ export default function FontSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -59,8 +59,6 @@ export default function QSelectBox({
const ref = useRef(null)
const handleClickSelectOption = (option) => {
console.log('🚀 ~ handleClickSelectOption ~ option:', option)
setSelected(showKey !== '' ? option[showKey] : option.name)
onChange?.(option, params)
}
@ -77,7 +75,11 @@ export default function QSelectBox({
useOnClickOutside(ref, handleClose)
return (
<div className={`sort-select ${openSelect ? 'active' : ''}`} ref={ref} onClick={disabled ? () => {} : () => setOpenSelect(!openSelect)}>
<div
className={`sort-select ${openSelect ? 'active' : ''} ${disabled ? 'disabled' : ''}`}
ref={ref}
onClick={disabled ? () => {} : () => setOpenSelect(!openSelect)}
>
<p>{selected}</p>
<ul className="select-item-wrap">
{options?.length > 0 &&

View File

@ -54,31 +54,6 @@ export default function ArchiveTable({ clsCode }) {
fetchData()
}, [search.searchValue, search.searchFlag])
//
const handleDetailFileListDown = async (noticeNo) => {
const url = `/api/board/detail`
const params = new URLSearchParams({
noticeNo: noticeNo,
})
const apiUrl = `${url}?${params.toString()}`
const resultData = await get({ url: apiUrl })
if (resultData) {
if (resultData.result.code === 200) {
const boardDetailFileList = resultData.data.listFile
if (boardDetailFileList && Array.isArray(boardDetailFileList)) {
boardDetailFileList.forEach((boardFile) => {
handleFileDown(boardFile)
})
}
} else {
alert(resultData.result.message)
}
}
}
return (
<>
{boardList.length > 0 ? (
@ -101,7 +76,7 @@ export default function ArchiveTable({ clsCode }) {
</div>
<div className="file-down-box">
{/* 첨부파일 */}
<button type="button" className="file-down-btn" onClick={() => handleDetailFileListDown(board.noticeNo)}></button>
<button type="button" className="file-down-btn" onClick={() => handleFileDown(board.noticeNo, 'Y')}></button>
</div>
</div>
))}

View File

@ -41,6 +41,7 @@ export default function Table({ clsCode }) {
schTitle: search.searchValue ? search.searchValue : '',
startRow: startRow,
endRow: endRow,
schMainYn: 'N',
})
const apiUrl = `${url}?${params.toString()}`

View File

@ -61,7 +61,7 @@ export default function BoardDetailModal({ noticeNo, setOpen }) {
<dt>{getMessage('board.sub.fileList')}</dt>
{boardDetail.listFile.map((boardFile) => (
<dd key={boardFile.encodeFileNo}>
<button type="button" className="down" onClick={() => handleFileDown(boardFile)}>
<button type="button" className="down" onClick={() => handleFileDown(boardFile.fileNo, 'N')}>
{boardFile.srcFileNm}
</button>
</dd>

View File

@ -99,7 +99,9 @@ export default function Estimate({}) {
const initEstimate = (currPid = currentPid) => {
console.log('🚀 ~ initEstimate ~ currPid:', currPid)
closeAll()
setMenuNumber(5)
setObjectNo(objectRecoil.floorPlanObjectNo)
setPlanNo(currPid)
@ -133,11 +135,10 @@ export default function Estimate({}) {
useEffect(() => {
console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan)
if (selectedPlan) initEstimate(selectedPlan.ordering)
if (selectedPlan) initEstimate(selectedPlan.planNo)
}, [selectedPlan])
useEffect(() => {
closeAll()
initEstimate()
}, [])
@ -619,7 +620,7 @@ export default function Estimate({}) {
updates.partAdd = '0'
updates.saleTotPrice = (Number(amount.replaceAll(',', '')) * estimateContextState.itemList[index].salePrice.replaceAll(',', '')).toLocaleString()
updates.showSaleTotPrice = (
Number(amount.replaceAll(',', '')) * estimateContextState.itemList[index].showSalePrice?.replaceAll(',', '')
Number(amount.replaceAll(',', '')) * estimateContextState.itemList[index].salePrice?.replaceAll(',', '')
).toLocaleString()
updateList = estimateContextState.itemList.map((item) => {
@ -681,7 +682,6 @@ export default function Estimate({}) {
let updateList = []
let updates = {}
get({ url: apiUrl }).then((res) => {
// console.log('::::::::', res)
updates.objectNo = objectNo
updates.planNo = planNo
updates.itemId = res.itemId
@ -706,7 +706,6 @@ export default function Estimate({}) {
updates.openFlg = res.openFlg
if (estimateContextState.estimateType === 'YJSS') {
// console.log('YJSS:::,', res.pkgMaterialFlg)
if (res.pkgMaterialFlg === '0') {
updates.showSalePrice = '0'
updates.showSaleTotPrice = '0'
@ -721,14 +720,19 @@ export default function Estimate({}) {
//104671
let bomList = res.itemBomList
// console.log('updates::', updates)
updateList = estimateContextState.itemList.map((item) => {
if (item.dispOrder === dispOrder) {
if (item?.addFlg) {
return { ...item, ...updates, saleTotPrice: '' }
} else {
if (estimateContextState.estimateType === 'YJSS') {
return { ...item, ...updates, salePrice: '', saleTotPrice: '' }
// return { ...item, ...updates, salePrice: '', saleTotPrice: '' }
//
if (updates.pkgMaterialFlg === '1') {
return { ...item, ...updates, showSalePrice: updates.salePrice }
} else {
return { ...item, ...updates, salePrice: '', saleTotPrice: '' }
}
} else {
return { ...item, ...updates }
}
@ -739,7 +743,6 @@ export default function Estimate({}) {
return item
}
})
//paDispOrder
if (bomList) {
bomList.map((bomItem, index) => {
@ -879,7 +882,6 @@ export default function Estimate({}) {
}
const calculateYJSSTotals = (itemList) => {
// console.log(':::itemList::', itemList)
itemList.sort((a, b) => a.dispOrder - b.dispOrder)
makeUniqueSpecialNoteCd(itemList)
itemList.forEach((item) => {
@ -918,7 +920,6 @@ export default function Estimate({}) {
}
}
})
// console.log('itemList::', itemList)
let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
@ -949,30 +950,138 @@ export default function Estimate({}) {
setItemChangeYn(false)
} else {
estimateContextState.itemList.forEach((item) => {
if (estimateContextState.estimateType === 'YJSS' && !item.paDispOrder && item.pkgMaterialFlg === '0') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (estimateContextState.estimateType === 'YJSS' && item.openFlg === '1') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (estimateContextState.estimateType === 'YJSS' && item.paDispOrder) {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
})
estimateContextState.itemList.forEach((item) => {
if (estimateContextState.estimateType === 'YJOD' && item.openFlg === '1') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (estimateContextState.estimateType === 'YJOD' && item.paDispOrder) {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
})
let totals = {
totAmount: 0,
totVolKw: 0,
supplyPrice: 0,
vatPrice: 0,
totPrice: 0,
addSupplyPrice: 0,
pkgTotPrice: 0,
}
estimateContextState.itemList.sort((a, b) => a.dispOrder - b.dispOrder)
makeUniqueSpecialNoteCd(estimateContextState.itemList)
if (estimateContextState.estimateType === 'YJSS') {
estimateContextState.itemList.forEach((item) => {
if (estimateContextState.estimateType === 'YJSS' && !item.paDispOrder && item.pkgMaterialFlg === '0') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (estimateContextState.estimateType === 'YJSS' && item.openFlg === '1') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (estimateContextState.estimateType === 'YJSS' && item.paDispOrder) {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
})
estimateContextState.itemList.forEach((item) => {
if (item.delFlg === '0') {
let amount = Number(item.amount?.replace(/[^0-9]/g, '').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') {
const saleTotPrice = amount * salePrice
totals.addSupplyPrice += saleTotPrice
}
if (!item.paDispOrder) {
if (item.pkgMaterialFlg === '0') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
} else {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (item.openFlg === '1') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
}
})
let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
totals.supplyPrice = totals.addSupplyPrice + totals.pkgTotPrice
totals.vatPrice = totals.supplyPrice * 0.1
totals.totPrice = totals.supplyPrice + totals.vatPrice
setEstimateContextState({
pkgTotPrice: totals.pkgTotPrice,
totAmount: totals.totAmount,
totVolKw: totals.totVolKw.toFixed(2),
supplyPrice: totals.supplyPrice.toFixed(0), //
vatPrice: totals.vatPrice.toFixed(0), //
totPrice: totals.totPrice.toFixed(0), //
})
} else {
estimateContextState.itemList.forEach((item) => {
if (estimateContextState.estimateType === 'YJOD' && item.openFlg === '1') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (estimateContextState.estimateType === 'YJOD' && item.paDispOrder) {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
})
estimateContextState.itemList.forEach((item) => {
delete item.showSalePrice
delete item.showSaleTotPrice
if (item.delFlg === '0') {
let amount = Number(item.amount?.replace(/[^0-9]/g, '').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.supplyPrice += price
totals.totAmount += amount
if (item.paDispOrder) {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (item.openFlg === '1') {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
}
})
totals.vatPrice = totals.supplyPrice * 0.1
totals.totPrice = totals.supplyPrice + totals.vatPrice
setEstimateContextState({
totAmount: totals.totAmount,
totVolKw: totals.totVolKw.toFixed(2),
supplyPrice: totals.supplyPrice.toFixed(0), //
vatPrice: totals.vatPrice.toFixed(0), //
totPrice: totals.totPrice.toFixed(0), //
})
}
}
}, [itemChangeYn, estimateContextState.itemList])
@ -1006,7 +1115,7 @@ export default function Estimate({}) {
<div className="estimate-tit">{getMessage('estimate.detail.objectNo')}</div>
<div className="estimate-name">
{/* {objectNo} (Plan No: {estimateContextState.planNo}) */}
{objectNo} (Plan No: {planNo})
{currentObjectNo} (Plan No: {planNo})
</div>
</div>
<div className="estimate-box">
@ -1076,7 +1185,6 @@ export default function Estimate({}) {
</th>
<td>
<div className="input-wrap" style={{ width: '350px' }}>
{/* <input type="text" className="input-light" defaultValue={estimateContextState?.charger} onBlur={handleBlurCharger} /> */}
<input
type="text"
className="input-light"
@ -1095,7 +1203,6 @@ export default function Estimate({}) {
<td colSpan={3}>
<div className="form-flex-wrap">
<div className="input-wrap mr5" style={{ width: '610px' }}>
{/* <input type="text" className="input-light" defaultValue={estimateContextState?.objectName} onBlur={handleBlurObjectName} /> */}
<input
type="text"
className="input-light"

View File

@ -1,6 +1,6 @@
'use client'
import { useEffect, useRef } from 'react'
import { useContext, useEffect, useRef } from 'react'
import { useRecoilValue } from 'recoil'
@ -14,21 +14,25 @@ import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitial
import { currentMenuState } from '@/store/canvasAtom'
import { totalDisplaySelector } from '@/store/settingAtom'
import { MENU } from '@/common/common'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { QcastContext } from '@/app/QcastProvider'
export default function CanvasFrame() {
const canvasRef = useRef(null)
const { canvas } = useCanvas('canvas')
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
const currentMenu = useRecoilValue(currentMenuState)
const { floorPlanState } = useContext(FloorPlanContext)
const { contextMenu, handleClick } = useContextMenu()
const { selectedPlan } = usePlan()
const { currentCanvasPlan } = usePlan()
const totalDisplay = useRecoilValue(totalDisplaySelector) //
const { setIsGlobalLoading } = useContext(QcastContext)
const loadCanvas = () => {
if (canvas) {
canvas?.clear() // .
if (selectedPlan?.canvasStatus) {
canvas?.loadFromJSON(JSON.parse(selectedPlan.canvasStatus), function () {
if (currentCanvasPlan?.canvasStatus && floorPlanState.objectNo === currentCanvasPlan.objectNo) {
canvas?.loadFromJSON(JSON.parse(currentCanvasPlan.canvasStatus), function () {
canvasLoadInit() //config
canvas?.renderAll() // .
})
@ -39,7 +43,11 @@ export default function CanvasFrame() {
useEffect(() => {
loadCanvas()
}, [selectedPlan, canvas])
}, [currentCanvasPlan, canvas])
useEffect(() => {
setIsGlobalLoading(false)
}, [])
return (
<div className="canvas-frame">

View File

@ -30,22 +30,22 @@ export default function CanvasLayout({ children }) {
<div className="canvas-layout">
<div className={`canvas-page-list ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
<div className="canvas-plane-wrap">
{plans.map((plan) => (
{plans.map((plan, index) => (
<button
key={`plan-${plan.id}`}
className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`}
onClick={() => handleCurrentPlan(plan.id)}
>
<span>{`Plan ${plan.ordering}`}</span>
{plan.ordering !== 1 && (
<span>{`Plan ${plan.planNo}`}</span>
{index !== 0 && (
<i
className="close"
onClick={(e) =>
swalFire({
text: `Plan ${plan.ordering} ` + getMessage('plan.message.confirm.delete'),
text: `Plan ${plan.planNo} ` + getMessage('plan.message.confirm.delete'),
type: 'confirm',
confirmFn: () => {
handleDeletePlan(e, plan.id)
handleDeletePlan(e, plan)
},
})
}

View File

@ -41,9 +41,10 @@ import { isObjectNotEmpty } from '@/util/common-utils'
import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json'
import { MENU } from '@/common/common'
import { MENU, POLYGON_TYPE } from '@/common/common'
import { QcastContext } from '@/app/QcastProvider'
export default function CanvasMenu(props) {
const { menuNumber, setMenuNumber } = props
const pathname = usePathname()
@ -101,6 +102,8 @@ export default function CanvasMenu(props) {
const { setIsGlobalLoading } = useContext(QcastContext)
//
const { selectedPlan } = usePlan()
const handleExcelPdfFileDown = async (donwloadType, drawingFlg) => {
const url = '/api/estimate/excel-download'
@ -164,18 +167,23 @@ export default function CanvasMenu(props) {
setType('surface')
break
case 4:
setType('module')
if (!checkMenuAndCanvasState()) {
swalFire({ text: getMessage('menu.validation.canvas.roof') })
return
} else {
setType('module')
}
break
case 5:
// let pid = urlParams.get('pid')
promiseGet({ url: `/api/estimate/${objectNo}/${pid}/detail` }).then((res) => {
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) {
const estimateDetail = res.data
if (estimateDetail.docNo) {
if (estimateDetail.tempFlg === '0' && estimateDetail.estimateDate !== null) {
setMenuNumber(menu.index)
setCurrentMenu(menu.title)
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
router.push(`/floor-plan/estimate/5?pid=${pid}&objectNo=${objectNo}`)
router.push(`/floor-plan/estimate/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
} else {
swalFire({ text: getMessage('estimate.menu.move.valid1') })
}
@ -183,13 +191,13 @@ export default function CanvasMenu(props) {
})
break
case 6:
promiseGet({ url: `/api/estimate/${objectNo}/${pid}/detail` }).then((res) => {
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) {
const estimateDetail = res.data
if (estimateDetail.docNo) {
if (estimateDetail.tempFlg === '0') {
setMenuNumber(menu.index)
setCurrentMenu(menu.title)
router.push(`/floor-plan/simulator/${menu.index}?pid=${pid}&objectNo=${objectNo}`)
router.push(`/floor-plan/simulator/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
} else {
swalFire({ text: getMessage('simulator.menu.move.valid1') })
}
@ -203,8 +211,10 @@ export default function CanvasMenu(props) {
setCurrentMenu(menu.title)
}
if (pathname !== '/floor-plan' && pathname !== '/floor-plan/estimate/5' && pathname !== '/floor-plan/simulator/6') {
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
if (pathname !== '/floor-plan') {
if (menu.index !== 0) {
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
}
}
}
@ -235,6 +245,20 @@ export default function CanvasMenu(props) {
await saveCanvas()
}
//
const handleLeaveCanvas = () => {
swalFire({
text: getMessage('plan.message.leave'),
type: 'confirm',
confirmButtonText: getMessage('plan.message.corfirm.yes'),
cancelButtonText: getMessage('plan.message.confirm.no'),
confirmFn: async () => {
await handleSaveCanvas()
router.push(`/management/stuff`)
},
})
}
const [placementInitialId, setPlacementInitialId] = useState(uuidv4())
const placementInitialProps = {
id: placementInitialId,
@ -323,6 +347,14 @@ export default function CanvasMenu(props) {
return (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && menu.index === 2)
}
const checkMenuAndCanvasState = () => {
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
//
const isExist = roofs?.some((roof) => roof.roofMaterial)
console.log('🚀 ~ checkMenuAndCanvasState ~ isExist:', isExist)
return isExist
}
useEffect(() => {
if (isObjectNotEmpty(estimateRecoilState)) {
if (estimateRecoilState?.createUser === 'T01') {
@ -368,7 +400,9 @@ export default function CanvasMenu(props) {
*/
const handleEstimateLockController = (estimateRecoilState) => {
swalFire({
text: estimateRecoilState.lockFlg === '0' ? getMessage('estimate.detail.lock.alertMsg') : getMessage('estimate.detail.unlock.alertMsg'),
// text: estimateRecoilState.lockFlg === '0' ? getMessage('estimate.detail.lock.alertMsg') : getMessage('estimate.detail.unlock.alertMsg'),
html: estimateRecoilState.lockFlg === '0' ? getMessage('estimate.detail.lock.alertMsg') : getMessage('estimate.detail.unlock.alertMsg'),
confirmButtonText: estimateRecoilState.lockFlg === '1' ? getMessage('estimate.detail.unlock.confirmBtnName') : '',
type: 'confirm',
confirmFn: async () => {
setIsGlobalLoading(true)
@ -511,7 +545,7 @@ export default function CanvasMenu(props) {
</div>
<div className="btn-from">
<button className="btn08" onClick={handleSaveCanvas}></button>
<button className="btn09"></button>
<button className="btn09" onClick={handleLeaveCanvas}></button>
</div>
</>
)}

View File

@ -1,37 +1,53 @@
'use client'
import { useEffect } from 'react'
//import { useRecoilState } from 'recoil'
import CanvasMenu from '@/components/floor-plan/CanvasMenu'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { usePopup } from '@/hooks/usePopup'
//import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
//import { correntObjectNoState } from '@/store/settingAtom'
import '@/styles/contents.scss'
import { notFound, useSearchParams } from 'next/navigation'
import { useRecoilState } from 'recoil'
import { correntObjectNoState } from '@/store/settingAtom'
export default function FloorPlan({ children }) {
//const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext)
//const [correntObjectNo, setCorrentObjectNo] = useRecoilState(correntObjectNoState)
const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState)
const searchParams = useSearchParams()
const objectNo = searchParams.get('objectNo')
const pid = searchParams.get('pid')
const { closeAll } = usePopup()
const { menuNumber, setMenuNumber } = useCanvasMenu()
const { fetchSettings } = useCanvasSetting()
const { fetchSettings, fetchBasicSettings } = useCanvasSetting()
// URL objectNo
useEffect(() => {
if (!objectNo) {
notFound()
}
setCurrentObjectNo(objectNo)
}, [objectNo, setCurrentObjectNo])
// fetch
useEffect(() => {
if (!correntObjectNo) return // correntObjectNo
if(menuNumber === null) {
setMenuNumber(1)
}
fetchSettings()
fetchBasicSettings()
return () => {
closeAll()
}
}, [correntObjectNo])
const modalProps = {
menuNumber,
setMenuNumber,
}
useEffect(() => {
///setCorrentObjectNo(floorPlanState.objectNo)
//console.log('FloorPlan objectNo ', floorPlanState.objectNo, correntObjectNo)
setMenuNumber(1)
fetchSettings()
return () => {
closeAll()
}
}, [])
return (
<>
<div className="canvas-wrap">

View File

@ -15,7 +15,7 @@ export default function Slope({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.slope.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -45,6 +45,7 @@ export default function Slope({ id, pos = { x: 50, y: 230 } }) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -126,7 +126,7 @@ export default function AuxiliaryDrawing({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.auxiliary.drawing')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -160,6 +160,7 @@ export default function AuxiliaryDrawing({ id, pos = { x: 50, y: 230 } }) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -46,7 +46,7 @@ export default function AuxiliaryEdit(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage(type === 'copy' ? 'modal.auxiliary.copy' : 'modal.auxiliary.move')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -111,6 +111,7 @@ export default function AuxiliaryEdit(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -14,7 +14,7 @@ export default function AuxiliarySize(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.auxiliary.size.edit')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -63,6 +63,7 @@ export default function AuxiliarySize(props) {
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -11,6 +11,11 @@ import { usePopup } from '@/hooks/usePopup'
import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { useEvent } from '@/hooks/useEvent'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { addedRoofsState } from '@/store/settingAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
import Swal from 'sweetalert2'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const { getMessage } = useMessage()
@ -20,13 +25,32 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const orientationRef = useRef(null)
const { initEvent } = useEvent()
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
const addedRoofs = useRecoilValue(addedRoofsState)
// const { initEvent } = useContext(EventContext)
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting()
const handleBtnNextStep = () => {
if (tabNum === 1) {
orientationRef.current.handleNextStep()
} else if (tabNum === 2) {
if (!isObjectNotEmpty(moduleSelectionData.module)) {
Swal.fire({
title: getMessage('module.not.found'),
icon: 'warning',
})
return
}
if (addedRoofs.length !== moduleSelectionData.roofConstructions.length) {
Swal.fire({
title: getMessage('construction.length.difference'),
icon: 'warning',
})
return
}
}
setTabNum(tabNum + 1)
}
@ -51,7 +75,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lx-2`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.module.circuit.setting.default')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -115,6 +139,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
)}
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -1,28 +1,31 @@
import { useEffect, useState, useReducer } from 'react'
import { useEffect, useState, useReducer, useRef } from 'react'
import { useRecoilValue, useRecoilState } from 'recoil'
import { addedRoofsState } from '@/store/settingAtom'
import { canvasSettingState, pitchSelector } from '@/store/canvasAtom'
import { currentCanvasPlanState } from '@/store/canvasAtom'
import { useMessage } from '@/hooks/useMessage'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useModuleSelection } from '@/hooks/module/useModuleSelection'
import ModuleTabContents from './ModuleTabContents'
import { useDebounceCallback, useDebounceValue } from 'usehooks-ts'
import { useDebounceValue } from 'usehooks-ts'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { isObjectNotEmpty } from '@/util/common-utils'
export default function Module({ setTabNum }) {
const { getMessage } = useMessage()
const addedRoofs = useRecoilValue(addedRoofsState) //
const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState) //
const [roofTab, setRoofTab] = useState(0) //
const {
moduleSelectionInitParams,
selectedModules,
raftCodes,
roughnessCodes,
windSpeedCodes,
managementState,
moduleList,
selectedSurfaceType,
installHeight,
standardWindSpeed,
verticalSnowCover,
handleChangeModule,
handleChangeSurfaceType,
@ -31,8 +34,8 @@ export default function Module({ setTabNum }) {
handleChangeVerticalSnowCover,
} = useModuleSelection({ addedRoofs })
const [inputInstallHeight, setInputInstallHeight] = useState(installHeight)
const [inputVerticalSnowCover, setInputVerticalSnowCover] = useState(verticalSnowCover)
const [inputInstallHeight, setInputInstallHeight] = useState()
const [inputVerticalSnowCover, setInputVerticalSnowCover] = useState()
const [debouncedInstallHeight] = useDebounceValue(inputInstallHeight, 500)
const [debouncedVerticalSnowCover] = useDebounceValue(inputVerticalSnowCover, 500)
@ -44,18 +47,38 @@ export default function Module({ setTabNum }) {
}, moduleSelectionData)
useEffect(() => {
handleChangeInstallHeight(debouncedInstallHeight)
if (installHeight) {
setInputInstallHeight(installHeight)
}
if (verticalSnowCover) {
setInputVerticalSnowCover(verticalSnowCover)
}
}, [installHeight, verticalSnowCover])
useEffect(() => {
if (tempModuleSelectionData.roofConstructions.length > 0) {
if (tempModuleSelectionData.common.moduleItemId && isObjectNotEmpty(tempModuleSelectionData.module)) {
// temp (addedRoofs)
if (tempModuleSelectionData.roofConstructions.length === addedRoofs.length) {
setModuleSelectionData(tempModuleSelectionData)
moduleSelectedDataTrigger(tempModuleSelectionData)
}
}
}
}, [tempModuleSelectionData])
useEffect(() => {
if (debouncedInstallHeight) {
handleChangeInstallHeight(debouncedInstallHeight)
}
}, [debouncedInstallHeight])
useEffect(() => {
handleChangeVerticalSnowCover(debouncedVerticalSnowCover)
if (debouncedVerticalSnowCover) {
handleChangeVerticalSnowCover(debouncedVerticalSnowCover)
}
}, [debouncedVerticalSnowCover])
useEffect(() => {
setInputInstallHeight(installHeight)
setInputVerticalSnowCover(verticalSnowCover)
}, [installHeight, verticalSnowCover])
const moduleData = {
header: [
{ name: getMessage('module'), width: 150, prop: 'module', type: 'color-box' },
@ -69,16 +92,12 @@ export default function Module({ setTabNum }) {
rows: [],
}
useEffect(() => {}, [roofTab])
useEffect(() => {
console.log('moduleSelectionData', moduleSelectionData)
}, [])
const handleRoofTab = (tab) => {
setRoofTab(tab)
}
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
return (
<>
<div className="roof-module-tab2-overflow">
@ -114,21 +133,20 @@ export default function Module({ setTabNum }) {
</tr>
</thead>
<tbody>
{selectedModules.itemList &&
selectedModules.itemList.map((row) => (
<>
<tr>
<td>
<div className="color-wrap">
<span className="color-box" style={{ backgroundColor: row.color }}></span>
<span className="name">{row.itemNm}</span>
</div>
</td>
<td className="al-r">{Number(row.shortAxis).toFixed(0)}</td>
<td className="al-r">{Number(row.longAxis).toFixed(0)}</td>
<td className="al-r">{Number(row.wpOut).toFixed(0)}</td>
</tr>
</>
{selectedModules &&
selectedModules.itemList &&
selectedModules.itemList.map((row, index) => (
<tr key={index}>
<td>
<div className="color-wrap">
<span className="color-box" style={{ backgroundColor: row.color }}></span>
<span className="name">{row.itemNm}</span>
</div>
</td>
<td className="al-r">{Number(row.shortAxis).toFixed(0)}</td>
<td className="al-r">{Number(row.longAxis).toFixed(0)}</td>
<td className="al-r">{Number(row.wpOut).toFixed(0)}</td>
</tr>
))}
</tbody>
</table>
@ -232,11 +250,10 @@ export default function Module({ setTabNum }) {
<div style={{ display: roofTab === index ? 'block' : 'none' }} key={index}>
<ModuleTabContents
key={index}
index={index}
tabIndex={index}
addRoof={roof}
roofTab={index}
moduleConstructionSelectionData={moduleSelectionData.roofConstructions[index]}
setModuleSelectionData={setModuleSelectionData}
setAddedRoofs={setAddedRoofs}
roofTab={roofTab}
tempModuleSelectionData={tempModuleSelectionData}
setTempModuleSelectionData={setTempModuleSelectionData}
/>

View File

@ -1,288 +1,42 @@
import { useEffect, useState, useRef } from 'react'
import { useRecoilValue } from 'recoil'
import { pitchTextSelector } from '@/store/canvasAtom'
import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { moduleSelectionInitParamsState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty } from '@/util/common-utils'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useModuleTabContents } from '@/hooks/module/useModuleTabContents'
export default function ModuleTabContents({
addRoof,
roofTab,
moduleConstructionSelectionData,
setModuleSelectionData,
tempModuleSelectionData,
setTempModuleSelectionData,
}) {
export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab, tempModuleSelectionData, setTempModuleSelectionData }) {
const { getMessage } = useMessage()
const [roofMaterial, setRoofMaterial] = useState(addRoof) //`
const globalPitchText = useRecoilValue(pitchTextSelector) //
const { findCommonCode } = useCommonCode()
const [raftCodes, setRaftCodes] = useState([]) //
const [trestleList, setTrestleList] = useState([])
const [constMthdList, setConstMthdList] = useState([])
const [roofBaseList, setRoofBaseList] = useState([])
const [constructionList, setConstructionList] = useState([{}]) //
const [selectedRaftBase, setSelectedRaftBase] = useState({}) //
const [selectedTrestle, setSelectedTrestle] = useState({}) //
const [selectedConstMthd, setSelectedConstMthd] = useState({}) //
const [selectedRoofBase, setSelectedRoofBase] = useState({}) //
const [selectedConstruction, setSelectedConstruction] = useState({}) //
const [constructionListParams, setConstructionListParams] = useState({})
const [trestleParams, setTrestleParams] = useState({}) //, ,, api
const [constructionParams, setConstructionParams] = useState({}) // api
const [roofBaseParams, setRoofBaseParams] = useState({}) // api
const moduleSelectionInitParams = useRecoilValue(moduleSelectionInitParamsState) // ex) ,
const { getTrestleList, getConstructionList } = useMasterController()
const constructionRef = useRef([])
const [cvrYn, setCvrYn] = useState('N')
const [snowGdPossYn, setSnowGdPossYn] = useState('N')
const [cvrChecked, setCvrChecked] = useState(false)
const [snowGdChecked, setSnowGdChecked] = useState(false)
const [isExistData, setIsExistData] = useState(false)
//
const handleChangeRaftBase = (option) => {
setSelectedRaftBase(option)
setTrestleParams({ ...trestleParams, raftBaseCd: option.clCode })
setTrestleList([]) //
setConstMthdList([]) //
setRoofBaseList([]) //
setConstructionList([]) //
}
//
const handleChangeTrestle = (option) => {
setSelectedTrestle(option) //
setConstructionParams({ ...trestleParams, trestleMkrCd: option.trestleMkrCd, constMthdCd: '', roofBaseCd: '' })
setConstMthdList([]) //
setRoofBaseList([]) //
setConstructionList([]) //
}
//
const handleChangeConstMthd = (option) => {
setSelectedConstMthd(option) //
setRoofBaseParams({ ...trestleParams, trestleMkrCd: selectedTrestle.trestleMkrCd, constMthdCd: option.constMthdCd, roofBaseCd: '' })
setConstructionList([]) //
}
//
const handleChangeRoofBase = (option) => {
// if (option) {
setConstructionListParams({
...moduleSelectionInitParams,
...roofBaseParams,
roofBaseCd: option.roofBaseCd,
inclCd: addRoof.pitch,
})
setSelectedRoofBase(option)
}
const getModuleOptionsListData = async (params) => {
const optionsList = await getTrestleList(params)
if (optionsList.data.length > 0) {
if (optionsList.data[0].trestleMkrCd && optionsList.data[0].constMthdCd === null) {
setTrestleList(optionsList.data)
if (isExistData) {
setSelectedTrestle({ ...moduleConstructionSelectionData.trestle })
} else {
setConstMthdList([])
setRoofBaseList([])
}
}
if (optionsList.data[0].trestleMkrCd && optionsList.data[0].constMthdCd && optionsList.data[0].roofBaseCd === null) {
setConstMthdList(optionsList.data)
if (isExistData) {
setSelectedConstMthd({ ...moduleConstructionSelectionData.trestle })
} else {
setRoofBaseList([])
}
}
if (optionsList.data[0].trestleMkrCd && optionsList.data[0].constMthdCd && optionsList.data[0].roofBaseCd) {
setRoofBaseList(optionsList.data)
if (isExistData) {
setSelectedRoofBase({ ...moduleConstructionSelectionData.trestle })
}
}
}
}
const getConstructionListData = async (params) => {
if (params.trestleMkrCd && params.constMthdCd && params.roofBaseCd) {
const optionsList = await getConstructionList(params)
setConstructionList(optionsList.data)
}
}
const handleConstruction = (index) => {
if (index > -1) {
const isPossibleIndex = constructionRef.current
.map((el, i) => (el.classList.contains('white') || el.classList.contains('blue') ? i : -1))
.filter((index) => index !== -1)
isPossibleIndex.forEach((index) => {
if (constructionRef.current[index].classList.contains('blue')) {
constructionRef.current[index].classList.remove('blue')
constructionRef.current[index].classList.add('white')
}
})
constructionRef.current[index].classList.remove('white')
constructionRef.current[index].classList.add('blue')
const selectedConstruction = constructionList[index]
selectedConstruction.roofIndex = roofTab
selectedConstruction.setupCover = false //
selectedConstruction.setupSnowCover = false //
selectedConstruction.selectedIndex = index
setCvrYn(selectedConstruction.cvrYn)
setSnowGdPossYn(selectedConstruction.snowGdPossYn)
setSelectedConstruction(selectedConstruction)
} else {
constructionRef.current.forEach((ref) => {
ref.classList.remove('blue')
})
}
}
useEffect(() => {
if (isObjectNotEmpty(selectedRoofBase) && isObjectNotEmpty(selectedConstruction)) {
const newRoofConstructions = {
roofIndex: roofTab,
addRoof: addRoof,
trestle: selectedRoofBase,
construction: selectedConstruction,
}
const index = tempModuleSelectionData.roofConstructions.findIndex((obj) => obj.roofIndex === roofTab)
if (index > -1) {
const newArray = [
...tempModuleSelectionData.roofConstructions.slice(0, index),
newRoofConstructions,
...tempModuleSelectionData.roofConstructions.slice(index + 1),
]
setTempModuleSelectionData({ roofConstructions: newArray })
} else {
setTempModuleSelectionData({ roofConstructions: [...tempModuleSelectionData.roofConstructions, { ...newRoofConstructions }] })
}
}
}, [selectedConstruction])
const handleCvrChecked = () => {
setCvrChecked(!cvrChecked)
}
const handleSnowGdChecked = () => {
setSnowGdChecked(!snowGdChecked)
}
useEffect(() => {
setSelectedConstruction({ ...selectedConstruction, setupCover: cvrChecked })
}, [cvrChecked])
useEffect(() => {
setSelectedConstruction({ ...selectedConstruction, setupSnowCover: snowGdChecked })
}, [snowGdChecked])
useEffect(() => {
if (isExistData) {
setConstructionListParams({
...moduleSelectionInitParams,
...roofBaseParams,
roofBaseCd: selectedRoofBase.roofBaseCd,
inclCd: addRoof.pitch,
})
}
}, [selectedRoofBase])
useEffect(() => {
if (isExistData && constructionList.length > 0) {
const selectedIndex = moduleConstructionSelectionData.construction.selectedIndex
handleConstruction(selectedIndex)
}
}, [constructionList])
useEffect(() => {
// 202600
const raftCodeList = findCommonCode('203800')
//
raftCodeList.forEach((obj) => {
obj.name = obj.clCodeNm
obj.id = obj.clCode
})
setRaftCodes(raftCodeList)
}, [])
useEffect(() => {
//
if (
moduleSelectionInitParams.illuminationTp &&
moduleSelectionInitParams.instHt &&
moduleSelectionInitParams.stdSnowLd &&
moduleSelectionInitParams.stdWindSpeed
) {
const isModuleLoaded = moduleSelectionInitParams.hasOwnProperty('moduleTpCd') //
if (isModuleLoaded) {
setTrestleParams({ moduleTpCd: moduleSelectionInitParams.moduleTpCd, roofMatlCd: addRoof.roofMatlCd, raftBaseCd: addRoof.raftBaseCd })
setConstructionList([])
if (isObjectNotEmpty(moduleConstructionSelectionData)) {
setConstructionParams({ ...moduleConstructionSelectionData.trestle, constMthdCd: '', roofBaseCd: '' })
setRoofBaseParams({ ...moduleConstructionSelectionData.trestle, roofBaseCd: '' })
setCvrChecked(moduleConstructionSelectionData.construction.setupCover)
setSnowGdChecked(moduleConstructionSelectionData.construction.setupSnowCover)
setIsExistData(true)
}
}
}
setTempModuleSelectionData({ common: moduleSelectionInitParams })
}, [moduleSelectionInitParams])
useEffect(() => {
if (isObjectNotEmpty(trestleParams)) {
getModuleOptionsListData(trestleParams)
}
}, [trestleParams])
useEffect(() => {
if (isObjectNotEmpty(constructionParams)) {
getModuleOptionsListData(constructionParams)
}
}, [constructionParams])
useEffect(() => {
if (isObjectNotEmpty(roofBaseParams)) {
getModuleOptionsListData(roofBaseParams)
}
}, [roofBaseParams])
useEffect(() => {
if (isObjectNotEmpty(constructionListParams)) {
getConstructionListData(constructionListParams)
}
}, [constructionListParams])
useEffect(() => {
if (isObjectNotEmpty(tempModuleSelectionData)) {
setModuleSelectionData(tempModuleSelectionData)
}
}, [tempModuleSelectionData])
const {
raftCodes,
trestleList,
constMthdList,
roofBaseList,
constructionList,
globalPitchText,
selectedTrestle,
selectedConstMthd,
selectedRoofBase,
constructionRef,
cvrYn,
cvrChecked,
snowGdPossYn,
snowGdChecked,
lengthBase,
hajebichi,
lengthRef,
hajebichiRef,
setLengthBase,
setHajebichi,
handleChangeRaftBase,
handleChangeTrestle,
handleChangeConstMthd,
handleChangeRoofBase,
handleConstruction,
handleCvrChecked,
handleSnowGdChecked,
} = useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab, tempModuleSelectionData, setTempModuleSelectionData })
return (
<>
@ -300,21 +54,21 @@ export default function ModuleTabContents({
<>
<div className="eaves-keraba-th">L</div>
<div className="eaves-keraba-td">
<div className="keraba-flex">
<div className="outline-form">
<div className="grid-select">
<input
type="text"
className="input-origin block"
value={roofMaterial.lenBase}
disabled={roofMaterial.lenAuth === 'R' ? true : false}
/>
</div>
</div>
<div className="grid-select">
<input
type="text"
className="input-origin block"
value={lengthBase}
onChange={(e) => setLengthBase(e.target.value)}
disabled={roofMaterial.lenAuth === 'R' ? true : false}
ref={lengthRef}
/>
</div>
</div>
</>
)}
</div>
<div className="eaves-keraba-item">
{roofMaterial && ['C', 'R'].includes(roofMaterial.raftAuth) && (
<>
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.rafter.margin')}</div>
@ -335,22 +89,21 @@ export default function ModuleTabContents({
</div>
</>
)}
</div>
<div className="eaves-keraba-item">
{roofMaterial && ['C', 'R'].includes(roofMaterial.roofPchAuth) && (
<>
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.rafter.margin')}</div>
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.hajebichi')}</div>
<div className="eaves-keraba-td">
<div className="keraba-flex">
<div className="outline-form">
<span>垂木の間隔</span>
<div className="grid-select">
<input
type="text"
className="input-origin block"
value={roofMaterial.hajebichi}
disabled={roofMaterial.roofPchAuth === 'R' ? true : false}
/>
</div>
</div>
<div className="grid-select">
<input
type="text"
className="input-origin block"
disabled={roofMaterial.roofPchAuth === 'R' ? true : false}
onChange={(e) => setHajebichi(e.target.value)}
value={hajebichi}
ref={hajebichiRef}
/>
</div>
</div>
</>
@ -454,22 +207,22 @@ export default function ModuleTabContents({
<div className="d-check-box pop">
<input
type="checkbox"
id={`ch01_${roofTab}`}
id={`ch01_${tabIndex}`}
disabled={cvrYn === 'N' ? true : false}
defaultChecked={cvrChecked}
checked={cvrChecked || false}
onChange={handleCvrChecked}
/>
<label htmlFor={`ch01_${roofTab}`}>{getMessage('modal.module.basic.setting.module.eaves.bar.fitting')}</label>
<label htmlFor={`ch01_${tabIndex}`}>{getMessage('modal.module.basic.setting.module.eaves.bar.fitting')}</label>
</div>
<div className="d-check-box pop">
<input
type="checkbox"
id={`ch02_${roofTab}`}
id={`ch02_${tabIndex}`}
disabled={snowGdPossYn === 'N' ? true : false}
defaultChecked={snowGdChecked}
checked={snowGdChecked || false}
onChange={handleSnowGdChecked}
/>
<label htmlFor={`ch02_${roofTab}`}>{getMessage('modal.module.basic.setting.module.blind.metal.fitting')}</label>
<label htmlFor={`ch02_${tabIndex}`}>{getMessage('modal.module.basic.setting.module.blind.metal.fitting')}</label>
</div>
</div>
</div>

View File

@ -1,12 +1,15 @@
import { forwardRef, useImperativeHandle, useState } from 'react'
import { forwardRef, useContext, useEffect, useImperativeHandle, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useOrientation } from '@/hooks/module/useOrientation'
import { getDegreeInOrientation } from '@/util/canvas-util'
import { numberCheck } from '@/util/common-utils'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
export const Orientation = forwardRef(({ tabNum }, ref) => {
const { getMessage } = useMessage()
const { trigger: canvasPopupStatusTrigger } = useCanvasPopupStatusController(1)
const { nextStep, compasDeg, setCompasDeg } = useOrientation()
const [hasAnglePassivity, setHasAnglePassivity] = useState(false)
@ -17,8 +20,13 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
const handleNextStep = () => {
nextStep()
canvasPopupStatusTrigger(compasDeg)
}
useEffect(() => {
checkDegree(compasDeg)
}, [compasDeg])
const checkDegree = (e) => {
if (numberCheck(Number(e)) && Number(e) >= -180 && Number(e) <= 180) {
setCompasDeg(Number(e))
@ -30,7 +38,6 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
return (
<>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.module.basic.setting.orientation.setting')}</div>
<div className="outline-wrap">
<div className="guide">{getMessage('modal.module.basic.setting.orientation.setting.info')}</div>
<div className="roof-module-compas">
@ -64,7 +71,7 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
</div>
<div className="center-wrap">
<div className="d-check-box pop">
<input type="checkbox" id="ch99" checked={!hasAnglePassivity} onChange={() => setHasAnglePassivity(!hasAnglePassivity)} />
<input type="checkbox" id="ch99" checked={hasAnglePassivity} onChange={() => setHasAnglePassivity(!hasAnglePassivity)} />
<label htmlFor="ch99">{getMessage('modal.module.basic.setting.orientation.setting.angle.passivity')}-180 180</label>
</div>
<div className="outline-form">
@ -73,7 +80,7 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
type="text"
className="input-origin block"
value={compasDeg}
readOnly={hasAnglePassivity}
readOnly={!hasAnglePassivity}
placeholder={0}
onChange={
(e) => checkDegree(e.target.value)

View File

@ -1,14 +1,17 @@
import { forwardRef, useEffect, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { checkedModuleState } from '@/store/canvasAtom'
import { useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil'
import { selectedModuleState, moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { checkedModuleState, currentCanvasPlanState } from '@/store/canvasAtom'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useModulePlace } from '@/hooks/module/useModulePlace'
const Placement = forwardRef((props, refs) => {
const { getMessage } = useMessage()
const [isChidori, setIsChidori] = useState('false')
const [isChidori, setIsChidori] = useState(false)
const [isChidoriNotAble, setIsChidoriNotAble] = useState(false)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const [setupLocation, setSetupLocation] = useState('center')
const [isMaxSetup, setIsMaxSetup] = useState('false')
const [selectedItems, setSelectedItems] = useState({})
@ -21,9 +24,13 @@ const Placement = forwardRef((props, refs) => {
//
useEffect(() => {
console.log('🚀 ~ Placement ~ moduleSelectionData:', moduleSelectionData)
console.log('🚀 ~ Placement ~ selectedModules:', selectedModules)
makeModuleInstArea()
if (moduleSelectionData) {
//1
const isChidroriValue = moduleSelectionData.roofConstructions.some((item) => item.construction.plvrYn === 'N')
if (isChidroriValue) {
setIsChidoriNotAble(true)
}
}
}, [])
//
@ -45,10 +52,15 @@ const Placement = forwardRef((props, refs) => {
}
const handleChangeChidori = (e) => {
setIsChidori(e.target.value)
const bool = e.target.value === 'true' ? true : false
setIsChidori(bool)
refs.isChidori.current = e.target.value
}
useEffect(() => {
console.log('isChidori', isChidori)
}, [isChidori])
const handleSetupLocation = (e) => {
setSetupLocation(e.target.value)
refs.setupLocation.current = e.target.value
@ -127,19 +139,19 @@ const Placement = forwardRef((props, refs) => {
<div className="self-item-td">
<div className="pop-form-radio">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra01" checked={isChidori === 'true'} value={'true'} onChange={handleChangeChidori} />
<input
type="radio"
name="radio01"
id="ra01"
checked={isChidori}
disabled={isChidoriNotAble}
value={'true'}
onChange={(e) => handleChangeChidori(e)}
/>
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.module.placement.do')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio02"
id="ra02"
value={'false'}
defaultChecked
checked={isChidori === 'false'}
onChange={handleChangeChidori}
/>
<input type="radio" name="radio02" id="ra02" checked={!isChidori} value={'false'} onChange={(e) => handleChangeChidori(e)} />
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.module.placement.do.not')}</label>
</div>
</div>

View File

@ -6,20 +6,21 @@ import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp'
import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup'
import PassivityCircuitAllocation from './step/type/PassivityCircuitAllocation'
import { useAxios } from '@/hooks/useAxios'
import { useMasterController } from '@/hooks/common/useMasterController'
import { get } from 'react-hook-form'
import { correntObjectNoState } from '@/store/settingAtom'
import { useRecoilValue } from 'recoil'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { useRecoilState } from 'recoil'
import { powerConditionalState } from '@/store/circuitTrestleAtom'
import { makersState, modelsState, modelState, pcsCheckState, selectedMakerState, selectedModelsState, seriesState } from '@/store/circuitTrestleAtom'
import { POLYGON_TYPE } from '@/common/common'
import { useSwal } from '@/hooks/useSwal'
import { canvasState } from '@/store/canvasAtom'
import { useTrestle } from '@/hooks/module/useTrestle'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { v4 as uuidv4 } from 'uuid'
import { stepUpListDataState } from '@/store/circuitTrestleAtom'
const ALLOCATION_TYPE = {
AUTO: 'auto',
@ -28,62 +29,455 @@ const ALLOCATION_TYPE = {
export default function CircuitTrestleSetting({ id }) {
const { getMessage } = useMessage()
const { closePopup } = usePopup()
// 1: (+ )
// 2:
const { apply } = useTrestle()
const { swalFire } = useSwal()
const canvas = useRecoilValue(canvasState)
const [makers, setMakers] = useRecoilState(makersState)
const [selectedMaker, setSelectedMaker] = useRecoilState(selectedMakerState)
const [series, setSeries] = useRecoilState(seriesState)
const [models, setModels] = useRecoilState(modelsState)
const [selectedModels, setSelectedModels] = useRecoilState(selectedModelsState)
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const [tabNum, setTabNum] = useState(1)
const [allocationType, setAllocationType] = useState(ALLOCATION_TYPE.AUTO)
const [makers, setMakers] = useState([])
const [series, setSeries] = useState([])
const [models, setModels] = useState([])
const [selectedMaker, setSelectedMaker] = useState(null)
const [selectedModels, setSelectedModels] = useState(null)
const [selectedSeries, setSelectedSeries] = useState(null)
const correntObjectNo = useRecoilValue(correntObjectNoState)
const { getPcsMakerList } = useMasterController()
const [circuitAllocationType, setCircuitAllocationType] = useState(1)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const { apply } = useTrestle()
const selectedModules = useRecoilValue(selectedModuleState)
const { getPcsAutoRecommendList, getPcsVoltageChk } = useMasterController()
// ()
const [selectedStepUpValues, setSelectedStepUpValues] = useState({})
const [getStepUpSelections, setGetStepUpSelections] = useState(null)
const [stepUpListData, setStepUpListData] = useRecoilState(stepUpListDataState)
useEffect(() => {
// console.log(canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE))
// if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length === 0) {
// swalFire({
// title: ' .',
// type: 'alert',
// confirmFn: () => {
// closePopup(id)
// },
// })
// }
if (!managementState) {
setManagementState(managementStateLoaded)
}
}, [])
// useEffect(() => {
// console.log('🚀 ~ CircuitTrestleSetting ~ series:', series)
// const selectedSeries = series.filter((s) => s.selectd).map((s) => s.pcsSerCd)
// if (selectedSeries.length > 0) {
// getPcsMakerList(selectedSeries).then((res) => {
// setModels(res.data)
// })
// }
// }, [series])
//
const [circuitAllocationType, setCircuitAllocationType] = useState(1)
useEffect(() => {
if (allocationType === ALLOCATION_TYPE.PASSIVITY && tabNum === 2) {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
canvas.remove(...notAllocationModules)
canvas.renderAll()
}
}, [tabNum])
useEffect(() => {
console.log('stepUpListData >>> ', stepUpListData)
}, [stepUpListData])
const onAutoRecommend = () => {
if (series.filter((s) => s.selected).length === 0) {
swalFire({
title: '시리즈를 선택해 주세요.',
type: 'alert',
})
return
}
const params = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
if (selectedModels.length === 0) {
getPcsAutoRecommendList(params).then((res) => {
if (res.data?.pcsItemList) {
const itemList = models.filter((model) => {
return res.data?.pcsItemList.map((item) => item.itemId).includes(model.itemId)
})
const selectedModels = itemList.map((model) => {
return {
...model,
id: uuidv4(),
}
})
const pcsVoltageChkParams = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
setSelectedModels(selectedModels)
getPcsVoltageChk(pcsVoltageChkParams).then((res) => {
setTabNum(2)
})
} else {
//
if (res.result.resultCode === 'E') {
swalFire({
title: res.result.resultMsg,
type: 'alert',
})
} else {
swalFire({
title: '파워컨디셔너를 추가해 주세요.',
type: 'alert',
})
}
}
})
} else {
getPcsVoltageChk(params).then((res) => {
setTabNum(2)
})
}
}
const getOptYn = () => {
return {
maxConnYn: pcsCheck.max ? 'Y' : 'N',
smpCirYn: pcsCheck.division ? 'Y' : 'N',
coldZoneYn: managementState?.coldRegionFlg === '1' ? 'Y' : 'N',
}
}
const getPcsItemList = () => {
return models.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
const getUseModuleItemList = () => {
return selectedModules.itemList.map((m) => {
return {
itemId: m.itemId,
mixMatlNo: m.mixMatlNo,
}
})
}
const getRoofSurfaceList = () => {
return canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
.map((obj) => {
getModuleList(obj)
return {
roofSurfaceId: obj.id,
roofSurface: canvas
.getObjects()
.filter((o) => o.id === obj.parentId)[0]
.directionText.replace(/[0-9]/g, ''),
roofSurfaceIncl: canvas.getObjects().filter((o) => o.id === obj.parentId)[0].roofMaterial.pitch,
moduleList: getModuleList(obj).map((module) => {
return {
itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber ? module.circuitNumber : null,
pcsItemId: module.circuit ? module.circuit?.pcsItemId : null,
}
}),
}
})
}
const getModuleList = (surface) => {
let moduleList = []
let [xObj, yObj] = [{}, {}]
let [xPoints, yPoints] = [[], []]
surface.modules.forEach((module) => {
if (!xObj[module.left]) {
xObj[module.left] = module.left
xPoints.push(module.left)
}
if (!yObj[module.top]) {
yObj[module.top] = module.top
yPoints.push(module.top)
}
})
switch (surface.direction) {
case 'south':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => b - a)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => a.left - b.left)
} else {
temp.sort((a, b) => b.left - a.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'north':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => a - b)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => b.left - a.left)
} else {
temp.sort((a, b) => a.left - b.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'west':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => a - b)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => a.top - b.top)
} else {
temp.sort((a, b) => b.top - a.top)
}
moduleList = [...moduleList, ...temp]
})
break
case 'east':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => b - a)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => b.top - a.top)
} else {
temp.sort((a, b) => a.top - b.top)
}
moduleList = [...moduleList, ...temp]
})
break
default:
return []
}
return moduleList
}
const onAutoAllocation = () => {
let moduleStdQty = 0
let moduleMaxQty = 0
const selectedModels = models.filter((m) => m.selected)
if (selectedModels.length === 0) {
onAutoRecommend()
} else {
moduleStdQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleStdQty)
}, 0)
moduleMaxQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleMaxQty)
}, 0)
}
// const target = pcsCheck.max ? moduleMaxQty : moduleStdQty
// const placementModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
// if (placementModules.length > target) {
// swalFire({
// title: ' . .',
// type: 'alert',
// })
// return
// }
// setAllocationType(ALLOCATION_TYPE.AUTO)
// setTabNum(2)
}
const onPassivityAllocation = () => {
if (selectedModels.length === 0) {
const params = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
getPcsAutoRecommendList(params).then((res) => {
if (res.data?.pcsItemList) {
const itemList = models.filter((model) => {
return res.data?.pcsItemList.map((item) => item.itemId).includes(model.itemId)
})
const selectedModels = itemList.map((model) => {
return {
...model,
id: uuidv4(),
}
})
const PcsVoltageChkParams = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
setSelectedModels(selectedModels)
getPcsVoltageChk(PcsVoltageChkParams).then((res) => {})
} else {
swalFire({
title: '파워컨디셔너를 추가해 주세요.',
type: 'alert',
})
}
})
} else if (pcsCheck.max) {
const moduleStdQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleStdQty)
}, 0)
const moduleMaxQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleMaxQty)
}, 0)
const target = pcsCheck.max ? moduleMaxQty : moduleStdQty
const placementModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
if (placementModules.length > target) {
swalFire({
title: '배치가능 매수를 초과합니다. 파워컨디셔너를 다시 선택해 주세요.',
type: 'alert',
})
return
}
}
setAllocationType(ALLOCATION_TYPE.PASSIVITY)
}
// StepUp
const handleStepUpValuesSelected = (selectionData) => {
const { gooodsNo } = selectionData
setSelectedStepUpValues((prev) => ({
...prev,
[gooodsNo]: selectionData,
}))
}
// StepUp
const handleStepUpInitialize = (getCurrentSelections) => {
setGetStepUpSelections(() => getCurrentSelections)
}
// apply
const onApply = () => {
//
const currentSelections = getStepUpSelections ? getStepUpSelections() : {}
console.log('currentSelections >>> ', currentSelections)
//
const hasSelections = Object.values(currentSelections).some((stepUpConfig) => Object.values(stepUpConfig).length > 0)
console.log('hasSelections >>> ', hasSelections)
if (!hasSelections) {
swalFire({
title: '승압 설정값을 선택해주세요.1',
type: 'alert',
})
return
}
//
console.log('Applying StepUp configurations:', currentSelections)
// StepUp stepUpListData
//const stepUpData = getStepUpSelections().stepUpListData
//console.log('stepUpData >>> ', stepUpData)
// stepUpListData Recoil state
// setStepUpListData(stepUpData)
//
const configurations = Object.values(currentSelections)
.map((stepUpConfig) => {
const firstConfig = Object.values(stepUpConfig)[0] //
return {
pcsInfo: firstConfig.pcsInfo,
allocation: firstConfig.allocation,
}
})
.filter((config) => config.pcsInfo && config.allocation) //
console.log('Processed configurations:', configurations)
// stepUpListData Recoil state
setStepUpListData(configurations)
// apply
if (configurations.length > 0) {
apply()
} else {
swalFire({
title: '승압 설정값을 선택해주세요.2',
type: 'alert',
})
}
}
const onClickPrev = () => {
setAllocationType(ALLOCATION_TYPE.AUTO)
swalFire({
text: '할당한 회로 번호가 초기화됩니다.',
type: 'alert',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas
.getObjects()
.filter((obj) => obj.name === 'module' && selectedModels.map((model) => model.id).includes(obj.circuit?.circuitInfo?.id))
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
})
},
})
}
const powerConditionalSelectProps = {
tabNum,
setTabNum,
makers,
setMakers,
selectedMaker,
setSelectedMaker,
series,
setSeries,
models,
setModels,
selectedModels,
setSelectedModels,
managementState,
}
const circuitProps = {
const passivityProps = {
tabNum,
setTabNum,
pcsCheck,
selectedModels,
setSelectedModels,
getOptYn,
getUseModuleItemList,
getRoofSurfaceList,
}
const stepUpProps = {
tabNum,
setTabNum,
models,
setModels,
circuitAllocationType,
setCircuitAllocationType,
getOptYn, // Y/N
getUseModuleItemList, // List
getRoofSurfaceList, //
getPcsItemList, // PCS
onValuesSelected: handleStepUpValuesSelected, //
}
return (
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }}>
<div className={`modal-pop-wrap l-2`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.circuit.trestle.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -98,14 +492,14 @@ export default function CircuitTrestleSetting({ id }) {
</div>
</div>
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && <PowerConditionalSelect {...powerConditionalSelectProps} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && <PassivityCircuitAllocation {...powerConditionalSelectProps} />}
{tabNum === 2 && <StepUp />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && <PassivityCircuitAllocation {...passivityProps} />}
{tabNum === 2 && <StepUp {...stepUpProps} onInitialize={handleStepUpInitialize} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => setTabNum(2)}>
<button className="btn-frame modal mr5" onClick={() => onAutoAllocation()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}
</button>
<button className="btn-frame modal act" onClick={() => setAllocationType(ALLOCATION_TYPE.PASSIVITY)}>
<button className="btn-frame modal act" onClick={() => onPassivityAllocation()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}
</button>
</div>
@ -125,12 +519,14 @@ export default function CircuitTrestleSetting({ id }) {
<button className="btn-frame modal mr5" onClick={() => setTabNum(1)}>
{getMessage('modal.common.prev')}
</button>
<button className="btn-frame modal act" onClick={() => apply()}>
{/* <button className="btn-frame modal act" onClick={() => apply()}> */}
<button className="btn-frame modal act" onClick={onApply}>
{getMessage('modal.common.save')}({getMessage('modal.circuit.trestle.setting.circuit.allocation')})
</button>
</div>
)}
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -1,36 +1,43 @@
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useEvent } from '@/hooks/useEvent'
import { useMessage } from '@/hooks/useMessage'
import { makerState, modelState, seriesState } from '@/store/circuitTrestleAtom'
import { useSwal } from '@/hooks/useSwal'
import { pcsCheckState } from '@/store/circuitTrestleAtom'
import { globalLocaleStore } from '@/store/localeAtom'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { isNullOrUndefined } from '@/util/common-utils'
import { useContext, useEffect, useState } from 'react'
import { useRecoilState } from 'recoil'
import { useRecoilValue } from 'recoil'
import { v4 as uuidv4 } from 'uuid'
const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }]
export default function PowerConditionalSelect(props) {
let { tabNum, setTabNum } = props
const [makerData, setMakerData] = useRecoilState(makerState)
const [makers, setMakers] = useState(makerData.makers)
const [selectedMaker, setSelectedMaker] = useState(makerData.selectedMaker)
const [series, setSeries] = useRecoilState(seriesState)
const [seriesList, setSeriesList] = useState(series.series)
const [selectedSeries, setSelectedSeries] = useState(series.selectedSeries)
const model = useRecoilValue(modelState)
const [models, setModels] = useState(model.models)
const [selectedModels, setSelectedModels] = useState(model.selectedModels)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
let {
tabNum,
setTabNum,
makers,
setMakers,
selectedMaker,
setSelectedMaker,
series,
setSeries,
models,
setModels,
selectedModels,
setSelectedModels,
managementState,
} = props
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const { getMessage } = useMessage()
const [selectedRow, setSelectedRow] = useState(null)
const globalLocale = useRecoilValue(globalLocaleStore)
const { getPcsMakerList, getPcsModelList } = useMasterController()
const selectedModules = useRecoilValue(selectedModuleState)
const { swalFire } = useSwal()
const modelHeader = [
{ name: getMessage('시리즈'), width: '15%', prop: 'pcsSerNm', type: 'color-box' },
{ name: getMessage('명칭'), width: '15%', prop: 'itemNm', type: 'color-box' },
{
name: `${getMessage('modal.circuit.trestle.setting.power.conditional.select.rated.output')} (kW)`,
@ -57,86 +64,115 @@ export default function PowerConditionalSelect(props) {
useEffect(() => {
if (makers.length === 0) {
getPcsMakerList().then((res) => {
console.log('getPcsMakerList', res.data)
setMakers(res.data)
})
}
if (!managementState) {
console.log('🚀 ~ useEffect ~ managementState:', managementState)
setManagementState(managementStateLoaded)
}
// promiseGet({ url: `/api/object/${correntObjectNo}/detail` }).then((res) => {
// console.log('🚀 ~ useEffect ~ /api/object/${correntObjectNo}/detail:', res)
// // coldRegionFlg-, conType// (~,)
// })
}, [])
useEffect(() => {
console.log('🚀 ~ PowerConditionalSelect ~ selectedMaker:', selectedMaker)
if (selectedMaker) {
setSelectedModels([])
getPcsMakerList(selectedMaker).then((res) => {
setSeriesList(
res.data.map((series) => {
return { ...series, selected: false }
}),
)
const checkValidation = () => {
const checkedSeries = series.filter((s) => s.selected)
if (checkedSeries.length === 0) {
swalFire({
title: 'PCS 시리즈를 선택해 주세요.',
icon: 'warning',
})
return false
} else if (checkedSeries.length === 1) {
if (checkedSeries[0].pcsMkrMultiType === 'SINGLE-P' && checkedSeries[0].pcsSerParallelYn === 'Y') {
swalFire({
title: '병설은 단독으로 안 됨',
icon: 'warning',
})
}
return false
}
}, [selectedMaker])
return true
}
useEffect(() => {
console.log('🚀 ~ useEffect ~ seriesList:', seriesList)
if (seriesList.filter((series) => series.selected).length === 0) return
const pcsMkrCd = seriesList.filter((series) => series.selected)[0]?.pcsMkrCd
const pcsSerList = seriesList
.filter((series) => series.selected)
.map((series) => {
return { pcsSerCd: series.pcsSerCd }
})
const onCheckSeries = (data) => {
console.log('data', data)
const copySeries = series.map((s) => {
return {
...s,
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : s.selected,
}
})
setSeries(copySeries)
console.log('copySeries', copySeries)
handleSetmodels(copySeries.filter((s) => s.selected))
}
const handleSetmodels = (selectedSeries) => {
console.log('series', selectedSeries)
if (selectedSeries.length === 0) {
setModels([])
setSelectedModels([])
return
}
const pcsMkrCd = selectedSeries[0]?.pcsMkrCd
const pcsSerList = selectedSeries.map((series) => {
return { pcsSerCd: series.pcsSerCd }
})
const moduleItemList = selectedModules.itemList?.map((module) => {
return {
itemId: module.itemId,
mixMatlNo: module.mixMatlNo,
}
})
console.log('🚀 ~ useEffect ~ moduleItemList:', selectedModules)
getPcsModelList({ pcsMkrCd, pcsSerList, moduleItemList }).then((res) => {
if (res?.result.code === 200) {
console.log('🚀 ~ useEffect ~ res:', res.data)
if (res?.result.code === 200 && res?.data) {
setModels(
res.data.map((model) => {
return {
...model,
moduleStdQty: parseInt(model.moduleStdQty),
moduleMaxQty: parseInt(model.moduleMaxQty),
code: uuidv4(),
selected: false,
}
}),
)
} else {
setModels([])
setSelectedModels([])
}
})
}, [seriesList])
const onCheckSeries = (series) => {
setSeriesList((prev) => prev.map((s) => ({ ...s, selected: s.pcsSerCd === series.pcsSerCd ? !s.selected : s.selected })))
}
const onAddSelectedModel = () => {
setSelectedModels([...selectedModels, selectedRow])
if (selectedRow === null) return
if (selectedModels.length === 3) {
swalFire({
title: '최대 3개까지 선택할 수 있습니다.',
icon: 'warning',
})
return
}
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4() }])
setSelectedRow(null)
}
useEffect(() => {
const selectedModelsIds = selectedModels.map((model) => model.itemId)
const onRemoveSelectedModel = (model) => {
setSelectedModels(selectedModels.filter((m) => m.id !== model.id))
}
const onChangeMaker = (option) => {
if (option) {
setModels([])
setSelectedMaker(option)
getPcsMakerList(option).then((res) => {
console.log('getPcsMakerList(series)', res.data)
setSeries(
res.data.map((series) => {
return { ...series, selected: false }
}),
)
})
}
}
setModels(
models.map((model) => {
return {
...model,
selected: selectedModelsIds.includes(model.itemId) === selectedRow.itemId ? true : false,
}
}),
)
}, [selectedModels])
return (
<>
<div className="outline-form mb15">
@ -151,19 +187,19 @@ export default function PowerConditionalSelect(props) {
sourceKey="pcsMkrCd"
targetKey="pcsMkrCd"
value={selectedMaker}
onChange={(option) => setSelectedMaker(option)}
onChange={(option) => onChangeMaker(option)}
/>
</div>
{managementState?.conType === '1' && (
{managementState?.coldRegionFlg === '1' && (
<span className="thin">{getMessage('modal.circuit.trestle.setting.power.conditional.select.cold.region')}</span>
)}
</div>
<div className="module-table-box mb10">
<div className="module-table-inner">
<div className="circuit-check-inner overflow">
{seriesList?.map((series, index) => (
{series?.map((series, index) => (
<div className="d-check-box pop sel">
<input type="checkbox" id={`"ch0"${index}`} onClick={() => onCheckSeries(series)} checked={series.selected} />
<input type="checkbox" id={`"ch0"${index}`} onChange={() => onCheckSeries(series)} checked={series.selected} />
<label htmlFor={`"ch0"${index}`}>{globalLocale === 'ko' ? series.pcsSerNm : series.pcsSerNmJp}</label>
</div>
))}
@ -185,15 +221,13 @@ export default function PowerConditionalSelect(props) {
</tr>
</thead>
<tbody>
{models
?.filter((model) => !model.selected)
.map((model, index) => (
<tr key={index} onClick={() => setSelectedRow(model)} className={model === selectedRow ? 'on' : ''}>
{modelHeader.map((header) => (
<td>{model[header.prop]}</td>
))}
</tr>
))}
{models?.map((model, index) => (
<tr key={index} onClick={() => setSelectedRow(model)} className={model === selectedRow ? 'on' : ''}>
{modelHeader.map((header) => (
<td>{model[header.prop]}</td>
))}
</tr>
))}
</tbody>
</table>
</div>
@ -206,7 +240,7 @@ export default function PowerConditionalSelect(props) {
<div className="circuit-data-form">
{selectedModels?.map((model) => (
<span className="normal-font">
{model.itemNm} <button className="del"></button>
{model.itemNm} <button className="del" onClick={() => onRemoveSelectedModel(model)}></button>
</span>
))}
</div>
@ -214,11 +248,11 @@ export default function PowerConditionalSelect(props) {
</div>
<div className="slope-wrap">
<div className="d-check-box pop mb15">
<input type="checkbox" id="ch03" />
<input type="checkbox" id="ch03" checked={pcsCheck.division} onChange={() => setPcsCheck({ ...pcsCheck, division: !pcsCheck.division })} />
<label htmlFor="ch03">{getMessage('modal.circuit.trestle.setting.power.conditional.select.check1')}</label>
</div>
<div className="d-check-box pop">
<input type="checkbox" id="ch04" />
<input type="checkbox" id="ch04" checked={pcsCheck.max} onChange={() => setPcsCheck({ ...pcsCheck, max: !pcsCheck.max })} />
<label className="red" htmlFor="ch04">
{getMessage('modal.circuit.trestle.setting.power.conditional.select.check2')}
</label>

View File

@ -1,133 +1,416 @@
import { useState } from 'react'
import { useRecoilValue } from 'recoil'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useMessage } from '@/hooks/useMessage'
import { canvasState } from '@/store/canvasAtom'
import { modelState, pcsCheckState } from '@/store/circuitTrestleAtom'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { useContext, useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
import { useMessage } from '@/hooks/useMessage'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useMasterController } from '@/hooks/common/useMasterController'
const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }]
export default function StepUp({}) {
export default function StepUp(props) {
const { getMessage } = useMessage()
const [moduleTab, setModuleTab] = useState(1)
const [moduleTabs, setModuleTabs] = useState({})
const [arrayLength, setArrayLength] = useState(3) //module-table-inner
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const { models } = props
const { getPcsVoltageStepUpList, getPcsAutoRecommendList } = useMasterController()
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const canvas = useRecoilValue(canvasState)
const selectedModules = useRecoilValue(selectedModuleState)
const [stepUpListData, setStepUpListData] = useState([])
const [optCodes, setOptCodes] = useState([])
useCanvasPopupStatusController(6)
const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore)
if (Object.keys(canvasPopupStatusState[6]).length !== 0) {
const [selectedRows, setSelectedRows] = useState({})
const [isManualSelection, setIsManualSelection] = useState({})
//
const [selectedValues, setSelectedValues] = useState({})
// useCanvasPopupStatusController(6)
// const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore)
// if (Object.keys(canvasPopupStatusState[6]).length !== 0) {
// console.log('🚀 ~ useEffect ~ canvasPopupStatusState :', canvasPopupStatusState)
// }
useEffect(() => {
// PCS
fetchStepUpData()
}, [])
// PCS
const fetchStepUpData = async () => {
try {
const params = {
useYn: props.getOptYn(), // Y/N
useModuleItemList: props.getUseModuleItemList(), // List
roofSurfaceList: props.getRoofSurfaceList(), //
pcsItemList: props.getPcsItemList(), // PCS
}
// PCS
const res = await getPcsVoltageStepUpList(params)
if (res?.result.code === 200 && res?.data) {
const dataArray = Array.isArray(res.data) ? res.data : [res.data]
const stepUpListData = formatStepUpListData(dataArray)
// PCS SET
setStepUpListData(stepUpListData)
// PCS
const formattedOptCodes = formatOptionCodes(res.data.optionList)
setOptCodes(formattedOptCodes)
}
} catch (error) {
console.error('Error fetching step up data:', error)
}
}
// PCS
const formatOptionCodes = (optionList = []) => {
return optionList?.map((opt) => ({
code: opt.pcsOptCd ? opt.pcsOptCd : '',
name: opt.pcsOptNm ? opt.pcsOptNm : '',
nameJp: opt.pcsOptNmJp ? opt.pcsOptNmJp : '',
}))
}
// // PCS
// const formatStepUpListData = (dataArray = []) => {
// return dataArray?.map((stepUps) => ({
// ...stepUps,
// optionList: formatOptionList(stepUps.optionList),
// pcsItemList: formatPcsItemList(stepUps.pcsItemList),
// selectedPcsItem: formatPcsItemList(stepUps.pcsItemList),
// }))
// }
// PCS
const formatStepUpListData = (dataArray = []) => {
const formattedData = dataArray?.map((stepUps) => ({
...stepUps,
optionList: formatOptionList(stepUps.optionList),
pcsItemList: formatPcsItemList(stepUps.pcsItemList),
selectedPcsItem: formatPcsItemList(stepUps.pcsItemList),
}))
// selectedValues
const initialSelectedValues = {}
formattedData.forEach((stepUp) => {
stepUp.pcsItemList.forEach((pcsItem, pcsIdx) => {
const pcsKey = `${stepUp.id}_${pcsIdx}`
// (rmdYn === 'Y')
const recommendedRow = pcsItem.serQtyList.find((item) => item.rmdYn === 'Y')
if (recommendedRow) {
const selectionData = {
stepUpId: pcsItem.goodsNo,
pcsInfo: {
itemId: pcsItem.itemId,
goodsNo: pcsItem.goodsNo,
pcsMkrCd: pcsItem.pcsMkrCd,
pcsSerCd: pcsItem.pcsSerCd,
},
allocation: {
serQty: recommendedRow.serQty,
paralQty: recommendedRow.paralQty,
},
}
initialSelectedValues[stepUp.id] = {
...initialSelectedValues[stepUp.id],
[pcsKey]: selectionData,
}
}
})
})
setSelectedValues(initialSelectedValues)
return formattedData
}
// PCS
const formatOptionList = (optionList = []) => {
return optionList?.map((option) => ({
pcsOptCd: option.pcsOptCd ? option.pcsOptCd : '',
pcsOptNm: option.pcsOptNm ? option.pcsOptNm : '',
pcsOptNmJp: option.pcsOptNmJp ? option.pcsOptNmJp : '',
}))
}
// PCS
const formatPcsItemList = (pcsItemList = []) => {
return pcsItemList?.map((item) => ({
goodsNo: item.goodsNo ? item.goodsNo : '',
itemId: item.itemId ? item.itemId : '',
itemNm: item.itemNm ? item.itemNm : '',
pcsMkrCd: item.pcsMkrCd ? item.pcsMkrCd : '',
pcsSerCd: item.pcsSerCd ? item.pcsSerCd : '',
connList: formatConnList(item.connList),
serQtyList: formatSerQtyList(item.serQtyList),
}))
}
// PCS
const formatConnList = (connList = []) => {
if (!connList) return [] // null
return connList?.map((conn) => ({
connAllowCur: conn.connAllowCur ? conn.connAllowCur : 0,
connMaxParalCnt: conn.connMaxParalCnt ? conn.connMaxParalCnt : 0,
goodsNo: conn.goodsNo ? conn.goodsNo : '',
itemId: conn.itemId ? conn.itemId : '',
itemNm: conn.itemNm ? conn.itemNm : '',
vstuParalCnt: conn.vstuParalCnt ? conn.vstuParalCnt : 0,
}))
}
// PCS
const formatSerQtyList = (serQtyList = []) => {
return serQtyList?.map((qty) => ({
serQty: qty.serQty ? qty.serQty : 0,
paralQty: qty.paralQty ? qty.paralQty : 0,
rmdYn: qty.rmdYn ? qty.rmdYn : 'N',
usePossYn: qty.usePossYn ? qty.usePossYn : 'Y',
}))
}
//
const handleTabChange = (goodsNo, idx, tabNumber) => {
setModuleTabs((prev) => ({
...prev,
[`${goodsNo}_${idx}`]: tabNumber,
}))
}
//
const handleRowClick = (goodsNo, pcsIdx, serQtyIdx, serQty, paralQty) => {
const rowKey = `${goodsNo}_${pcsIdx}_${serQtyIdx}`
const pcsKey = `${goodsNo}_${pcsIdx}`
console.log('goodsNo >> ', goodsNo, serQty, paralQty)
// PCS
const pcsItem = stepUpListData.find((stepUp) => stepUp.pcsItemList.find((item) => item.goodsNo === goodsNo))?.pcsItemList[pcsIdx]
if (!pcsItem) {
console.error('PCS item not found:', { goodsNo, pcsIdx })
return
}
// -
const selectionData = {
goodsNo: goodsNo,
pcsInfo: {
itemId: pcsItem?.itemId,
goodsNo: pcsItem?.goodsNo,
pcsMkrCd: pcsItem?.pcsMkrCd,
pcsSerCd: pcsItem?.pcsSerCd,
},
allocation: {
serQty: serQty,
paralQty: paralQty,
},
}
//
setSelectedValues((prev) => ({
...prev,
[goodsNo]: {
...prev[goodsNo],
[pcsKey]: selectionData,
},
}))
//
if (props.onValuesSelected) {
props.onValuesSelected(selectionData)
}
setSelectedRows((prev) => {
// stepUpId
const currentStepUpSelections = prev[goodsNo] || {}
// ,
if (currentStepUpSelections[pcsKey] === rowKey) {
return prev
}
return {
...prev,
[goodsNo]: {
...currentStepUpSelections,
[pcsKey]: rowKey,
},
}
})
// ,
setIsManualSelection((prev) => ({
...prev,
[goodsNo]: {
...prev[goodsNo],
[pcsKey]: true,
},
}))
}
//
const getCurrentSelections = () => {
return selectedValues
}
// props getCurrentSelections
useEffect(() => {
if (props.onInitialize) {
props.onInitialize(getCurrentSelections)
}
}, [])
// stepUpListData useEffect
useEffect(() => {
if (props.onInitialize) {
// onInitialize props
props.onInitialize(() => ({
...getCurrentSelections(),
stepUpListData, // stepUpListData
}))
}
}, [stepUpListData])
return (
<>
<div className="properties-setting-wrap outer">
<div className="circuit-overflow">
{/* 3개일때 className = by-max */}
<div className={`module-table-box ${arrayLength === 3 ? 'by-max' : ''}`}>
{Array.from({ length: arrayLength }).map((_, idx) => (
<div key={idx} className="module-table-inner">
<div className="mb-box">
<div className="circuit-table-tit">HQJP-KA55-5</div>
<div className="roof-module-table overflow-y min">
<table>
<thead>
<tr>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.serial.amount')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.total.amount')}</th>
</tr>
</thead>
<tbody>
<tr className="on">
<td className="al-r">10</td>
<td className="al-r">0</td>
</tr>
<tr>
<td className="al-r">10</td>
<td className="al-r">0</td>
</tr>
<tr>
<td className="al-r">10</td>
<td className="al-r">0</td>
</tr>
<tr>
<td className="al-r">10</td>
<td className="al-r">0</td>
</tr>
<tr>
<td className="al-r">10</td>
<td className="al-r">0</td>
</tr>
<tr>
<td className="al-r">10</td>
<td className="al-r">0</td>
</tr>
</tbody>
</table>
{stepUpListData.map((stepUp, index) => (
<div key={index} className={`module-table-box ${stepUp.pcsItemList.length === 3 ? 'by-max' : ''}`}>
{stepUp?.pcsItemList.map((_, idx) => (
<div key={idx} className="module-table-inner">
<div className="mb-box">
<div className="circuit-table-tit">{stepUp.pcsItemList[idx].goodsNo}</div>
<div className="roof-module-table overflow-y min">
<table>
<thead>
<tr>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.serial.amount')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.total.amount')}</th>
</tr>
</thead>
<tbody>
{stepUp.pcsItemList[idx].serQtyList.map((item, serQtyIdx) => {
const rowKey = `${stepUp.pcsItemList[idx].goodsNo}_${idx}_${serQtyIdx}`
const pcsKey = `${stepUp.pcsItemList[idx].goodsNo}_${idx}`
return (
<tr
key={rowKey}
className={`${
(!isManualSelection[stepUp.pcsItemList[idx].goodsNo]?.[pcsKey] && item.rmdYn === 'Y') ||
(selectedRows[stepUp.pcsItemList[idx].goodsNo] && selectedRows[stepUp.pcsItemList[idx].goodsNo][pcsKey] === rowKey)
? 'on'
: ''
}`}
onClick={() => handleRowClick(stepUp.pcsItemList[idx].goodsNo, idx, serQtyIdx, item.serQty, item.paralQty)}
style={{ cursor: 'pointer' }}
>
<td className="al-r">{item.serQty}</td>
<td className="al-r">{item.paralQty}</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
<div className="module-box-tab mb10">
<button
className={`module-btn ${(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 1 ? 'act' : ''}`}
onClick={() => handleTabChange(stepUp.pcsItemList[idx].goodsNo, idx, 1)}
>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.connected')}
</button>
<button
className={`module-btn ${(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 2 ? 'act' : ''}`}
onClick={() => handleTabChange(stepUp.pcsItemList[idx].goodsNo, idx, 2)}
>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.option')}
</button>
</div>
<div className="circuit-table-flx-wrap">
{(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 1 && (
<div className="circuit-table-flx-box">
<div className="roof-module-table min mb10">
<table>
<thead>
<tr>
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.circuit.amount')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
</tr>
</thead>
<tbody>
<tr>
<td className="al-c">
{stepUp.pcsItemList[idx].connList?.[0]?.goodsNo ? stepUp.pcsItemList[idx].connList?.[0]?.goodsNo : '-'}
</td>
<td className="al-c">
{stepUp.pcsItemList[idx].connList?.[0]?.connMaxParalCnt
? (stepUp.pcsItemList[idx].connList?.[0]?.connMaxParalCnt ?? '-')
: '-'}
</td>
<td className="al-c">
{stepUp.pcsItemList[idx].connList?.[0]?.vstuParalCnt ? stepUp.pcsItemList[idx].connList?.[0]?.vstuParalCnt : '-'}
</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
{(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 2 && (
<div className="circuit-table-flx-box">
<div className="roof-module-table min mb10">
<table>
<thead>
<tr>
{/* <th></th>
<th>昇圧回路数</th> */}
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
</tr>
</thead>
<tbody>
<tr>
<td className="al-c">-</td>
<td className="al-c">-</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
<div className="module-box-tab mb10">
<button className={`module-btn ${moduleTab === 1 ? 'act' : ''}`} onClick={() => setModuleTab(1)}>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.connected')}
</button>
<button className={`module-btn ${moduleTab === 2 ? 'act' : ''}`} onClick={() => setModuleTab(2)}>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.option')}
</button>
</div>
<div className="circuit-table-flx-wrap">
{moduleTab === 1 && (
<div className="circuit-table-flx-box">
<div className="roof-module-table min mb10">
<table>
<thead>
<tr>
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.circuit.amount')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
</tr>
</thead>
<tbody>
<tr>
<td className="al-c">KTN-CBD4C</td>
<td className="al-r">4</td>
<td className="al-r">0</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
{moduleTab === 2 && (
<div className="circuit-table-flx-box">
<div className="roof-module-table min mb10">
<table>
<thead>
<tr>
<th>名称</th>
<th>昇圧回路数</th>
</tr>
</thead>
<tbody>
<tr>
<td className="al-c">-</td>
<td className="al-c">-</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
))}
</div>
))}
</div>
))}
</div>
<div className="slope-wrap">
<div className="outline-form">
<span className="mr10" style={{ width: 'auto' }}>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}
</span>
<div className="grid-select mr10">
<QSelectBox title={'電力検出ユニット (モニター付き)'} options={SelectOption01} />
</div>
{optCodes.length > 0 && (
<div className="grid-select mr10">
{/* <QSelectBox title={'電力検出ユニット (モニター付き)'} /> */}
<QSelectBox options={optCodes} title={optCodes[0].name} value={optCodes[0].name} sourceKey="code" targetKey="code" showKey="name" />
</div>
)}
</div>
</div>
</div>

View File

@ -1,35 +1,449 @@
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { POLYGON_TYPE } from '@/common/common'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal'
import { canvasState } from '@/store/canvasAtom'
import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { useContext, useEffect, useState } from 'react'
import { useRecoilValue } from 'recoil'
export default function PassivityCircuitAllocation() {
export default function PassivityCircuitAllocation(props) {
const {
tabNum,
setTabNum,
selectedModels,
getOptYn: getApiProps,
getUseModuleItemList: getSelectedModuleList,
getSelectModelList: getSelectModelList,
getRoofSurfaceList,
getModelList,
} = props
const { swalFire } = useSwal()
const { getMessage } = useMessage()
const moduleData = {
header: [
{ name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' },
{ name: getMessage('modal.circuit.trestle.setting.circuit'), prop: 'circuit' },
{
name: getMessage('Q.TRON M-G2'),
prop: 'moduleName',
},
{
name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`,
prop: 'powerGeneration',
},
],
rows: [
{
roofShape: { name: 'M 1' },
circuit: { name: 'M 1' },
moduleName: { name: '8' },
powerGeneration: { name: '3,400' },
},
{
roofShape: { name: 'M 1' },
circuit: { name: 'M 1' },
moduleName: { name: '8' },
powerGeneration: { name: '3,400' },
},
],
const canvas = useRecoilValue(canvasState)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const selectedModules = useRecoilValue(selectedModuleState)
const moduleStatistics = useRecoilValue(moduleStatisticsState)
// const [totalWpout, setTotalWpout] = useState(0)
const [selectedPcs, setSelectedPcs] = useState(selectedModels[0])
// const { header, rows: row } = moduleStatistics
const [header, setHeader] = useState(moduleStatistics.header)
const [rows, setRows] = useState(moduleStatistics.rows)
const [footer, setFooter] = useState(['합계'])
const [circuitNumber, setCircuitNumber] = useState(1)
const [targetModules, setTargetModules] = useState([])
const { getPcsManualConfChk } = useMasterController()
useEffect(() => {
console.log('header, rows', header, rows)
console.log('selectedModels', selectedModels)
// setSurfaceInfo()
setTableData()
if (!managementState) {
setManagementState(managementStateLoaded)
}
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((obj) => {
obj.on('mousedown', (e) => handleTargetModules(obj))
})
return () => {
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((obj) => {
obj.set({ strokeWidth: 0.3 })
obj.off('mousedown')
})
canvas.renderAll()
}
}, [])
const handleTargetModules = (obj) => {
if (!Array.isArray(targetModules)) {
setTargetModules([])
return
}
setTargetModules((prev) => {
if (prev.includes(obj.id)) {
obj.set({ strokeWidth: 0.3 })
return prev.filter((o) => o !== obj.id)
} else {
obj.set({ strokeWidth: 2 })
return [...prev, obj.id]
}
})
canvas.renderAll()
}
const setSurfaceInfo = () => {
const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name)
// setHeaders([header[0], { name: '', prop: 'circuit' }, ...header.slice(1)])
setRows(
rows.map((row) => {
return {
...row,
circuit: '',
}
}),
)
let totals = {}
rows.forEach((row) => {
if (header.length === 4) {
if (!totals[header[2].prop]) totals[header[2].prop] = 0
totals[header[2].prop] += +row[header[2].prop]
} else if (header.length === 5) {
if (!totals[header[2].prop]) totals[header[2].prop] = 0
totals[header[2].prop] += +row[header[2].prop]
if (!totals[header[3].prop]) totals[header[3].prop] = 0
totals[header[3]] += +row[header[3]]
}
})
setFooter([
...['합계', ''],
...Object.keys(totals).map((key) => {
return totals[key]
}),
Object.keys(totals).reduce((acc, key) => {
return acc + totals[key]
}, 0),
])
// let totalWpout = 0
// const rows = surfaces.map((surface) => {
// let wpOut = 0
// let moduleInfo = {}
// surface.modules.forEach((module) => {
// wpOut += +module.moduleInfo.wpOut
// if (!moduleInfo[module.moduleInfo.itemId]) moduleInfo[module.moduleInfo.itemId] = 0
// moduleInfo[module.moduleInfo.itemId]++
// })
// totalWpout += wpOut
// console.log('🚀 ~ moduleData.rows=surfaces.map ~ module:', module)
// return {
// roofShape: DIRECTION[surface.direction],
// powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }),
// ...moduleInfo,
// }
// })
// setTotalWpout(totalWpout)
// -> ->
// wpOut
// setModuleData({
// header: [
// { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' },
// { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' },
// ...selectedModules.itemList.map((module) => {
// return {
// name: module.itemNm,
// prop: module.itemId,
// }
// }),
// {
// name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`,
// prop: 'powerGeneration',
// },
// ],
// rows: rows,
// })
}
const handleCircuitNumberFix = () => {
if (!circuitNumber || circuitNumber === 0) {
swalFire({
text: '회로번호를 1 이상입력해주세요.',
type: 'alert',
icon: 'warning',
})
return
} else if (targetModules.length === 0) {
swalFire({
text: '모듈을 선택해주세요.',
type: 'alert',
icon: 'warning',
})
return
} else if (selectedModels.length > 1) {
const uniqueCircuitNumbers = [
...new Set(
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuitNumber)
.map((obj) => obj.circuitNumber),
),
]
let result = false
uniqueCircuitNumbers.forEach((number) => {
if (
number.split('-')[1] === circuitNumber + ')' &&
number.split('-')[0] !== '(' + (selectedModels.findIndex((model) => model.id === selectedPcs.id) + 1)
) {
result = true
}
})
if (result) {
swalFire({
text: '회로 번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로 번호를 설정하십시오.',
type: 'alert',
icon: 'warning',
})
return
}
}
canvas.discardActiveObject()
canvas
.getObjects()
.filter((obj) => targetModules.includes(obj.id))
.forEach((obj) => {
const moduleCircuitText = new fabric.Text(getCircuitNumber(), {
left: obj.left + obj.width / 2,
top: obj.top + obj.height / 2,
fill: 'black',
fontSize: 20,
width: obj.width,
height: obj.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
parentId: obj.id,
circuitInfo: selectedPcs,
})
obj.set({
strokeWidth: 0.3,
})
obj.pcsItemId = selectedPcs.itemId
obj.circuit = moduleCircuitText
obj.circuitNumber = getCircuitNumber()
canvas.add(moduleCircuitText)
})
const roofSurfaceList = canvas
.getObjects()
.filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name)
.map((surface) => {
return {
roofSurfaceId: surface.id,
roofSurface: surface.direction,
roofSurfaceIncl: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
moduleList: surface.modules.map((module) => {
return {
itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber,
pcsItemId: module.pcsItemId,
}
}),
}
})
const pcsItemList = selectedModels.map((model) => {
return {
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
itemId: model.itemId,
itemNm: model.itemNm,
goodsNo: model.goodsNo,
serQtyList: [
{
serQty: 0,
paralQty: 0,
rmdYn: 'Y',
usePossYn: 'Y',
roofSurfaceList: roofSurfaceList,
},
],
}
})
const params = {
...getApiProps(),
useModuleItemList: getSelectedModuleList(),
pcsItemList: pcsItemList,
}
getPcsManualConfChk(params).then((res) => {
if (res.resultCode === 'E') {
swalFire({
text: res.resultMsg,
type: 'alert',
icon: 'warning',
confirmFn: () => {
const circuitNumbers = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber' && targetModules.includes(obj.parentId))
canvas.remove(...circuitNumbers)
canvas
.getObjects()
.filter((obj) => obj.name === 'module' && targetModules.includes(obj.id))
.forEach((obj) => {
obj.pcsItemId = null
obj.circuit = null
obj.circuitNumber = null
})
canvas.renderAll()
},
})
return
}
setTargetModules([])
setCircuitNumber(+circuitNumber + 1)
setTableData()
})
}
const getCircuitNumber = () => {
if (selectedModels.length === 1) {
return `(${circuitNumber})`
} else {
return `(${selectedModels.findIndex((model) => model.id === selectedPcs.id) + 1}-${circuitNumber})`
}
}
const setTableData = () => {
const tempHeader = [
{ name: '지붕면', prop: 'name' },
{ name: '회로', prop: 'circuit' },
...selectedModules.itemList.map((module) => {
return {
name: module.itemNm,
prop: module.itemId,
}
}),
{ name: '발전량(kW)', prop: 'wpOut' },
]
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
const surfaceIds = surfaces.map((surface) => surface.parentId)
const surfaceObjects = {}
const rows = surfaces.map((surface) => {
const moduleObject = {}
surfaceObjects[surface.id] = {
roofSurface: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText,
circuit: '-',
amount: 0,
wpOut: 0,
circuits: {},
}
surface.modules.forEach((module) => {
if (!surfaceObjects[surface.id][module.moduleInfo.itemId]) {
//
surfaceObjects[surface.id][module.moduleInfo.itemId] = 0 //
}
surfaceObjects[surface.id][module.moduleInfo.itemId]++
surfaceObjects[surface.id].wpOut += +module.moduleInfo.wpOut
if (module.circuit) {
if (!surfaceObjects[surface.id].circuits[module.circuitNumber]) {
surfaceObjects[surface.id].circuits[module.circuitNumber] = {
circuit: module.circuitNumber,
wpOut: 0,
circuits: { wpOut: 0 },
}
if (!surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId]) {
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId] = 0
}
}
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId]++
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits.wpOut += +module.moduleInfo.wpOut
surfaceObjects[surface.id].wpOut -= +module.moduleInfo.wpOut
surfaceObjects[surface.id][module.moduleInfo.itemId]--
}
})
})
console.log('rows', rows)
console.log('surfaceObjects', surfaceObjects)
let tempRows = []
Object.keys(surfaceObjects).forEach((key) => {
let tempRow = {
name: surfaceObjects[key].roofSurface,
circuit: surfaceObjects[key].circuit,
wpOut: surfaceObjects[key].wpOut,
}
selectedModules.itemList.forEach((module) => {
tempRow[module.itemId] = surfaceObjects[key][module.itemId]
})
tempRows.push(tempRow)
Object.keys(surfaceObjects[key].circuits).forEach((circuit) => {
let row = {
name: surfaceObjects[key].roofSurface,
circuit: surfaceObjects[key].circuits[circuit].circuit,
wpOut: surfaceObjects[key].circuits[circuit].circuits.wpOut,
}
selectedModules.itemList.forEach((module) => {
row[module.itemId] = surfaceObjects[key].circuits[circuit].circuits[module.itemId]
})
tempRows.push(row)
})
})
const tempFooter = {
name: '총합',
circuit: '-',
wpOut: tempRows.reduce((acc, row) => acc + row.wpOut, 0),
}
selectedModules.itemList.forEach((module) => {
tempFooter[module.itemId] = tempRows.reduce((acc, row) => acc + row[module.itemId], 0)
})
console.log('tempHeader, tempRows, tempFooter', tempHeader, tempRows, tempFooter)
setHeader(tempHeader)
setRows(tempRows.filter((row) => row.wpOut !== 0))
setFooter(tempFooter)
}
const initSelectedPcsCircuitNumber = () => {
swalFire({
title: '선택된 파워 컨디셔너의 회로할당을 초기화합니다.',
type: 'confirm',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas.getObjects().filter((obj) => obj.name === 'module' && obj.circuit?.circuitInfo?.id === selectedPcs.id)
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
})
setTargetModules([])
canvas.renderAll()
canvas.discardActiveObject()
},
})
}
const initAllPcsCircuitNumber = () => {
canvas.discardActiveObject()
swalFire({
title: '회로 할당의 설정을 초기화합니다.',
type: 'confirm',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas
.getObjects()
.filter((obj) => obj.name === 'module' && selectedModels.map((model) => model.id).includes(obj.circuit?.circuitInfo?.id))
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
})
setTargetModules([])
canvas.renderAll()
},
})
}
return (
<>
<div className="properties-setting-wrap outer">
@ -39,26 +453,35 @@ export default function PassivityCircuitAllocation() {
<div className="bold-font mb10">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}</div>
<div className="normal-font mb15">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.info')}</div>
<div className="roof-module-table overflow-y">
<table>
<thead>
<tr>
{moduleData.header.map((header) => (
<th key={header.prop}>{header.name}</th>
{header && (
<table>
<thead>
<tr>
{header.map((header, index) => (
<th key={'header' + index}>{header.name}</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row, index) => (
<tr key={'row' + index}>
{header.map((header, i) => (
<td className="al-c" key={'rowcell' + i}>
{row[header.prop]}
</td>
))}
</tr>
))}
</tr>
</thead>
<tbody>
{moduleData.rows.map((row, index) => (
<tr key={index}>
{moduleData.header.map((header) => (
<td className="al-c" key={header.prop}>
{row[header.prop].name}
<tr>
{header.map((header, i) => (
<td className="al-c" key={'footer' + i}>
{footer[header.prop]}
</td>
))}
</tr>
))}
</tbody>
</table>
</tbody>
</table>
)}
</div>
</div>
</div>
@ -69,7 +492,27 @@ export default function PassivityCircuitAllocation() {
<div className="bold-font">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional')}</div>
</div>
<div className="hexagonal-item">
<div className="d-check-radio pop mb10">
{selectedModels.map((model, index) => (
<div className="d-check-radio pop mb10" key={'model' + index}>
<input
type="radio"
name="radio01"
id={`ra0${index + 1}`}
value={model}
checked={selectedPcs?.id === model.id}
onChange={() => setSelectedPcs(model)}
/>
<label htmlFor={`ra0${index + 1}`}>
{model.itemNm} (
{getMessage(
'modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info',
managementState?.coldRegionFlg === '1' ? [model.serMinQty, model.serColdZoneMaxQty] : [model.serMinQty, model.serMaxQty],
)}
)
</label>
</div>
))}
{/* <div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra01" />
<label htmlFor="ra01">HQJP-KA55-5 (標準回路2枚10)</label>
</div>
@ -80,7 +523,7 @@ export default function PassivityCircuitAllocation() {
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra03" />
<label htmlFor="ra03">HQJP-KA55-5 (標準回路2枚10)</label>
</div>
</div>*/}
</div>
</div>
</div>
@ -92,16 +535,25 @@ export default function PassivityCircuitAllocation() {
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num')}
</span>
<div className="input-grid mr5" style={{ width: '70px' }}>
<input type="text" className="input-origin block" />
<input
type="text"
className="block input-origin"
value={circuitNumber}
min={1}
max={99}
onChange={(e) => setCircuitNumber(e.target.value)}
/>
</div>
<button className="btn-frame roof">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix')}</button>
<button className="btn-frame roof" onClick={() => handleCircuitNumberFix()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix')}
</button>
</div>
</div>
<div className="circuit-right-wrap">
<button className="btn-frame roof mr5">
<button className="btn-frame roof mr5" onClick={() => initSelectedPcsCircuitNumber()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset')}
</button>
<button className="btn-frame roof mr5">
<button className="btn-frame roof mr5" onClick={() => initAllPcsCircuitNumber()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset')}
</button>
</div>

View File

@ -85,7 +85,7 @@ export default function DimensionLineSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('contextmenu.display.edit')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -141,6 +141,7 @@ export default function DimensionLineSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -18,7 +18,7 @@ export default function Distance(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.distance')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -68,6 +68,7 @@ export default function Distance(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -40,7 +40,7 @@ export default function EavesGableEdit({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.eaves.gable.edit')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -62,6 +62,7 @@ export default function EavesGableEdit({ id, pos = { x: 50, y: 230 } }) {
{type === TYPES.SHED && <Shed {...shedProps} />}
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -65,7 +65,7 @@ export default function FlowDirectionSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ml mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.shape.flow.direction.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -176,6 +176,7 @@ export default function FlowDirectionSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -179,7 +179,7 @@ export default function DotLineGrid(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ssm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.canvas.setting.grid.dot.line.setting')}</h1>
<button
className="modal-close"
@ -293,6 +293,7 @@ export default function DotLineGrid(props) {
</div>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</WithDraggable>
)
}

View File

@ -22,7 +22,7 @@ export default function GridCopy(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.grid.copy')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -77,6 +77,7 @@ export default function GridCopy(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -75,7 +75,7 @@ export default function GridMove(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.grid.move')} </h1>
<button className="modal-close" onClick={handleClose}>
닫기
@ -156,6 +156,7 @@ export default function GridMove(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -52,7 +52,7 @@ export default function LinePropertySetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('contextmenu.line.property.edit')} </h1>
<button className="modal-close" onClick={() => handleClosePopup()}>
닫기
@ -91,6 +91,7 @@ export default function LinePropertySetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -18,7 +18,11 @@ export default function OuterLineWall({ props }) {
className="input-origin block"
value={length1}
ref={length1Ref}
onFocus={(e) => (length1Ref.current.value = '')}
onFocus={(e) => {
if (length1Ref.current.value === '0') {
length1Ref.current.value = ''
}
}}
onChange={(e) => onlyNumberInputChange(e, setLength1)}
placeholder="3000"
/>

View File

@ -16,7 +16,7 @@ export default function CircuitNumberEdit(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title"> {getMessage('modal.module.circuit.number.edit')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -42,6 +42,7 @@ export default function CircuitNumberEdit(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -84,7 +84,7 @@ export default function PanelEdit(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">
{getMessage([PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type) ? 'modal.move.setting' : 'modal.copy.setting')}{' '}
</h1>
@ -139,6 +139,7 @@ export default function PanelEdit(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -26,7 +26,7 @@ export default function ColumnInsert(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.panel.column.insert')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -105,6 +105,7 @@ export default function ColumnInsert(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -29,7 +29,7 @@ export default function ColumnRemove(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.panel.column.remove')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -115,6 +115,7 @@ export default function ColumnRemove(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -26,7 +26,7 @@ export default function RowInsert(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.row.insert')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -105,6 +105,7 @@ export default function RowInsert(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -29,7 +29,7 @@ export default function RowRemove(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.row.remove')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -115,6 +115,7 @@ export default function RowRemove(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -18,7 +18,7 @@ export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.roof.cover.movement.shape.updown')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -33,7 +33,6 @@ export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) {
))}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{type === TYPE.FLOW_LINE && <FlowLine {...flowLineProps} />}
{type === TYPE.UP_DOWN && <Updown {...updownProps} />}
</div>
@ -43,6 +42,7 @@ export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -42,7 +42,7 @@ export default function DormerOffset(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{title}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -103,6 +103,7 @@ export default function DormerOffset(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -77,7 +77,7 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lrr`} style={{ visibility: isHidden ? 'hidden' : 'visible' }}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.object')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -92,7 +92,6 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
))}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{buttonAct === 1 && <OpenSpace ref={objectPlacement} />}
{buttonAct === 2 && <Shadow ref={objectPlacement} />}
{buttonAct === 3 && <TriangleDormer ref={dormerPlacement} />}
@ -109,6 +108,7 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -23,7 +23,7 @@ export default function RoofMaterialSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.roof.material.edit')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -39,6 +39,7 @@ export default function RoofMaterialSetting(props) {
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -47,7 +47,7 @@ export default function SizeSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ssm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.size.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -95,6 +95,7 @@ export default function SizeSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -10,7 +10,7 @@ export default function PropertiesSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ssm`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.canvas.setting.wallline.properties.setting')}</h1>
<button className="modal-close" onClick={() => closeModal(id)}>
닫기
@ -38,6 +38,7 @@ export default function PropertiesSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -116,7 +116,7 @@ export default function WallLineSetting(props) {
return (
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.cover.outline.drawing')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}></button>
</div>
@ -152,7 +152,6 @@ export default function WallLineSetting(props) {
</button>
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('modal.cover.outline.setting')}</div>
{type === OUTER_LINE_TYPE.OUTER_LINE ? (
<OuterLineWall props={outerLineProps} />
) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? (
@ -184,6 +183,7 @@ export default function WallLineSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -3,6 +3,8 @@
import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { useRecoilValue, useResetRecoilState } from 'recoil'
export default function PanelBatchStatistics() {
const { getMessage } = useMessage()
@ -11,6 +13,7 @@ export default function PanelBatchStatistics() {
x: 0,
y: 30,
})
const { header, rows, footer } = useRecoilValue(moduleStatisticsState)
return (
<WithDraggable isShow={true} handle=".penal-wrap" pos={pos}>
@ -21,14 +24,26 @@ export default function PanelBatchStatistics() {
<table className="penal-table">
<thead>
<tr>
<th>{getMessage('modal.panel.batch.statistic.roof.shape')}</th>
<th>{getMessage('modal.panel.batch.statistic.power.generation.amount')} (kW)</th>
{header.map((item, index) => (
<th key={index}>{item.name}</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row, index) => (
<tr key={index}>
{header.map((item, i) => (
<td key={index}>
{typeof row[item.prop] === 'number' ? row[item.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : row[item.prop]}
</td>
))}
</tr>
))}
<tr>
<td>{getMessage('modal.panel.batch.statistic.total')}</td>
<td className="al-r">0.000</td>
{footer.map((item, index) => (
<td key={index}>{typeof item === 'number' ? item.toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : item}</td>
// <td className="al-r">{item.amount}</td>
))}
</tr>
</tbody>
</table>

View File

@ -123,7 +123,7 @@ export default function PlacementShapeDrawing({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.drawing')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -142,7 +142,6 @@ export default function PlacementShapeDrawing({ id, pos = { x: 50, y: 230 } }) {
))}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{buttonAct === 1 && <OuterLineWall props={outerLineProps} />}
{buttonAct === 2 && <RightAngle props={rightAngleProps} />}
{buttonAct === 3 && <DoublePitch props={doublePitchProps} />}
@ -155,10 +154,11 @@ export default function PlacementShapeDrawing({ id, pos = { x: 50, y: 230 } }) {
{getMessage('modal.cover.outline.rollback')}
</button>
<button className="btn-frame modal act" onClick={handleFix}>
{getMessage('modal.cover.outline.fix')}
{getMessage('modal.placement.surface.drawing.fix')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -56,20 +56,24 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
]
//
useEffect(() => {
if (!basicSetting || !currentRoof || Object.keys(currentRoof).length === 0 || Object.keys(basicSetting).length === 0) return
const raftCodeList = findCommonCode('203800')
setRaftCodes(raftCodeList)
// useEffect(() => {
// if (!basicSetting || !currentRoof || Object.keys(currentRoof).length === 0 || Object.keys(basicSetting).length === 0) return
// const raftCodeList = findCommonCode('203800')
// setRaftCodes(raftCodeList)
// console.log('🚀 ~ useEffect ~ >>>>>>>>>>>>> raftCodeList 11 :', raftCodeList)
if (addedRoofs[0].roofAngleSet && addedRoofs[0].roofAngleSet?.length > 0) {
setCurrentRoof({ ...currentRoof, roofSizeSet: String(addedRoofs[0].roofSizeSet), roofAngleSet: addedRoofs[0].roofAngleSet })
} else if (basicSetting.roofAngleSet && basicSetting.roofAngleSet?.length > 0) {
setCurrentRoof({ ...currentRoof, roofSizeSet: String(basicSetting.roofSizeSet), roofAngleSet: basicSetting.roofAngleSet })
}
}, [])
// if (addedRoofs[0].roofAngleSet && addedRoofs[0].roofAngleSet?.length > 0) {
// setCurrentRoof({ ...currentRoof, roofSizeSet: String(addedRoofs[0].roofSizeSet), roofAngleSet: addedRoofs[0].roofAngleSet })
// } else if (basicSetting.roofAngleSet && basicSetting.roofAngleSet?.length > 0) {
// setCurrentRoof({ ...currentRoof, roofSizeSet: String(basicSetting.roofSizeSet), roofAngleSet: basicSetting.roofAngleSet })
// }
// }, [])
useEffect(() => {
if (addedRoofs.length > 0) {
const raftCodeList = findCommonCode('203800')
setRaftCodes(raftCodeList)
setCurrentRoof({ ...addedRoofs[0] })
}
}, [addedRoofs])
@ -155,20 +159,20 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
...roofInfo,
},
//roofs: addedRoofs,
roofsData: {
roofApply: true,
roofSeq: 0,
roofMatlCd: currentRoof.roofMatlCd,
roofWidth: currentRoof.width,
roofHeight: currentRoof.length,
roofHajebichi: currentRoof.hajebichi,
roofGap: currentRoof.raft,
roofLayout: currentRoof.layout,
roofSizeSet: currentRoof.roofSizeSet,
roofAngleSet: currentRoof.roofAngleSet,
roofPitch: currentRoof.pitch,
roofAngle: currentRoof.angle,
},
// roofsData: {
// roofApply: true,
// roofSeq: 0,
// roofMatlCd: currentRoof.roofMatlCd,
// roofWidth: currentRoof.width,
// roofHeight: currentRoof.length,
// roofHajebichi: currentRoof.hajebichi,
// roofGap: currentRoof.raft,
// roofLayout: currentRoof.layout,
// roofSizeSet: currentRoof.roofSizeSet,
// roofAngleSet: currentRoof.roofAngleSet,
// roofPitch: currentRoof.pitch,
// roofAngle: currentRoof.angle,
// },
})
basicSettingSave()
@ -177,7 +181,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ll mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.initial.setting')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -256,7 +260,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
title={
currentRoof?.roofSizeSet === '3' ? getMessage('modal.placement.initial.setting.size.none.pitch') : currentRoof?.roofMatlNm
}
ref={roofRef.roofCd}
//ref={roofRef.roofCd}
options={roofMaterials.map((roof) => {
return { ...roof, name: globalLocale === 'ko' ? roof.roofMatlNm : roof.roofMatlNmJp }
})}
@ -338,13 +342,14 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
{currentRoof && ['C', 'R'].includes(currentRoof.raftAuth) && (
<div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span>
{raftCodes.length > 0 && (
{raftCodes?.length > 0 && (
<div className="select-wrap" style={{ width: '160px' }}>
<QSelectBox
options={raftCodes}
ref={roofRef.rafter}
//ref={roofRef.rafter}
title={
raftCodes.find((r) => r.clCode === (currentRoof?.raft === undefined ? currentRoof?.raftBaseCd : currentRoof?.raft)).clCodeNm
raftCodes?.find((r) => r.clCode === (currentRoof?.raft === undefined ? currentRoof?.raftBaseCd : currentRoof?.raft))
.clCodeNm
}
value={currentRoof?.raft === undefined ? currentRoof?.raftBaseCd : currentRoof?.raft}
onChange={(e) => handleRafterChange(e.clCode)}
@ -418,6 +423,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
</div>
{showSizeGuideModal && <SizeGuide setShowSizeGuidModal={setShowSizeGuidModal} />}
{showMaterialGuideModal && <MaterialGuide setShowMaterialGuidModal={setShowMaterialGuidModal} />}
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -242,7 +242,7 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lr-2`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.arrangement')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -290,6 +290,7 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
</div>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -63,7 +63,7 @@ export default function ActualSizeSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ssm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.actual.size.setting')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -116,6 +116,7 @@ export default function ActualSizeSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -45,7 +45,7 @@ export default function ContextRoofAllocationSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lr mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.estimate.roof.alloc')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -79,133 +79,134 @@ export default function ContextRoofAllocationSetting(props) {
</button>
</div>
<div className="grid-option-wrap">
{currentRoofList.map((roof, index) => {
return (
<div className="grid-option-box" key={index}>
<div className="d-check-radio pop no-text">
<input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} />
<label
htmlFor="ra01"
onClick={(e) => {
handleDefaultRoofMaterial(index)
}}
></label>
</div>
<div className="grid-option-block-form">
<div className="block-box">
<div className="flex-ment">
<div className="grid-select" style={{ width: '248px' }}>
<QSelectBox
options={roofMaterials}
value={roof}
showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
onChange={(e) => handleChangeRoofMaterial(e, index)}
/>
</div>
{index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>}
</div>
{currentRoofList.length > 0 &&
currentRoofList.map((roof, index) => {
return (
<div className="grid-option-box" key={index}>
<div className="d-check-radio pop no-text">
<input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} />
<label
htmlFor="ra01"
onClick={(e) => {
handleDefaultRoofMaterial(index)
}}
></label>
</div>
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('slope')}</span>
<div className="input-grid" style={{ width: '214px' }}>
<input
type="text"
className="input-origin block"
onChange={(e) => {
handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index)
}}
defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
/>
<div className="grid-option-block-form">
<div className="block-box">
<div className="flex-ment">
<div className="grid-select" style={{ width: '248px' }}>
<QSelectBox
options={roofMaterials}
value={roof}
showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
onChange={(e) => handleChangeRoofMaterial(e, index)}
/>
</div>
{index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>}
</div>
<span>{pitchText}</span>
</div>
</div>
{(roof.widAuth || roof.lenAuth) && (
<div className="block-box">
{roof.widAuth && (
<div className="flex-ment">
<span>W</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.width} readOnly={roof.widAuth === 'R'} />
</div>
<div className="flex-ment">
<span>{getMessage('slope')}</span>
<div className="input-grid" style={{ width: '214px' }}>
<input
type="text"
className="input-origin block"
onChange={(e) => {
handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index)
}}
defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
/>
</div>
)}
{roof.lenAuth && (
<div className="flex-ment">
<span>L</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.length} readOnly={roof.lenAuth === 'R'} />
</div>
</div>
)}
<span>{pitchText}</span>
</div>
</div>
)}
{(roof.raftAuth || roof.roofPchAuth) && (
<div className="block-box">
{roof.raftAuth && (
<div className="block-box">
{(roof.widAuth || roof.lenAuth) && (
<div className="block-box">
{roof.widAuth && (
<div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span>
{raftCodes.length > 0 && (
<div className="grid-select" style={{ width: '160px' }}>
<QSelectBox
options={raftCodes}
value={roof}
showKey={'clCodeNm'}
sourceKey={'clCode'}
targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
/>
</div>
)}
</div>
</div>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}>
<input
type="text"
className="input-origin block"
value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'}
/>
<span>W</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.width} readOnly={roof.widAuth === 'R'} />
</div>
</div>
</div>
)}
</div>
)}
<div className="block-box">
<div className="icon-btn-wrap">
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index)
}}
>
{getMessage('modal.roof.alloc.select.parallel')}
<i className="allocation01"></i>
</button>
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index)
}}
>
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i>
</button>
)}
{roof.lenAuth && (
<div className="flex-ment">
<span>L</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.length} readOnly={roof.lenAuth === 'R'} />
</div>
</div>
)}
</div>
)}
{(roof.raftAuth || roof.roofPchAuth) && (
<div className="block-box">
{roof.raftAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span>
{raftCodes.length > 0 && (
<div className="grid-select" style={{ width: '160px' }}>
<QSelectBox
options={raftCodes}
value={roof}
showKey={'clCodeNm'}
sourceKey={'clCode'}
targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
/>
</div>
)}
</div>
</div>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}>
<input
type="text"
className="input-origin block"
value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'}
/>
</div>
</div>
</div>
)}
</div>
)}
<div className="block-box">
<div className="icon-btn-wrap">
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index)
}}
>
{getMessage('modal.roof.alloc.select.parallel')}
<i className="allocation01"></i>
</button>
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index)
}}
>
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i>
</button>
</div>
</div>
</div>
</div>
</div>
)
})}
)
})}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSaveContext}>
@ -213,6 +214,7 @@ export default function ContextRoofAllocationSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -49,7 +49,7 @@ export default function RoofAllocationSetting(props) {
<div className={`modal-pop-wrap lr mount`}>
{currentRoofList && (
<>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.estimate.roof.alloc')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -235,6 +235,7 @@ export default function RoofAllocationSetting(props) {
</div>
</>
)}
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -31,7 +31,7 @@ export default function RoofShapePassivitySetting({ id, pos = { x: 50, y: 230 }
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxm`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.roof.cover.roof.shape.passivity.setting')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -67,6 +67,7 @@ export default function RoofShapePassivitySetting({ id, pos = { x: 50, y: 230 }
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -90,7 +90,7 @@ export default function RoofShapeSetting({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lr mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.roof.shape.setting')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -108,7 +108,6 @@ export default function RoofShapeSetting({ id, pos = { x: 50, y: 230 } }) {
))}
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('setting')}</div>
{shapeNum === 1 && <Ridge {...ridgeProps} />}
{(shapeNum === 2 || shapeNum === 3) && <Pattern {...patternProps} />}
{shapeNum === 4 && <Side {...sideProps} />}
@ -120,6 +119,7 @@ export default function RoofShapeSetting({ id, pos = { x: 50, y: 230 } }) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -75,7 +75,7 @@ export default function SettingModal01(props) {
<>
<WithDraggable isShow={true} pos={{ x: 1275, y: 180 }}>
<div className={`modal-pop-wrap sm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.canvas.setting')}</h1>
<button className="modal-close" onClick={() => closePopup(id, true)}>
닫기
@ -100,6 +100,7 @@ export default function SettingModal01(props) {
{buttonAct === 2 && <SecondOption {...secondProps} />}
{buttonAct === 3 && <GridOption {...gridProps} />}
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
</>

View File

@ -192,7 +192,7 @@ export default function DimensionLineSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.canvas.setting.font.plan.absorption.dimension.line')} </h1>
<button
className="modal-close"
@ -258,6 +258,7 @@ export default function DimensionLineSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -57,7 +57,7 @@ export default function PlanSizeSetting(props) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xsm mount`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.canvas.setting.font.plan.absorption.plan.size.setting')}</h1>
<button
className="modal-close"
@ -104,6 +104,7 @@ export default function PlanSizeSetting(props) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -41,7 +41,7 @@ export default function WallLineOffsetSetting({ id, pos = { x: 50, y: 230 } }) {
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head">
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.wallline.offset.setting')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
@ -66,6 +66,7 @@ export default function WallLineOffsetSetting({ id, pos = { x: 50, y: 230 } }) {
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)

View File

@ -221,7 +221,7 @@ export default function Header(props) {
return (
<>
{!isGlobalLoading && !(pathName.includes('login') || pathName.includes('join') || sessionState.pwdInitYn === 'N') && (
{!(pathName.includes('login') || pathName.includes('join') || sessionState.pwdInitYn === 'N') && (
<header className={isDimmed}>
<div className="header-inner">
<div className="header-right">

View File

@ -10,12 +10,12 @@ import { useRecoilValue } from 'recoil'
import { useRouter } from 'next/navigation'
import { globalLocaleStore } from '@/store/localeAtom'
import { queryStringFormatter } from '@/util/common-utils'
import MainSkeleton from '../ui/MainSkeleton'
import { useMainContentsController } from '@/hooks/main/useMainContentsController'
import { QcastContext } from '@/app/QcastProvider'
import { useSwal } from '@/hooks/useSwal'
import BoardDetailModal from '../community/modal/BoardDetailModal'
import { handleFileDown } from '@/util/board-utils'
export default function MainContents() {
const { swalFire } = useSwal()
@ -23,26 +23,53 @@ export default function MainContents() {
const { getMessage } = useMessage()
const router = useRouter()
const globalLocaleState = useRecoilValue(globalLocaleStore)
const { promiseGet } = useAxios(globalLocaleState)
const { promiseGet, get } = useAxios(globalLocaleState)
//
const [recentNoticeList, setRecentNoticeList] = useState([])
//FAQ
const [recentFaqList, setRecentFaqList] = useState([])
const { qcastState } = useContext(QcastContext)
const { qcastState, setIsGlobalLoading } = useContext(QcastContext)
const { fetchObjectList, initObjectList } = useMainContentsController()
//
const [boardList, setBoardList] = useState([])
useEffect(() => {
fetchObjectList()
fetchNoticeList()
fetchFaqList()
//
fetchArchiveList()
return () => {
initObjectList()
}
}, [])
//
const fetchArchiveList = async () => {
const url = `/api/board/list`
const params = new URLSearchParams({
schNoticeTpCd: 'QC',
schNoticeClsCd: 'DOWN',
startRow: 1,
endRow: 2,
schMainYn: 'Y',
})
const apiUrl = `${url}?${params.toString()}`
const resultData = await get({ url: apiUrl })
if (resultData) {
if (resultData.result.code === 200) {
setBoardList(resultData.data)
} else {
alert(resultData.result.message)
}
}
}
//
const fetchNoticeList = async () => {
try {
@ -105,6 +132,7 @@ export default function MainContents() {
key={row.objectNo}
className="recently-item"
onClick={() => {
setIsGlobalLoading(true)
if (row.tempFlg === '0') {
router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`, { scroll: false })
} else {
@ -114,7 +142,7 @@ export default function MainContents() {
>
<div className="item-inner">
<span className="time">{dayjs(row.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')}</span>
<span>{row.tempFlg === '0' ? row.objectNo : getMessage('stuff.gridData.tempObjectNo')}</span>
<span className="product">{row.tempFlg === '0' ? row.objectNo : getMessage('stuff.gridData.tempObjectNo')}</span>
<span>{row.objectName ? row.objectName : '-'}</span>
<span>{row.saleStoreName}</span>
</div>
@ -183,14 +211,19 @@ export default function MainContents() {
)}
</ProductItem>
<ProductItem num={4} name={'Data Download'}>
<div className="data-download-wrap">
<button className="data-down" type="button" onClick={() => swalFire({ text: getMessage('main.content.alert.noFile'), type: 'alert' })}>
<span>{getMessage('main.content.download1')}</span>
</button>
<button className="data-down" type="button" onClick={() => swalFire({ text: getMessage('main.content.alert.noFile'), type: 'alert' })}>
<span>{getMessage('main.content.download2')}</span>
</button>
</div>
{boardList.length > 0 ? (
<div className="data-download-wrap">
{boardList?.map((board) => (
<button type="button" key={board.noticeNo} className="data-down" onClick={() => handleFileDown(board.noticeNo, 'Y')}>
<span>{board.title}</span>
</button>
))}
</div>
) : (
<div className="file-down-nodata">
<h3>{getMessage('common.message.no.data')}</h3>
</div>
)}
</ProductItem>
<ProductItem num={5} name={'Sales Contact info'}>
<ul className="contact-info-list">

View File

@ -15,12 +15,12 @@ import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json'
import QPagination from '../common/pagination/QPagination'
import { SessionContext } from '@/app/SessionProvider'
import { useSwal } from '@/hooks/useSwal'
import { QcastContext } from '@/app/QcastProvider'
export default function Stuff() {
const { setIsGlobalLoading } = useContext(QcastContext)
const { swalFire } = useSwal()
const resetStuffRecoil = useResetRecoilState(stuffSearchState)
const { session } = useContext(SessionContext)
const setAppMessageState = useSetRecoilState(appMessageStore)
@ -41,20 +41,18 @@ export default function Stuff() {
//
const copyNo = async (value) => {
// try {
// await navigator.clipboard.writeText(value)
// alert(getMessage('stuff.detail.header.successCopy'))
// } catch (error) {
// alert(getMessage('stuff.detail.header.failCopy'))
// }
// Navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
console.log('trttt')
await navigator.clipboard
.writeText(value)
.then(() => {
alert(getMessage('stuff.detail.header.successCopy'))
swalFire({
text: getMessage('stuff.detail.header.successCopy'),
type: 'alert',
})
})
.catch(() => {
.catch((e) => {
console.log(e)
alert(getMessage('stuff.detail.header.failCopy'))
})
} else {
@ -71,7 +69,10 @@ export default function Stuff() {
try {
document.execCommand('copy')
alert(getMessage('stuff.detail.header.successCopy'))
swalFire({
text: getMessage('stuff.detail.header.successCopy'),
type: 'alert',
})
} catch (err) {
alert(getMessage('stuff.detail.header.failCopy'))
} finally {
@ -122,7 +123,7 @@ export default function Stuff() {
type="button"
className="copy_ico"
onClick={() => {
copyNo(params.value)
copyNo(params?.value)
}}
></button>
</>
@ -219,6 +220,9 @@ export default function Stuff() {
pageSize: stuffSearchParams?.pageSize ? stuffSearchParams.pageSize : 100,
}
if (!params.saleStoreId) {
params.saleStoreId = session.storeId
}
async function fetchData() {
const apiUrl = `/api/object/list?${queryStringFormatter(params)}`
await get({
@ -271,6 +275,17 @@ export default function Stuff() {
stuffSearchParams.schSortType = defaultSortType
stuffSearchParams.pageNo = stuffSearchParams.pageNo
if (!stuffSearchParams.saleStoreId) {
stuffSearchParams.saleStoreId = session.storeId
}
if (stuffSearchParams.schMyDataCheck) {
if (session.storeLvl === '1') {
//schOtherSelSaleStoreId schSelSaleStoreId saleStoreId
stuffSearchParams.schOtherSelSaleStoreId = ''
stuffSearchParams.schSelSaleStoreId = session.storeId
}
}
async function fetchData() {
const apiUrl = `/api/object/list?${queryStringFormatter(stuffSearchParams)}`
await get({ url: apiUrl }).then((res) => {
@ -301,6 +316,15 @@ export default function Stuff() {
stuffSearchParams.schSortType = defaultSortType
setPageNo(1)
if (!params.saleStoreId) {
stuffSearchParams.saleStoreId = session.storeId
}
if (stuffSearchParams.schMyDataCheck) {
//schOtherSelSaleStoreId schSelSaleStoreId saleStoreId
stuffSearchParams.schOtherSelSaleStoreId = ''
stuffSearchParams.schSelSaleStoreId = session.storeId
}
async function fetchData() {
const apiUrl = `/api/object/list?${queryStringFormatter(stuffSearchParams)}`
await get({ url: apiUrl }).then((res) => {
@ -336,6 +360,7 @@ export default function Stuff() {
code: 'S',
pageNo: 1,
pageSize: 100,
schMyDataCheck: false,
}
setStuffSearch({

View File

@ -4,7 +4,6 @@ import { useState, useEffect, useRef, useContext } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import { Button } from '@nextui-org/react'
import Select, { components } from 'react-select'
import Link from 'next/link'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
@ -289,10 +288,12 @@ export default function StuffDetail() {
display: 'none',
}
}
// if (managementState?.createUser === 'T01' && session?.userId !== 'T01') {
//createUser T01 T01 !!!!!!!!
//buttonStyle = { display: 'none' }
// }
if (managementState?.createUser === 'T01') {
if (session.userId !== 'T01') {
// #474
buttonStyle = { display: 'none' }
}
}
return (
<>
<div className="grid-cell-btn">
@ -301,9 +302,9 @@ export default function StuffDetail() {
type="button"
className="grid-btn"
onClick={() => {
//mid:5(), /pid:
setFloorPlanObjectNo({ floorPlanObjectNo: params.data.objectNo })
setIsGlobalLoading(true)
setMenuNumber(5)
router.push(`/floor-plan/estimate/5?pid=${params.data.planNo}&objectNo=${params.data.objectNo}`)
}}
>
@ -349,6 +350,10 @@ export default function StuffDetail() {
if (res?.data?.createUser === 'T01' && session?.userId !== 'T01') {
//createUser T01 T01
setShowButton('none')
} else {
if (session.userId !== res?.data?.createUser) {
setShowButton('none')
}
}
if (isObjectNotEmpty(res.data)) {
let surfaceTypeValue
@ -357,7 +362,7 @@ export default function StuffDetail() {
} else if (res.data.surfaceType === 'Ⅱ') {
surfaceTypeValue = '2'
}
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue })
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue, firstFlag: 'Y' })
} else {
setManagementState({})
swalFire({
@ -449,7 +454,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)
@ -526,6 +530,11 @@ export default function StuffDetail() {
get({ url: url }).then((res) => {
if (!isEmptyArray(res)) {
if (session?.storeId === 'T01') {
//
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
firstList = res.filter((row) => row.saleStoreLevel === '1')
firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
@ -648,7 +657,7 @@ export default function StuffDetail() {
// saltAreaFlg 1 true
form.setValue('saltAreaFlg', managementState.saltAreaFlg === '1' ? true : false)
//
let installHeight = managementState.installHeight ? managementState.installHeight.split('.')[0] : '0'
let installHeight = managementState.installHeight ? managementState.installHeight.split('.')[0] : ''
form.setValue('installHeight', installHeight)
// null 0
if (managementState.conType === null) {
@ -984,7 +993,7 @@ export default function StuffDetail() {
form.setValue('saltAreaFlg', false)
}
let installHeight = info.installHeight ? info.installHeight.split('.')[0] : '0'
let installHeight = info.installHeight ? info.installHeight.split('.')[0] : ''
form.setValue('installHeight', installHeight)
form.setValue('remarks', info.remarks)
@ -1024,6 +1033,8 @@ export default function StuffDetail() {
const _objectNameOmit = watch('objectNameOmit')
// saleStoreId: '', //1 ID
const _saleStoreId = watch('saleStoreId')
// 2
const _otherSaleStoreId = watch('otherSaleStoreId')
// zipNo: '', //
const _zipNo = watch('zipNo')
// prefId: '', //
@ -1042,6 +1053,7 @@ export default function StuffDetail() {
useEffect(() => {
if (editMode === 'NEW') {
const formData = form.getValues()
let errors = {}
if (!formData.receiveUser || formData.receiveUser.trim().length === 0) {
errors.receiveUser = true
@ -1056,6 +1068,12 @@ export default function StuffDetail() {
errors.saleStoreId = true
}
if (session?.storeLvl === '2') {
if (!formData.otherSaleStoreId) {
errors.otherSaleStoreId = true
}
}
if (!formData.zipNo) {
errors.zipNo = true
}
@ -1098,6 +1116,12 @@ export default function StuffDetail() {
errors.saleStoreId = true
}
if (session?.storeLvl === '2') {
if (!formData.otherSaleStoreId) {
errors.otherSaleStoreId = true
}
}
if (!formData.zipNo) {
errors.zipNo = true
}
@ -1129,6 +1153,7 @@ export default function StuffDetail() {
_objectName,
_objectNameOmit,
_saleStoreId,
_otherSaleStoreId,
_zipNo,
_prefId,
_address,
@ -1357,7 +1382,7 @@ export default function StuffDetail() {
// 2 otherSaleStoreId
if (session.storeLvl !== '1') {
if (params.saleStoreLevel === '1') {
return swalFire({ text: getMessage('stuff.detail.tempSave.message4'), type: 'alert' })
return swalFire({ text: getMessage('stuff.detail.tempSave.message3'), type: 'alert' })
}
}
@ -1367,13 +1392,12 @@ export default function StuffDetail() {
setIsGlobalLoading(true)
//
if (res.status === 201) {
setIsGlobalLoading(false)
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
swalFire({
text: getMessage('stuff.detail.save'),
type: 'alert',
confirmFn: () => {
setIsGlobalLoading(false)
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
},
})
@ -1390,13 +1414,13 @@ export default function StuffDetail() {
setIsGlobalLoading(true)
if (res.status === 201) {
setIsGlobalLoading(false)
setFloorPlanObjectNo({ floorPlanObjectNo: res.data.objectNo })
swalFire({
text: getMessage('stuff.detail.save'),
type: 'alert',
confirmFn: () => {
setIsGlobalLoading(false)
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
callDetailApi(objectNo)
},
})
}
@ -1408,6 +1432,25 @@ export default function StuffDetail() {
}
}
const callDetailApi = async (objectNo) => {
await promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
if (res?.data?.createUser === 'T01' && session?.userId !== 'T01') {
setShowButton('none')
} else {
if (session.userId !== res?.data?.createUser) {
setShowButton('none')
}
}
let surfaceTypeValue
if (res.data.surfaceType === 'Ⅲ・Ⅳ') {
surfaceTypeValue = '3'
} else {
surfaceTypeValue = '2'
}
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue })
})
}
//
const onTempSave = async () => {
const formData = form.getValues()
@ -1447,6 +1490,13 @@ export default function StuffDetail() {
params.saleStoreLevel = session.storeLvl
}
if (session.storeLvl !== '1') {
// 1 2 saleStoreLevel = 1
if (params.saleStoreLevel === '1') {
return swalFire({ text: getMessage('stuff.detail.tempSave.message3'), type: 'alert' })
}
}
//
if (params?.receiveUser !== '') {
if (params?.receiveUser.trim().length > 10) {
@ -1460,11 +1510,11 @@ export default function StuffDetail() {
.then((res) => {
setIsGlobalLoading(true)
if (res.status === 201) {
setIsGlobalLoading(false)
swalFire({
text: getMessage('stuff.detail.tempSave.message1'),
type: 'alert',
confirmFn: () => {
setIsGlobalLoading(false)
router.push(`/management/stuff/tempdetail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
},
})
@ -1479,11 +1529,11 @@ export default function StuffDetail() {
.then((res) => {
setIsGlobalLoading(true)
if (res.status === 201) {
setIsGlobalLoading(false)
swalFire({
text: getMessage('stuff.detail.tempSave.message1'),
type: 'alert',
confirmFn: () => {
setIsGlobalLoading(false)
router.push(`/management/stuff/tempdetail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
},
})
@ -1511,7 +1561,7 @@ export default function StuffDetail() {
confirmFn: () => {
setFloorPlanObjectNo({ floorPlanObjectNo: '' })
del({ url: `/api/object/${objectNo}?${queryStringFormatter(delParams)}` })
.then((res) => {
.then(() => {
setIsGlobalLoading(true)
setFloorPlanObjectNo({ floorPlanObjectNo: '' })
if (session.storeId === 'T01') {
@ -1587,6 +1637,13 @@ export default function StuffDetail() {
//
const getCellDoubleClicked = (params) => {
//#474
if (managementState.createUser === 'T01') {
if (session.userId !== 'T01') {
return false
}
}
if (params?.column?.colId !== 'estimateDate') {
if (params?.data?.planNo && params?.data?.objectNo) {
let objectNo = params?.data?.objectNo
@ -1603,6 +1660,31 @@ export default function StuffDetail() {
}
}
const CustomOption = (props) => {
const { data, innerRef, innerProps, isSelected, isFocused, isDisabled } = props
const customClass = data.saleStoreId === 'T01' || data.priority !== 'B' ? 'special-option' : ''
// /
const optionClass = `${customClass} ${isSelected ? 'custom__option--is-selected' : ''} ${isFocused ? 'custom__option--is-focused' : ''} ${isDisabled ? 'custom__option--is-disabled' : ''}`
return (
<div ref={innerRef} {...innerProps} className={`custom__option ${optionClass}`}>
{data.label}
</div>
)
}
const CustomOption2 = (props) => {
const { data, innerRef, innerProps, isSelected, isFocused, isDisabled } = props
const customClass = data.priority !== 'B' ? 'special-option' : ''
// /
const optionClass = `${customClass} ${isSelected ? 'custom__option--is-selected' : ''} ${isFocused ? 'custom__option--is-focused' : ''} ${isDisabled ? 'custom__option--is-disabled' : ''}`
return (
<div ref={innerRef} {...innerProps} className={`custom__option ${optionClass}`}>
{data.label}
</div>
)
}
return (
<>
{(editMode === 'NEW' && (
@ -1623,11 +1705,21 @@ export default function StuffDetail() {
{getMessage('stuff.detail.btn.save')}
</Button>
)}
<Link href="/management/stuff" scroll={false}>
{/* <Link href="/management/stuff" scroll={false}>
<button type="button" className="btn-origin grey">
{getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</Link> */}
<button
type="button"
className="btn-origin grey"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff`, { scroll: false })
}}
>
{getMessage('stuff.detail.btn.moveList')}
</button>
</div>
</div>
<div className="infomation-table">
@ -1760,6 +1852,7 @@ export default function StuffDetail() {
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
components={{ Option: CustomOption }}
></Select>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -1792,6 +1885,7 @@ export default function StuffDetail() {
value={showSaleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
// components={{ Option: CustomOption }}
></Select>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -1823,6 +1917,7 @@ export default function StuffDetail() {
value={showSaleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
// components={{ Option: CustomOption }}
></Select>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -1875,11 +1970,11 @@ export default function StuffDetail() {
? true
: false
}
// isDisabled={otherSaleStoreList != null && otherSaleStoreList.length === 1 ? true : false}
isClearable={true}
value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions
})}
components={{ Option: CustomOption2 }}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -2123,11 +2218,21 @@ export default function StuffDetail() {
{getMessage('stuff.detail.btn.save')}
</Button>
)}
<Link href="/management/stuff" scroll={false}>
{/* <Link href="/management/stuff" scroll={false}>
<button type="button" className="btn-origin grey">
{getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</Link> */}
<button
type="button"
className="btn-origin grey"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff`, { scroll: false })
}}
>
{getMessage('stuff.detail.btn.moveList')}
</button>
</div>
</div>
</form>
@ -2142,11 +2247,21 @@ export default function StuffDetail() {
{managementState?.tempFlg === '0' ? (
<>
<div className="left-unit-box">
<Link href="/management/stuff" scroll={false}>
{/* <Link href="/management/stuff" scroll={false}>
<button type="button" className="btn-origin grey mr5">
{getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</Link> */}
<button
type="button"
className="btn-origin grey mr5"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff`, { scroll: false })
}}
>
{getMessage('stuff.detail.btn.moveList')}
</button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')}
</Button>
@ -2167,11 +2282,21 @@ export default function StuffDetail() {
{getMessage('stuff.detail.btn.save')}
</Button>
)}
<Link href="/management/stuff" scroll={false}>
{/* <Link href="/management/stuff" scroll={false}>
<button type="button" className="btn-origin grey">
{getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</Link> */}
<button
type="button"
className="btn-origin grey"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff`, { scroll: false })
}}
>
{getMessage('stuff.detail.btn.moveList')}
</button>
</div>
</>
)}
@ -2296,7 +2421,7 @@ export default function StuffDetail() {
<>
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
menuPlacement={'auto'}
// menuPlacement={'auto'}
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
@ -2312,6 +2437,7 @@ export default function StuffDetail() {
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
components={{ Option: CustomOption }}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -2352,6 +2478,7 @@ export default function StuffDetail() {
value={showSaleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
// components={{ Option: CustomOption }}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -2386,6 +2513,7 @@ export default function StuffDetail() {
return option.saleStoreId
}
})}
// components={{ Option: CustomOption }}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -2425,19 +2553,22 @@ export default function StuffDetail() {
onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
// isDisabled={
// managementState?.tempFlg === '0'
// ? true
// : session?.storeLvl === '1' && form.watch('saleStoreId') != ''
// ? false
// : false
// }
isDisabled={managementState?.tempFlg === '0' ? true : false}
isDisabled={
managementState?.tempFlg === '0'
? true
: session?.storeLvl === '1'
? otherSaleStoreList.length > 0
? false
: true
: otherSaleStoreList.length === 1
? true
: false
}
isClearable={managementState?.tempFlg === '0' ? false : true}
// isClearable={managementState?.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : true}
value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions
})}
// components={{ Option: CustomOption2 }}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
@ -2721,11 +2852,21 @@ export default function StuffDetail() {
</div>
{/* 진짜R 플랜끝 */}
<div className="sub-right-footer">
<Link href="/management/stuff" scroll={false}>
{/* <Link href="/management/stuff" scroll={false}>
<button type="button" className="btn-origin grey mr5">
{getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</Link> */}
<button
type="button"
className="btn-origin grey mr5"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff`, { scroll: false })
}}
>
{getMessage('stuff.detail.btn.moveList')}
</button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')}
</Button>
@ -2746,11 +2887,21 @@ export default function StuffDetail() {
{getMessage('stuff.detail.btn.save')}
</Button>
)}
<Link href="/management/stuff" scroll={false}>
{/* <Link href="/management/stuff" scroll={false}>
<button type="button" className="btn-origin grey">
{getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</Link> */}
<button
type="button"
className="btn-origin grey"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff`, { scroll: false })
}}
>
{getMessage('stuff.detail.btn.moveList')}
</button>
</div>
</>
)}

View File

@ -1,31 +1,26 @@
'use client'
import { useContext } from 'react'
import { useContext, useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage'
import dayjs from 'dayjs'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
// import { ManagementContext } from '@/app/management/ManagementProvider'
import { useSwal } from '@/hooks/useSwal'
export default function StuffHeader() {
const { getMessage } = useMessage()
const { swalFire } = useSwal()
const { managementState } = useContext(GlobalDataContext)
//
// const copyObjectNo = async (objectNo) => {
// await navigator.clipboard.writeText(objectNo)
// alert(getMessage('stuff.detail.header.successCopy'))
// try {
// } catch (error) {
// alert(getMessage('stuff.detail.header.failCopy'))
// }
// }
const copyObjectNo = async (objectNo) => {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard
.writeText(objectNo)
.then(() => {
alert(getMessage('stuff.detail.header.successCopy'))
swalFire({
text: getMessage('stuff.detail.header.successCopy'),
type: 'alert',
})
})
.catch(() => {
alert(getMessage('stuff.detail.header.failCopy'))
@ -44,7 +39,10 @@ export default function StuffHeader() {
try {
document.execCommand('copy')
alert(getMessage('stuff.detail.header.successCopy'))
swalFire({
text: getMessage('stuff.detail.header.successCopy'),
type: 'alert',
})
} catch (err) {
alert(getMessage('stuff.detail.header.failCopy'))
} finally {
@ -69,7 +67,9 @@ export default function StuffHeader() {
</div>
<div className="sub-table-box">
<div className="info-title">{getMessage('stuff.detail.header.specificationConfirmDate')}</div>
<div className="info-inner">{managementState?.specificationConfirmDate}</div>
<div className="info-inner">
{managementState?.specificationConfirmDate ? `${dayjs(managementState.specificationConfirmDate).format('YYYY.MM.DD HH:mm:ss')}` : ''}
</div>
</div>
<div className="sub-table-box">
<div className="info-title">{getMessage('stuff.detail.header.lastEditDatetime')}</div>

View File

@ -10,7 +10,7 @@ import JA from '@/locales/ja.json'
import { stuffSearchState } from '@/store/stuffAtom'
import { isEmptyArray } from '@/util/common-utils'
import dayjs from 'dayjs'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
import { useMessage } from '@/hooks/useMessage'
import { isObjectNotEmpty } from '@/util/common-utils'
@ -20,6 +20,7 @@ import { SessionContext } from '@/app/SessionProvider'
import { QcastContext } from '@/app/QcastProvider'
export default function StuffSearchCondition() {
const router = useRouter()
const { session } = useContext(SessionContext)
const setAppMessageState = useSetRecoilState(appMessageStore)
const globalLocaleState = useRecoilValue(globalLocaleStore)
@ -342,7 +343,7 @@ export default function StuffSearchCondition() {
})
} else {
if (session?.storeLvl === '2') {
if (otherSaleStoreList.length > 1) {
if (otherSaleStoreList.length === 1) {
setOtherSaleStoreId(session.storeId)
stuffSearch.schOtherSelSaleStoreId = session.storeId
stuffSearch.schObjectNo = ''
@ -355,6 +356,24 @@ export default function StuffSearchCondition() {
stuffSearch.schTempFlg = ''
stuffSearch.schMyDataCheck = false
stuffSearch.startRow = 1
stuffSearch.endRow = 100
stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1
stuffSearch.pageSize = 100
} else if (otherSaleStoreList.length > 1) {
setOtherSaleStoreId('')
stuffSearch.schOtherSelSaleStoreId = session.storeId
stuffSearch.schObjectNo = ''
stuffSearch.schAddress = ''
stuffSearch.schObjectName = ''
stuffSearch.schSaleStoreName = ''
stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = ''
stuffSearch.schMyDataCheck = false
stuffSearch.startRow = 1
stuffSearch.endRow = 100
stuffSearch.schSortType = 'U'
@ -446,6 +465,7 @@ export default function StuffSearchCondition() {
allList = res
allList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = res.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
setSchSelSaleStoreList(allList)
setFavoriteStoreList(favList)
setShowSaleStoreList(favList)
@ -503,13 +523,23 @@ export default function StuffSearchCondition() {
})
} else {
if (stuffSearch.code === 'S') {
setOtherSaleStoreId(session?.storeId)
setStuffSearch({
...stuffSearch,
code: 'S',
schSelSaleStoreId: res[0].saleStoreId,
schOtherSelSaleStoreId: otherList[0].saleStoreId,
})
if (otherList.length === 1) {
setOtherSaleStoreId(session?.storeId)
setStuffSearch({
...stuffSearch,
code: 'S',
schSelSaleStoreId: res[0].saleStoreId,
schOtherSelSaleStoreId: otherList[0].saleStoreId,
})
} else {
setOtherSaleStoreId('')
setStuffSearch({
...stuffSearch,
code: 'S',
schSelSaleStoreId: res[0].saleStoreId,
schOtherSelSaleStoreId: '',
})
}
} else {
setOtherSaleStoreId(stuffSearch?.schOtherSelSaleStoreId)
setStuffSearch({
@ -542,7 +572,7 @@ export default function StuffSearchCondition() {
const onInputChange = (key) => {
//
setMyDataCheck(false)
stuffSearch.schMyDataCheck = false
if (key !== '') {
setShowSaleStoreList(schSelSaleStoreList)
} else {
@ -560,7 +590,6 @@ export default function StuffSearchCondition() {
setOtherSaleStoreId('')
setSchSelSaleStoreId(key.saleStoreId)
stuffSearch.schSelSaleStoreId = key.saleStoreId
//T01 1
// 1 saleStoreId 2 API
let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}`
let otherList
@ -719,19 +748,61 @@ export default function StuffSearchCondition() {
setMyDataCheck(stuffSearch.schMyDataCheck)
}
} else {
setStartDate(stuffSearch?.schFromDt ? stuffSearch.schFromDt : dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'))
setEndDate(stuffSearch?.schToDt ? stuffSearch.schToDt : dayjs(new Date()).format('YYYY-MM-DD'))
setObjectNo(stuffSearch.schObjectNo ? stuffSearch.schObjectNo : objectNo)
setSaleStoreName(stuffSearch.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName)
setAddress(stuffSearch.schAddress ? stuffSearch.schAddress : address)
setobjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName)
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
setTempFlg(stuffSearch.schTempFlg ? stuffSearch.schTempFlg : tempFlg)
setMyDataCheck(stuffSearch.schMyDataCheck)
if (session.storeLvl !== '1') {
stuffSearch.schSelSaleStoreId = ''
if (stuffSearch.code === 'DELETE') {
//1
if (session.storeLvl === '1') {
stuffSearch.schOtherSelSaleStoreId = ''
setOtherSaleStoreId('')
} else {
//2
//34
stuffSearch.schOtherSelSaleStoreId = ''
setOtherSaleStoreId('')
}
setObjectNo('')
setSaleStoreName('')
setAddress('')
setobjectName('')
setDispCompanyName('')
setReceiveUser('')
objectNoRef.current.value = ''
saleStoreNameRef.current.value = ''
addressRef.current.value = ''
objectNameRef.current.value = ''
dispCompanyNameRef.current.value = ''
receiveUserRef.current.value = ''
stuffSearch.schObjectNo = ''
stuffSearch.schAddress = ''
stuffSearch.schObjectName = ''
stuffSearch.schSaleStoreName = ''
stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = ''
stuffSearch.schMyDataCheck = false
stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')
stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD')
stuffSearch.startRow = 1
stuffSearch.endRow = 100
stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1
stuffSearch.pageSize = 100
} else {
setStartDate(stuffSearch?.schFromDt ? stuffSearch.schFromDt : dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'))
setEndDate(stuffSearch?.schToDt ? stuffSearch.schToDt : dayjs(new Date()).format('YYYY-MM-DD'))
setObjectNo(stuffSearch.schObjectNo ? stuffSearch.schObjectNo : objectNo)
setSaleStoreName(stuffSearch.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName)
setAddress(stuffSearch.schAddress ? stuffSearch.schAddress : address)
setobjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName)
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
setTempFlg(stuffSearch.schTempFlg ? stuffSearch.schTempFlg : tempFlg)
setMyDataCheck(stuffSearch.schMyDataCheck)
if (session.storeLvl !== '1') {
stuffSearch.schSelSaleStoreId = ''
}
}
}
@ -801,10 +872,12 @@ export default function StuffSearchCondition() {
if (e.target.checked) {
stuffSearch.schMyDataCheck = e.target.value
setMyDataCheck(true)
if (otherSaleStoreList.length > 1) {
stuffSearch.schSelSaleStoreId = otherSaleStoreId
stuffSearch.schOtherSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = session.storeId
setOtherSaleStoreId(session.storeId)
} else {
stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = session.storeId
}
} else {
setMyDataCheck(false)
@ -813,6 +886,30 @@ export default function StuffSearchCondition() {
}
}
const CustomOption = (props) => {
const { data, innerRef, innerProps, isSelected, isFocused, isDisabled } = props
const customClass = data.saleStoreId === 'T01' || data.priority !== 'B' ? 'special-option' : ''
// /
const optionClass = `${customClass} ${isSelected ? 'custom__option--is-selected' : ''} ${isFocused ? 'custom__option--is-focused' : ''} ${isDisabled ? 'custom__option--is-disabled' : ''}`
return (
<div ref={innerRef} {...innerProps} className={`custom__option ${optionClass}`}>
{data.label}
</div>
)
}
const CustomOption2 = (props) => {
const { data, innerRef, innerProps, isSelected, isFocused, isDisabled } = props
const customClass = data.priority !== 'B' ? 'special-option' : ''
// /
const optionClass = `${customClass} ${isSelected ? 'custom__option--is-selected' : ''} ${isFocused ? 'custom__option--is-focused' : ''} ${isDisabled ? 'custom__option--is-disabled' : ''}`
return (
<div ref={innerRef} {...innerProps} className={`custom__option ${optionClass}`}>
{data.label}
</div>
)
}
return (
<>
{/* 퍼블적용시작 */}
@ -822,12 +919,21 @@ export default function StuffSearchCondition() {
<h3>{getMessage('stuff.search.title')}</h3>
</div>
<div className="left-unit-box">
<Link href="/management/stuff/tempReg" scroll={false}>
{/* <Link href="/management/stuff/tempdetail" scroll={false}> */}
{/* <Link href="/management/stuff/tempReg" scroll={false}>
<button type="button" className="btn-origin navy mr5">
{getMessage('stuff.search.btn.register')}
</button>
</Link>
</Link> */}
<button
type="button"
className="btn-origin navy mr5"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff/tempReg`, { scroll: false })
}}
>
{getMessage('stuff.search.btn.register')}
</button>
<button type="button" className="btn-origin navy mr5" onClick={onSubmit}>
{getMessage('stuff.search.btn.search')}
</button>
@ -1078,6 +1184,7 @@ export default function StuffSearchCondition() {
})}
isDisabled={session?.storeLvl !== '1' ? true : session?.storeId !== 'T01' ? true : false}
isClearable={true}
components={{ Option: CustomOption }}
/>
)}
{session?.storeId !== 'T01' && session?.storeLvl === '1' && (
@ -1162,6 +1269,7 @@ export default function StuffSearchCondition() {
value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSaleStoreId
})}
components={{ Option: CustomOption2 }}
/>
</div>
<div className="d-check-box light">

View File

@ -40,8 +40,8 @@ export default function StuffSubHeader({ type }) {
if (isObjectNotEmpty(managementState)) {
if (managementState.createUser === 'T01') {
if (session.userId !== 'T01') {
// #457
// setButtonStyle('none')
// #457 #474
setButtonStyle('none')
}
}
}
@ -66,87 +66,85 @@ export default function StuffSubHeader({ type }) {
}
return (
!isGlobalLoading && (
<>
<div className="sub-header">
<div className="sub-header-inner">
{type === 'list' && (
<>
<Link href={'#'}>
<h1 className="sub-header-title">{getMessage('header.menus.management')}</h1>
</Link>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.stuffList')}</span>
</li>
</ul>
</>
)}
{type === 'temp' && (
<>
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
</Link>
</li>
</ul>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.newStuff')}</span>
</li>
</ul>
</>
)}
{type === 'detail' && (
<>
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
</Link>
</li>
<li className="title-item" style={{ display: buttonStyle }}>
<a className="sub-header-title" onClick={moveFloorPlan}>
<span className="icon drawing"></span>
{getMessage('stuff.temp.subTitle2')}
</a>
</li>
</ul>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.detail')}</span>
</li>
</ul>
</>
)}
</div>
<>
<div className="sub-header">
<div className="sub-header-inner">
{type === 'list' && (
<>
<Link href={'#'}>
<h1 className="sub-header-title">{getMessage('header.menus.management')}</h1>
</Link>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.stuffList')}</span>
</li>
</ul>
</>
)}
{type === 'temp' && (
<>
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
</Link>
</li>
</ul>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.newStuff')}</span>
</li>
</ul>
</>
)}
{type === 'detail' && (
<>
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
</Link>
</li>
<li className="title-item" style={{ display: buttonStyle }}>
<a className="sub-header-title" onClick={moveFloorPlan}>
<span className="icon drawing"></span>
{getMessage('stuff.temp.subTitle2')}
</a>
</li>
</ul>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.detail')}</span>
</li>
</ul>
</>
)}
</div>
</>
)
</div>
</>
)
}

View File

@ -56,9 +56,6 @@ export default function FindAddressPop(props) {
//
const searchPostNum = () => {
// //7830060
// //9302226
// //0790177 3
const params = {
zipcode: watch('zipNo'),
}
@ -122,6 +119,28 @@ export default function FindAddressPop(props) {
}
}
//
const getCellDoubleClicked = (event) => {
setAddress1(event.data.address1)
setAddress2(event.data.address2)
setAddress3(event.data.address3)
setPrefId(event.data.prefcode)
setZipNo(event.data.zipcode)
if (event.data.prefcode == null) {
return alert(getMessage('stuff.addressPopup.error.message2'))
} else {
props.zipInfo({
zipNo: event.data.zipcode,
address1: event.data.address1,
address2: event.data.address2,
address3: event.data.address3,
prefId: event.data.prefcode,
})
}
props.setShowAddressButtonValid(false)
}
return (
<div className="modal-popup">
<div className="modal-dialog middle">
@ -146,7 +165,7 @@ export default function FindAddressPop(props) {
<button className="search-btn" onClick={searchPostNum}></button>
</div>
<div className="address-grid">
<FindAddressPopQGrid {...gridProps} getSelectedRowdata={getSelectedRowdata} />
<FindAddressPopQGrid {...gridProps} getSelectedRowdata={getSelectedRowdata} getCellDoubleClicked={getCellDoubleClicked} />
</div>
</div>
<div className="footer-btn-wrap">

View File

@ -48,6 +48,11 @@ export default function FindAddressPopGrid(props) {
props.getSelectedRowdata(selectedData)
}
//
const onCellDoubleClicked = useCallback((event) => {
props.getCellDoubleClicked(event)
}, [])
return (
<div className="ag-theme-quartz" style={{ height: 400 }}>
<AgGridReact
@ -58,6 +63,7 @@ export default function FindAddressPopGrid(props) {
defaultColDef={defaultColDef}
pagination={isPageable}
onSelectionChanged={onSelectionChanged}
onCellDoubleClicked={onCellDoubleClicked}
overlayNoRowsTemplate={`<span className="ag-overlay-loading-center">${getMessage('stuff.grid.noData')}</span>`}
/>
</div>

View File

@ -8,19 +8,12 @@ import SingleDatePicker from '@/components/common/datepicker/SingleDatePicker'
import dayjs from 'dayjs'
import PlanRequestPopQGrid from './PlanRequestPopQGrid'
import { isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import Select from 'react-select'
import QPagination from '@/components/common/pagination/QPagination'
export default function PlanRequestPop(props) {
const [pageNo, setPageNo] = useState(1) //
const [pageSize, setPageSize] = useState(20) //
const [totalCount, setTotalCount] = useState(0) //
//
const { commonCode, findCommonCode } = useCommonCode()
// const [planStatCdList, setPlanStatCdList] = useState([])
const globalLocaleState = useRecoilValue(globalLocaleStore)
const [planReqObject, setPlanReqObject] = useState({})
@ -71,16 +64,6 @@ export default function PlanRequestPop(props) {
}
}
//
const onSelectionChange = (key) => {
if (isObjectNotEmpty(key)) {
setSchPlanStatCd(key.clCode)
} else {
//X
setSchPlanStatCd('')
}
}
//
const onSubmit = (page, type) => {
const params = {
@ -194,7 +177,8 @@ export default function PlanRequestPop(props) {
{
field: 'title',
headerName: getMessage('stuff.planReqPopup.gridHeader.title'),
minWidth: 150,
minWidth: 250,
cellStyle: { textAlign: 'left' },
},
{
field: 'address1',
@ -234,13 +218,6 @@ export default function PlanRequestPop(props) {
}
}
// useEffect(() => {
// const code1 = findCommonCode(115800) //
// if (code1 != null) {
// setPlanStatCdList(code1)
// }
// }, [commonCode])
useEffect(() => {
onSubmit(pageNo, 'S')
}, [])
@ -266,6 +243,13 @@ export default function PlanRequestPop(props) {
}
}
//
const getCellDoubleClicked = (event) => {
setPlanReqObject(event.data)
props.planReqInfo(event.data)
props.setShowDesignRequestButtonValid(false)
}
return (
<div className="modal-popup">
<div className="modal-dialog big">
@ -431,9 +415,11 @@ export default function PlanRequestPop(props) {
</select>
</div>
</div>
<PlanRequestPopQGrid {...gridProps} getSelectedRowdata={getSelectedRowdata} />
<div className="pagination-wrap">
<QPagination pageNo={pageNo} pageSize={pageSize} pagePerBlock={10} totalCount={totalCount} handleChangePage={handleChangePage} />
<div className="q-grid">
<PlanRequestPopQGrid {...gridProps} getSelectedRowdata={getSelectedRowdata} getCellDoubleClicked={getCellDoubleClicked} />
<div className="pagination-wrap">
<QPagination pageNo={pageNo} pageSize={pageSize} pagePerBlock={10} totalCount={totalCount} handleChangePage={handleChangePage} />
</div>
</div>
</div>
</div>

View File

@ -22,8 +22,8 @@ export default function PlanRequestPopQGrid(props) {
flex: 1,
minWidth: 100,
sortable: false,
suppressMovable: false,
resizable: false,
suppressMovable: true,
resizable: true,
suppressSizeToFit: false,
}
}, [])
@ -48,6 +48,11 @@ export default function PlanRequestPopQGrid(props) {
props.getSelectedRowdata(selectedData)
}
//
const onCellDoubleClicked = useCallback((event) => {
props.getCellDoubleClicked(event)
}, [])
return (
<div className="ag-theme-quartz" style={{ height: 350 }}>
<AgGridReact
@ -58,6 +63,8 @@ export default function PlanRequestPopQGrid(props) {
defaultColDef={defaultColDef}
pagination={isPageable}
onSelectionChanged={onSelectionChanged}
onCellDoubleClicked={onCellDoubleClicked}
autoSizeAllColumns={true}
overlayNoRowsTemplate={`<span className="ag-overlay-loading-center">${getMessage('stuff.grid.noData')}</span>`}
/>
</div>

View File

@ -39,7 +39,6 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
if (resultData) {
setInfo(resultData)
setPassword(resultData.password)
} else {
alert(getMessage('common.message.no.data'))
}
@ -236,7 +235,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.category')}</th>
<td>
<div className="input-wrap">
<input type="text" className="input-light" value={info?.groupName || ''} readOnly />
<input type="text" className="input-light" value={info?.category || ''} readOnly />
</div>
</td>
</tr>

View File

@ -16,26 +16,23 @@ import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { convertNumberToPriceDecimal } from '@/util/common-utils'
import { usePlan } from '@/hooks/usePlan'
import { usePopup } from '@/hooks/usePopup'
// import { useSearchParams } from 'next/navigation'
import { usePopup, closeAll } from '@/hooks/usePopup'
import { QcastContext } from '@/app/QcastProvider'
export default function Simulator() {
// global
const { setIsGlobalLoading } = useContext(QcastContext)
const { floorPlanState } = useContext(FloorPlanContext)
const { objectNo, pid } = floorPlanState
// const searchParams = useSearchParams()
// const objectNo = searchParams.get('objectNo')
// const pid = searchParams.get('pid')
const { selectedPlan } = usePlan()
const chartRef = useRef(null)
//
const { setMenuNumber } = useCanvasMenu()
useEffect(() => {
setMenuNumber(6)
}, [])
const { closeAll } = usePopup()
const { get } = useAxios()
const { getMessage } = useMessage()
@ -43,12 +40,6 @@ export default function Simulator() {
//
const [chartData, setChartData] = useState([])
const { closeAll } = usePopup()
useEffect(() => {
closeAll()
}, [])
const data = {
labels: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
datasets: [
@ -114,7 +105,6 @@ export default function Simulator() {
}
useEffect(() => {
console.log('🚀 ~ useEffect ~ selectedPlan:', selectedPlan)
/* 초기화 작업 */
setChartData([])
setObjectDetail({})
@ -125,11 +115,13 @@ export default function Simulator() {
setHatsudenryouPeakcutAll([])
setHatsudenryouPeakcutAllSnow([])
if (objectNo) {
fetchObjectDetail(objectNo)
if (objectNo && pid && selectedPlan) {
fetchObjectDetail(objectNo, selectedPlan.planNo)
fetchSimulatorNotice()
setPwrGnrSimType('D')
setPwrRecoil({ ...pwrRecoil, type: 'D' })
setMenuNumber(6)
closeAll()
}
}, [objectNo, pid, selectedPlan])
@ -148,10 +140,13 @@ export default function Simulator() {
const [hatsudenryouPeakcutAll, setHatsudenryouPeakcutAll] = useState([])
const [hatsudenryouPeakcutAllSnow, setHatsudenryouPeakcutAllSnow] = useState([])
const fetchObjectDetail = async (objectNo) => {
const apiUrl = `/api/pwrGnrSimulation/calculations?objectNo=${objectNo}&planNo=${pid}`
const fetchObjectDetail = async (objectNo, currentPid) => {
setIsGlobalLoading(true)
const apiUrl = `/api/pwrGnrSimulation/calculations?objectNo=${objectNo}&planNo=${currentPid}`
const resultData = await get({ url: apiUrl })
if (resultData) {
setObjectDetail(resultData)
if (resultData.hatsudenryouAll) {
@ -174,12 +169,14 @@ export default function Simulator() {
setModuleInfoList(resultData.roofModuleList)
}
}
setIsGlobalLoading(false)
}
//
const [content, setContent] = useState('')
const fetchSimulatorNotice = async () => {
setIsGlobalLoading(true)
get({ url: '/api/pwrGnrSimulation/guideInfo' }).then((res) => {
if (res.data) {
setContent(res.data.replaceAll('\n', '<br/>'))
@ -187,6 +184,7 @@ export default function Simulator() {
setContent(getMessage('common.message.no.data'))
}
})
setIsGlobalLoading(false)
}
// , list type
@ -257,7 +255,7 @@ export default function Simulator() {
{/* 적설조건 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub7')}</div>
<div className="estimate-name">{objectDetail.snowfall} cm</div>
<div className="estimate-name">{objectDetail.snowfall ? `${objectDetail.snowfall}cm` : ''} </div>
</div>
{/* 풍속조건 */}
<div className="estimate-box">
@ -356,7 +354,10 @@ export default function Simulator() {
{/* 지붕면 */}
<td>{moduleInfo.roofSurface}</td>
{/* 경사각 */}
<td>{convertNumberToPriceDecimal(moduleInfo.slopeAngle)}{moduleInfo.classType == 0 ? "寸":"º"}</td>
<td>
{convertNumberToPriceDecimal(moduleInfo.slopeAngle)}
{moduleInfo.classType == 0 ? '寸' : 'º'}
</td>
{/* 방위각(도) */}
<td>{convertNumberToPriceDecimal(moduleInfo.azimuth)}</td>
{/* 태양전지모듈 */}

View File

@ -1,28 +1,90 @@
'use client'
import { useEffect } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import useSWR from 'swr'
import useSWRMutation from 'swr/mutation'
import { useAxios } from '../useAxios'
import { useRecoilState } from 'recoil'
import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
import { unescapeString } from '@/util/common-utils'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { compasDegAtom } from '@/store/orientationAtom'
import { currentCanvasPlanState } from '@/store/canvasAtom'
export function useCanvasPopupStatusController(popupType) {
const [canvasPopupStatusState, setCanvasPopupStatusState] = useRecoilState(canvasPopupStatusStore)
export function useCanvasPopupStatusController(param = 1) {
const popupType = parseInt(param)
const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom)
const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState)
const { getFetcher, postFetcher } = useAxios()
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
// console.log('🚀 ~ Orientation ~ currentCanvasPlan:', currentCanvasPlan)
const {
data: popupStatus,
error,
isLoading,
} = useSWR(popupType ? 'canvas-popup-status--data' : null, () => getFetcher(`http://localhost:8080/api/tutorial?popupType=${popupType}`))
} = useSWR(
popupType ? `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}` : null,
getFetcher,
)
useEffect(() => {
// console.log('🚀 ~ useEffect ~ popupStatus:', popupStatus)
if (popupStatus) {
setCanvasPopupStatusState({ ...canvasPopupStatusState, [popupType]: popupStatus })
switch (parseInt(popupStatus?.popupType)) {
case 1:
setCompasDeg(popupStatus.popupStatus)
break
case 2:
setModuleSelectionDataStore(JSON.parse(unescapeString(popupStatus.popupStatus)))
break
case 3:
break
case 4:
break
case 5:
break
case 6:
break
default:
}
} else {
switch (popupType) {
case 1:
setCompasDeg(0)
break
case 2:
setModuleSelectionDataStore({
common: {},
roofConstructions: [],
})
break
case 3:
break
case 4:
break
case 5:
break
case 6:
break
default:
}
}
}, [popupStatus])
const { trigger, isMutating } = useSWRMutation('canvas-popup-status-update', postFetcher)
const { trigger, isMutating } = useSWRMutation(
`/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}`,
(url, { arg }) => {
const params = {
objectNo: currentCanvasPlan.objectNo,
planNo: parseInt(currentCanvasPlan.planNo),
popupType: popupType.toString(),
popupStatus: popupType === 1 ? arg : JSON.stringify(arg).replace(/"/g, '\"'),
}
postFetcher(`/api/v1/canvas-popup-status`, params)
},
)
return { trigger }
}

View File

@ -523,10 +523,26 @@ export function useCommonUtils() {
if (object) {
canvas?.remove(object)
// if (object.id) {
// const group = canvas.getObjects().filter((obj) => obj.id === object.id)
// group.forEach((obj) => canvas?.remove(obj))
// }
if (object.id) {
const group = canvas.getObjects().filter((obj) => obj.id === object.id)
group.forEach((obj) => canvas?.remove(obj))
}
if (object.type === 'group') {
object._objects.forEach((obj) => {
if (obj.hasOwnProperty('texts')) {
obj.texts.forEach((text) => {
canvas?.remove(text)
})
}
})
} else {
if (object.hasOwnProperty('texts')) {
object.texts.forEach((text) => {
canvas?.remove(text)
})
}
}
}
}
@ -609,6 +625,21 @@ export function useCommonUtils() {
commonDeleteText(obj)
})
}
selectedObj.forEach((obj) => {
if (obj.type === 'group') {
obj._objects.forEach((lines) => {
if (lines.hasOwnProperty('arrow')) {
canvas
.getObjects()
.filter((obj1) => obj1.name === 'arrow' && lines.id === obj1.parentId)
.forEach((arrow) => {
canvas?.remove(arrow)
})
}
})
}
})
}
const moveObject = () => {

View File

@ -4,6 +4,8 @@ import { useSwal } from '@/hooks/useSwal'
import { getQueryString } from '@/util/common-utils'
import { trestleRequest, constructionRequest, trestleDetailRequest } from '@/models/apiModels'
import { POST } from '@/app/api/image-upload/route'
import { canvasState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
/**
* 마스터 컨트롤러
@ -54,9 +56,9 @@ export function useMasterController() {
*/
const getTrestleList = async (params) => {
const paramString = getQueryString(params)
console.log('🚀🚀 ~ getTrestleList ~ paramString:', paramString)
// console.log('🚀🚀 ~ getTrestleList ~ paramString:', paramString)
return await get({ url: '/api/v1/master/getTrestleList' + paramString }).then((res) => {
console.log('🚀🚀 ~ getTrestleList ~ res:', res)
// console.log('🚀🚀 ~ getTrestleList ~ res:', res)
return res
})
}
@ -80,9 +82,9 @@ export function useMasterController() {
*/
const getConstructionList = async (params) => {
const paramString = getQueryString(params)
console.log('🚀🚀 ~ getConstructionList ~ paramString:', paramString)
// console.log('🚀🚀 ~ getConstructionList ~ paramString:', paramString)
return await get({ url: '/api/v1/master/getConstructionList' + paramString }).then((res) => {
console.log('🚀🚀 ~ getConstructionList ~ res:', res)
// console.log('🚀🚀 ~ getConstructionList ~ res:', res)
return res
})
}
@ -128,18 +130,88 @@ export function useMasterController() {
}
/**
* PCS 메이커, 시리즈 목록 조회
* @param {PCS 메이커코드} pcsMkrCd
* @param {혼합모듈번호} mixMatlNo
* 모듈 타입별 아이템 목록 조회
* @param {PCS 메이커코드} pcsMkrCd
* @param {PCS시리즈코드 목록} pcsSerList
* @param {모듈아이템 ID 목록} moduleItemList
* @returns
*/
const getPcsModelList = async (params = null) => {
const test = {
pcsMkrCd: 'MKR003',
pcsSerList: [{ pcsSerCd: 'SER007' }, { pcsSerCd: 'SER009' }, { pcsSerCd: 'SER010' }],
moduleItemList: [{ itemId: '107015', mixMatlNo: '' }, { itemId: '107077' }, { itemId: '107015' }],
moduleItemList: [
{ itemId: '107015', mixMatlNo: null },
{ itemId: '107077', mixMatlNo: null },
{ itemId: '107015', mixMatlNo: null },
],
}
return await post({ url: '/api/v1/master/getPcsSeriesItemList', data: test }).then((res) => {
return await post({ url: '/api/v1/master/getPcsSeriesItemList', data: params }).then((res) => {
return res
})
}
/**
* 시리즈중 자동으로 추천 PCS 정보 조회
* @param {Max접속(과적)여부} maxConnYn
* @param {동일회로도여부} smpCirYn
* @param {한랭지여부} coldZoneYn
* @param {사용된 모듈 아이템 List} useModuleItemList
* @param {지붕면별 목록} roofSurfaceList
* @param {PCS 제품 목록} pcsItemList
* @returns
*/
const getPcsAutoRecommendList = async (params = null) => {
return await post({ url: '/api/v1/master/getPcsAutoRecommendList', data: params }).then((res) => {
return res
})
}
const getPcsManualConfChk = async (params = null) => {
return await post({ url: '/api/v1/master/getPcsMenualConfChk', data: params }).then((res) => {
return res
})
}
/**
* PCS로 회로 구성 가능 여부 체크
* @param {Max접속(과적)여부} maxConnYn
* @param {동일회로도여부} smpCirYn
* @param {한랭지여부} coldZoneYn
* @param {사용된 모듈 아이템 List} useModuleItemList
* @param {지붕면별 목록} roofSurfaceList
* @param {PCS 제품 목록} pcsItemList
* @returns
*/
const getPcsVoltageChk = async (params = null) => {
return await post({ url: '/api/v1/master/getPcsVoltageChk', data: params }).then((res) => {
return res
})
}
/**
* PCS 승압설정 정보 조회
* @param {Max접속(과적)여부} maxConnYn
* @param {동일회로도여부} smpCirYn
* @param {한랭지여부} coldZoneYn
* @param {사용된 모듈아이템 목록} useModuleItemList
* @param {지붕면 목록} roofSurfaceList
* @param {PCS 아이템 목록} pcsItemList
* @returns
*/
const getPcsVoltageStepUpList = async (params2 = null) => {
const params = {
...params2,
maxConnYn: params2.useYn.maxConnYn,
smpCirYn: params2.useYn.smpCirYn,
coldZoneYn: params2.useYn.coldZoneYn,
useModuleItemList: params2.useModuleItemList,
roofSurfaceList: params2.roofSurfaceList,
pcsItemList: params2.pcsItemList,
}
return await post({ url: '/api/v1/master/getPcsVoltageStepUpList', data: params }).then((res) => {
return res
})
}
@ -152,5 +224,9 @@ export function useMasterController() {
getTrestleDetailList,
getPcsMakerList,
getPcsModelList,
getPcsAutoRecommendList,
getPcsVoltageChk,
getPcsManualConfChk,
getPcsVoltageStepUpList,
}
}

View File

@ -20,15 +20,24 @@ export function useRoofFn() {
const { addPitchText } = useLine()
//면형상 선택 클릭시 지붕 패턴 입히기
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial = selectedRoofMaterial) {
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial = selectedRoofMaterial, isForceChange = false) {
if (!polygon) {
return
}
if (isForceChange) {
if (polygon.roofMaterial) {
polygon.roofMaterial = null
}
}
if (polygon.roofMaterial) {
return
}
const ratio = window.devicePixelRatio || 1
const layout = roofMaterial.layout
let width = (roofMaterial.width ?? 226) / 10
let height = (roofMaterial.length ?? 158) / 10
let width = (roofMaterial.width || 226) / 10
let height = (roofMaterial.length || 158) / 10
const index = roofMaterial.index ?? 0
let roofStyle = 2
const inputPatternSize = { width: width, height: height } //임시 사이즈

View File

@ -80,6 +80,7 @@ export const useEstimateController = (planNo) => {
res.data.pkgAsp = roundedNumber.toString()
}
setEstimateContextState(res.data)
}
}
@ -384,7 +385,7 @@ export const useEstimateController = (planNo) => {
if (res.status === 201) {
estimateData.newFileList = []
swalFire({ text: getMessage('estimate.detail.save.alertMsg'), type: 'alert' })
fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo)
fetchSetting(estimateData.objectNo, estimateData.planNo)
}
})
} catch (e) {
@ -409,7 +410,7 @@ export const useEstimateController = (planNo) => {
const params = {
saleStoreId: session.storeId,
sapSalesStoreCd: session.custCd,
objectNo: objectRecoil.floorPlanObjectNo,
objectNo: estimateData.objectNo,
planNo: sendPlanNo,
copySaleStoreId: otherSaleStoreId ? otherSaleStoreId : saleStoreId,
copyReceiveUser: copyReceiveUser,

View File

@ -389,6 +389,7 @@ export function useModule() {
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
let isWarning = false
canvas.discardActiveObject()
moduleSetupSurface.set({ modules: otherModules })
canvas.remove(...columnModules)
canvas.renderAll()
@ -503,6 +504,7 @@ export function useModule() {
let isWarning = false
canvas.discardActiveObject()
moduleSetupSurface.set({ modules: otherModules })
canvas.remove(...rowModules)
canvas.renderAll()
@ -852,8 +854,12 @@ export function useModule() {
const modulesRemove = () => {
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE)
canvas.remove(...modules)
const modules = canvas
.getObjects()
.filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE && activeModule.id !== obj.id)
const surface = canvas.getObjects().filter((obj) => obj.id === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)[0]
surface.set({ modules: modules })
canvas.remove(activeModule)
canvas.renderAll()
}

View File

@ -1,5 +1,5 @@
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasState, checkedModuleState, isManualModuleSetupState, selectedModuleState } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasSettingState, canvasState, checkedModuleState, isManualModuleSetupState, selectedModuleState } from '@/store/canvasAtom'
import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon } from '@/util/canvas-util'
import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom'
import offsetPolygon, { calculateAngle } from '@/util/qpolygon-utils'
@ -8,14 +8,13 @@ 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'
import { QLine } from '@/components/fabric/QLine'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
export function useModuleBasicSetting() {
const canvas = useRecoilValue(canvasState)
@ -23,14 +22,17 @@ export function useModuleBasicSetting() {
const roofDisplay = useRecoilValue(roofDisplaySelector)
const [moduleSetupSurface, setModuleSetupSurface] = useRecoilState(moduleSetupSurfaceState)
const [moduleIsSetup, setModuleIsSetup] = useRecoilState(moduleIsSetupState)
const { addTargetMouseEventListener, addCanvasMouseEventListener, initEvent, removeMouseEvent } = useEvent()
const { addCanvasMouseEventListener, initEvent, removeMouseEvent } = useEvent()
const { swalFire } = useSwal()
const canvasSetting = useRecoilValue(canvasSettingState)
const compasDeg = useRecoilValue(compasDegAtom)
const { setSurfaceShapePattern } = useRoofFn()
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
const checkedModule = useRecoilValue(checkedModuleState)
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
const setModuleStatistics = useSetRecoilState(moduleStatisticsState)
const canvasSetting = useRecoilValue(canvasSettingState)
useEffect(() => {
// console.log('basicSetting', basicSetting)
@ -44,7 +46,6 @@ export function useModuleBasicSetting() {
}, [])
// const { addTargetMouseEventListener, addCanvasMouseEventListener, initEvent } = useContext(EventContext)
let selectedModuleInstSurfaceArray = []
//모듈,회로에서 다른메뉴 -> 배치면으로 갈 경수 초기화
const restoreModuleInstArea = () => {
@ -69,104 +70,6 @@ export function useModuleBasicSetting() {
})
}
const makeModuleInstArea = () => {
//지붕 객체 반환
const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof')
let offsetLength = canvasSetting.roofSizeSet === 3 ? -90 : -20
if (!roofs) {
return
}
roofs.forEach((roof) => {
const isExistSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.parentId === roof.id)
if (isExistSurface) {
return
}
setSurfaceShapePattern(roof, roofDisplay.column, true) //패턴 변경
const offsetPoints = offsetPolygon(roof.points, offsetLength) //안쪽 offset
//모듈설치영역?? 생성
const surfaceId = uuidv4()
let setupSurface = new QPolygon(offsetPoints, {
stroke: 'red',
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
selectable: true,
parentId: roof.id, //가대 폴리곤의 임시 인덱스를 넣어줌
name: POLYGON_TYPE.MODULE_SETUP_SURFACE,
flowDirection: roof.direction,
direction: roof.direction,
flipX: roof.flipX,
flipY: roof.flipY,
surfaceId: surfaceId,
originX: 'center',
originY: 'center',
modules: [],
roofMaterial: roof.roofMaterial,
// angle: -compasDeg,
})
setupSurface.setViewLengthText(false)
canvas.add(setupSurface) //모듈설치면 만들기
//지붕면 선택 금지
roof.set({
selectable: false,
})
//모듈설치면 클릭이벤트
addTargetMouseEventListener('mousedown', setupSurface, function () {
toggleSelection(setupSurface)
})
})
}
//설치 범위 지정 클릭 이벤트
const toggleSelection = (setupSurface) => {
const isExist = selectedModuleInstSurfaceArray.some((obj) => obj.parentId === setupSurface.parentId)
//최초 선택일때
if (!isExist) {
//기본 선택이랑 스트로크 굵기가 같으면 선택 안됨으로 봄
setupSurface.set({
...setupSurface,
strokeWidth: 3,
strokeDashArray: [0],
fill: 'transparent',
})
canvas.discardActiveObject() // 객체의 활성 상태 해제
//중복으로 들어가는걸 방지하기 위한 코드
canvas?.renderAll()
selectedModuleInstSurfaceArray.push(setupSurface)
} else {
//선택후 재선택하면 선택안됨으로 변경
setupSurface.set({
...setupSurface,
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
})
canvas.discardActiveObject() // 객체의 활성 상태 해제
//폴리곤에 커스텀 인덱스를 가지고 해당 배열 인덱스를 찾아 삭제함
const removeIndex = setupSurface.parentId
const removeArrayIndex = selectedModuleInstSurfaceArray.findIndex((obj) => obj.parentId === removeIndex)
selectedModuleInstSurfaceArray.splice(removeArrayIndex, 1)
}
canvas?.renderAll()
setModuleSetupSurface([...selectedModuleInstSurfaceArray])
}
/**
* trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 진입여부를 확인
* 확인 셀을 이동시킴
@ -188,15 +91,7 @@ export function useModuleBasicSetting() {
}
const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴
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 batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체
const moduleOptions = {
fill: checkedModule[0].color,
@ -447,17 +342,7 @@ export function useModuleBasicSetting() {
//도머 객체를 가져옴
if (batchObjects) {
batchObjects.forEach((object) => {
let dormerTurfPolygon
if (object.type === 'group') {
//도머는 그룹형태임
dormerTurfPolygon = batchObjectGroupToTurfPolygon(object)
} else {
//개구, 그림자
object.set({ points: rectToPolygon(object) })
dormerTurfPolygon = polygonToTurfPolygon(object)
}
let dormerTurfPolygon = polygonToTurfPolygon(object, true)
const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인
//겹치면 안됨
if (intersection) {
@ -479,9 +364,11 @@ export function useModuleBasicSetting() {
//안겹치면 넣는다
// tempModule.setCoords()
moduleOptions.surfaceId = trestlePolygon.id
let manualModule = new QPolygon(tempModule.points, { ...moduleOptions })
let manualModule = new QPolygon(tempModule.points, { ...moduleOptions, moduleInfo: checkedModule[0] })
canvas?.add(manualModule)
manualDrawModules.push(manualModule)
getModuleStatistics()
} else {
swalFire({ text: getMessage('module.place.overlab') })
}
@ -516,15 +403,7 @@ export function useModuleBasicSetting() {
?.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && !moduleSetupSurfaces.includes(obj)) //설치면이 아닌것
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 batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체
if (moduleSetupSurfaces.length === 0) {
swalFire({ text: getMessage('module.place.no.surface') })
@ -578,18 +457,7 @@ export function useModuleBasicSetting() {
const objectsIncludeSurface = (turfModuleSetupSurface) => {
let containsBatchObjects = []
containsBatchObjects = batchObjects.filter((batchObject) => {
let convertBatchObject
if (batchObject.type === 'group') {
//도머는 그룹형태임
convertBatchObject = batchObjectGroupToTurfPolygon(batchObject)
} else {
//개구, 그림자
batchObject.set({ points: rectToPolygon(batchObject) })
canvas?.renderAll() // set된걸 바로 적용하기 위해
convertBatchObject = polygonToTurfPolygon(batchObject) //rect를 폴리곤으로 변환 -> turf 폴리곤으로 변환
}
let convertBatchObject = polygonToTurfPolygon(batchObject)
// 폴리곤 안에 도머 폴리곤이 포함되어있는지 확인해서 반환하는 로직
return turf.booleanContains(turfModuleSetupSurface, convertBatchObject) || turf.booleanWithin(convertBatchObject, turfModuleSetupSurface)
})
@ -697,6 +565,7 @@ export function useModuleBasicSetting() {
checkedModule.forEach((module, index) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
const flowLines = getFlowLines(moduleSetupSurface, module)
//육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
let startPoint = flowLines.bottom
@ -746,8 +615,8 @@ export function useModuleBasicSetting() {
for (let i = 0; i <= totalWidth; i++) {
leftMargin = i === 0 ? 0 : intvHor * i
chidoriLength = 0
if (isChidori) {
chidoriLength = j % 2 === 0 ? 0 : width / 2
if (isChidori && !isMaxSetup) {
chidoriLength = j % 2 === 0 ? 0 : width / 2 - intvHor
}
square = [
@ -762,7 +631,7 @@ export function useModuleBasicSetting() {
let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id }
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
@ -847,7 +716,7 @@ export function useModuleBasicSetting() {
for (let j = 0; j < totalHeight; j++) {
leftMargin = j === 0 ? 0 : intvVer * j
chidoriLength = 0
if (isChidori) {
if (isChidori && !isMaxSetup) {
chidoriLength = i % 2 === 0 ? 0 : height / 2
}
@ -864,7 +733,7 @@ export function useModuleBasicSetting() {
let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
// if (disjointFromTrestle && isDisjoint) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id }
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
@ -958,8 +827,8 @@ export function useModuleBasicSetting() {
for (let i = 0; i < diffRightEndPoint; i++) {
leftMargin = i === 0 ? 0 : intvHor * i
chidoriLength = 0
if (isChidori) {
chidoriLength = j % 2 === 0 ? 0 : width / 2
if (isChidori && !isMaxSetup) {
chidoriLength = j % 2 === 0 ? 0 : width / 2 - intvHor
}
square = [
@ -975,7 +844,7 @@ export function useModuleBasicSetting() {
let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
// if (disjointFromTrestle && isDisjoint) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id }
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
@ -1058,8 +927,8 @@ export function useModuleBasicSetting() {
leftMargin = j === 0 ? 0 : intvVer * j
chidoriLength = 0
if (isChidori) {
chidoriLength = i % 2 === 0 ? 0 : height / 2
if (isChidori && !isMaxSetup) {
chidoriLength = i % 2 === 0 ? 0 : height / 2 - intvHor
}
square = [
@ -1075,7 +944,7 @@ export function useModuleBasicSetting() {
let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
// if (disjointFromTrestle && isDisjoint) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id }
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
@ -1118,6 +987,8 @@ export function useModuleBasicSetting() {
const flowDirection = moduleSetupSurface.flowDirection
console.log('moduleSetupSurface', moduleSetupSurface)
let intvHor =
flowDirection === 'south' || flowDirection === 'north'
? moduleSetupSurface.trestleDetail.moduleIntvlHor
@ -1204,7 +1075,7 @@ export function useModuleBasicSetting() {
})
moduleSetupSurface.set({ modules: moduleSetupArray })
getModuleStatistics()
// const moduleArray = [...moduleIsSetup]
// moduleArray.push({
// surfaceId: moduleSetupSurface.surfaceId,
@ -1304,13 +1175,13 @@ export function useModuleBasicSetting() {
const pointX2 = coords[2].x + ((coords[2].y - top) / (coords[2].y - coords[1].y)) * (coords[1].x - coords[2].x)
const pointY2 = top
const finalLine = new QLine([pointX1, pointY1, pointX2, pointY2], {
stroke: 'red',
strokeWidth: 1,
selectable: true,
})
canvas?.add(finalLine)
canvas?.renderAll()
// const finalLine = new QLine([pointX1, pointY1, pointX2, pointY2], {
// stroke: 'red',
// strokeWidth: 1,
// selectable: true,
// })
// canvas?.add(finalLine)
// canvas?.renderAll()
let rtnObj
//평평하면
@ -1427,13 +1298,13 @@ export function useModuleBasicSetting() {
const pointX2 = top
const pointY2 = coords[2].y + ((coords[2].x - top) / (coords[2].x - coords[1].x)) * (coords[1].y - coords[2].y)
const finalLine = new QLine([pointX1, pointY1, pointX2, pointY2], {
stroke: 'red',
strokeWidth: 1,
selectable: true,
})
canvas?.add(finalLine)
canvas?.renderAll()
// const finalLine = new QLine([pointX1, pointY1, pointX2, pointY2], {
// stroke: 'red',
// strokeWidth: 1,
// selectable: true,
// })
// canvas?.add(finalLine)
// canvas?.renderAll()
let rtnObj
//평평하면
@ -1839,6 +1710,8 @@ export function useModuleBasicSetting() {
}
})
}
getModuleStatistics()
}
const autoFlatroofModuleSetup = (placementFlatRef) => {
@ -2229,7 +2102,7 @@ export function useModuleBasicSetting() {
})
moduleSetupSurface.set({ modules: setupedModules })
getModuleStatistics()
// console.log('moduleSetupSurface', moduleSetupSurface)
// console.log('setupedModules', setupedModules)
@ -2277,8 +2150,63 @@ export function useModuleBasicSetting() {
return isDisjoint
}
const getModuleStatistics = () => {
const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name)
console.log('🚀 ~ getModuleStatistics ~ surfaces:', surfaces)
let totalWpout = 0
let moduleInfo = {}
const rows = surfaces.map((surface) => {
let wpOut = 0
moduleInfo = {}
surface.modules.forEach((module) => {
if (!moduleInfo[module.moduleInfo.itemId]) {
moduleInfo[module.moduleInfo.itemId] = { name: module.moduleInfo.itemNm, amount: 0, id: module.moduleInfo.itemId }
}
wpOut += +module.moduleInfo.wpOut
moduleInfo[module.moduleInfo.itemId].amount++
})
totalWpout += wpOut
console.log('🚀 ~ moduleData.rows=surfaces.map ~ module:', module)
const rowObject = {}
Object.keys(moduleInfo).forEach((key) => {
rowObject[key] = moduleInfo[key].amount
})
return {
...rowObject, // 총 발전량 = 발전량 * 모듈 개수
...surface,
name: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText, // 지붕면
// powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }),
wpOut: wpOut,
}
})
console.log('🚀 ~ getModuleStatistics ~ rows:', rows)
console.log('🚀 ~ getModuleStatistics ~ moduleInfo:', moduleInfo)
const header = [
{ name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'name' },
...Object.keys(moduleInfo).map((key) => {
return { name: moduleInfo[key].name, prop: key }
}),
{ name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'wpOut' },
]
let footer = ['합계']
let footerData = {}
rows.forEach((row) => {
Object.keys(moduleInfo).map((key) => {
if (!footerData[key]) footerData[key] = 0
footerData[key] += row[key]
})
})
Object.keys(footerData).forEach((key) => {
footer.push(footerData[key])
})
footer.push(totalWpout)
console.log({ header: header, rows, footer: footer })
setModuleStatistics({ header: header, rows, footer: footer })
}
return {
makeModuleInstArea,
manualModuleSetup,
autoModuleSetup,
restoreModuleInstArea,

View File

@ -1,47 +1,59 @@
import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useMasterController } from '@/hooks/common/useMasterController'
import { canvasState } from '@/store/canvasAtom'
import { canvasSettingState, canvasState, currentCanvasPlanState, moduleSetupSurfaceState } from '@/store/canvasAtom'
import { POLYGON_TYPE, BATCH_TYPE } from '@/common/common'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { roofDisplaySelector } from '@/store/settingAtom'
import offsetPolygon from '@/util/qpolygon-utils'
import { v4 as uuidv4 } from 'uuid'
import { QPolygon } from '@/components/fabric/QPolygon'
import { useEvent } from '@/hooks/useEvent'
export function useModulePlace() {
const canvas = useRecoilValue(canvasState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터
const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
const [trestleDetailParams, setTrestleDetailParams] = useState([])
const [trestleDetailList, setTrestleDetailList] = useState([])
const selectedModules = useRecoilValue(selectedModuleState)
const { getTrestleDetailList } = useMasterController()
const canvasSetting = useRecoilValue(canvasSettingState)
const { setSurfaceShapePattern } = useRoofFn()
const roofDisplay = useRecoilValue(roofDisplaySelector)
const { addTargetMouseEventListener } = useEvent()
const setModuleSetupSurface = useSetRecoilState(moduleSetupSurfaceState)
useEffect(() => {
console.log('🚀 ~ useModulePlace ~ moduleSelectionData:', moduleSelectionData)
}, [])
if (moduleSelectionData) {
const common = moduleSelectionData.common
const roofConstructions = moduleSelectionData.roofConstructions
useEffect(() => {
const common = moduleSelectionData.common
const roofConstructions = moduleSelectionData.roofConstructions
const listParams = roofConstructions.map((item) => {
return {
...common,
moduleTpCd: selectedModules.itemTp,
roofMatlCd: item.trestle.roofMatlCd,
trestleMkrCd: item.trestle.trestleMkrCd,
constMthdCd: item.trestle.constMthdCd,
roofBaseCd: item.trestle.roofBaseCd,
constTp: item.construction.constTp,
mixMatlNo: selectedModules.mixMatlNo,
roofPitch: selectedModules.roofPchBase ? selectedModules.roofPchBase : null,
inclCd: String(item.addRoof.pitch),
roofIndex: item.addRoof.index,
}
})
setTrestleDetailParams(listParams)
const listParams = roofConstructions.map((item) => {
return {
...common,
moduleTpCd: selectedModules.itemTp,
roofMatlCd: item.trestle.roofMatlCd,
trestleMkrCd: item.trestle.trestleMkrCd,
constMthdCd: item.trestle.constMthdCd,
roofBaseCd: item.trestle.roofBaseCd,
constTp: item.construction.constTp,
mixMatlNo: selectedModules.mixMatlNo,
roofPitch: item.addRoof.roofPchBase ? item.addRoof.roofPchBase : null,
inclCd: String(item.addRoof.pitch),
roofIndex: item.addRoof.index,
workingWidth: item.addRoof.lenBase,
}
})
setTrestleDetailParams(listParams)
}
}, [moduleSelectionData])
const getTrestleDetailListData = async () => {
const trestleDetailList = await getTrestleDetailList(trestleDetailParams)
setTrestleDetailList(trestleDetailList)
if (trestleDetailList.length > 0) {
setTrestleDetailList(trestleDetailList)
}
}
useEffect(() => {
@ -51,33 +63,168 @@ export function useModulePlace() {
}, [trestleDetailParams])
useEffect(() => {
console.log('🚀 ~ useModulePlace ~ trestleDetailList:', trestleDetailList)
//지붕을 가져옴
canvas
.getObjects()
.filter((roof) => roof.name === 'roof')
.forEach((roof) => {
const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번
trestleDetailList.forEach((detail) => {
if (Number(detail.data.roofIndex) === roofIndex) {
//roof에 상세 데이터 추가
roof.set({ trestleDetail: detail.data })
//surface에 상세 데이터 추가
canvas
.getObjects()
.filter((surface) => surface.name === 'moduleSetupSurface' && surface.parentId === roof.id)
.forEach((surface) => {
surface.set({ trestleDetail: detail.data, roofMaterial: roof.roofMaterial })
})
}
if (trestleDetailList.length > 0) {
//지붕을 가져옴
canvas
.getObjects()
.filter((roof) => roof.name === 'roof')
.forEach((roof) => {
const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번
trestleDetailList.forEach((detail) => {
if (Number(detail.data.roofIndex) === roofIndex) {
//roof에 상세 데이터 추가
roof.set({ trestleDetail: detail.data })
//배치면 설치 영역
makeModuleInstArea(roof, detail.data)
//surface에 상세 데이터 추가
}
})
})
console.log('roof', roof)
})
}
}, [trestleDetailList])
const makeModuleInstArea = (roof, trestleDetail) => {
//지붕 객체 반환
if (!roof) {
return
}
const batchObjects = canvas
?.getObjects()
.filter(
(obj) =>
obj.name === BATCH_TYPE.OPENING ||
obj.name === BATCH_TYPE.SHADOW ||
obj.name === BATCH_TYPE.TRIANGLE_DORMER ||
obj.name === BATCH_TYPE.PENTAGON_DORMER,
) //도머s 객체
//도머도 외곽을 따야한다
const batchObjectOptions = {
stroke: 'red',
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
selectable: true,
name: POLYGON_TYPE.OBJECT_SURFACE,
originX: 'center',
originY: 'center',
}
batchObjects.forEach((obj) => {
if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) {
const groupPoints = obj.groupPoints
const offsetObjects = offsetPolygon(groupPoints, 10)
const dormerOffset = new QPolygon(offsetObjects, batchObjectOptions)
dormerOffset.setViewLengthText(false)
canvas.add(dormerOffset) //모듈설치면 만들기
} else {
const points = obj.points
const offsetObjects = offsetPolygon(points, 10)
const offset = new QPolygon(offsetObjects, batchObjectOptions)
offset.setViewLengthText(false)
canvas.add(offset) //모듈설치면 만들기
}
})
const isExistSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.parentId === roof.id)
if (isExistSurface) {
return
}
let offsetLength = canvasSetting.roofSizeSet === 3 ? -90 : (trestleDetail.eaveIntvl / 10) * -1
setSurfaceShapePattern(roof, roofDisplay.column, true) //패턴 변경
const offsetPoints = offsetPolygon(roof.points, offsetLength) //안쪽 offset
//모듈설치영역?? 생성
const surfaceId = uuidv4()
let setupSurface = new QPolygon(offsetPoints, {
stroke: 'red',
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
selectable: true,
parentId: roof.id, //가대 폴리곤의 임시 인덱스를 넣어줌
name: POLYGON_TYPE.MODULE_SETUP_SURFACE,
flowDirection: roof.direction,
direction: roof.direction,
flipX: roof.flipX,
flipY: roof.flipY,
surfaceId: surfaceId,
originX: 'center',
originY: 'center',
modules: [],
roofMaterial: roof.roofMaterial,
trestleDetail: trestleDetail,
// angle: -compasDeg,
})
setupSurface.setViewLengthText(false)
canvas.add(setupSurface) //모듈설치면 만들기
//지붕면 선택 금지
roof.set({
selectable: false,
})
//모듈설치면 클릭이벤트
addTargetMouseEventListener('mousedown', setupSurface, function () {
toggleSelection(setupSurface)
})
}
let selectedModuleInstSurfaceArray = []
//설치 범위 지정 클릭 이벤트
const toggleSelection = (setupSurface) => {
const isExist = selectedModuleInstSurfaceArray.some((obj) => obj.parentId === setupSurface.parentId)
//최초 선택일때
if (!isExist) {
//기본 선택이랑 스트로크 굵기가 같으면 선택 안됨으로 봄
setupSurface.set({
...setupSurface,
strokeWidth: 3,
strokeDashArray: [0],
fill: 'transparent',
})
canvas.discardActiveObject() // 객체의 활성 상태 해제
//중복으로 들어가는걸 방지하기 위한 코드
canvas?.renderAll()
selectedModuleInstSurfaceArray.push(setupSurface)
} else {
//선택후 재선택하면 선택안됨으로 변경
setupSurface.set({
...setupSurface,
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
})
canvas.discardActiveObject() // 객체의 활성 상태 해제
//폴리곤에 커스텀 인덱스를 가지고 해당 배열 인덱스를 찾아 삭제함
const removeIndex = setupSurface.parentId
const removeArrayIndex = selectedModuleInstSurfaceArray.findIndex((obj) => obj.parentId === removeIndex)
selectedModuleInstSurfaceArray.splice(removeArrayIndex, 1)
}
canvas?.renderAll()
setModuleSetupSurface([...selectedModuleInstSurfaceArray])
}
return {
selectedModules,
}

View File

@ -3,42 +3,50 @@ import { useContext, useEffect, useState } from 'react'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { selectedModuleState, moduleSelectionInitParamsState } from '@/store/selectedModuleOptions'
import { pitchSelector } from '@/store/canvasAtom'
import { selectedModuleState, moduleSelectionInitParamsState, moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty } from '@/util/common-utils'
export function useModuleSelection(props) {
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const globalPitch = useRecoilValue(pitchSelector) //피치
const [roughnessCodes, setRoughnessCodes] = useState([]) //면조도 목록
const [windSpeedCodes, setWindSpeedCodes] = useState([]) //기준풍속 목록
const [moduleList, setModuleList] = useState([{}]) //모듈 목록
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //선택된 모듈
const [selectedSurfaceType, setSelectedSurfaceType] = useState({}) //선택된 면조도
const [installHeight, setInstallHeight] = useState('0') //설치 높이
const [installHeight, setInstallHeight] = useState() //설치 높이
const [standardWindSpeed, setStandardWindSpeed] = useState({}) //기준풍속
const [verticalSnowCover, setVerticalSnowCover] = useState('0') //수직적설량
const [verticalSnowCover, setVerticalSnowCover] = useState() //수직적설량
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //선택된 모듈
const [moduleSelectionInitParams, setModuleSelectionInitParams] = useRecoilState(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등
const { getModuleTypeItemList } = useMasterController()
const { findCommonCode } = useCommonCode()
//탭별 파라메터 초기화
useEffect(() => {
const bindInitData = () => {
setInstallHeight(managementState?.installHeight)
setStandardWindSpeed(managementState?.standardWindSpeedId)
setVerticalSnowCover(managementState?.verticalSnowCover)
setSelectedSurfaceType(managementState?.surfaceType)
}
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터
//탭별 파라메터 초기화
useEffect(() => {
bindInitData()
const initParams = {
illuminationTp: managementState?.surfaceTypeValue, //면조도
instHt: managementState?.installHeight, //설치높이
stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속
stdSnowLd: managementState?.verticalSnowCover, //기준적설량
}
if (selectedModules) {
initParams.moduleTpCd = selectedModules.itemTp
initParams.moduleItemId = selectedModules.itemId
}
setModuleSelectionInitParams(initParams)
}, [managementState])
@ -67,8 +75,10 @@ export function useModuleSelection(props) {
}
//새로고침시 데이터 날아가는거 방지
if (!managementState) {
if (managementState === null) {
setManagementState(managementStateLoaded)
} else {
bindInitData()
}
getModuleData(roofsIds)
@ -76,14 +86,23 @@ export function useModuleSelection(props) {
const getModuleData = async (roofsIds) => {
const list = await getModuleTypeItemList(roofsIds)
//selectbox에 이름을 넣는다
list.data.forEach((item) => {
item.name = item.itemNm
})
//셀렉트박스 데이터 초기화
setModuleList(list.data)
if (list.data.length > 0) {
//selectbox에 이름을 넣는다
list.data.forEach((item) => {
item.name = item.itemNm
})
//셀렉트박스 데이터 초기화
setModuleList(list.data)
}
}
//데이터가 있으면 모듈 자동 선택
useEffect(() => {
if (moduleList.length > 0 && isObjectNotEmpty(moduleSelectionData.module)) {
handleChangeModule(moduleSelectionData.module)
}
}, [moduleList])
const handleChangeModule = (option) => {
//선택된 모듈
setSelectedModules(option) //선택값 저장
@ -101,31 +120,50 @@ export function useModuleSelection(props) {
...moduleSelectionInitParams,
illuminationTp: option.clCode,
})
setManagementState({
...managementState,
surfaceType: option.clCodeNm,
surfaceTypeValue: option.clCode,
})
}
const handleChangeWindSpeed = (option) => {
setModuleSelectionInitParams({
...moduleSelectionInitParams,
surfaceType: option.clCode,
stdWindSpeed: option.clCode,
})
setManagementState({
...managementState,
standardWindSpeedId: option.clCode,
})
}
const handleChangeInstallHeight = (option) => {
setInstallHeight(option)
setModuleSelectionInitParams({
...moduleSelectionInitParams,
instHt: option,
})
setManagementState({
...managementState,
installHeight: option,
})
}
const handleChangeVerticalSnowCover = (option) => {
setVerticalSnowCover(option)
setModuleSelectionInitParams({
...moduleSelectionInitParams,
stdSnowLd: option,
})
setManagementState({
...managementState,
verticalSnowCover: option,
})
}
useEffect(() => {

View File

@ -0,0 +1,419 @@
import { useEffect, useState, useRef } from 'react'
import { useRecoilValue, useRecoilState } from 'recoil'
import { pitchTextSelector } from '@/store/canvasAtom'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { moduleSelectionDataState, moduleSelectionInitParamsState, selectedModuleState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty, isEqualObjects } from '@/util/common-utils'
import { addedRoofsState } from '@/store/settingAtom'
export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab, tempModuleSelectionData, setTempModuleSelectionData }) {
const addRoofsArray = useRecoilValue(addedRoofsState)
const globalPitchText = useRecoilValue(pitchTextSelector) //피치 텍스트
const { findCommonCode } = useCommonCode()
const [raftCodes, setRaftCodes] = useState([]) //가대 목록
const [trestleList, setTrestleList] = useState([])
const [constMthdList, setConstMthdList] = useState([])
const [roofBaseList, setRoofBaseList] = useState([])
const [constructionList, setConstructionList] = useState([{}]) //공법 목록
const [selectedRaftBase, setSelectedRaftBase] = useState({}) //선택된 가대
const [selectedTrestle, setSelectedTrestle] = useState({}) //선택된 가대
const [selectedConstMthd, setSelectedConstMthd] = useState({}) //선택된 공법
const [selectedRoofBase, setSelectedRoofBase] = useState({}) //선택된 지붕밑바탕
const [selectedConstruction, setSelectedConstruction] = useState({}) //선택된 공법
const [constructionListParams, setConstructionListParams] = useState({})
const [trestleParams, setTrestleParams] = useState({}) //서까래, 가대메이커,공법,지붕밑바탕 관련 api호출 파라메터
const [constructionParams, setConstructionParams] = useState({}) //공법 관련 api호출 파라메터
const [roofBaseParams, setRoofBaseParams] = useState({}) //지붕밑바탕 관련 api호출 파라메터
const moduleSelectionInitParams = useRecoilValue(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등
const moduleSelectionInitOriginData = useRef(moduleSelectionInitParams)
const { getTrestleList, getConstructionList } = useMasterController()
const constructionRef = useRef([])
const [cvrYn, setCvrYn] = useState('N')
const [snowGdPossYn, setSnowGdPossYn] = useState('N')
const [cvrChecked, setCvrChecked] = useState(false)
const [snowGdChecked, setSnowGdChecked] = useState(false)
const [isExistData, setIsExistData] = useState(false)
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //선택된 모듈
const [moduleConstructionSelectionData, setModuleConstructionSelectionData] = useState()
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터
const [hajebichi, setHajebichi] = useState(0)
const [lengthBase, setLengthBase] = useState(0)
const hajebichiRef = useRef()
const lengthRef = useRef()
//서까래간격 변경
const handleChangeRaftBase = (option) => {
setSelectedRaftBase(option)
setTrestleParams({ ...trestleParams, raftBaseCd: option.clCode }) //가대메이커
setConstMthdList([]) //공법 초기화
setRoofBaseList([]) //지붕밑바탕 초기화
setConstructionList([]) //공법 초기화
}
//처마력바 체크
const handleCvrChecked = () => {
setCvrChecked(!cvrChecked)
setSelectedConstruction({ ...selectedConstruction, setupCover: !cvrChecked })
}
//눈막이금구 체크
const handleSnowGdChecked = () => {
setSnowGdChecked(!snowGdChecked)
setSelectedConstruction({ ...selectedConstruction, setupSnowCover: !snowGdChecked })
}
const getConstructionListData = async (params) => {
if (params.trestleMkrCd && params.constMthdCd && params.roofBaseCd) {
const optionsList = await getConstructionList(params)
setConstructionList(optionsList.data)
}
}
useEffect(() => {
setHajebichi(addRoof.hajebichi)
setLengthBase(addRoof.lenBase)
// 202600 경사도
const raftCodeList = findCommonCode('203800')
//서까래 코드
raftCodeList.forEach((obj) => {
obj.name = obj.clCodeNm
obj.id = obj.clCode
})
setRaftCodes(raftCodeList)
console.log('moduleSelectionData', moduleSelectionData)
}, [])
//리코일에 데이터가 담기는 시점에 시작
useEffect(() => {
if (
isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex]) &&
isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex].trestle) &&
isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex].construction)
) {
setModuleConstructionSelectionData(moduleSelectionData.roofConstructions[tabIndex])
}
}, [moduleSelectionData])
useEffect(() => {
if (isObjectNotEmpty(moduleConstructionSelectionData)) {
setIsExistData(true)
}
}, [moduleConstructionSelectionData])
//높이를 변경하면 addRoofs에 적용
// useEffect(() => {
// const copyAddRoof = { ...addRoof }
// copyAddRoof.length = Number(lengthBase)
// copyAddRoof.lenBase = lengthBase
// const index = addRoof.index
// const newArray = [...addRoofsArray.slice(0, index), copyAddRoof, ...addRoofsArray.slice(index + 1)]
// setAddedRoofs(newArray)
// }, [lengthBase])
// //망둥어 피치를 변경하면 addRoof 변경
// useEffect(() => {
// const copyAddRoof = { ...addRoof }
// copyAddRoof.hajebichi = Number(hajebichi)
// copyAddRoof.roofPchBase = hajebichi
// const index = addRoof.index
// const newArray = [...addRoofsArray.slice(0, index), copyAddRoof, ...addRoofsArray.slice(index + 1)]
// setAddedRoofs(newArray)
// }, [hajebichi])
useEffect(() => {
if (isExistData) {
setConstructionListParams({
...moduleSelectionInitParams,
...roofBaseParams,
roofBaseCd: selectedRoofBase.roofBaseCd,
inclCd: addRoof.pitch,
roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0,
raftBaseCd: addRoof.raftBaseCd,
})
}
}, [selectedRoofBase])
useEffect(() => {
if (
isExistData &&
constructionList.length > 0 &&
isObjectNotEmpty(moduleConstructionSelectionData?.construction) &&
moduleConstructionSelectionData?.construction.hasOwnProperty('constPossYn') ///키가 있으면
) {
const selectedIndex = moduleConstructionSelectionData.construction.selectedIndex
const construction = constructionList[selectedIndex]
if (construction.constPossYn === 'Y') {
handleConstruction(selectedIndex)
}
}
}, [constructionList])
//모듈 변경
useEffect(() => {
//lengbase는 무조건 있다고 가정 하고 최초에 실행 방지
if (selectedModules) {
//가대메이커 파라메터 만들기
setTrestleParams({
moduleTpCd: selectedModules.itemTp,
roofMatlCd: addRoof.roofMatlCd,
raftBaseCd: addRoof.raftBaseCd,
workingWidth: lengthBase,
})
}
}, [selectedModules])
//가대메이커 api 호출
useEffect(() => {
if (isObjectNotEmpty(trestleParams)) {
getModuleOptionsListData(trestleParams, 'trestle')
}
}, [trestleParams])
//가대메이커 변경 함수
const handleChangeTrestle = (option) => {
setSelectedTrestle(option) //선택값 저장
setConstructionParams({ ...trestleParams, trestleMkrCd: option.trestleMkrCd, constMthdCd: '', roofBaseCd: '' })
}
useEffect(() => {
if (isObjectNotEmpty(constructionParams)) {
getModuleOptionsListData(constructionParams, 'construction')
}
}, [constructionParams])
//공법 변경
const handleChangeConstMthd = (option) => {
setSelectedConstMthd(option) //선택된값 저장
setRoofBaseParams({
...trestleParams,
trestleMkrCd: selectedTrestle.trestleMkrCd,
constMthdCd: option.constMthdCd,
roofBaseCd: '',
})
}
useEffect(() => {
if (isObjectNotEmpty(roofBaseParams)) {
getModuleOptionsListData(roofBaseParams, 'roofBase')
}
}, [roofBaseParams])
const handleChangeRoofBase = (option) => {
setConstructionListParams({
...moduleSelectionInitParams,
trestleMkrCd: selectedTrestle.trestleMkrCd,
constMthdCd: selectedConstMthd.constMthdCd,
roofBaseCd: option.roofBaseCd,
inclCd: addRoof.pitch,
roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0,
raftBaseCd: addRoof.raftBaseCd,
roofMatlCd: addRoof.roofMatlCd,
})
setSelectedRoofBase(option)
}
//공법 리스트 변경 함수
useEffect(() => {
if (isObjectNotEmpty(constructionListParams)) {
getConstructionListData(constructionListParams)
}
}, [constructionListParams])
//공법 선택 함수
const handleConstruction = (index) => {
if (index > -1) {
const isPossibleIndex = constructionRef.current
.map((el, i) => (el.classList.contains('white') || el.classList.contains('blue') ? i : -1))
.filter((index) => index !== -1)
isPossibleIndex.forEach((index) => {
if (constructionRef.current[index].classList.contains('blue')) {
constructionRef.current[index].classList.remove('blue')
constructionRef.current[index].classList.add('white')
}
})
constructionRef.current[index].classList.remove('white')
constructionRef.current[index].classList.add('blue')
const selectedConstruction = constructionList[index]
selectedConstruction.roofIndex = roofTab
selectedConstruction.setupCover = false //처마력바 설치 여부
selectedConstruction.setupSnowCover = false //눈막이금구 설치 여부
selectedConstruction.selectedIndex = index
setCvrYn(selectedConstruction.cvrYn)
setSnowGdPossYn(selectedConstruction.snowGdPossYn)
//기존에 선택된 데이터가 있으면 체크한다
if (moduleConstructionSelectionData && moduleConstructionSelectionData.construction) {
selectedConstruction.setupCover = moduleConstructionSelectionData.construction.setupCover || false
selectedConstruction.setupSnowCover = moduleConstructionSelectionData.construction.setupSnowCover || false
setCvrChecked(selectedConstruction.setupCover)
setSnowGdChecked(selectedConstruction.setupSnowCover)
}
setSelectedConstruction(selectedConstruction)
} else {
constructionRef.current.forEach((ref) => {
ref.classList.remove('blue')
})
}
}
//공법 선택시 이후 프로세스
useEffect(() => {
if (isObjectNotEmpty(selectedRoofBase) && isObjectNotEmpty(selectedConstruction)) {
if (tabIndex === roofTab) {
const common = { ...moduleSelectionInitParams }
const module = { ...selectedModules }
const newRoofConstructions = {
roofIndex: tabIndex,
addRoof: addRoof,
trestle: selectedRoofBase,
construction: selectedConstruction,
}
const index = tempModuleSelectionData.roofConstructions.findIndex((obj) => obj.roofIndex === tabIndex)
if (index > -1) {
const newArray = [
...tempModuleSelectionData.roofConstructions.slice(0, index),
newRoofConstructions,
...tempModuleSelectionData.roofConstructions.slice(index + 1),
]
setTempModuleSelectionData({ common: common, module: module, roofConstructions: newArray })
} else {
setTempModuleSelectionData({
common: common,
module: module,
roofConstructions: [...tempModuleSelectionData.roofConstructions, { ...newRoofConstructions }],
})
}
}
}
}, [selectedConstruction])
const getModuleOptionsListData = async (params, type) => {
const optionsList = await getTrestleList(params)
if (optionsList.data.length > 0) {
if (type === 'trestle') {
setTrestleList(optionsList.data)
if (isExistData) {
handleChangeTrestle(moduleConstructionSelectionData?.trestle)
} else {
setConstMthdList([])
setRoofBaseList([])
}
} else if (type === 'construction') {
setConstMthdList(optionsList.data)
if (isExistData) {
handleChangeConstMthd(moduleConstructionSelectionData?.trestle)
} else {
setRoofBaseList([])
}
} else if (type === 'roofBase') {
setRoofBaseList(optionsList.data)
if (isExistData) {
handleChangeRoofBase(moduleConstructionSelectionData?.trestle)
}
}
}
}
useEffect(() => {
//모듈이 선택되어있을때
if (moduleSelectionInitOriginData.current.moduleItemId && moduleSelectionInitOriginData.current.moduleTpCd) {
//초기에 들어온 데이터가 수정된 데이터가 값이 다르다면`
if (!isEqualObjects(moduleSelectionInitOriginData.current, moduleSelectionInitParams)) {
//가대 선택 초기화
setSelectedTrestle({})
//공법 선택 초기화
setSelectedConstMthd({})
//지붕밑바탕 선택 초기화
setSelectedRoofBase({})
//공법 리스트 초기화
setConstructionList([])
// 기본 정보 초기화
setModuleSelectionData({
...moduleSelectionData,
roofConstructions: [],
})
// 선택 데이터 초 기화
setModuleConstructionSelectionData({
addRoof: addRoof,
trestle: {},
construction: {},
})
//임시 데이터 초기화
setTempModuleSelectionData({
...moduleSelectionData,
roofConstructions: [],
})
//처마커버 해제
setCvrChecked(false)
//눈막이금구 해제
setSnowGdChecked(false)
// 데이터 없음으로 변경
setIsExistData(false)
//변경된 데이터를 ref에 저장
moduleSelectionInitOriginData.current = moduleSelectionInitParams
}
}
}, [moduleSelectionInitParams])
return {
raftCodes,
trestleList,
constMthdList,
roofBaseList,
constructionList,
globalPitchText,
selectedTrestle,
selectedConstMthd,
selectedRoofBase,
constructionRef,
cvrYn,
cvrChecked,
snowGdPossYn,
snowGdChecked,
lengthBase,
hajebichi,
lengthRef,
hajebichiRef,
setLengthBase,
setHajebichi,
handleChangeRaftBase,
handleChangeTrestle,
handleChangeConstMthd,
handleChangeRoofBase,
handleConstruction,
handleCvrChecked,
handleSnowGdChecked,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -93,7 +93,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
})
if (!selectedSurface) {
swalFire({ text: '지붕안에 그려야해요', icon: 'error' })
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
initEvent() //이벤트 초기화
if (setIsHidden) setIsHidden(false)
return
@ -150,7 +150,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//지붕 밖으로 그렸을때
if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
//일단 지워
deleteTempObjects()
return
@ -162,14 +162,14 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon))
if (isCross) {
swalFire({ text: '겹치기 불가요...', icon: 'error' })
swalFire({ text: getMessage('batch.object.notinstall.cross'), icon: 'error' })
deleteTempObjects()
return
}
}
isDown = false
rect.set({ name: objName, parentId: selectedSurface.id })
rect.set({ name: objName, parentId: selectedSurface.id, points: rectToPolygon(rect) })
rect.setCoords()
initEvent()
@ -232,7 +232,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//지붕 밖으로 그렸을때
if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
//일단 지워
deleteTempObjects()
return
@ -244,14 +244,14 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon))
if (isCross) {
swalFire({ text: '겹치기 불가요...', icon: 'error' })
swalFire({ text: getMessage('batch.object.notinstall.cross'), icon: 'error' })
deleteTempObjects()
return
}
}
isDown = false
rect.set({ name: objName, parentId: selectedSurface.id })
rect.set({ name: objName, parentId: selectedSurface.id, points: rectToPolygon(rect) })
rect.setCoords()
initEvent()
if (setIsHidden) setIsHidden(false)
@ -377,12 +377,9 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
console.log('trianglePolygon', trianglePolygon)
console.log('selectedSurfacePolygon', selectedSurfacePolygon)
//지붕 밖으로 그렸을때
if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) {
swalFire({ text: '도머를 배치할 수 없습니다.', icon: 'error' })
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
//일단 지워
deleteTempObjects()
return
@ -406,6 +403,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
direction = 'north'
}
const groupPoints = offsetRef > 0 ? triangleToPolygon(dormerOffset) : triangleToPolygon(dormer)
let splitedTriangle = offsetRef > 0 ? splitDormerTriangle(dormerOffset, directionRef) : splitDormerTriangle(dormer, directionRef)
canvas?.remove(offsetRef > 0 ? dormerOffset : dormer)
@ -499,6 +498,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
parentId: selectedSurface.id,
originX: 'center',
originY: 'center',
groupPoints: groupPoints,
})
canvas?.add(objectGroup)
@ -604,7 +604,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//지붕 밖으로 그렸을때
if (!turf.booleanWithin(pentagonPolygon, selectedSurfacePolygon)) {
swalFire({ text: '도머를 배치할 수 없습니다.', icon: 'error' })
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
//일단 지워
deleteTempObjects()
return
@ -708,6 +708,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
const groupPolygon = offsetPolygon ? [leftPentagon, rightPentagon, offsetPolygon] : [leftPentagon, rightPentagon]
const groupPoints = offsetRef > 0 ? pentagonOffsetPoints : pentagonPoints
const objectGroup = new fabric.Group(groupPolygon, {
subTargetCheck: true,
@ -717,6 +718,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
groupYn: true,
originX: 'center',
originY: 'center',
groupPoints: groupPoints,
})
canvas?.add(objectGroup)

View File

@ -1,4 +1,4 @@
import { useEffect, useState, useRef } from 'react'
import { useEffect, useState, useRef, useContext } from 'react'
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import {
adsorptionPointModeState,
@ -35,6 +35,7 @@ import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementSha
import { useCanvasMenu } from '../common/useCanvasMenu'
import { menuTypeState } from '@/store/menuAtom'
import { usePopup } from '../usePopup'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
const defaultDotLineGridSetting = {
INTERVAL: {
@ -58,17 +59,22 @@ export function useCanvasSetting() {
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
const resetSettingModalFirstOptions = useResetRecoilState(settingModalFirstOptionsState)
const resetSettingModalSecondOptions = useResetRecoilState(settingModalSecondOptionsState)
const [selectedFont, setSelectedFont] = useState()
const [selectedFontWeight, setSelectedFontWeight] = useState()
const [selectedFontSize, setSelectedFontSize] = useState()
const [selectedFontColor, setSelectedFontColor] = useState()
const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom)
const resetGlobalFont = useResetRecoilState(globalFontAtom)
const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState)
const [adsorptionRange, setAdsorptionRange] = useRecoilState(adsorptionRangeState)
const [planSizeSettingMode, setPlanSizeSettingMode] = useRecoilState(planSizeSettingState)
const resetPlanSizeSettingMode = useResetRecoilState(planSizeSettingState)
const [dimensionLineSettings, setDimensionLineSettings] = useRecoilState(dimensionLineSettingsState)
const resetDimensionLineSettings = useResetRecoilState(dimensionLineSettingsState)
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState)
@ -117,9 +123,13 @@ export function useCanvasSetting() {
const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
const { floorPlanState } = useContext(FloorPlanContext)
const { closeAll } = usePopup()
useEffect(() => {
console.log('correntObjectNo', correntObjectNo)
setFetchRoofMaterials(!fetchRoofMaterials)
if (fetchRoofMaterials) {
addRoofMaterials()
@ -159,21 +169,28 @@ export function useCanvasSetting() {
setBasicSettings({ ...basicSetting, selectedRoofMaterial: selectedRoofMaterial })
}
const previousObjectNoRef = useRef(null)
const previousRoofMaterialsRef = useRef(null)
useEffect(() => {
// 지붕재 select 정보가 존재해야 배치면초기설정 DB 정보 비교 후 지붕재 정보를 가져올 수 있음
if (roofMaterials.length !== 0 && JSON.stringify(previousRoofMaterialsRef.current) !== JSON.stringify(roofMaterials)) {
// 지붕재 select 정보 비교 후 변경된 것이 없으면 1회만 실행
if (
(!previousObjectNoRef.current && !correntObjectNo && previousObjectNoRef.current !== correntObjectNo) ||
(roofMaterials.length !== 0 && JSON.stringify(previousRoofMaterialsRef.current) !== JSON.stringify(roofMaterials))
) {
// 1회만 실행
if (roofMaterials && previousRoofMaterialsYn === 'N') {
fetchBasicSettings()
previousRoofMaterialsYn = 'Y'
if (correntObjectNo) {
fetchBasicSettings()
previousRoofMaterialsYn = 'Y'
}
}
// 이전 값을 업데이트
previousObjectNoRef.current = correntObjectNo
previousRoofMaterialsRef.current = roofMaterials
}
}, [roofMaterials])
}, [roofMaterials, correntObjectNo])
useEffect(() => {
if (!canvas) {
@ -181,6 +198,9 @@ export function useCanvasSetting() {
}
const { column } = corridorDimension
const lengthTexts = canvas.getObjects().filter((obj) => obj.name === 'lengthText')
lengthTexts.forEach((obj) => {
obj.set({ text: '' })
})
switch (column) {
case 'corridorDimension':
lengthTexts.forEach((obj) => {
@ -206,7 +226,6 @@ export function useCanvasSetting() {
}, [corridorDimension])
useEffect(() => {
console.log('🚀 ~ useEffect ~ settingsDataSave:', settingsDataSave)
if (settingsDataSave !== undefined) onClickOption2()
}, [settingsData])
@ -297,8 +316,8 @@ export function useCanvasSetting() {
})
roofsArray = res.map((item) => {
return {
roofApply: true,
roofSeq: 0,
roofApply: item.roofApply,
roofSeq: item.roofSeq,
roofMatlCd: item.roofMatlCd,
roofWidth: item.roofWidth,
roofHeight: item.roofHeight,
@ -328,6 +347,7 @@ export function useCanvasSetting() {
roofGap: 'HEI_455',
roofLayout: 'P',
roofPitch: 4,
roofAngle: 21.8,
},
]
}
@ -354,7 +374,6 @@ export function useCanvasSetting() {
}
})
}
console.log('🚀 ~ fetchBasicSettings ~ addRoofs:', addRoofs)
setAddedRoofs(addRoofs)
setBasicSettings({
...basicSetting,
@ -362,16 +381,16 @@ export function useCanvasSetting() {
roofSizeSet: roofsRow[0].roofSizeSet,
roofAngleSet: roofsRow[0].roofAngleSet,
roofsData: roofsArray,
selectedRoofMaterial: addRoofs[0],
selectedRoofMaterial: addRoofs.find((roof) => roof.selected),
})
})
} catch (error) {
console.error('Data fetching error:', error)
}
if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
setBasicSettings({ ...canvasSetting })
}
// if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
// setBasicSettings({ ...canvasSetting })
// }
setCanvasSetting({ ...basicSetting })
}
@ -438,7 +457,7 @@ export function useCanvasSetting() {
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${correntObjectNo}` })
console.log('res', res)
if (res) {
if (Object.keys(res).length > 0) {
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] }))
const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item }))
@ -527,26 +546,27 @@ export function useCanvasSetting() {
//그리드 색 설정
setGridColor(res.gridColor)
} else {
//조회된 글꼴 데이터가 없는 경우
//조회된 글꼴 데이터가 없는 경우 (데이터 초기화)
//흡착점 ON/OFF
setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: false })
//치수선 설정
setDimensionLineSettings({ ...dimensionLineSettings })
// setDimensionLineSettings({ ...dimensionLineSettings, ...dimensionLineSettingsState.default })
resetDimensionLineSettings()
//도면크기 설정
setPlanSizeSettingMode({ ...planSizeSettingMode })
// setPlanSizeSettingMode({ ...planSizeSettingMode, ...planSizeSettingState.default })
resetPlanSizeSettingMode()
// 데이터 설정
setSettingModalFirstOptions({
...settingModalFirstOptions,
})
setSettingModalSecondOptions({
...settingModalSecondOptions,
})
// setSettingModalFirstOptions({ ...settingModalFirstOptions, ...settingModalFirstOptionsState.default })
resetSettingModalFirstOptions()
//setSettingModalSecondOptions({ ...settingModalSecondOptions, ...settingModalSecondOptionsState.default })
resetSettingModalSecondOptions()
setGlobalFont({ ...globalFont })
// setGlobalFont({ ...globalFont, ...globalFontAtom.default })
resetGlobalFont()
//점/선 그리드
setDotLineGridSettingState({ ...defaultDotLineGridSetting })
@ -671,7 +691,7 @@ export function useCanvasSetting() {
// HTTP POST 요청 보내기
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData })
.then((res) => {
// swalFire({ text: getMessage(res.returnMessage) })
//swalFire({ text: getMessage(res.returnMessage) })
// Canvas 디스플레이 설정 시 해당 옵션 적용
frontSettings()
@ -679,7 +699,8 @@ export function useCanvasSetting() {
fetchSettings()
})
.catch((error) => {
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
//swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
swalFire({ text: error.message, icon: 'error' })
})
//setAdsorptionRange(item.range)
@ -770,6 +791,7 @@ export function useCanvasSetting() {
adsorptionRange,
setAdsorptionRange,
fetchSettings,
fetchBasicSettings,
frontSettings,
globalFont,
setGlobalFont,

View File

@ -120,37 +120,49 @@ export function usePropertiesSetting(id) {
}
const handleFix = () => {
if (!confirm('외벽선 속성 설정을 완료하시겠습니까?')) {
return
}
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const isClose = confirm('외벽선 속성 설정을 완료하시겠습니까?')
if (isClose) {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const notSetAttributes = lines.filter((line) => !line.attributes?.type)
if (notSetAttributes.length > 0) {
alert('설정되지 않은 외벽선이 있습니다.')
return
}
const notSetAttributes = lines.filter((line) => !line.attributes?.type)
if (notSetAttributes.length > 0) {
// 세팅이 하나라도 안되어있으면 초기화
lines.forEach((line) => {
line.set({
stroke: '#000000',
strokeWidth: 4,
})
})
canvas.discardActiveObject()
closePopup(id)
return
}
lines.forEach((line) => {
line.set({
attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
stroke: '#000000',
strokeWidth: 4,
lines.forEach((line) => {
line.set({
attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
stroke: '#000000',
strokeWidth: 4,
})
hideLine(line)
})
hideLine(line)
})
const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' })
const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' })
wall.lines = [...lines]
wall.lines = [...lines]
const roof = drawRoofPolygon(wall)
const roof = drawRoofPolygon(wall)
setPoints([])
canvas.renderAll()
roof.drawHelpLine()
setPoints([])
canvas.renderAll()
roof.drawHelpLine()
closePopup(id)
closePopup(id)
return
} else {
return
}
}
const closeModal = (fn) => {

View File

@ -24,6 +24,8 @@ import { useRoofFn } from '@/hooks/common/useRoofFn'
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import { globalLocaleStore } from '@/store/localeAtom'
import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
// 지붕면 할당
export function useRoofAllocationSetting(id) {
@ -42,7 +44,7 @@ export function useRoofAllocationSetting(id) {
const [currentRoofMaterial, setCurrentRoofMaterial] = useState(roofMaterials[0]) // 팝업 내 기준 지붕재
const [roofList, setRoofList] = useRecoilState(addedRoofsState) // 배치면 초기설정에서 선택한 지붕재 배열
const [editingLines, setEditingLines] = useState([])
const [currentRoofList, setCurrentRoofList] = useState(null)
const [currentRoofList, setCurrentRoofList] = useState([])
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const [basicInfo, setBasicInfo] = useState(null)
@ -52,6 +54,8 @@ export function useRoofAllocationSetting(id) {
const { setSurfaceShapePattern } = useRoofFn()
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
useEffect(() => {
setCurrentRoofList(roofList)
}, [])
@ -169,6 +173,7 @@ export function useRoofAllocationSetting(id) {
roofSizeSet: res[0].roofSizeSet,
roofAngleSet: res[0].roofAngleSet,
roofsData: roofsArray,
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
})
setBasicInfo({
roofSizeSet: '' + res[0].roofSizeSet,
@ -188,7 +193,7 @@ export function useRoofAllocationSetting(id) {
roofSizeSet: Number(basicSetting.roofSizeSet),
roofAngleSet: basicSetting.roofAngleSet,
roofAllocationList: currentRoofList.map((item, index) => ({
roofApply: item.selected === null || item.selected === undefined ? 'true' : item.selected,
roofApply: item.selected,
roofSeq: index,
roofMatlCd: item.roofMatlCd === null || item.roofMatlCd === undefined ? 'ROOF_ID_WA_53A' : item.roofMatlCd,
roofWidth: item.width === null || item.width === undefined ? 0 : Number(item.width),
@ -269,6 +274,7 @@ export function useRoofAllocationSetting(id) {
setRoofList(newRoofList)
const selectedRoofMaterial = newRoofList.find((roof) => roof.selected)
setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial)
modifyModuleSelectionData()
closeAll()
}
@ -368,6 +374,8 @@ export function useRoofAllocationSetting(id) {
closeAll()
setMenuNumber(3)
setMenuType('surface')
modifyModuleSelectionData()
}
const setLineSize = (id, size) => {
@ -499,6 +507,16 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
// 모듈 선택에서 선택한 데이터 초기화
const modifyModuleSelectionData = () => {
if (moduleSelectionData.roofConstructions.length > 0) {
setModuleSelectionData({ ...moduleSelectionData, roofConstructions: [] })
moduleSelectedDataTrigger({ ...moduleSelectionData, roofConstructions: [] })
}
}
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
return {
handleSave,
onAddRoofMaterial,

View File

@ -1,6 +1,6 @@
'use client'
import { useRecoilValue } from 'recoil'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasState, globalPitchState } from '@/store/canvasAtom'
import { MENU, POLYGON_TYPE } from '@/common/common'
import { getIntersectionPoint } from '@/util/canvas-util'
@ -16,11 +16,13 @@ import { fontSelector } from '@/store/fontAtom'
import { slopeSelector } from '@/store/commonAtom'
import { QLine } from '@/components/fabric/QLine'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { outerLinePointsState } from '@/store/outerLineAtom'
export function useSurfaceShapeBatch() {
const { getMessage } = useMessage()
const { drawDirectionArrow } = usePolygon()
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const [points, setPoints] = useRecoilState(outerLinePointsState)
const canvas = useRecoilValue(canvasState)
const globalPitch = useRecoilValue(globalPitchState)
@ -649,11 +651,12 @@ export function useSurfaceShapeBatch() {
const deleteAllSurfacesAndObjects = () => {
swalFire({
text: '배치면 내용을 전부 삭제하시겠습니까?',
text: getMessage('batch.canvas.delete.all'),
type: 'confirm',
confirmFn: () => {
canvas.clear()
swalFire({ text: '삭제 완료 되었습니다.' })
setPoints([])
swalFire({ text: getMessage('plan.message.delete') })
},
// denyFn: () => {
// swalFire({ text: '취소되었습니다.', icon: 'error' })

View File

@ -97,13 +97,11 @@ export function useAxios(lang = '') {
const getFetcher = async (url) => {
const res = await get({ url })
console.log('🚀 ~ getFetcher ~ res:', res)
return res
}
const postFetcher = async (url, { arg }) => {
const postFetcher = async (url, arg) => {
const res = await post({ url, data: arg })
console.log('🚀 ~ postFetcher ~ res:', res)
return res
}

Some files were not shown because too many files have changed in this diff Show More