'use client' import 'chart.js/auto' import { Bar } from 'react-chartjs-2' import dayjs from 'dayjs' import { v4 as uuidv4 } from 'uuid' import { useEffect, useState, useRef, useContext } from 'react' import { useRecoilState } from 'recoil' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { pwrGnrSimTypeState } from '@/store/simulatorAtom' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' 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' export default function Simulator() { 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 { get } = useAxios() const { getMessage } = useMessage() // 차트 관련 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: [ { label: 'kWh', data: chartData.slice(0, 12).map((item) => { const num = Number(item.replaceAll(',', '')) return isNaN(num) ? 0 : num }), backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)', 'rgba(0, 99, 132, 0.2)', 'rgba(0, 162, 235, 0.2)', 'rgba(0, 206, 86, 0.2)', 'rgba(0, 192, 192, 0.2)', 'rgba(0, 102, 255, 0.2)', 'rgba(0, 159, 64, 0.2)', ], borderColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)', 'rgba(0, 99, 132, 0.2)', 'rgba(0, 162, 235, 0.2)', 'rgba(0, 206, 86, 0.2)', 'rgba(0, 192, 192, 0.2)', 'rgba(0, 102, 255, 0.2)', 'rgba(0, 159, 64, 0.2)', ], borderWidth: 1, }, ], } const options = { plugins: { legend: { position: 'top', }, }, scales: { x: { grid: { display: false, }, }, y: { beginAtZero: true, grid: { display: true, }, }, }, } useEffect(() => { console.log('🚀 ~ useEffect ~ selectedPlan:', selectedPlan) /* 초기화 작업 */ setChartData([]) setObjectDetail({}) setModuleInfoList([]) setPcsInfoList([]) setHatsudenryouAll([]) setHatsudenryouAllSnow([]) setHatsudenryouPeakcutAll([]) setHatsudenryouPeakcutAllSnow([]) if (objectNo) { fetchObjectDetail(objectNo) fetchSimulatorNotice() setPwrGnrSimType('D') setPwrRecoil({ ...pwrRecoil, type: 'D' }) } }, [objectNo, pid, selectedPlan]) // 물건 상세 정보 조회 const [objectDetail, setObjectDetail] = useState({}) // 모듈배치정보 조회 const [moduleInfoList, setModuleInfoList] = useState([]) // 파워컨디셔너 조회 const [pcsInfoList, setPcsInfoList] = useState([]) // 타입별 list 조회 const [hatsudenryouAll, setHatsudenryouAll] = useState([]) const [hatsudenryouAllSnow, setHatsudenryouAllSnow] = useState([]) const [hatsudenryouPeakcutAll, setHatsudenryouPeakcutAll] = useState([]) const [hatsudenryouPeakcutAllSnow, setHatsudenryouPeakcutAllSnow] = useState([]) const fetchObjectDetail = async (objectNo) => { const apiUrl = `/api/pwrGnrSimulation/calculations?objectNo=${objectNo}&planNo=${pid}` const resultData = await get({ url: apiUrl }) if (resultData) { setObjectDetail(resultData) if (resultData.hatsudenryouAll) { setHatsudenryouAll(resultData.hatsudenryouAll) } if (resultData.hatsudenryouAllSnow) { setHatsudenryouAllSnow(resultData.hatsudenryouAllSnow) } if (resultData.hatsudenryouPeakcutAll) { setHatsudenryouPeakcutAll(resultData.hatsudenryouPeakcutAll) } if (resultData.hatsudenryouPeakcutAllSnow) { setHatsudenryouPeakcutAllSnow(resultData.hatsudenryouPeakcutAllSnow) setChartData(resultData.hatsudenryouPeakcutAllSnow) } if (resultData.pcsList) { setPcsInfoList(resultData.pcsList) } if (resultData.roofModuleList) { setModuleInfoList(resultData.roofModuleList) } } } // 시뮬레이션 안내사항 조회 const [content, setContent] = useState('') const fetchSimulatorNotice = async () => { get({ url: '/api/pwrGnrSimulation/guideInfo' }).then((res) => { if (res.data) { setContent(res.data.replaceAll('\n', '
')) } else { setContent(getMessage('common.message.no.data')) } }) } // 차트 데이터 변경 시, list type 셋팅 const [pwrGnrSimType, setPwrGnrSimType] = useState('D') const [pwrRecoil, setPwrRecoil] = useRecoilState(pwrGnrSimTypeState) const handleChartChangeData = (type) => { setPwrRecoil({ ...pwrRecoil, type: type }) switch (type) { case 'A': setChartData(hatsudenryouAll) break case 'B': setChartData(hatsudenryouAllSnow) break case 'C': setChartData(hatsudenryouPeakcutAll) break case 'D': setChartData(hatsudenryouPeakcutAllSnow) break } } return (
{/* 물건번호 */}
{getMessage('simulator.title.sub1')}
{objectDetail.objectNo} {`${objectDetail.planNo ? `(Plan No: ${objectDetail.planNo})` : ''}`}
{/* 작성일 */}
{getMessage('simulator.title.sub2')}
{objectDetail.drawingEstimateCreateDate ? `${dayjs(objectDetail.drawingEstimateCreateDate).format('YYYY.MM.DD')}` : ''}
{/* 시스템용량 */}
{getMessage('simulator.title.sub3')}
{objectDetail.capacity ? `${convertNumberToPriceDecimal(objectDetail.capacity)} kW` : ''}
{/* 연간예측발전량 */}
{getMessage('simulator.title.sub4')}
{chartData[chartData.length - 1]}
{/* 도도부현 */}
{getMessage('simulator.title.sub5')}
{objectDetail.prefName}
{/* 일사량 관측지점 */}
{getMessage('simulator.title.sub6')}
{objectDetail.areaName}
{/* 적설조건 */}
{getMessage('simulator.title.sub7')}
{objectDetail.snowfall} cm
{/* 풍속조건 */}
{getMessage('simulator.title.sub8')}
{objectDetail.standardWindSpeedId}
{/* chart */}

{getMessage('simulator.table.sub9')}

{/* 예측발전량 */}
{chartData.length > 0 ? ( {chartData.map((data) => ( ))} ) : ( )}
1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 {getMessage('simulator.table.sub6')}
{data}
{getMessage('common.message.no.data')}
{moduleInfoList.length > 0 ? ( moduleInfoList.map((moduleInfo) => { return ( <> {/* 지붕면 */} {/* 경사각 */} {/* 방위각(도) */} {/* 태양전지모듈 */} {/* 매수 */} ) }) ) : ( )}
{getMessage('simulator.table.sub1')} {getMessage('simulator.table.sub2')} {getMessage('simulator.table.sub3')} {getMessage('simulator.table.sub4')} {getMessage('simulator.table.sub5')}
{moduleInfo.roofSurface}{convertNumberToPriceDecimal(moduleInfo.slopeAngle)}{moduleInfo.classType == 0 ? "寸":"º"}{convertNumberToPriceDecimal(moduleInfo.azimuth)}
{moduleInfo.itemNo}
{convertNumberToPriceDecimal(moduleInfo.amount)}
{getMessage('common.message.no.data')}
{moduleInfoList.length > 0 && (
{getMessage('simulator.table.sub6')}
{moduleInfoList.reduce((acc, moduleInfo) => convertNumberToPriceDecimal(Number(acc) + Number(moduleInfo.amount)), 0)}
)}
{pcsInfoList.length > 0 ? ( pcsInfoList.map((pcsInfo) => { return ( <> {/* 파워컨디셔너 */} {/* 대 */} ) }) ) : ( )}
{getMessage('simulator.table.sub7')} {getMessage('simulator.table.sub8')}
{pcsInfo.itemNo}
{convertNumberToPriceDecimal(pcsInfo.amount)}
{getMessage('common.message.no.data')}
{getMessage('simulator.notice.sub1')}
{getMessage('simulator.notice.sub2')}
{/* 시뮬레이션 안내사항 */}
) }