Files
frontend/apps/sn/app/(map-layout)/map/components/popupComponent/chart/infilChart.tsx
T

287 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 { TInftwtAnls, TOilqData } from './aplcnYms';
import * as fn from './aplcnYms';
import { useInfilChartModalStore } from '../chartModalStore'; // 모달 상태 관리 스토어
type ModalOpenProp = {
pplMngNo?: string, // 관로관리번호
}
type DataType = { label: string; val: number };
const InfilChart = ({ pplMngNo }: ModalOpenProp) => {
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useInfilChartModalStore(); // 모달 상태 관리 스토어
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 [selectedAplcnYm, setSelectedAplcnYm] = useState("");
const [inftwtAnlss, setInftwtAnlss] = useState<TInftwtAnls[]>([]);
const [inftwtAnlsInfos, setInftwtAnlsInfos] = useState<any[]>([{ val: 0, text: '선택' }]); // 침입수분석정보 options
const [inftwtAnls, setInftwtAnls] = useState<TInftwtAnls | null>(null); // 침입수분석정보
const [selectedInftwtAnls, setSelectedInftwtAnls] = useState<number>(0); // 침입수분석 정보 선택시 사용
const [chartData, setChartData] = useState<{ chartData1: DataType[]; chartData2: DataType[] }>({
chartData1: [], chartData2: [],
});
const [inftwtQty, setInftwtQty] = useState<number>(0); // 침입수량
const aplcnYms = fn.useAplcnYms('inftwtAnlsRslt'); // 상수사용월 데이터 가져오기
pplMngNo = "L" + pplMngNo; // inp파일에 하수관로와 맨홀의 번호가 같으면 분석 오류가 발행하여
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.LINE;
const chartConfig = {
chartData1: { label: '순오수량', color: "red", },
chartData2: { label: '실측하수량', color: "orange", }
} as ChartConfig;
useEffect(() => {
if (isModalOpen === false) {
setPopupOpen(true); // 모달이 닫힐 때 조회조건팝업은 열어두기
setSelectedAplcnYm(""); // 상수사용월 초기화
setInftwtAnlss([]); // 침입수분석 초기화
setInftwtAnlsInfos([{ val: 0, text: '선택' }]); // 침입수분석정보 초기화
setInftwtAnls(null); // 침입수분석정보 초기화
setSelectedInftwtAnls(0); // 침입수분석 일련번호 초기화
setChartData({ chartData1: [], chartData2: [], }); // 차트 데이터 초기화
setInftwtQty(0); // 침입수량 초기화
}
}, [isModalOpen]);
// 상수사용월 변경 핸들러
const handleAplcnYmChange = async (val: string | number) => {
const selectedValue = String(val);
console.log("선택된 상수사용월:", selectedValue);
setSelectedAplcnYm(selectedValue);
// 즉시 관련 상태 초기화
setInftwtAnls(null);
// 빈 값이면 초기화만 하고 종료
if (!selectedValue || selectedValue === "0" || selectedValue === "") {
setInftwtAnlsInfos([{ val: 0, text: '선택' }]);
return;
}
// API 호출
try {
const data = await fn.selectInftwtAnls(selectedValue);
setInftwtAnlss(data ?? []);
setInftwtAnlsInfos(fn.getOptionsInftwtAnlsInfo(data));
} catch (error) {
console.error("selectInftwtAnls 에러:", error);
setInftwtAnlss([]);
setInftwtAnlsInfos([{ val: 0, text: '선택' }]);
}
setSelectedInftwtAnls(0);
};
// 분석정보 변경 핸들러
const handleInftwtAnlsSnChange = (val: string | number) => {
const selectedValue = Number(val);
setSelectedInftwtAnls(selectedValue);
// 선택된 침입수분석 정보에 대한 처리 로직
if (selectedValue === 0) {
setInftwtAnls(null);
return;
}
const selectedAnls = inftwtAnlss.find(anls => anls.inftwtAnlsSn === selectedValue);
if (selectedAnls) {
setInftwtAnls(selectedAnls);
}
};
const closePopup = () => { // 팝업 닫기
setPopupOpen(false);
}
const infilRsltChart = () => { // 그래프 & 팝업 닫기
fn.selectInftwtAnlsRslt(selectedInftwtAnls, pplMngNo).then((data) => {// 침입수분석 결과 조회
const rsltData = fn.getChartDataInftwtAnlsRslt(data ?? []);
setChartData(prev => ({
...prev,
chartData1: rsltData // 침입수분석결과
}));
});
fn.selectOilq(selectedInftwtAnls, pplMngNo).then((data) => {// 유량 조회
const rsltData = fn.getChartDataOilq(data ?? []);
setChartData(prev => ({
...prev,
chartData2: rsltData // 유량
}));
}).catch((err) => {
console.error("selectOilq 에러:", err);
setChartData(prev => ({
...prev,
chartData2: [] // 유량 데이터 초기화
}));
});
fn.selectPplInftwtQty(selectedInftwtAnls, pplMngNo).then((data) => {// 침입수량 조회
if (data > 0) {
setInftwtQty(data);
}
});
setPopupOpen(false);
};
const renderBody = () => (
<>
<div className="text-black text-3xl font-bold mb-5">침입수분석결과</div>
<div className='grid grid-cols-[1fr_3fr] gap-4'>
<div className="h-[90%] 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">
{(selectedAplcnYm) ? moment(selectedAplcnYm, "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="ml-5 text-black text-xl">침입수량 : </span>
<span className="w-[35px] inline-block text-right text-black text-xl font-bold">{inftwtQty}</span>
<span className="ml-2 text-black text-xl">m³/d</span>
</div>
</div>
</div>
{/* 차트 */}
<div className="h-[90%] bg-white text-3xl">
<MainChart chartConfig={chartConfig} chartForm={chartForm} chartData={chartData} chartTitle={'침입수량 그래프'}
yFieldText2="시간" 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={selectedAplcnYm}
onSelectValue={handleAplcnYmChange}
/>
</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={inftwtAnlsInfos}
value={selectedInftwtAnls}
onSelectValue={handleInftwtAnlsSnChange}
/>
</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={inftwtAnls?.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={inftwtAnls?.atflHrPttnNm ?? ""}
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={inftwtAnls?.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={inftwtAnls?.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={inftwtAnls?.atflOilqNm ?? ""}
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={infilRsltChart}>
선택조건 적용
</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(InfilChart);