300 lines
12 KiB
TypeScript
300 lines
12 KiB
TypeScript
'use client'
|
|
import { CHART_FORM, type ChartConfig, MainChart, UiModal } from "@common/business_components";
|
|
import { SelectBox } from '@common/business_components/ui';
|
|
import { Button, Input, Label } from '@common/components';
|
|
import React, { useEffect, useState } from 'react';
|
|
import moment from "moment";
|
|
|
|
import type { TRdiiAnls } from './aplcnYms';
|
|
import * as fn from './aplcnYms';
|
|
import { useRdiiChartModalStore } from '../chartModalStore'; // 모달 상태 관리 스토어
|
|
|
|
type ModalOpenProp = {
|
|
pplMngNo: string, // 관로관리번호
|
|
}
|
|
// 차트
|
|
type lineBarChartData = {
|
|
label : string;
|
|
lineVal0 : number;
|
|
barVal0 : number;
|
|
}
|
|
|
|
|
|
const RdiiChart = ({ pplMngNo }: ModalOpenProp) => {
|
|
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useRdiiChartModalStore(); // 모달 상태 관리 스토어
|
|
const [popupOpen, setPopupOpen] = React.useState(false); // 조회조건팝업
|
|
const buttonRef = React.useRef<HTMLButtonElement>(null); // 버튼 참조
|
|
const [popupPosition, setPopupPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 }); // 팝업 위치
|
|
const [aplcnYm, setAplcnYm] = useState("");
|
|
const [rdiiAnlss, setRdiiAnlss] = useState<TRdiiAnls[]>([]);
|
|
const [rdiiAnlsInfos, setRdiiAnlsInfos] = useState<{ text: string; val: number; hidden?: boolean }[]>([{ val: 0, text: '선택' }]); // 강우유입수분석정보 options
|
|
const [rdiiAnls, setRdiiAnls] = useState<TRdiiAnls | null>(null); // 강우유입수분석정보
|
|
const [rainInfwtAnlsSn, setRainInfwtAnlsSn] = useState<number>(0); // 강우유입수분석 정보 선택시 사용
|
|
const [chartData, setChartData] = useState<lineBarChartData[]>([]);
|
|
const [rdiiQty, setRdiiQty] = useState<string>("0"); // 강우유입수량
|
|
const [rainTotal, setRainTotal] = useState<string>("0"); // 적용강우량
|
|
const [totalVolume, setTotalVolume] = useState<string>("0"); // 총체적 m³/mm
|
|
const aplcnYms = fn.useAplcnYms('rdiiAnlsRslt'); // 상수사용월 데이터 가져오기
|
|
pplMngNo = "L"+pplMngNo; // "L13101003";
|
|
|
|
const openPopup = () => {
|
|
if (buttonRef.current) {
|
|
const rect = buttonRef.current.getBoundingClientRect(); // 버튼 위치 계산
|
|
setPopupPosition({
|
|
top: rect.bottom + window.scrollY, // 버튼 아래쪽
|
|
left: rect.left + window.scrollX, // 버튼 왼쪽
|
|
});
|
|
}
|
|
setPopupOpen(true); // 팝업 열기
|
|
};
|
|
|
|
const chartForm = CHART_FORM.LINEBAR2;
|
|
const chartConfig = {
|
|
barVal0: {
|
|
label: '강수량',
|
|
color: "#33AAFF",
|
|
},
|
|
lineVal0: {
|
|
label: 'RDII',
|
|
color: "#FF0000",
|
|
},
|
|
} as ChartConfig;
|
|
|
|
useEffect(() => {
|
|
if (isModalOpen === false) {
|
|
setPopupOpen(true); // 모달이 닫힐 때 팝업은
|
|
setAplcnYm(""); // 상수사용월 초기화
|
|
setRdiiAnlss([]); // 강우유입수분석 초기화
|
|
setRdiiAnlsInfos([{ val: 0, text: '선택' }]); // 강우유입수분석정보 초기화
|
|
setRdiiAnls(null); // 강우유입수분석정보 초기화
|
|
setRainInfwtAnlsSn(0); // 강우유입수분석 일련번호 초기화
|
|
setChartData([]); // 차트 데이터 초기화
|
|
setRdiiQty("0"); // 강우유입수량 초기화
|
|
setRainTotal("0"); // 적용강우량 초기화
|
|
setTotalVolume("0"); // 총체적 m³/mm 초기화
|
|
}
|
|
}, [isModalOpen]);
|
|
|
|
// 상수사용월 변경시 분석 정보 리스트 가져오기
|
|
useEffect(() => {
|
|
// aplcnYm이 비어있거나 "0"이면 API 호출하지 않음
|
|
if (!aplcnYm || aplcnYm === "0" || aplcnYm === "") {
|
|
setRainInfwtAnlsSn(0); // 초기화
|
|
setRdiiAnlsInfos([]);
|
|
return;
|
|
}
|
|
fn.selectRdiiAnls(aplcnYm)
|
|
.then((data) => {
|
|
setRdiiAnlss(data ?? []); // 선택한 월의 분석성공한 RDII분석데이터[]
|
|
setRdiiAnlsInfos(fn.getOptionsRdiiAnlsInfo(data));
|
|
setRdiiAnls(null); // 오수전환율 이후 초기화
|
|
setRainInfwtAnlsSn(0); // 초기화
|
|
})
|
|
.catch((error) => {
|
|
console.error("selectrdiiAnls 에러:", error);
|
|
setRdiiAnlss([]);
|
|
setRdiiAnlsInfos([]);
|
|
});
|
|
}, [aplcnYm]);
|
|
|
|
// 값 표시
|
|
useEffect(() => {
|
|
// 선택된 강우유입수분석 정보에 대한 처리 로직
|
|
if (rainInfwtAnlsSn === 0) return;
|
|
const selectedAnls = rdiiAnlss.find(anls => anls.rainInfwtAnlsSn === rainInfwtAnlsSn);
|
|
if (selectedAnls) {
|
|
setRdiiAnls(selectedAnls);
|
|
}
|
|
}, [rainInfwtAnlsSn, rdiiAnlss]);
|
|
|
|
const closePopup = () => { // 팝업 닫기
|
|
setPopupOpen(false);
|
|
}
|
|
const rdiiRsltChart = () => { // 그래프 & 팝업 닫기
|
|
fetchFilteredData();
|
|
fn.selectPplRdiiQty(rainInfwtAnlsSn, pplMngNo).then((data) => {// 강우유입수량 조회
|
|
setRdiiQty(Math.round(data.rdiih*24).toLocaleString('ko-KR')); // cmd: m³/d 단위로 변환
|
|
if (data.raintotal && data.rainTotal !== 0) {
|
|
setRainTotal(data.raintotal.toLocaleString('ko-KR')); // 총강우량mm
|
|
setTotalVolume(Math.round(data.rdiih * data.sustaintime / data.raintotal).toLocaleString('ko-KR')); // 총체적 m³/mm
|
|
}
|
|
});
|
|
setPopupOpen(false);
|
|
};
|
|
|
|
const fetchFilteredData: () => Promise<void> = async () => {
|
|
const rsltData = await fn.selectRdiiAnlsRslt(rainInfwtAnlsSn, pplMngNo);
|
|
const rsltDataformatted = fn.getChartDataRdiiAnlsRslt(rsltData ?? []); // format 변경
|
|
const rainData = await fn.selectRainData(rainInfwtAnlsSn);
|
|
const rainDataformatted = fn.getChartDataRainData(rainData ?? []); // format 변경
|
|
const rainMap = new Map(rainDataformatted.map(item => [item.label, item.barVal0]));
|
|
|
|
rsltDataformatted.forEach(item => {
|
|
const matchedVal = rainMap.get(item.label);
|
|
if (matchedVal !== undefined) {
|
|
item.barVal0 = matchedVal;
|
|
}
|
|
});
|
|
setChartData(rsltDataformatted); // 차트 데이터 설정
|
|
}
|
|
const renderBody = () => (
|
|
<>
|
|
<div className="text-black text-3xl font-bold mb-5">RDII분석결과</div>
|
|
|
|
<div className='grid grid-cols-[1fr_3fr] gap-4'>
|
|
<div className="grid grid-rows-4 gap-4 mb-4">
|
|
<Button className="bg-white text-white w-[130px] font-bold px-4 mt-2 py-2" onClick={openPopup}>
|
|
분석 입력현황 조회
|
|
</Button>
|
|
{/* 상수사용량 적용연월 */}
|
|
<div className="bg-white px-4 py-2 ">
|
|
<span className="text-2xl text-red-600 font-bold">● 상수사용량 적용연월</span>
|
|
<div className="flex items-center mt-2">
|
|
<span className="ml-5 text-black text-xl font-bold">
|
|
{(aplcnYm)? moment(aplcnYm, "YYYYMM").format("YYYY-MM"):""}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 강우유입수량 분석결과 */}
|
|
<div className="bg-white px-4 py-2 ">
|
|
<span className="text-2xl text-red-600 font-bold">● 강우유입수량 분석결과</span>
|
|
<div className="flex items-center mt-2">
|
|
<span className="w-[95px] inline-block text-right text-black text-xl">평균RDII : </span>
|
|
<span className="w-[45px] inline-block text-right text-black text-xl font-bold"> {rdiiQty}</span>
|
|
<span className="ml-2 text-black"> m³/d</span>
|
|
</div>
|
|
<div className="flex items-center mt-2">
|
|
<span className="w-[95px] inline-block text-right text-black text-xl">적용강우량 : </span>
|
|
<span className="w-[45px] inline-block text-right text-black text-xl font-bold"> {rainTotal}</span>
|
|
<span className="ml-2 text-black"> mm</span>
|
|
</div>
|
|
<div className="flex items-center mt-2">
|
|
<span className="w-[95px] inline-block text-right text-black text-xl">강우량대비RDII : </span>
|
|
<span className="w-[45px] inline-block text-right text-black text-xl font-bold"> {totalVolume}</span>
|
|
<span className="ml-2 text-black"> m³/mm</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/* 차트 */}
|
|
<div className="h-[90%] bg-white text-2xl">
|
|
<MainChart chartConfig={chartConfig} chartForm={chartForm} chartData={chartData} chartTitle={'RDII 그래프'}
|
|
yFieldText2="강수량(mm)" yFieldText="유량(m³/h)" />
|
|
</div>
|
|
</div>
|
|
{popupOpen && (
|
|
<div
|
|
className="absolute bg-gray-100 border border-gray-300 w-[440px] shadow-lg p-6 rounded text-2xl"
|
|
style={{
|
|
top: popupPosition.top,
|
|
left: popupPosition.left,
|
|
zIndex: 1000,
|
|
}}
|
|
>
|
|
<div className="font-bold mb-6 text-3xl">강우유입수분석 입력현황</div>
|
|
<div className='flex flex-col'>
|
|
<div className='flex items-center justify-between'>
|
|
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">상수사용월:</Label>
|
|
<SelectBox
|
|
className="w-[220px] mr-8 z-[51] mb-2"
|
|
selectClass="rounded-lg bg-white"
|
|
label=''
|
|
selectArray={aplcnYms}
|
|
value={aplcnYm}
|
|
onSelectValue={(val) => {
|
|
setAplcnYm(String(val));
|
|
}}
|
|
/>
|
|
</div>
|
|
<div className='flex items-center justify-between'>
|
|
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">분석정보:</Label>
|
|
<SelectBox
|
|
className="w-[220px] mr-8 z-[51] mb-2"
|
|
selectClass="rounded-lg bg-white"
|
|
label=''
|
|
selectArray={rdiiAnlsInfos}
|
|
value={rainInfwtAnlsSn}
|
|
onSelectValue={(val) => {
|
|
setRainInfwtAnlsSn(Number(val));
|
|
}}
|
|
/>
|
|
</div>
|
|
<div className='flex items-center justify-between'>
|
|
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">오수전환율:</Label>
|
|
<Input
|
|
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
|
placeholder=""
|
|
value={rdiiAnls?.drtwSwtcRt ?? ""}
|
|
readOnly={true}
|
|
/>
|
|
</div>
|
|
<div className='flex items-center justify-between'>
|
|
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">수용가-맨홀 매칭:</Label>
|
|
<Input
|
|
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
|
placeholder=""
|
|
value={rdiiAnls?.atflMpngNm ?? ""}
|
|
readOnly={true}
|
|
/>
|
|
</div>
|
|
<div className='flex items-center justify-between'>
|
|
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">관망도 파일명:</Label>
|
|
<Input
|
|
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
|
placeholder=""
|
|
value={rdiiAnls?.atflInpNm ?? ""}
|
|
readOnly={true}
|
|
/>
|
|
</div>
|
|
<div className='flex items-center justify-between'>
|
|
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">강우 파일명:</Label>
|
|
<Input
|
|
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
|
placeholder=""
|
|
value={rdiiAnls?.atflRainNm ?? ""}
|
|
readOnly={true}
|
|
/>
|
|
</div>
|
|
<div className='flex items-center justify-between'>
|
|
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">RTK계수 출처:</Label>
|
|
<Input
|
|
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
|
placeholder=""
|
|
value={rdiiAnls?.srcNm ?? ""}
|
|
readOnly={true}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex justify-end mt-4 space-x-2">
|
|
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={closePopup}>
|
|
닫기
|
|
</button>
|
|
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={rdiiRsltChart}>
|
|
선택조건 적용
|
|
</button>
|
|
</div>
|
|
</div>)}
|
|
{/* </Modal > */}
|
|
</>
|
|
)
|
|
|
|
return (
|
|
<UiModal
|
|
open={isModalOpen}
|
|
onOpenChange={setIsModalOpen}
|
|
headerTitle=""
|
|
bodyClass={`
|
|
min-h-[50vh]
|
|
w-[55vw]
|
|
max-w-none
|
|
max-h-none
|
|
overflow-visible
|
|
z-[50]
|
|
`}
|
|
body={renderBody()}
|
|
noFooterYn = 'Y'
|
|
/>
|
|
)
|
|
}
|
|
|
|
export default React.memo(RdiiChart); |