diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/chart/infilChart.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/chart/infilChart.tsx index 4086f1966..d9ccccf0e 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/chart/infilChart.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/chart/infilChart.tsx @@ -68,7 +68,7 @@ const InfilChart = ({ pplMngNo = '' }: ModalOpenProp) => { useEffect(() => { if (!isModalOpen) { - resetState(); + resetState(); // 모달이 닫힐 때 리셋 } }, [isModalOpen]); @@ -164,6 +164,7 @@ const InfilChart = ({ pplMngNo = '' }: ModalOpenProp) => { const handleReset = () => { resetState(); } + const renderBody = () => (
diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx index 39617eb21..12289254c 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx @@ -1,282 +1,318 @@ 'use client' -import { CHART_FORM, type ChartConfig, MainChart, UiModal } from "@common/business_components"; + +import React, { useEffect, useMemo, useState } from 'react'; +import moment from 'moment'; + +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'; // 모달 상태 관리 스토어 +import { useRdiiChartModalStore } from '../chartModalStore'; type ModalOpenProp = { - pplMngNo: string, // 관로관리번호 -} -// 차트 -type lineBarChartData = { - label : string; - lineVal0 : number; - barVal0 : number; -} + 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(null); // 버튼 참조 - const [popupPosition, setPopupPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 }); // 팝업 위치 - const [aplcnYm, setAplcnYm] = useState(""); +const INITIAL_ANALYSIS_OPTIONS = [{ val: 0, text: '선택' }]; + +const RdiiChart = ({ pplMngNo = '' }: ModalOpenProp) => { + const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useRdiiChartModalStore(); + + const [aplcnYm, setAplcnYm] = useState(''); const [rdiiAnlss, setRdiiAnlss] = useState([]); - const [rdiiAnlsInfos, setRdiiAnlsInfos] = useState<{ text: string; val: number; hidden?: boolean }[]>([{ val: 0, text: '선택' }]); // 강우유입수분석정보 options + const [rdiiAnlsInfos, setRdiiAnlsInfos] = useState<{ text: string; val: number; hidden?: boolean }[]>( + INITIAL_ANALYSIS_OPTIONS, + ); const [rdiiAnls, setRdiiAnls] = useState(null); // 강우유입수분석정보 - const [rainInfwtAnlsSn, setRainInfwtAnlsSn] = useState(0); // 강우유입수분석 정보 선택시 사용 - const [chartData, setChartData] = useState([]); - const [rdiiQty, setRdiiQty] = useState("0"); // 강우유입수량 - const [rainTotal, setRainTotal] = useState("0"); // 적용강우량 - const [totalVolume, setTotalVolume] = useState("0"); // 총체적 m³/mm + const [rainInfwtAnlsSn, setRainInfwtAnlsSn] = useState(0);// 강우유입수분석 정보 선택시 사용 + const [chartData, setChartData] = useState([]); + const [rdiiQty, setRdiiQty] = useState('0'); // 강우유입수량 + const [rainTotal, setRainTotal] = useState('0'); // 적용강우량 + const [totalVolume, setTotalVolume] = useState('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 normalizedPplMngNo = pplMngNo ? `L${pplMngNo}` : ''; const chartForm = CHART_FORM.LINEBAR2; const chartConfig = { - barVal0: { + barVal0: { label: '강수량', - color: "#33AAFF", + color: '#33AAFF', }, lineVal0: { label: 'RDII', - color: "#FF0000", + color: '#FF0000', }, } as ChartConfig; + const hasChartData = useMemo(() => chartData.length > 0, [chartData]); + + const resetState = () => { + setAplcnYm(''); // 상수사용월 초기화 + setRdiiAnlss([]); // 강우유입수분석 초기화 + setRdiiAnlsInfos(INITIAL_ANALYSIS_OPTIONS); // 강우유입수분석정보 초기화 + setRdiiAnls(null); // 강우유입수분석정보 초기화 + setRainInfwtAnlsSn(0); // 강우유입수분석 일련번호 초기화 + setChartData([]); + setRdiiQty('0'); // 강우유입수량 초기화 + setRainTotal('0');// 적용강우량 초기화 + setTotalVolume('0');// 총체적 m³/mm 초기화 + }; + 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 초기화 + if (!isModalOpen) { + resetState(); } }, [isModalOpen]); - // 상수사용월 변경시 분석 정보 리스트 가져오기 - useEffect(() => { - // aplcnYm이 비어있거나 "0"이면 API 호출하지 않음 - if (!aplcnYm || aplcnYm === "0" || aplcnYm === "") { - setRainInfwtAnlsSn(0); // 초기화 - setRdiiAnlsInfos([]); + const handleAplcnYmChange = async (val: string | number) => { + const selectedValue = String(val); + + setAplcnYm(selectedValue); + setRdiiAnlss([]); + setRdiiAnls(null); + setRainInfwtAnlsSn(0); + setChartData([]); + setRdiiQty('0'); + setRainTotal('0'); + setTotalVolume('0'); + + if (!selectedValue || selectedValue === '0') { + setRdiiAnlsInfos(INITIAL_ANALYSIS_OPTIONS); 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); + try { + const data = await fn.selectRdiiAnls(selectedValue); // 상수사용월 변경시 분석 정보 리스트 가져오기 + const list = data ?? []; + setRdiiAnlss(list); + setRdiiAnlsInfos(fn.getOptionsRdiiAnlsInfo(list)); + } catch (error) { + console.error('selectRdiiAnls 에러:', error); + setRdiiAnlss([]); + setRdiiAnlsInfos(INITIAL_ANALYSIS_OPTIONS); } - }, [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 = 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])); + const handleRdiiAnlsSnChange = (val: string | number) => { + const selectedValue = Number(val); + + setRainInfwtAnlsSn(selectedValue); + setChartData([]); + setRdiiQty('0'); + setRainTotal('0'); + setTotalVolume('0'); + + if (selectedValue === 0) { + setRdiiAnls(null); + return; + } + + const selectedAnls = rdiiAnlss.find((anls) => anls.rainInfwtAnlsSn === selectedValue) ?? null; + setRdiiAnls(selectedAnls); + }; + + const fetchFilteredData = async () => { + if (!rainInfwtAnlsSn || !normalizedPplMngNo) { + setChartData([]); + setRdiiQty('0'); + setRainTotal('0'); + setTotalVolume('0'); + return; + } + + try { + const [rsltData, rainData, qtyData] = await Promise.all([ + fn.selectRdiiAnlsRslt(rainInfwtAnlsSn, normalizedPplMngNo), + fn.selectRainData(rainInfwtAnlsSn), + fn.selectPplRdiiQty(rainInfwtAnlsSn, normalizedPplMngNo), + ]); + + const rsltDataFormatted = fn.getChartDataRdiiAnlsRslt(rsltData ?? []); + const rainDataFormatted = fn.getChartDataRainData(rainData ?? []); + 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 avgRdii = Number(qtyData?.rdiih ?? 0); + const appliedRainfall = Number(qtyData?.raintotal ?? 0); + const rdiiPerRainfall = + qtyData?.raintotal && qtyData?.raintotal !== 0 + ? Math.round(avgRdii * Number(qtyData?.sustaintime ?? 0) / qtyData.raintotal) + : 0; + + setRdiiQty(Math.round(avgRdii * 24).toLocaleString('ko-KR')); + setRainTotal(appliedRainfall.toLocaleString('ko-KR')); + setTotalVolume(rdiiPerRainfall.toLocaleString('ko-KR')); + } catch (error) { + console.error('rdiiRsltChart 에러:', error); + setChartData([]); + setRdiiQty('0'); + setRainTotal('0'); + setTotalVolume('0'); + } + }; + + const renderInfoInput = (label: string, value?: string | number | null) => ( +
+ + +
+ ); - rsltDataformatted.forEach(item => { - const matchedVal = rainMap.get(item.label); - if (matchedVal !== undefined) { - item.barVal0 = matchedVal; - } - }); - setChartData(rsltDataformatted); // 차트 데이터 설정 - } const renderBody = () => ( - <> -
RDII분석결과
- -
-
- - {/* 상수사용량 적용연월 */} -
- ● 상수사용량 적용연월 -
- - {(aplcnYm)? moment(aplcnYm, "YYYYMM").format("YYYY-MM"):""} - -
-
- - {/* 강우유입수량 분석결과 */} -
- ● 강우유입수량 분석결과 -
- 평균RDII : - {rdiiQty} - m³/d -
-
- 적용강우량 : - {rainTotal} - mm -
-
- 강우량대비RDII : - {totalVolume} - m³/mm -
-
-
- {/* 차트 */} -
- -
+
+
+
- {popupOpen && ( -
-
강우유입수분석 입력현황
-
-
- - { - setAplcnYm(String(val)); - }} - /> -
-
- - { - setRainInfwtAnlsSn(Number(val)); - }} - /> -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - + +
+
+

+ 강우유입수분석 선택 조건 +

+ +
+
+
+ + +
+ +
+ + +
+ + {renderInfoInput('오수전환율:', rdiiAnls?.drtwSwtcRt ?? '')} + {renderInfoInput('수용가-맨홀 매칭:', rdiiAnls?.atflMpngNm ?? '')} + {renderInfoInput('관망도 파일명:', rdiiAnls?.atflInpNm ?? '')} + {renderInfoInput('강우 파일명:', rdiiAnls?.atflRainNm ?? '')} + {renderInfoInput('RTK계수 출처:', rdiiAnls?.srcNm ?? '')}
-
- - + +
+ +    +
-
)} - {/* */} - - ) +
+ +
+

+ 강우유입수분석 결과 +

+ +
+
+
+ 상수사용량 적용연월 +
+
+ {aplcnYm ? moment(aplcnYm, 'YYYYMM').format('YYYY-MM') : '-'} +
+
+ +
+
+ 강우유입수량 분석결과 +
+
+
+ 평균RDII +
+ {rdiiQty} + m³/d +
+
+
+ 적용강우량 +
+ {rainTotal} + mm +
+
+
+ 강우량대비 RDII +
+ {totalVolume} + m³/mm +
+
+
+
+
+ +
+ {hasChartData ? ( + + ) : ( +
+ 데이터가 없습니다. +
+ )} +
+
+
+
+ ); return ( { onOpenChange={setIsModalOpen} headerTitle="" bodyClass={` - min-h-[50vh] - w-[55vw] - max-w-none - max-h-none - overflow-visible - z-[50] - `} + w-[78vw] + max-w-none + min-h-[74vh] + max-h-none + overflow-visible + z-[50] + `} body={renderBody()} - noFooterYn = 'Y' + noFooterYn="Y" /> - ) -} + ); +}; -export default React.memo(RdiiChart); \ No newline at end of file +export default React.memo(RdiiChart);