366 lines
13 KiB
JavaScript

'use client'
import 'chart.js/auto'
import { Bar } from 'react-chartjs-2'
import dayjs from 'dayjs'
import { useEffect, useState, useRef } from 'react'
import { useRecoilValue } from 'recoil'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage'
import { usePlan } from '@/hooks/usePlan'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { convertNumberToPriceDecimal } from '@/util/common-utils'
export default function Simulator() {
const { plans } = usePlan()
const plan = plans.find((plan) => plan.isCurrent === true)
const chartRef = useRef(null)
// recoil 물건번호
const objectRecoil = useRecoilValue(floorPlanObjectState)
const [objectNo, setObjectNo] = useState('')
useEffect(() => {
setObjectNo(objectRecoil.floorPlanObjectNo)
}, [objectRecoil])
// 캔버스 메뉴 넘버 셋팅
const { setMenuNumber } = useCanvasMenu()
useEffect(() => {
setMenuNumber(6)
}, [])
const { get } = useAxios()
const { getMessage } = useMessage()
// 차트 관련
const [chartData, setChartData] = useState([])
const data = {
labels: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
datasets: [
{
label: 'kWh',
data: chartData.slice(0, 12),
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(() => {
if (objectNo) {
fetchObjectDetail(objectNo)
}
fetchSimulatorNotice()
}, [objectNo, plan])
// 물건 상세 정보 조회
const [objectDetail, setObjectDetail] = useState({})
// 모듈배치정보 조회
const [moduleInfoList, setModuleInfoList] = useState([])
// 파워컨디셔너 조회
const [pcsInfoList, setPcsInfoList] = useState([])
const fetchObjectDetail = async (objectNo) => {
const apiUrl = `/api/pwrGnrSimulation/calculations?objectNo=${objectNo}&planNo=${plan?.id}`
const resultData = await get({ url: apiUrl })
if (resultData) {
setObjectDetail(resultData)
if (resultData.frcPwrGnrList) {
setChartData(resultData.frcPwrGnrList)
}
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', '<br/>'))
} else {
setContent(getMessage('common.message.no.data'))
}
})
}
return (
<div className="sub-content estimate">
<div className="sub-content-inner">
<div className="sub-content-box">
<div className="sub-table-box">
<div className="estimate-list-wrap">
{/* 물건번호 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub1')}</div>
<div className="estimate-name">
{objectDetail.objectNo} (Plan No: {objectDetail.planNo})
</div>
</div>
{/* 작성일 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub2')}</div>
<div className="estimate-name">{`${dayjs(objectDetail.drawingEstimateCreateDate).format('YYYY.MM.DD')}`}</div>
</div>
{/* 시스템용량 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub3')}</div>
<div className="estimate-name">{convertNumberToPriceDecimal(objectDetail.capacity)}kW</div>
</div>
{/* 연간예측발전량 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub4')}</div>
<div className="estimate-name">{convertNumberToPriceDecimal(objectDetail.anlFrcsGnrt)}</div>
</div>
</div>
<div className="estimate-list-wrap">
{/* 도도부현 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub5')}</div>
<div className="estimate-name">{objectDetail.prefName}</div>
</div>
{/* 일사량 관측지점 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub6')}</div>
<div className="estimate-name">{objectDetail.areaName}</div>
</div>
{/* 적설조건 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub7')}</div>
<div className="estimate-name">{objectDetail.snowfall}</div>
</div>
{/* 풍속조건 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub8')}</div>
<div className="estimate-name">{objectDetail.standardWindSpeedId}</div>
</div>
</div>
</div>
</div>
<div className="sub-content-box">
<div className="chart-wrap">
<div className="chart-inner">
<div className="sub-table-box">
<div className="chart-box">
<Bar ref={chartRef} data={data} options={options} />
</div>
<div className="table-box-title-wrap">
<div className="title-wrap">
<h3>{getMessage('simulator.table.sub9')} </h3>
</div>
</div>
{/* 예측발전량 */}
<div className="chart-month-table">
<table>
<thead>
<tr>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
<th>6</th>
<th>7</th>
<th>8</th>
<th>9</th>
<th>10</th>
<th>11</th>
<th>12</th>
<th>{getMessage('simulator.table.sub6')}</th>
</tr>
</thead>
<tbody>
{chartData.length > 0 ? (
<tr>
{chartData.map((data) => (
<td key={data}>{convertNumberToPriceDecimal(data)}</td>
))}
</tr>
) : (
<tr>
<td colSpan={13}>{getMessage('common.message.no.data')}</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
</div>
<div className="chart-table-wrap">
<div className="sub-table-box">
<div className="module-table ">
<table className="small">
<thead>
<tr>
<th>{getMessage('simulator.table.sub1')}</th>
<th>{getMessage('simulator.table.sub2')}</th>
<th>{getMessage('simulator.table.sub3')}</th>
<th>{getMessage('simulator.table.sub4')}</th>
<th>{getMessage('simulator.table.sub5')}</th>
</tr>
</thead>
<tbody>
{moduleInfoList.length > 0 ? (
moduleInfoList.map((moduleInfo) => {
return (
<>
<tr key={moduleInfo.itemId}>
{/* 지붕면 */}
<td>{moduleInfo.roofSurface}</td>
{/* 경사각 */}
<td>{convertNumberToPriceDecimal(moduleInfo.slope)}</td>
{/* 방위각(도) */}
<td>{convertNumberToPriceDecimal(moduleInfo.angle)}</td>
{/* 태양전지모듈 */}
<td>
<div className="overflow-lab">{moduleInfo.itemNo}</div>
</td>
{/* 매수 */}
<td>{moduleInfo.amount}</td>
</tr>
</>
)
})
) : (
<tr>
<td colSpan={5}>{getMessage('common.message.no.data')}</td>
</tr>
)}
</tbody>
</table>
{moduleInfoList.length > 0 && (
<div className="module-total">
<div className="total-title">{getMessage('simulator.table.sub6')}</div>
<div className="total-num">
{moduleInfoList.reduce((acc, moduleInfo) => convertNumberToPriceDecimal(Number(acc) + Number(moduleInfo.amount)), 0)}
</div>
</div>
)}
</div>
</div>
<div className="sub-table-box">
<div className="module-table ">
<table className="big">
<thead>
<tr>
<th>{getMessage('simulator.table.sub7')}</th>
<th>{getMessage('simulator.table.sub8')}</th>
</tr>
</thead>
<tbody>
{pcsInfoList.length > 0 ? (
pcsInfoList.map((pcsInfo) => {
return (
<>
<tr key={pcsInfo.itemId}>
{/* 파워컨디셔너 */}
<td className="al-l">
<div className="overflow-lab">{pcsInfo.itemNo}</div>
</td>
{/* 대 */}
<td>{pcsInfo.amount}</td>
</tr>
</>
)
})
) : (
<tr>
<td colSpan={2}>{getMessage('common.message.no.data')}</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div className="sub-content-box">
<div className="sub-table-box">
<div className="simulation-guide-wrap">
<div className="simulation-tit-wrap">
<span>
{getMessage('simulator.notice.sub1')}
<br />
{getMessage('simulator.notice.sub2')}
</span>
</div>
{/* 시뮬레이션 안내사항 */}
<div
className="simulation-guide-box"
dangerouslySetInnerHTML={{
__html: content,
}}
></div>
</div>
</div>
</div>
</div>
</div>
)
}