diff --git a/apps/fo/app/components/common/CalcRainEffect.tsx b/apps/fo/app/components/common/CalcRainEffect.tsx index beca33f78..3ea198016 100644 --- a/apps/fo/app/components/common/CalcRainEffect.tsx +++ b/apps/fo/app/components/common/CalcRainEffect.tsx @@ -9,67 +9,111 @@ * @author jsyang */ -export default function CalcRainEffect(data : any, weather='ALL') { - /* console.log("%c Calculate RainEffect !" , "background:blue;color:white"); - console.log("%c Data Length :"+data.length+" Weather : "+weather , "background:yellow;color:blue");*/ - // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) - for(let idx = 0; idx < data.length; idx++) { +export default function CalcRainEffect(data: any, weather = 'ALL') { + const rtnDataAll: any = []; + const rtnDataSunny: any = []; + const rtnDataRain: any = []; + let rtnData: any = []; + let rainEffectStd = 0; + for (let idx = 0; idx < data.length; idx++) { const item = data[idx]; - if(item){ - if(item.infoRnDay && Number(item.infoRnDay) >= 3) { // 강우량이 3 이상인 경우 - item.rainEffectDay = 1; - } else { - item.rainEffectDay = 0; - } - - if(item.infoRnDay == 'x'){ - item.infoRnDay = '0.0'; - item.toBeInfoRnDay = '0.0'; - }else{ - item.infoRnDay = Number(item.infoRnDay).toFixed(1); - item.toBeInfoRnDay = Number(item.infoRnDay).toFixed(1); - } + if (item.infoRnDay == null || item.infoRnDay == 'x' || item.infoRnDay == '') item.infoRnDay = 0; + if (Number(item.infoRnDay) >= 3) { // 강우일 + rainEffectStd = 2; + item.toBeInfoRnDay = item.infoRnDay; + } else { + rainEffectStd--; } - } - // 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정 - for(let idx = 0; idx < data.length; idx++) { - if(data[idx]) { - // 하루 전이 강우영향일(3 이상)인 경우 - if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay) >= 3) { - data[idx]!.rainEffectDay = 1; - } - // 이틀 전이 강우영향일(3 이상)인 경우 - if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay) >= 3) { - data[idx]!.rainEffectDay = 1; - } - } - } - - for(let idx = 0; idx < data.length; idx++) { - if(data[idx] && data[idx]?.rainEffectDay === 1) { - if(idx > 1){ + if (rainEffectStd < 0) { // 청천일 + item.rainEffectDay = 0; + rtnDataSunny.push(item); + } else if (rainEffectStd >= 0) { // 강우일 + 강우영향일 + item.rainEffectDay = 1; + if (idx > 1) { // 전날 비가 왔고 오늘 강우량 3미만인 경우 전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전날 강우량으로 설정 - if(data[idx-1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) { - data[idx]!.toBeInfoRnDay = data[idx-1]!.infoRnDay; + if (data[idx - 1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx - 1]?.infoRnDay.toString().trim()) >= 3) { + data[idx]!.toBeInfoRnDay = data[idx - 1]!.infoRnDay; } } - if(idx > 2){ + if (idx > 2) { // 전전날 비가 왔고 오늘 강우량 3미만인 경우 전전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전전날 강우량으로 설정 - if(data[idx-2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) { - data[idx]!.toBeInfoRnDay = data[idx-2]!.infoRnDay; + if (data[idx - 2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx - 2]?.infoRnDay.toString().trim()) >= 3) { + data[idx]!.toBeInfoRnDay = data[idx - 2]!.infoRnDay; } } + rtnDataRain.push(item); } + + rtnDataAll.push(item); } - let rtnData : any = []; + + // // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) + // for(let idx = 0; idx < data.length; idx++) { + // const item = data[idx]; + // if(item){ + // if(item.infoRnDay && Number(item.infoRnDay) >= 3) { // 강우량이 3 이상인 경우 + // item.rainEffectDay = 1; + // } else { + // item.rainEffectDay = 0; + // } + + // if(item.infoRnDay == 'x'){ + // item.infoRnDay = '0.0'; + // item.toBeInfoRnDay = '0.0'; + // }else{ + // item.infoRnDay = Number(item.infoRnDay).toFixed(1); + // item.toBeInfoRnDay = Number(item.infoRnDay).toFixed(1); + // } + // } + // } + + // // 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정 + // for(let idx = 0; idx < data.length; idx++) { + // if(data[idx]) { + // // 하루 전이 강우영향일(3 이상)인 경우 + // if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay) >= 3) { + // data[idx]!.rainEffectDay = 1; + // } + // // 이틀 전이 강우영향일(3 이상)인 경우 + // if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay) >= 3) { + // data[idx]!.rainEffectDay = 1; + // } + // } + // } + + // for(let idx = 0; idx < data.length; idx++) { + // if(data[idx] && data[idx]?.rainEffectDay === 1) { + // if(idx > 1){ + // // 전날 비가 왔고 오늘 강우량 3미만인 경우 전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전날 강우량으로 설정 + // if(data[idx-1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) { + // data[idx]!.toBeInfoRnDay = data[idx-1]!.infoRnDay; + // } + // } + // if(idx > 2){ + // // 전전날 비가 왔고 오늘 강우량 3미만인 경우 전전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전전날 강우량으로 설정 + // if(data[idx-2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) { + // data[idx]!.toBeInfoRnDay = data[idx-2]!.infoRnDay; + // } + // } + // } + // } + + // if (weather === 'ALL') { + // rtnData = data; + // } else if (weather === 'SUNNY') { + // rtnData = data.filter((item: any) => item.rainEffectDay === 0); + // } else { + // rtnData = data.filter((item: any) => item.rainEffectDay === 1); + // } + if (weather === 'ALL') { - rtnData = data; + rtnData = rtnDataAll; } else if (weather === 'SUNNY') { - rtnData = data.filter((item: any) => item.rainEffectDay === 0); + rtnData = rtnDataSunny; } else { - rtnData = data.filter((item: any) => item.rainEffectDay === 1); + rtnData = rtnDataRain; } return rtnData; } \ No newline at end of file diff --git a/apps/fo/app/components/common/DataForm.tsx b/apps/fo/app/components/common/DataForm.tsx index 48b428e32..2c99129b2 100644 --- a/apps/fo/app/components/common/DataForm.tsx +++ b/apps/fo/app/components/common/DataForm.tsx @@ -4,12 +4,39 @@ item: Record; } -export const roundNumber = (value : any, decimals: number) => { +/** + * yyyymm 형태의 문자열을 받아 해당 월의 일수를 반환 + * @param {string} yyyymm - 예: "202502", "202412" + * @returns {number} 해당 월의 일수 (예: 28, 29, 30, 31) + */ +export const getDaysInMonth = (yyyymm: string) => { + if (typeof yyyymm !== 'string' || yyyymm.length !== 6) { + throw new Error("입력은 'yyyymm' 형식의 문자열이어야 합니다. 예: '202502'"); + } + + const year = parseInt(yyyymm.slice(0, 4), 10); // "2025" -> 2025 + const month = parseInt(yyyymm.slice(4, 6), 10); // "02" -> 2 + + if (isNaN(year) || isNaN(month) || month < 1 || month > 12) { + throw new Error("유효한 년/월이 아닙니다."); + } + + // Date(year, month, 0) -> 전달의 마지막 날 + // month에 '다음달'을 넣고, 일(day)에 0을 주면 해당 월의 마지막 날짜가 됨 + return new Date(year, month, 0).getDate(); +} + +export const roundNumber = (value: any, decimals: number) => { if (typeof value === 'number') { return addCommas((Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals)).toFixed(decimals)); - } else if (typeof value === 'string' && !isNaN(Number(value))) { - return addCommas(Number(value).toFixed(decimals)); + } else if (typeof value === 'string') { + // 콤마가 포함된 문자열 처리 ('1,083.0' 같은 경우) + const cleanedValue = value.replace(/,/g, ''); + if (!isNaN(Number(cleanedValue))) { + return addCommas(Number(cleanedValue).toFixed(decimals)); + } } + return value; // 변환 불가능한 경우 원래 값 반환 } export const addCommas = (value: string | number): any => { @@ -18,48 +45,48 @@ export const addCommas = (value: string | number): any => { index === 0 ? part : part.replace(/(\d{3})/g, '$1,') ).join('.'); } else if (typeof value === 'string') { - return value.includes('.')?value.split('.').map((part, index) => + return value.includes('.') ? value.split('.').map((part, index) => index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part - ).join('.'):String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); + ).join('.') : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } } export default function DataForm({ type, column, item }: DataFormProps) { - if(item) { + if (item) { const value = item[column]; - switch(type){ + switch (type) { case 'date': - if(value && typeof value === 'string' && value.length >= 8) + if (value && typeof value === 'string' && value.length >= 8 && !value.includes('-')) item[column] = value.substring(0, 4) + "-" + value.substring(4, 6) + "-" + value.substring(6, 8); - break; + break; case 'number': - if(value && value != '') { + if (value && value != '') { item[column] = value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } - break; + break; case 'float0': - if(value) { - item[column] = item[column] = String(value).includes('.')?String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 1) / 1).split('.').map((part, index) => - index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part - ).join('.') - : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); + if (value) { + item[column] = item[column] = String(value).includes('.') ? String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 1) / 1).split('.').map((part, index) => + index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part + ).join('.') + : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } - break; + break; case 'float1': - if(value) { + if (value) { item[column] = roundNumber(value, 1); } - break; + break; case 'float2': - if(value) { + if (value) { item[column] = roundNumber(value, 2); } - break; + break; case 'float3': - if(value) { + if (value) { item[column] = roundNumber(value, 3); } - break; + break; } } } \ No newline at end of file diff --git a/apps/fo/app/components/common/FacilityTermModalHeader.tsx b/apps/fo/app/components/common/FacilityTermModalHeader.tsx index 52cee2ea3..4389e2f5a 100644 --- a/apps/fo/app/components/common/FacilityTermModalHeader.tsx +++ b/apps/fo/app/components/common/FacilityTermModalHeader.tsx @@ -4,14 +4,14 @@ import ListDiv from '@common/business_components/ui/list_div'; import { Table, TableCell, TableHead, TableRow } from '@common/components/ui'; import { useCallback, useEffect, useRef, useState } from 'react'; -type FacilityTermModalHeaderProps = { - fcltyCd : string; +type FacilityTermModalHeaderProps = { // T는 반드시 msrDt: string 필드를 가져야 한다 + fcltyCd: string; fcltyName: string; tabName: string; searchYear: string; searchList: T[]; ref: React.RefObject>; - queryClick:(returnType:ReturnType) => void; + queryClick: (returnType: ReturnType) => void; } export type ReturnType = { @@ -21,27 +21,28 @@ export type ReturnType = { filteredList: T[]; } -export default function FacilityTermModalHeader({ +export default function FacilityTermModalHeader({ searchList, - fcltyName, - tabName, + fcltyName, + tabName, searchYear, queryClick, ref }: FacilityTermModalHeaderProps) { - const {Common} = useFoStore((state) => state); + const { Common } = useFoStore((state) => state); const { selectFlowPanel } = Common; const [startDate, setStartDate] = useState(new Date(Number(searchYear), 0, 1)); const [endDate, setEndDate] = useState(new Date(Number(searchYear), 11, 31)); const startPickerRef = useRef(null); const endPickerRef = useRef(null); - const [flowPanel, setFlowPanel] = useState(selectFlowPanel[0]?.val ?? '00'); + const [flowPanel, setFlowPanel] = useState(selectFlowPanel[0]?.val ?? '0'); // 초기값 "전체" const [copySearchList, setCopySearchList] = useState(searchList); const [standSearchList, setStandSearchList] = useState(searchList); const isDateInRanges = (date: Date) => { const standYear = parseInt(searchYear); - const dateRanges:{start:Date, end:Date}[] = []; + const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0); + const dateRanges: { start: Date, end: Date }[] = []; if (tabName.includes("_summer")) { dateRanges.push({ @@ -51,7 +52,7 @@ export default function FacilityTermModalHeader({ } else if (tabName.includes("_winter")) { dateRanges.push({ start: new Date(standYear, 0, 1), - end: new Date(standYear, 1, 28) + end: new Date(standYear, 1, isLeapYear ? 29 : 28) }); } else { dateRanges.push({ @@ -70,67 +71,69 @@ export default function FacilityTermModalHeader({ useEffect(() => { let startDate = new Date(Number(searchYear), 0, 1); let endDate = new Date(Number(searchYear), 11, 31); + const standYear = Number(searchYear); + const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0); - if(tabName.includes("_summer")) { - startDate = new Date(Number(searchYear), 5, 1); - endDate = new Date(Number(searchYear), 7, 31); + if (tabName.includes("_summer")) { // 하절기 + startDate = new Date(Number(searchYear), 5, 1); // 6월 ~ + endDate = new Date(Number(searchYear), 7, 31); // 8월 setStartDate(startDate); setEndDate(endDate); - } else if (tabName.includes("_winter")) { - startDate = new Date(Number(searchYear), 0, 1); - endDate = new Date(Number(searchYear), 1, 28); + } else if (tabName.includes("_winter")) { // 동절기 + startDate = new Date(Number(searchYear), 0, 1); // 1월 ~ + endDate = new Date(Number(searchYear), 1, isLeapYear ? 29 : 28); // 2월 setStartDate(startDate); setEndDate(endDate); - } else { + } else { // 연간 startDate = new Date(Number(searchYear), 0, 1); endDate = new Date(Number(searchYear), 11, 31); setStartDate(startDate); setEndDate(endDate); } - + let filteredData: T[] = []; - if(tabName.includes("_rain")) { + if (tabName.includes("_rain")) { // 강우시 filteredData = searchList.filter((item) => { const itemDate = new Date((item as T & { msrDt: string }).msrDt); const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay; - - if(flowPanel === '2'){ + + if (flowPanel === '2') { //3~10mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 3 && infoRnDay < 10; - } else if(flowPanel === '3'){ + } else if (flowPanel === '3') { //10~20mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 10 && infoRnDay < 20; - } else if(flowPanel === '4'){ + } else if (flowPanel === '4') { //20~30mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 20 && infoRnDay < 30; - } else if(flowPanel === '5'){ + } else if (flowPanel === '5') { //30~40mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 30 && infoRnDay < 40; - } else if(flowPanel === '6'){ + } else if (flowPanel === '6') { //40~50mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 40 && infoRnDay < 50; - } else if(flowPanel === '7'){ + } else if (flowPanel === '7') { //50~60mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 50 && infoRnDay < 60; - } else if(flowPanel === '8'){ + } else if (flowPanel === '8') { const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 60; } else { - return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (rainEffectDay ===1); + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (rainEffectDay === 1); } }); - } else if(tabName.includes("_chuncheon")) { + } else if (tabName.includes("_chuncheon")) { // 청천시 filteredData = searchList.filter((item) => { const itemDate = new Date((item as T & { msrDt: string }).msrDt); const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay; - return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && rainEffectDay==0; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && rainEffectDay == 0; }); } else { filteredData = searchList.filter((item) => { @@ -146,7 +149,7 @@ export default function FacilityTermModalHeader({ }, [searchList, searchYear, tabName, flowPanel]); const handleStartDateSelect = (day: Date | undefined) => { - if(day && day > endDate) { + if (day && day > endDate) { alert('종료일은 시작일 이전일 수 없습니다.'); return; } @@ -169,7 +172,7 @@ export default function FacilityTermModalHeader({ }; const handleEndDateSelect = (day: Date | undefined) => { - if(day && day < startDate) { + if (day && day < startDate) { alert('종료일은 시작일 이후일 수 없습니다.'); return; } @@ -190,7 +193,7 @@ export default function FacilityTermModalHeader({ }); setCopySearchList(filteredData); }; - + const fncSetFilteredList = useCallback(() => { queryClick({ startDate: startDate, @@ -203,9 +206,9 @@ export default function FacilityTermModalHeader({ useEffect(() => { fncSetFilteredList(); }, [fncSetFilteredList]); - + useEffect(() => { - if(ref && ref.current) { + if (ref && ref.current) { const customRef = ref.current; customRef.startDate = startDate; customRef.endDate = endDate; @@ -222,18 +225,18 @@ export default function FacilityTermModalHeader({ {'시설명'} {tabName === "tab_term_rain" ? {fcltyName} : - {fcltyName}} + {fcltyName}} {tabName === "tab_term_rain" && ( <> {'강수구분'}
- setFlowPanel(val.toString())} - className="mx-3 w-[150px]" - label="" + className="mx-3 w-[150px]" + label="" selectClass="w-full p-1 border rounded bg-white" />
@@ -244,7 +247,7 @@ export default function FacilityTermModalHeader({
- handleStartDateSelect(date as Date)} @@ -258,7 +261,7 @@ export default function FacilityTermModalHeader({ handleEndDateSelect(date as Date)} + onSelect={(date) => handleEndDateSelect(date as Date)} className="w-full p-1 border rounded bg-white" disabled={(date) => !isDateInRanges(date)} defaultMonth={endDate} diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index b94fc21c1..6ab18b825 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -6,7 +6,10 @@ "use client" import { useFoStore } from "@/app/store"; -import { ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv, SelectBox, UITab, type SelectDataType } from "@common/business_components"; +import { + ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv + , SelectBox, UITab, type SelectDataType +} from "@common/business_components"; import { Button, TabsContent } from "@common/components/ui"; import { useEffect, useState } from "react"; import DashBoardFclty from "../dashboardMain/page"; @@ -50,9 +53,9 @@ type FacilityType = { export default function DashBoard() { // 입력값 상태 관리 - const { Common, initializeCommonData, searchMainGraph, searchRainManage, searchOperationStatus, OperationStatus, RainManage, MainGraph, PlanFclty } = useFoStore((state) => state); + const { Common, initializeCommonData, searchMainGraph, searchRainManage, searchOperationStatus + , OperationStatus, RainManage, MainGraph, PlanFclty } = useFoStore((state) => state); const [activeTab, setActiveTab] = useState('facilityInfo'); - const [filteredSigunData, setFilteredSigunData] = useState([{ text: "전체", val: '0' }]); const [sidoValue, setSidoValue] = useState('0'); const [sigunValue, setSigunValue] = useState('0'); diff --git a/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx index e084bf04d..55e6275c8 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx @@ -15,27 +15,13 @@ export type facilityInfoProps = { fcltyList?: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }[]; }; -export default function RainManageTab({searchYear = '', fcltyList = []}: facilityInfoProps) { - - const { - Common, - searchRainManage, - RainManage - } = useFoStore((state) => state); +export default function RainManageTab({ searchYear = '', fcltyList = [] }: facilityInfoProps) { + const { Common, searchRainManage, RainManage } = useFoStore((state) => state); const [hasSearched, setHasSearched] = useState(false); - // 이전 시설코드 저장 - const [prevFacilityCode, setPrevFacilityCode] = useState(''); - - const { - isInit, - } = Common; - - const { - upHeadListRainManage, - rainManageList, - } = RainManage; - + const [prevFacilityCode, setPrevFacilityCode] = useState(''); // 이전 시설코드 저장 + const { isInit, } = Common; + const { upHeadListRainManage, rainManageList, } = RainManage; const tableData = fcltyList; useEffect(() => { @@ -50,17 +36,17 @@ export default function RainManageTab({searchYear = '', fcltyList = []}: facilit useEffect(() => { setHasSearched(false); }, [searchYear]); - + return (
- {}} + onPageChange={() => { }} widthFixed={true} > diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx index 1bd8a6c89..811f1c0ff 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx @@ -9,7 +9,7 @@ import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { roundNumber } from "@/app/components/common/DataForm"; import { useFoStore } from "@/app/store"; import type { PrecipitationPropsDetailProps } from "@/app/store/facilityPrecipitation"; -import { DatePickerRange, downloadExcel, UiTable } from "@common/business_components/ui"; +import { DatePickerRange, downloadExcelHeaders, UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Table, TableCell, TableHead, TableRow } from "@common/components/ui"; import { useEffect, useRef, useState } from "react"; @@ -45,7 +45,7 @@ export default function PrecipitationModal(props: PrecipitationModalProps) { const standYear = parseInt(props.searchYear); return [{ start: new Date(standYear, 0, 1), - end: new Date(standYear, 11, 31) + end: new Date(standYear, 11, 31) //월의 index는 0부터 시작 }]; }; @@ -112,7 +112,6 @@ export default function PrecipitationModal(props: PrecipitationModalProps) { const getTableData = () => { const totals = calculateTotals(); totals.infoRnDay = roundNumber(totals.infoRnDay, 1); - return [ { bscFctCd: "", @@ -157,19 +156,26 @@ export default function PrecipitationModal(props: PrecipitationModalProps) { const excelDownload = () => { const totData = getTableData(); - const excelDownList: any[] = []; + + // 헤더 순서를 명시적으로 정의 + const headers = ["날짜", "강수량(mm/일)", "강우일(일)", "강우영향일(일)"] as const; + + const excelDownList: Record[] = []; if(totData.length > 0){ totData.forEach((item) => { - excelDownList.push({ - "날짜": item.rainDt, - "강수량(mm/일)": roundNumber(item.infoRnDay, 1), - "강우일(일)": roundNumber(item.rainDay, 0), - "강우영향일(일)": roundNumber(item.rainEffectDay, 0), - }); + // 순서를 보장하기 위해 헤더 순서대로 객체 생성 + const row: Record = {}; + row[headers[0]] = item.rainDt; + row[headers[1]] = roundNumber(item.infoRnDay, 1); + row[headers[2]] = roundNumber(item.rainDay, 0); + row[headers[3]] = roundNumber(item.rainEffectDay, 0); + excelDownList.push(row); }); } + if (excelDownList && excelDownList.length > 0) { - downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 강수현황', sheetNameArray: ['지하수유입량'], headerRange: 'A1:D1' }); + downloadExcelHeaders({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 강수현황' + , sheetNameArray: ['지하수유입량'], headerRange: 'A1:D1', headers }); } else if (totData.length == 0) { alert('다운받을 데이터가 없습니다.'); } diff --git a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx index 42512f802..4e0fffeb5 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -8,6 +8,7 @@ import FacilityTermModalHeader from "@/app/components/common/FacilityTermModalHeader"; import { useFoStore } from "@/app/store"; import type { FlowRateModalInterface, modalExcelType } from "@/app/store/flowRate"; +import { dataFormSetting } from "@/app/store/flowRate"; import { downloadExcel, UITab, UiTable } from "@common/business_components/ui"; import { Button, TabsContent } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; @@ -34,11 +35,8 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const [copyYearList, setCopyYearList] = useState([]); const [isLoading, setIsLoading] = useState(true); const prevExcelListRef = useRef(null); - const { - modalFlowRateListYear, - upHeadListFlowRateModalYear, - } = FlowRateModal; - + const { modalFlowRateListYear, upHeadListFlowRateModalYear, } = FlowRateModal; + const ref = useRef>({ startDate: new Date(), endDate: new Date(), @@ -52,11 +50,11 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const filteredData = setFilterAfterData(returnType.filteredList as FlowRateModalInterface[]); setCopyYearList(filteredData); }, []); - + // 필터링 된 후 최대, 최소, 평균 값 계산 const setFilterAfterData = (filteredData: FlowRateModalInterface[]) => { if (!filteredData || filteredData.length === 0) return []; - + // 쉼표가 포함된 문자열을 숫자로 변환하는 함수 const parseNumber = (value: string | number | null | undefined): number => { if (value === null || value === undefined || value === '') return 0; @@ -79,7 +77,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st let minreturnAmnt = parseNumber(filteredData[0]?.returnAmnt); let minefflAmnt = parseNumber(filteredData[0]?.efflAmnt); let mininfoRnDay = parseNumber(filteredData[0]?.infoRnDay && filteredData[0]?.infoRnDay.toString().trim() !== 'x' ? filteredData[0]?.infoRnDay.toString().trim() : 0); - let minNoProcessInflAmnt = 99999999; + let minNoProcessInflAmnt = 99999999; // 미처리하수 추정량 let avgtotInflAmnt = 0; let avginflAmnt = 0; @@ -89,7 +87,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st let avginfoRnDay = 0; let avgNoProcessInflAmnt = 0; let noProcessInflAmntCnt = 0; - + filteredData.forEach((item: FlowRateModalInterface) => { const totInflAmnt = parseNumber(item.totInflAmnt); const inflAmnt = parseNumber(item.inflAmnt); @@ -119,24 +117,30 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st avgefflAmnt += efflAmnt; avginfoRnDay += infoRnDay; - if(item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined){ - const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',','')); + if (item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined) { + const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',', '')); avgNoProcessInflAmnt += noProcessInflAmnt; maxNoProcessInflAmnt = Math.max(maxNoProcessInflAmnt, noProcessInflAmnt); minNoProcessInflAmnt = Math.min(minNoProcessInflAmnt, noProcessInflAmnt); - noProcessInflAmntCnt +=1; + noProcessInflAmntCnt += 1; } }); + const formattedData = filteredData.map((item: FlowRateModalInterface) => { + const newItem = { ...item }; + dataFormSetting(newItem); + return newItem; + }); + const newFilteredData = [ { msrDt: '평균', - totInflAmnt: avgtotInflAmnt && avgtotInflAmnt!=0 ? roundUp((avgtotInflAmnt / filteredData.length), 0) : 0, - inflAmnt: avginflAmnt && avginflAmnt!=0 ? roundUp((avginflAmnt / filteredData.length), 0) : 0, - sumFlow: avgsumFlow && avgsumFlow!=0 ? roundUp((avgsumFlow / filteredData.length), 0) : 0, - returnAmnt: avgreturnAmnt && avgreturnAmnt!=0 ? roundUp((avgreturnAmnt / filteredData.length), 0) : 0, - efflAmnt: avgefflAmnt && avgefflAmnt!=0 ? roundUp((avgefflAmnt / filteredData.length), 0) : 0, - noProcessInflAmnt : roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0), + totInflAmnt: avgtotInflAmnt && avgtotInflAmnt != 0 ? roundUp((avgtotInflAmnt / filteredData.length), 0) : 0, + inflAmnt: avginflAmnt && avginflAmnt != 0 ? roundUp((avginflAmnt / filteredData.length), 0) : 0, + sumFlow: avgsumFlow && avgsumFlow != 0 ? roundUp((avgsumFlow / filteredData.length), 0) : 0, + returnAmnt: avgreturnAmnt && avgreturnAmnt != 0 ? roundUp((avgreturnAmnt / filteredData.length), 0) : 0, + efflAmnt: avgefflAmnt && avgefflAmnt != 0 ? roundUp((avgefflAmnt / filteredData.length), 0) : 0, + noProcessInflAmnt: roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0), infoRnDay: avginfoRnDay > 0 ? roundUp((avginfoRnDay / filteredData.length), 1) : '0.0', rainEffectDay: 0, }, @@ -147,7 +151,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st sumFlow: roundUp(maxsumFlow, 0), returnAmnt: roundUp(maxreturnAmnt, 0), efflAmnt: roundUp(maxefflAmnt, 0), - noProcessInflAmnt : roundNumber(maxNoProcessInflAmnt, 0), + noProcessInflAmnt: roundNumber(maxNoProcessInflAmnt, 0), infoRnDay: maxinfoRnDay > 0 ? roundUp(maxinfoRnDay, 1) : '0.0', rainEffectDay: 0, }, @@ -158,11 +162,11 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st sumFlow: roundUp(minsumFlow, 0), returnAmnt: roundUp(minreturnAmnt, 0), efflAmnt: roundUp(minefflAmnt, 0), - noProcessInflAmnt : roundNumber(minNoProcessInflAmnt, 0), + noProcessInflAmnt: roundNumber(minNoProcessInflAmnt, 0), infoRnDay: mininfoRnDay > 0 ? roundUp(mininfoRnDay, 1) : '0.0', rainEffectDay: 0, }, - ...filteredData + ...formattedData ]; return newFilteredData; } @@ -185,7 +189,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const excelDownload = () => { const excelDownList: modalExcelType[] = []; - if(copyYearList.length > 0){ + if (copyYearList.length > 0) { copyYearList.forEach((item) => { excelDownList.push({ "날짜": item.msrDt, @@ -200,7 +204,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st }); } if (excelDownList && excelDownList.length > 0) { - downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 유량현황', sheetNameArray: [props.fcltyName + ' 유량현황'], headerRange: 'A1:H1' }); + downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear + '년 ' + props.fcltyName + ' 유량현황', sheetNameArray: [props.fcltyName + ' 유량현황'], headerRange: 'A1:H1' }); } else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) { alert('다운받을 데이터가 없습니다.'); } @@ -210,10 +214,10 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st return ( <> - - + {/* 연간 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -224,23 +228,23 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} />
- {}} - className="h-[370px]" - boldArray={[0,1,2]} + { }} + className="h-[370px]" + boldArray={[0, 1, 2]} />
- + {/* 하절기 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -251,23 +255,23 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} />
- {}} - className="h-[370px]" - boldArray={[0,1,2]} + { }} + className="h-[370px]" + boldArray={[0, 1, 2]} />
- + {/* 동절기 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -278,23 +282,23 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} />
- {}} - className="h-[370px]" - boldArray={[0,1,2]} + { }} + className="h-[370px]" + boldArray={[0, 1, 2]} />
- + {/* 청천시 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -305,23 +309,23 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} />
- {}} - className="h-[370px]" - boldArray={[0,1,2]} + { }} + className="h-[370px]" + boldArray={[0, 1, 2]} />
- + {/* 강우시 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -332,10 +336,11 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} />
- {}} className="h-[370px]" boldArray={[0,1,2]}/> + { }} className="h-[370px]" boldArray={[0, 1, 2]} />
- +
diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index 77d96fff6..a1a5e22d1 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -216,7 +216,7 @@ export default function ProcessFacilitySearch() { {selectedRow !== null && ( } - bodyClass="sm:max-w-[90vw] w-[1250px] h-[780px]" + bodyClass="sm:max-w-[90vw] w-[1250px] h-[100dvh] max-h-[780px]" open={selectedRow !== null} onOpenChange={(open: boolean) => !open && closeModal()} /> diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index 91bdb6ab0..009d72c9f 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -6,6 +6,7 @@ "use client" import { useFoStore } from "@/app/store"; +import { useShallow } from 'zustand/react/shallow'; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { useCallback, useEffect, useRef, useState } from "react"; @@ -13,19 +14,22 @@ import ProcessFacilityInfoModal from "./modal/page"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; export default function ProcessArea() { - const {Common, + const { + Common, ProcessArea, ProcessAreaSearch, initializeCommonData, searchProcessAreaList - } = useFoStore((state) => state) || { - Common: { isInit: false, selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" }, - ProcessArea: { processAreaList: [], processAreaCount: 0, excelList: [], upHeadList1: [] }, - ProcessAreaSearch: { processFacilityLabelArray: [] }, - initializeCommonData: () => {}, - searchProcessAreaList: () => {} - }; - + } = useFoStore( + useShallow((state) => ({ // 다른 무관한 상태가 변경되어도 이 컴포넌트는 불필요하게 다시 렌더링 되지 않음. + Common: state.Common, + ProcessArea: state.ProcessArea, + ProcessAreaSearch: state.ProcessAreaSearch, + initializeCommonData: state.initializeCommonData, + searchProcessAreaList: state.searchProcessAreaList, + })) + ); + const { isInit, selectSidoData, @@ -37,7 +41,7 @@ export default function ProcessArea() { selectSearchYear, btnClass, } = Common; - + const { processFacilityLabelArray, } = ProcessAreaSearch; @@ -54,11 +58,11 @@ export default function ProcessArea() { // 그리드 관련 const searchInputRef = useRef(null); - // 모달 상태 추가 + // 모달 상태 추가 const [selectedRow, setSelectedRow] = useState(null); const [fcltyNm, setFcltyNm] = useState(""); const [fcltyCd, setFcltyCd] = useState(""); - + const [resetPage, setResetPage] = useState(false); const [searchYearValue, setSearchYearValue] = useState(selectSearchYear[0]?.val || "0"); @@ -74,7 +78,7 @@ export default function ProcessArea() { sigunText: '', }); - const searchProcessArea = useCallback(({ sidoText, sigunText}: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchProcessArea = useCallback(({ sidoText, sigunText }: ReturnType, pageNo: number, pageCnt: number = 20) => { searchProcessAreaList(pageNo, pageCnt, sidoText, sigunText, searchYearValue); }, [searchProcessAreaList, searchYearValue]); @@ -118,11 +122,11 @@ export default function ProcessArea() { useEffect(() => { if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '처리구역정보', - sheetNameArray: ['처리구역정보'], - headerRange: 'A1:W1' + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '처리구역정보', + sheetNameArray: ['처리구역정보'], + headerRange: 'A1:W1' }); } }, [excelList]); @@ -143,7 +147,7 @@ export default function ProcessArea() { - setSearchYearValue(val.toString())} value={searchYearValue} selectClass={undefined}/> + setSearchYearValue(val.toString())} value={searchYearValue} selectClass={undefined} /> } rightChildren={undefined} selectSidoData={selectSidoData} @@ -169,9 +173,9 @@ export default function ProcessArea() { {selectedRow !== null && ( - } - bodyClass="sm:max-w-[90vw] w-[1200px] h-[900px]" + } + bodyClass="sm:max-w-[90vw] w-[1200px] h-[100dvh] max-h-[900px] overflow-y-auto" open={selectedRow !== null} onOpenChange={(open: boolean) => !open && closeModal()} /> diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index 856ab4631..9c3c612b5 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -292,7 +292,7 @@ export default function ProcessFacilitySearch() { {selectedRow !== null && ( } - bodyClass="sm:max-w-[70vw] sm:max-h-[95vh]" + bodyClass="sm:max-w-[70vw] h-[100dvh] max-h-[800px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} /> diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx index bc7fec4e8..223dc055a 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx @@ -8,7 +8,7 @@ import { roundNumber } from "@/app/components/common/DataForm"; import { useFoStore } from "@/app/store"; import type { modalTableType } from "@/app/store/sewageOccur"; -import { DateMonthPicker, downloadExcel, UiTable } from "@common/business_components/ui"; +import { DateMonthPicker, downloadExcelHeaders, UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Table, TableCell, TableHead, TableRow } from "@common/components/ui"; import { useEffect, useState } from "react"; @@ -69,20 +69,25 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd } }, [endYearMonth, startYearMonth]); - const excelDownload = () => { + const excelDownload = () => { + // 헤더 순서를 명시적으로 정의 + const headers = ["날짜", "물사용량(m³/일)", "오수전환율(%)", "오수발생량 추정(m³/일)"] as const; + const excelDownList: any[] = []; if(detailList.length > 0){ detailList.forEach((item) => { - excelDownList.push({ - "날짜": item.msrDt, - "물사용량(m³/일)": roundNumber(item.waterUsage, 0), - "오수전환율(%)": roundNumber(item.swageChangePercent, 0), - "오수발생량 추정(m³/일)": roundNumber(item.estimationSewage, 0), - }); + // 순서를 보장하기 위해 헤더 순서대로 객체 생성 + const row: Record = {}; + row[headers[0]] = item.msrDt; + row[headers[1]] = roundNumber(item.waterUsage, 0); + row[headers[2]] = roundNumber(item.swageChangePercent, 0); + row[headers[3]] = roundNumber(item.estimationSewage, 0); + excelDownList.push(row); }); } if (excelDownList && excelDownList.length > 0) { - downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 오수발생량 추정', sheetNameArray: [props.fcltyName + ' 오수발생량 추정'], headerRange: 'A1:D1' }); + downloadExcelHeaders({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 오수발생량 추정' + , sheetNameArray: [props.fcltyName + ' 오수발생량 추정'], headerRange: 'A1:D1', headers }); } else if (detailList.length == 0) { alert('다운받을 데이터가 없습니다.'); } diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index 001e816ae..31862e362 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -250,7 +250,7 @@ export default function PlanSewage() { facilityCd={fcltyCd} searchYear={searchYear} />} - bodyClass="sm:max-w-[90vw] w-[1000px] h-[770px]" + bodyClass="sm:max-w-[90vw] w-[1000px] h-[100dvh] max-h-[770px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} noHeaderYn="Y" diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx index 2e0f5f27e..02b1891ad 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx @@ -29,7 +29,7 @@ const tabList1 = [ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYear=new Date().getFullYear().toString()} : ModalProps) { // 그리드 관련 - const {Common, UnderWaterDetail, unserWaterModal} = useFoStore((state) => state); + const {Common, UnderWaterDetail, underWaterModal} = useFoStore((state) => state); const { btnClass } = Common; const [startYmDate, setStartYmDate] = useState(searchYear+'01'); const [endYmDate, setEndYmDate] = useState(searchYear+'12'); @@ -74,8 +74,8 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea }, [searchYear, tabTerm]); useEffect(()=>{ - unserWaterModal(fcltyCd, searchYear, searchYear+'01', searchYear+'12'); - }, [fcltyCd, searchYear, unserWaterModal]); + underWaterModal(fcltyCd, searchYear, searchYear+'01', searchYear+'12'); + }, [fcltyCd, searchYear, underWaterModal]); useEffect(() => { if(endYmDate < startYmDate) { @@ -93,8 +93,8 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea }, [startYmDate, endYmDate, gridListUnderWaterDetail, prevStartYmDate, prevEndYmDate]); useEffect(() => { - unserWaterModal(fcltyCd, searchYear, prevStartYmDate, prevEndYmDate); - } , [fcltyCd, searchYear, unserWaterModal, prevStartYmDate, prevEndYmDate]); + underWaterModal(fcltyCd, searchYear, prevStartYmDate, prevEndYmDate); + } , [fcltyCd, searchYear, underWaterModal, prevStartYmDate, prevEndYmDate]); const excelDownload = () => { const excelDownList: any[] = []; diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index 47e9ec912..a2ad7bfd6 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -251,7 +251,7 @@ export default function UnderWaterInput() { {selectedRow !== null && ( } - bodyClass="sm:max-w-[90vw] w-[1000px] h-[770px]" + bodyClass="sm:max-w-[90vw] w-[1000px] h-[100dvh] max-h-[770px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} noHeaderYn="Y" diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 09097d6e4..8f3b4dd8a 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -5,6 +5,7 @@ import { getFetch } from "@/app/components/api"; import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import DataForm, { roundNumber } from "@/app/components/common/DataForm"; +// import { getDaysInMonth } from "@/app/components/common/DataForm"; import { fetchPlanInfo, OSU_PERCENT, qltyDataSetting, roundUp } from "../common"; import { type FacilityWaterQltyProps } from "../facilityWaterQlty"; import { fetchFlowRateModalList } from "../flowRate"; @@ -216,6 +217,11 @@ export interface DrainageEquipmentExcelType { stepFourSep: number | '', } +// type WtrUsgYmProps = { +// bscFctCd: string, // 처리구역시설코드 +// levyYm: string, // 부과년월 +// wtrUsg: number, // 월별 물사용량(m³/월) +// } /** * Store - data */ @@ -722,17 +728,16 @@ const fetchFacilityPlan = async (targetYear: string | undefined, fcltyCd: string } }; -/* 시설정보 및 운영현황 - 운영실태 */ -// const fetchOperationStatus = async (searchYear: string | undefined, fcltyCd: string | undefined): Promise => { +// 시설들 월별 물사용량 정보 조회 +// const fetchWtrUsgYmList = async (searchYear: string | undefined, fcltCdList: string[]): Promise => { // try { -// const url = '/dashBoard/mngInfo/' + (searchYear ? searchYear : '2023') + '/' + (fcltyCd ? fcltyCd : ''); -// const res = await getFetch('fo', url); -// return { data: res.data, count: res.count } +// const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/' + searchYear, fcltCdList); +// return res; // } catch (error) { -// console.error('운영실태 데이터를 가져오는데 실패했습니다:', error); -// return { data: [], count: 0 }; +// console.error('시설들 월별 물사용량 데이터를 가져오는데 실패했습니다:', error); +// return null; // } -// } +// }; // 주요그래프 데이터 const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | undefined) => { @@ -749,14 +754,14 @@ const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | // 수질 데이터 청천시, 강우시 재계산 const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fcltyCd: string | undefined, mainGraphData: any) => { - const operList = { - inflBod: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입BOD - inflTN: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입TN - inflTP: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입TP - efflBod: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류BOD - efflTN: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류TN - efflTP: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류TP - tpInflTp: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, //총인 유입수질 TP(mg/L) + const operList = { + inflBod: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 유입BOD + inflTN: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 유입TN + inflTP: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 유입TP + efflBod: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 방류BOD + efflTN: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 방류TN + efflTP: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 방류TP + tpInflTp: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, //총인 유입수질 TP(mg/L) }; const nullToZero = (value: any) => { return value === null || value === undefined || value === '' ? 0 : Number(value); @@ -962,11 +967,11 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc operList.tpInflTp.yearAvg = operList.tpInflTp.yearTot / totalDay; orgData[5].yearAvg = qltyDataSetting(operList.inflBod.yearTot, totalDay, 1); // 연간 유입BOD - orgData[6].yearAvg = qltyDataSetting(operList.efflBod.yearTot,totalDay, 1); // 연간 방류BOD - orgData[7].yearAvg = qltyDataSetting(operList.inflTN.yearTot,totalDay, 3); // 연간 유입TN - orgData[8].yearAvg = qltyDataSetting(operList.efflTN.yearTot,totalDay, 3); // 연간 방류TN - orgData[9].yearAvg = qltyDataSetting(operList.inflTP.yearTot,totalDay, 3); // 연간 유입TP - orgData[10].yearAvg = qltyDataSetting(operList.efflTP.yearTot,totalDay, 3); // 연간 방류TP + orgData[6].yearAvg = qltyDataSetting(operList.efflBod.yearTot, totalDay, 1); // 연간 방류BOD + orgData[7].yearAvg = qltyDataSetting(operList.inflTN.yearTot, totalDay, 3); // 연간 유입TN + orgData[8].yearAvg = qltyDataSetting(operList.efflTN.yearTot, totalDay, 3); // 연간 방류TN + orgData[9].yearAvg = qltyDataSetting(operList.inflTP.yearTot, totalDay, 3); // 연간 유입TP + orgData[10].yearAvg = qltyDataSetting(operList.efflTP.yearTot, totalDay, 3); // 연간 방류TP //총인설비 orgData[11].yearAvg = qltyDataSetting(operList.tpInflTp.yearTot, noNullYearDay, 3); // 연간 총인 유입수질 TP orgData[12].yearAvg = qltyDataSetting(operList.efflTP.yearTot, totalDay, 3); // 연간 총인 유입수질 TP @@ -1060,7 +1065,7 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc orgData[11].winterSunnyMin = chungchunTpInflMin === 99999999 ? '0.000' : roundUp(chungchunTpInflMin, 3).toFixed(3); orgData[12].winterSunnyMin = chungchunEfflTpMin === 99999999 ? '0.000' : roundUp(chungchunEfflTpMin, 3).toFixed(3); - + return orgData; } else { @@ -1137,6 +1142,9 @@ export type DashBoardType = { mainGraphData: any; mainGraphYear: string; mainGraphFcltyCd: string; + flowRateData: any; + flowRateYear: string; + flowRateFcltyCd: string; }, DrainageEquipment: { @@ -1203,6 +1211,9 @@ export const dashBoardInitState: DashBoardType = { mainGraphData: null, mainGraphYear: '', mainGraphFcltyCd: '', + flowRateData: null, + flowRateYear: '', + flowRateFcltyCd: '', }, DrainageEquipment: { @@ -1460,30 +1471,41 @@ export const dashBoardReducer = ( isLoadingOperationStatus: true, }, })); - // const res = await fetchOperationStatus(searchYear, fcltyCd); // /dashBoard/mngInfo/ - // const data = res.data; - const operList = { - inFlow : {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + // const fcltCdList = [fcltyCd]; + //const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); // 수용가의 실제 물사용량 + + const operList = { + inFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - inflAmt: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999, yearSunny: 0 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + inflAmt: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999, yearSunny: 0 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - sumFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + sumFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - returnFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + returnFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - efflFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + efflFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, }; const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; @@ -1492,21 +1514,38 @@ export const dashBoardReducer = ( if (operationalStatusList) { // 유량 - 유입 if (operationalStatusList?.[0]) { - + // 연계처리수 let yearDay = 0, summerDay = 0, winterDay = 0; // 연간 일수, 하절기 일수, 동절기 일수 let summerRainDay = 0, summerChungchunDay = 0, winterChungchuDay = 0; // 하절기 강우 일수, 하절기 청천 일수, 동절기 청천 일수 - + // 연계처리수,지하수유입량 const bscFctCd = fcltyCd; - const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - 일별 유량 조회 + let res2: any = { data: [] }; + + // 이미 조회된 데이터가 있는지 확인 (연도와 시설코드가 같을 때만) + if (state.RainManage.flowRateYear === searchYear && state.RainManage.flowRateFcltyCd === fcltyCd && state.RainManage.flowRateData) { + res2 = state.RainManage.flowRateData; + } else { + res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - 일별 유량 조회 + // 조회된 데이터 저장 + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + flowRateData: res2, + flowRateYear: searchYear, + flowRateFcltyCd: fcltyCd, + } + })); + } //const calData = CalcRainEffect(clone(res2.data), 'SUNNY'); //const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); let cntSunnyDay = 0; // 청천일 수 // let chungcunSumFlow = 0; // 연간 청천 순수하수 - + let rainEffectDay = 0; yearDay = res2.data ? res2.data.length : 1; res2.data.forEach((item: any) => { // --일별 유량 start @@ -1516,7 +1555,7 @@ export const dashBoardReducer = ( const inflAmnt = item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0; const returnAmnt = item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0; const efflAmnt = item.efflAmnt && item.efflAmnt !== 'x' ? Number(item.efflAmnt.toString().trim()) : 0; - + if (item.infoRnDay == null) item.infoRnDay = 0; if (item.infoRnDay >= 3) { rainEffectDay = 2; @@ -1608,41 +1647,41 @@ export const dashBoardReducer = ( }); // --일별 유량 end // 연간 평균 - operList.inFlow.yearAvg = (yearDay > 0)? operList.inFlow.yearTot / yearDay : 0; - operList.inflAmt.yearAvg = (yearDay > 0)? operList.inflAmt.yearTot / yearDay : 0; - operList.sumFlow.yearAvg = (yearDay > 0)? operList.sumFlow.yearTot / yearDay : 0; - operList.returnFlow.yearAvg = (yearDay > 0)? operList.returnFlow.yearTot / yearDay : 0; - operList.efflFlow.yearAvg = (yearDay > 0)? operList.efflFlow.yearTot / yearDay : 0; + operList.inFlow.yearAvg = (yearDay > 0) ? operList.inFlow.yearTot / yearDay : 0; + operList.inflAmt.yearAvg = (yearDay > 0) ? operList.inflAmt.yearTot / yearDay : 0; + operList.sumFlow.yearAvg = (yearDay > 0) ? operList.sumFlow.yearTot / yearDay : 0; + operList.returnFlow.yearAvg = (yearDay > 0) ? operList.returnFlow.yearTot / yearDay : 0; + operList.efflFlow.yearAvg = (yearDay > 0) ? operList.efflFlow.yearTot / yearDay : 0; // 하절기 전기간 평균 - operList.inFlow.summerAvg = (summerDay > 0)? operList.inFlow.summerTot / summerDay : 0; - operList.inflAmt.summerAvg = (summerDay > 0)? operList.inflAmt.summerTot / summerDay : 0; - operList.sumFlow.summerAvg = (summerDay > 0)? operList.sumFlow.summerTot / summerDay : 0; - operList.returnFlow.summerAvg = (summerDay > 0)? operList.returnFlow.summerTot / summerDay : 0; - operList.efflFlow.summerAvg = (summerDay > 0)? operList.efflFlow.summerTot / summerDay : 0; + operList.inFlow.summerAvg = (summerDay > 0) ? operList.inFlow.summerTot / summerDay : 0; + operList.inflAmt.summerAvg = (summerDay > 0) ? operList.inflAmt.summerTot / summerDay : 0; + operList.sumFlow.summerAvg = (summerDay > 0) ? operList.sumFlow.summerTot / summerDay : 0; + operList.returnFlow.summerAvg = (summerDay > 0) ? operList.returnFlow.summerTot / summerDay : 0; + operList.efflFlow.summerAvg = (summerDay > 0) ? operList.efflFlow.summerTot / summerDay : 0; // 하절기 강우시 평균 - operList.inFlow.summerRainy = (summerRainDay > 0)? operList.inFlow.summerRainy / summerRainDay : 0; - operList.inflAmt.summerRainy = (summerRainDay > 0)? operList.inflAmt.summerRainy / summerRainDay : 0; - operList.sumFlow.summerRainy = (summerRainDay > 0)? operList.sumFlow.summerRainy / summerRainDay : 0; - operList.returnFlow.summerRainy = (summerRainDay > 0)? operList.returnFlow.summerRainy / summerRainDay : 0; - operList.efflFlow.summerRainy = (summerRainDay > 0)? operList.efflFlow.summerRainy / summerRainDay : 0; + operList.inFlow.summerRainy = (summerRainDay > 0) ? operList.inFlow.summerRainy / summerRainDay : 0; + operList.inflAmt.summerRainy = (summerRainDay > 0) ? operList.inflAmt.summerRainy / summerRainDay : 0; + operList.sumFlow.summerRainy = (summerRainDay > 0) ? operList.sumFlow.summerRainy / summerRainDay : 0; + operList.returnFlow.summerRainy = (summerRainDay > 0) ? operList.returnFlow.summerRainy / summerRainDay : 0; + operList.efflFlow.summerRainy = (summerRainDay > 0) ? operList.efflFlow.summerRainy / summerRainDay : 0; // 하절기 청천시 평균 - operList.inFlow.summerSunny = (summerChungchunDay > 0)? operList.inFlow.summerSunny / summerChungchunDay : 0; - operList.inflAmt.summerSunny = (summerChungchunDay > 0)? operList.inflAmt.summerSunny / summerChungchunDay : 0; - operList.sumFlow.summerSunny = (summerChungchunDay > 0)? operList.sumFlow.summerSunny / summerChungchunDay : 0; - operList.returnFlow.summerSunny = (summerChungchunDay > 0)? operList.returnFlow.summerSunny / summerChungchunDay : 0; - operList.efflFlow.summerSunny = (summerChungchunDay > 0)? operList.efflFlow.summerSunny / summerChungchunDay : 0; + operList.inFlow.summerSunny = (summerChungchunDay > 0) ? operList.inFlow.summerSunny / summerChungchunDay : 0; + operList.inflAmt.summerSunny = (summerChungchunDay > 0) ? operList.inflAmt.summerSunny / summerChungchunDay : 0; + operList.sumFlow.summerSunny = (summerChungchunDay > 0) ? operList.sumFlow.summerSunny / summerChungchunDay : 0; + operList.returnFlow.summerSunny = (summerChungchunDay > 0) ? operList.returnFlow.summerSunny / summerChungchunDay : 0; + operList.efflFlow.summerSunny = (summerChungchunDay > 0) ? operList.efflFlow.summerSunny / summerChungchunDay : 0; // 동절기 전기간 평균 - operList.inFlow.winterAvg = (winterDay > 0)? operList.inFlow.winterTot / winterDay : 0; - operList.inflAmt.winterAvg = (winterDay > 0)? operList.inflAmt.winterTot / winterDay : 0; - operList.sumFlow.winterAvg = (winterDay > 0)? operList.sumFlow.winterTot / winterDay : 0; - operList.returnFlow.winterAvg = (winterDay > 0)? operList.returnFlow.winterTot / winterDay : 0; - operList.efflFlow.winterAvg = (winterDay > 0)? operList.efflFlow.winterTot / winterDay : 0; + operList.inFlow.winterAvg = (winterDay > 0) ? operList.inFlow.winterTot / winterDay : 0; + operList.inflAmt.winterAvg = (winterDay > 0) ? operList.inflAmt.winterTot / winterDay : 0; + operList.sumFlow.winterAvg = (winterDay > 0) ? operList.sumFlow.winterTot / winterDay : 0; + operList.returnFlow.winterAvg = (winterDay > 0) ? operList.returnFlow.winterTot / winterDay : 0; + operList.efflFlow.winterAvg = (winterDay > 0) ? operList.efflFlow.winterTot / winterDay : 0; // 동절기 청천시 평균 - operList.inFlow.winterSunny = (winterChungchuDay > 0)? operList.inFlow.winterSunny / winterChungchuDay : 0; - operList.inflAmt.winterSunny = (winterChungchuDay > 0)? operList.inflAmt.winterSunny / winterChungchuDay : 0; - operList.sumFlow.winterSunny = (winterChungchuDay > 0)? operList.sumFlow.winterSunny / winterChungchuDay : 0; - operList.returnFlow.winterSunny = (winterChungchuDay > 0)? operList.returnFlow.winterSunny / winterChungchuDay : 0; - operList.efflFlow.winterSunny = (winterChungchuDay > 0)? operList.efflFlow.winterSunny / winterChungchuDay : 0; + operList.inFlow.winterSunny = (winterChungchuDay > 0) ? operList.inFlow.winterSunny / winterChungchuDay : 0; + operList.inflAmt.winterSunny = (winterChungchuDay > 0) ? operList.inflAmt.winterSunny / winterChungchuDay : 0; + operList.sumFlow.winterSunny = (winterChungchuDay > 0) ? operList.sumFlow.winterSunny / winterChungchuDay : 0; + operList.returnFlow.winterSunny = (winterChungchuDay > 0) ? operList.returnFlow.winterSunny / winterChungchuDay : 0; + operList.efflFlow.winterSunny = (winterChungchuDay > 0) ? operList.efflFlow.winterSunny / winterChungchuDay : 0; // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) operationalStatusList[0].yearAvg = roundUp(operList.inFlow.yearAvg, 0); // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) @@ -1656,15 +1695,18 @@ export const dashBoardReducer = ( operationalStatusList[0].winterSunnyMax = roundUp(operList.inFlow.winterSunnyMax, 0); // 동절기 유입 최대 operationalStatusList[0].winterSunnyAvg = roundUp(operList.inFlow.winterAvg, 0); // 동절기 유입 평균 - // 지하수유입량 + // 청천시 유입(순수하수) 평균 const usage = operList.inflAmt.yearSunny / cntSunnyDay; // 연간 청천 순수하수 평균 const summerUsage = operList.inflAmt.summerSunny; // 하절기 청천 순수하수 평균 const winterUsage = operList.inflAmt.winterSunny; // 동절기 청천 순수하수 평균 - - // 임시 계산변수값들 메인에 대입 - operationalStatusList[0].groundWaterAvg = Math.round((usage - (usage * 0.65 * OSU_PERCENT)) * 100) / 100; - operationalStatusList[0].groundWaterSummer = Math.round((summerUsage - (summerUsage * 0.65 * OSU_PERCENT)) * 100) / 100; - operationalStatusList[0].groundWaterWinter = Math.round((winterUsage - (winterUsage * 0.65 * OSU_PERCENT)) * 100) / 100; + // 물사용량 = 유입평균 * 0.65 + const wtrUsg = operList.inflAmt.yearAvg * 0.65; // 연간 물사용량 평균 + const wtrUsgSummer = operList.inflAmt.summerAvg * 0.65; // 하절기 물사용량 평균 + const wtrUsgWinter = operList.inflAmt.winterAvg * 0.65; // 동절기 물사용량 평균 + // 지하수유입량 + operationalStatusList[0].groundWaterAvg = Math.round((usage - (wtrUsg * OSU_PERCENT)) * 100) / 100; + operationalStatusList[0].groundWaterSummer = Math.round((summerUsage - (wtrUsgSummer * OSU_PERCENT)) * 100) / 100; + operationalStatusList[0].groundWaterWinter = Math.round((winterUsage - (wtrUsgWinter * OSU_PERCENT)) * 100) / 100; // 오염물질 // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) @@ -1759,8 +1801,9 @@ export const dashBoardReducer = ( const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd, mainGraphData); // 수질 데이터 청천시, 강우시 재계산 // 총인설비가 없을 경우 제외 - console.log('총인시설 여부 : ', mainGraphData.data.wqltObjs?.tpFctYn); - const tpFctYn = mainGraphData.data.wqltObjs?.tpFctYn; + console.log('총인시설 여부 : ', mainGraphData.data.wqltObjs?.[0].tpFctYn); + + const tpFctYn = mainGraphData.data.wqltObjs?.[0].tpFctYn; // console.log('rtnData : ', rtnData); if (tpFctYn !== 'Y') { @@ -1947,6 +1990,24 @@ export const dashBoardReducer = ( })); } + let res2: any = { data: [] }; + // 이미 조회된 데이터가 있는지 확인 (연도와 시설코드가 같을 때만) + if (state.RainManage.flowRateYear === searchYear && state.RainManage.flowRateFcltyCd === fcltyCd && state.RainManage.flowRateData) { + res2 = state.RainManage.flowRateData; + } else { + res2 = await fetchFlowRateModalList(fcltyCd, searchYear); // /fclt/flow/ - 일별 유량 조회 + // 조회된 데이터 저장 + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + flowRateData: res2, + flowRateYear: searchYear, + flowRateFcltyCd: fcltyCd, + } + })); + } + set((state: DashBoardType) => ({ ...state, RainManage: { @@ -1970,10 +2031,9 @@ export const dashBoardReducer = ( const itemList = ['계', '3~10mm 미만', '10~20mm 미만', '20~30mm 미만', '30~40mm 미만', '40~50mm 미만', '50~60mm 미만', '60mm 이상']; const rainRate = ['0', '0', '0', '0', '0', '0', '0', '0']; - const rainDate = [0, 0, 0, 0, 0, 0, 0, 0]; - const inflAmtCnt = [0, 0, 0, 0, 0, 0, 0, 0]; - const inflAmnt = [0, 0, 0, 0, 0, 0, 0, 0]; - const fcltyCpct = [0, 0, 0, 0, 0, 0, 0, 0]; + const rainDate: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; + const inflAmnt: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; + const fcltyCpct: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltBod: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltCod: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltSs: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; @@ -2016,6 +2076,7 @@ export const dashBoardReducer = ( let totEfflWqltSs = 0; let totEfflWqltTn = 0; let totEfflWqltTp = 0; + let totInflAmnt = 0; rainEffectList.forEach((item: RainManageListProps) => { totInflAssctBfrWqltBod += item.inflAssctBfrWqltBod ? Number(item.inflAssctBfrWqltBod.toString().trim()) : 0; @@ -2028,13 +2089,13 @@ export const dashBoardReducer = ( totEfflWqltSs += item.efflWqltSs ? Number(item.efflWqltSs.toString().trim()) : 0; totEfflWqltTn += item.efflWqltTn ? Number(item.efflWqltTn.toString().trim()) : 0; totEfflWqltTp += item.efflWqltTp ? Number(item.efflWqltTp.toString().trim()) : 0; + totInflAmnt += item.inflAmnt ? Number(item.inflAmnt.toString().trim()) : 0; const toBeRain = item.toBeInfoRnDay ? Number(item.toBeInfoRnDay) : 0; if (toBeRain >= 3 && toBeRain < 10) { - rainDate[1] = Number(rainDate[1] || 0) + 1; - inflAmtCnt[1] = Number(inflAmtCnt[1] || 0) + 1; - inflAmnt[1] = Number(inflAmnt[1] || 0) + Number(item.inflAmnt || 0); + rainDate[1] = (rainDate[1] || 0) + 1; + inflAmnt[1] = (inflAmnt[1] || 0) + Number(item.inflAmnt || 0); fcltyCpct[1] = 0; inflAssctBfrWqltBodCnt[1] = Number(inflAssctBfrWqltBodCnt[1] || 0) + 1; inflAssctBfrWqltBod[1] = Number(inflAssctBfrWqltBod[1] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2057,9 +2118,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[1] = Number(efflWqltTpCnt[1] || 0) + 1; efflWqltTp[1] = Number(efflWqltTp[1] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 10 && toBeRain < 20) { - rainDate[2] = Number(rainDate[2] || 0) + 1; - inflAmtCnt[2] = Number(inflAmtCnt[2] || 0) + 1; - inflAmnt[2] = Number(inflAmnt[2] || 0) + Number(item.inflAmnt || 0); + rainDate[2] = (rainDate[2] || 0) + 1; + inflAmnt[2] = (inflAmnt[2] || 0) + Number(item.inflAmnt || 0); fcltyCpct[2] = 0; inflAssctBfrWqltBodCnt[2] = Number(inflAssctBfrWqltBodCnt[2] || 0) + 1; inflAssctBfrWqltBod[2] = Number(inflAssctBfrWqltBod[2] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2082,9 +2142,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[2] = Number(efflWqltTpCnt[2] || 0) + 1; efflWqltTp[2] = Number(efflWqltTp[2] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 20 && toBeRain < 30) { - rainDate[3] = Number(rainDate[3] || 0) + 1; - inflAmtCnt[3] = Number(inflAmtCnt[3] || 0) + 1; - inflAmnt[3] = Number(inflAmnt[3] || 0) + Number(item.inflAmnt || 0); + rainDate[3] = (rainDate[3] || 0) + 1; + inflAmnt[3] = (inflAmnt[3] || 0) + Number(item.inflAmnt || 0); fcltyCpct[3] = 0; inflAssctBfrWqltBodCnt[3] = Number(inflAssctBfrWqltBodCnt[3] || 0) + 1; inflAssctBfrWqltBod[3] = Number(inflAssctBfrWqltBod[3] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2107,9 +2166,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[3] = Number(efflWqltTpCnt[3] || 0) + 1; efflWqltTp[3] = Number(efflWqltTp[3] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 30 && toBeRain < 40) { - rainDate[4] = Number(rainDate[4] || 0) + 1; - inflAmtCnt[4] = Number(inflAmtCnt[4] || 0) + 1; - inflAmnt[4] = Number(inflAmnt[4] || 0) + Number(item.inflAmnt || 0); + rainDate[4] = (rainDate[4] || 0) + 1; + inflAmnt[4] = (inflAmnt[4] || 0) + Number(item.inflAmnt || 0); fcltyCpct[4] = item.inflAmnt && Number(item.inflAmnt) !== 0 ? Number(Math.round(Number(item.inflAmnt) / Number(item.fctCpc) * 10) / 10) : 0; inflAssctBfrWqltBodCnt[4] = Number(inflAssctBfrWqltBodCnt[4] || 0) + 1; inflAssctBfrWqltBod[4] = Number(inflAssctBfrWqltBod[4] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2132,9 +2190,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[4] = Number(efflWqltTpCnt[4] || 0) + 1; efflWqltTp[4] = Number(efflWqltTp[4] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 40 && toBeRain < 50) { - rainDate[5] = Number(rainDate[5] || 0) + 1; - inflAmtCnt[5] = Number(inflAmtCnt[5] || 0) + 1; - inflAmnt[5] = Number(inflAmnt[5] || 0) + Number(item.inflAmnt || 0); + rainDate[5] = (rainDate[5] || 0) + 1; + inflAmnt[5] = (inflAmnt[5] || 0) + Number(item.inflAmnt || 0); fcltyCpct[5] = 0; inflAssctBfrWqltBodCnt[5] = Number(inflAssctBfrWqltBodCnt[5] || 0) + 1; inflAssctBfrWqltBod[5] = Number(inflAssctBfrWqltBod[5] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2157,9 +2214,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[5] = Number(efflWqltTpCnt[5] || 0) + 1; efflWqltTp[5] = Number(efflWqltTp[5] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 50 && toBeRain < 60) { - rainDate[6] = Number(rainDate[6] || 0) + 1; - inflAmtCnt[6] = Number(inflAmtCnt[6] || 0) + 1; - inflAmnt[6] = Number(inflAmnt[6] || 0) + Number(item.inflAmnt || 0); + rainDate[6] = (rainDate[6] || 0) + 1; + inflAmnt[6] = (inflAmnt[6] || 0) + Number(item.inflAmnt || 0); fcltyCpct[6] = 0; inflAssctBfrWqltBodCnt[6] = Number(inflAssctBfrWqltBodCnt[6] || 0) + 1; inflAssctBfrWqltBod[6] = Number(inflAssctBfrWqltBod[6] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2182,9 +2238,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[6] = Number(efflWqltTpCnt[6] || 0) + 1; efflWqltTp[6] = Number(efflWqltTp[6] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 60) { - rainDate[7] = Number(rainDate[7] || 0) + 1; - inflAmtCnt[7] = Number(inflAmtCnt[7] || 0) + 1; - inflAmnt[7] = Number(inflAmnt[7] || 0) + Number(item.inflAmnt || 0); + rainDate[7] = (rainDate[7] || 0) + 1; + inflAmnt[7] = (inflAmnt[7] || 0) + Number(item.inflAmnt || 0); fcltyCpct[7] = 0; inflAssctBfrWqltBodCnt[7] = Number(inflAssctBfrWqltBodCnt[7] || 0) + 1; inflAssctBfrWqltBod[7] = Number(inflAssctBfrWqltBod[7] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2209,6 +2264,40 @@ export const dashBoardReducer = ( } }); + // 유량 = 순수하수 + 연계처리수 + 총인설비반류수 + const rainEffFlowList: any[] = CalcRainEffect(res2.data, 'RAIN_DAY'); + totInflAmnt = 0; inflAmnt.fill(0); rainDate.fill(0); + rainEffFlowList.forEach((item: any) => { // --일별 유량 start + const toBeRain = item.toBeInfoRnDay ? Number(item.toBeInfoRnDay) : 0; + const inflAmntOne = item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0; + const sumFlowOne = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; + const returnAmntOne = item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0; + const inflowOne = inflAmntOne + sumFlowOne + returnAmntOne; + totInflAmnt = totInflAmnt + inflowOne; // 유량합계 + if (toBeRain >= 3 && toBeRain < 10) { + inflAmnt[1] = (inflAmnt[1] || 0) + inflowOne; + rainDate[1] = (rainDate[1] || 0) + 1; + } else if (toBeRain >= 10 && toBeRain < 20) { + inflAmnt[2] = (inflAmnt[2] || 0) + inflowOne; + rainDate[2] = (rainDate[2] || 0) + 1; + } else if (toBeRain >= 20 && toBeRain < 30) { + inflAmnt[3] = (inflAmnt[3] || 0) + inflowOne; + rainDate[3] = (rainDate[3] || 0) + 1; + } else if (toBeRain >= 30 && toBeRain < 40) { + inflAmnt[4] = (inflAmnt[4] || 0) + inflowOne; + rainDate[4] = (rainDate[4] || 0) + 1; + } else if (toBeRain >= 40 && toBeRain < 50) { + inflAmnt[5] = (inflAmnt[5] || 0) + inflowOne; + rainDate[5] = (rainDate[5] || 0) + 1; + } else if (toBeRain >= 50 && toBeRain < 60) { + inflAmnt[6] = (inflAmnt[6] || 0) + inflowOne; + rainDate[6] = (rainDate[6] || 0) + 1; + } else if (toBeRain >= 60) { + inflAmnt[7] = (inflAmnt[7] || 0) + inflowOne; + rainDate[7] = (rainDate[7] || 0) + 1; + } + }); // --일별 유량 end + // Process the data and create rain management list if (res.data && res.data.dsWqltObjs && res.data.dsWqltObjs.length > 0) { // 설계 유입수질 데이터 가져오기 - 0값이 있으면 이전 차수에서 가져오기 @@ -2267,16 +2356,8 @@ export const dashBoardReducer = ( return count > 0 ? Number((value / count)) : 0; }; - // 데이터 있는 항목만 계산 - let dataIsCount = 0; - for (let idx = 0; idx < inflAmnt.length; idx++) { - if (Number(inflAmnt[idx]) > 0) { - dataIsCount++; - } - } - - for (let idx = 0; idx < inflAmnt.length; idx++) { - inflAmnt[idx] = calculateAverage(Number(inflAmnt[idx]), Number(inflAmtCnt[idx])); + for (let idx = 1; idx < inflAmnt.length; idx++) { + inflAmnt[idx] = rainDate[idx] ? Math.round((inflAmnt[idx] || 0) / (rainDate[idx] || 0)) : 0; inflAssctBfrWqltBod[idx] = calculateAverage(Number(inflAssctBfrWqltBod[idx]), Number(inflAssctBfrWqltBodCnt[idx])); inflAssctBfrWqltToc[idx] = calculateAverage(Number(inflAssctBfrWqltToc[idx]), Number(inflAssctBfrWqltTocCnt[idx])); inflAssctBfrWqltSs[idx] = calculateAverage(Number(inflAssctBfrWqltSs[idx]), Number(inflAssctBfrWqltSsCnt[idx])); @@ -2294,7 +2375,9 @@ export const dashBoardReducer = ( return Number((arr.slice(1).reduce((sum, val) => sum + Number(val), 0))); }; - inflAmnt[0] = calculateAverage(calculateTotal(inflAmnt), dataIsCount); + + // console.log(totInflAmnt); + inflAmnt[0] = Math.round((totInflAmnt / totItemCnt)); // calculateAverage(totInflAmnt, totItemCnt); fcltyCpct[0] = calculateTotal(fcltyCpct); inflAssctBfrWqltBod[0] = Number((Math.round((totInflAssctBfrWqltBod / totItemCnt) * 10) / 10).toFixed(1)); inflAssctBfrWqltToc[0] = Number((Math.round((totInflAssctBfrWqltToc / totItemCnt) * 10) / 10).toFixed(1)); diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 94d4b9326..7bec0be97 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -1,6 +1,6 @@ import { getFetch } from "@/app/components/api"; import type { TableUpperProps } from "../dashboard"; -import DataForm, { roundNumber } from "@/app/components/common/DataForm"; +import DataForm from "@/app/components/common/DataForm"; import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty"; import CommaToNumber from "@/app/components/common/CommaToNumber"; @@ -12,34 +12,34 @@ import CommaToNumber from "@/app/components/common/CommaToNumber"; /** * (1) 메인페이지 */ -const FlowRateSearchLabelArray:string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; +const FlowRateSearchLabelArray: string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; export type flowRateListProps = { - bscFctCd : string, - sido : string, - gugun : string, - bscFctNm : string, - daddr : string, - fctCpc : number, - lclgvrnmntNm : string, - totInflAmnt : number | '', - inflAmnt : number | '', - sumFlow : number | '', - returnAmnt : number | '', - efflAmnt : number | '', - rgnNm : string, - rvbsn : string, - lgbsn : string, - mdmbsn : string, - infoRnDay : number | '', + bscFctCd: string, + sido: string, + gugun: string, + bscFctNm: string, + daddr: string, + fctCpc: number, + lclgvrnmntNm: string, + totInflAmnt: number | '', + inflAmnt: number | '', + sumFlow: number | '', + returnAmnt: number | '', + efflAmnt: number | '', + rgnNm: string, + rvbsn: string, + lgbsn: string, + mdmbsn: string, + infoRnDay: number | '', } export interface ExcelType { 시설코드: string, - 권역:string|'', - 단위유역:string|'', - 중권역:string|'', - 환경청:string|'', + 권역: string | '', + 단위유역: string | '', + 중권역: string | '', + 환경청: string | '', 시도: string, 시군구: string, 시설이름: string, @@ -66,105 +66,105 @@ export type modalExcelType = { * (2) 모달 */ export interface FlowRateModalInterface { - msrDt : string, - totInflAmnt : number | '', - inflAmnt : number | '', - sumFlow : number | '', - returnAmnt : number | '', - efflAmnt : number | '', - infoRnDay : number | string | '', - rainEffectDay : number | string | '' , - noProcessInflAmnt : number | string | '' + msrDt: string, + totInflAmnt: number | '', + inflAmnt: number | '', + sumFlow: number | '', + returnAmnt: number | '', + efflAmnt: number | '', + infoRnDay: number | string | '', + rainEffectDay: number | string | '', + noProcessInflAmnt: number | string | '' } export type FlowRateModalProps = { - msrDt : string, - totInflAmnt : number, - inflAmnt : number, - sumFlow : number, - returnAmnt : number, - efflAmnt : number, - infoRnDay : number | string | '', - rainEffectDay : number | string | '', - noProcessInflAmnt : number | string | '' + msrDt: string, + totInflAmnt: number, + inflAmnt: number, + sumFlow: number, + returnAmnt: number, + efflAmnt: number, + infoRnDay: number | string | '', + rainEffectDay: number | string | '', + noProcessInflAmnt: number | string | '' } /**==================================== * Store - data ====================================*/ - /** - * (1) 메인페이지 - */ +/** +* (1) 메인페이지 +*/ // 리스트 (행정별) -const upHeadList1:TableUpperProps[] = [ +const upHeadList1: TableUpperProps[] = [ { id: "A", title: "행정명", row: 0, colSpan: 2, widthPercent: 16 }, - { id: "sido", title: "시도", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "gugun", title: "시군구", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10}, + { id: "sido", title: "시도", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "gugun", title: "시군구", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 }, { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, - { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 } + { id: "fctCpc", title: "시설용량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "efflAmnt", title: '방류량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 } ]; // 리스트 (권역별) -const upHeadList2:TableUpperProps[] = [ +const upHeadList2: TableUpperProps[] = [ { id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 24 }, - { id: "rvbsn", title: "권역", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "lgbsn", title: "단위유역", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "mdmbsn", title: "중권역", upName:"upChangeRe", row:1, widthPercent: 8 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe", row: 1, widthPercent: 8 }, { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 }, { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, - { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 10 }, - { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 } + { id: "fctCpc", title: "시설용량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "efflAmnt", title: '방류량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 } ]; // 리스트 (환경청별별) -const upHeadList3:TableUpperProps[] = [ +const upHeadList3: TableUpperProps[] = [ { id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 15 }, - { id: "rvbsn", title: "권역", upName:"upChangeRe1", row:1, widthPercent: 5 }, - { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", row:1, widthPercent: 5 }, - { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", row:1, widthPercent: 5 }, - { id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 7 }, - { id: "B", title: "행정명", row: 0 ,colSpan: 2, widthPercent: 10 }, - { id: "sido", title: "시도", upName:"upChangeRe2", row:1, widthPercent: 5 }, - { id: "gugun", title: "시군구", upName:"upChangeRe2", row:1, widthPercent: 5 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe1", row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe1", row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe1", row: 1, widthPercent: 5 }, + { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "B", title: "행정명", row: 0, colSpan: 2, widthPercent: 10 }, + { id: "sido", title: "시도", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "gugun", title: "시군구", upName: "upChangeRe2", row: 1, widthPercent: 5 }, { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 7 }, { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, - { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 } + { id: "fctCpc", title: "시설용량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "efflAmnt", title: '방류량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 } ]; -const flowRateList:flowRateListProps[] = [ +const flowRateList: flowRateListProps[] = [ ] /** * (2) 모달 */ -const upHeadListFlowRateModal:TableUpperProps[] = [ - { id: "msrDt", title: "날짜"}, - { id: "totInflAmnt", title: "총 유입량(m³/일)", align:"right"}, - { id: "inflAmnt", title: "하수유입량(m³/일)", align:"right"}, - { id: "sumFlow", title: "연계처리량(m³/일)", align:"right"}, - { id: "returnAmnt", title: "총인 반류수량(m³/일)", align:"right"}, - { id: "efflAmnt", title: "방류량(m³/일)", align:"right"}, - { id: "noProcessInflAmnt", title: "미처리하수 추정량(m³/일)", align:"right"}, - { id: "infoRnDay", title: "강우량(mm/일)", align:"right"} +const upHeadListFlowRateModal: TableUpperProps[] = [ + { id: "msrDt", title: "날짜" }, + { id: "totInflAmnt", title: "총 유입량(m³/일)", align: "right" }, + { id: "inflAmnt", title: "하수유입량(m³/일)", align: "right" }, + { id: "sumFlow", title: "연계처리량(m³/일)", align: "right" }, + { id: "returnAmnt", title: "총인 반류수량(m³/일)", align: "right" }, + { id: "efflAmnt", title: "방류량(m³/일)", align: "right" }, + { id: "noProcessInflAmnt", title: "미처리하수 추정량(m³/일)", align: "right" }, + { id: "infoRnDay", title: "강우량(mm/일)", align: "right" } ] -const modalFlowRateListYear:FlowRateModalProps[] = [ +const modalFlowRateListYear: FlowRateModalProps[] = [ ] /**==================================== @@ -172,12 +172,13 @@ const modalFlowRateListYear:FlowRateModalProps[] = [ ====================================*/ const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { try { - const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const tailStr = partCd ? '/' + partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; const res = await getFetch('fo', url); return { data: res.data, count: res.count } } catch (error) { console.error('시설정보 유량현황 데이터를 가져오는데 실패했습니다:', error); + console.log(error); return { data: [], count: 0 }; } } @@ -186,12 +187,12 @@ export const fetchFlowRateModalList = async (bscFctCd: string, searchYear: strin try { const url = '/fclt/flow/' + bscFctCd + '/' + searchYear; const res = await getFetch('fo', url); - + // msrDt 오름차순으로 정렬 const sortedData = res.data.sort((a: FlowRateModalInterface, b: FlowRateModalInterface) => { return new Date(a.msrDt).getTime() - new Date(b.msrDt).getTime(); }); - + return { data: sortedData } } catch (error) { console.error('시설정보 유량현황 모달 데이터를 가져오는데 실패했습니다:', error); @@ -206,69 +207,69 @@ export const fetchFlowRateModalList = async (bscFctCd: string, searchYear: strin export type FlowRateSearchActions = { searchFlowRateList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; - - searchFlowRateModalList : (bscFctCd: string, searchYear: string) => void; + + searchFlowRateModalList: (bscFctCd: string, searchYear: string) => void; } export type FlowRateSearchType = { FlowRateSearch: { isInit: boolean; - flowRateSearchLabelArray:string[]; + flowRateSearchLabelArray: string[]; }, - FlowRateList : { - isInit : boolean; + FlowRateList: { + isInit: boolean; upHeadList1: TableUpperProps[]; upHeadList2: TableUpperProps[]; upHeadList3: TableUpperProps[]; - flowRateList:flowRateListProps[]; + flowRateList: flowRateListProps[]; flowRateCount: number; excelList: ExcelType[]; isLoading: boolean; }, - FlowRateModal : { - isInit : boolean; - modalFlowRateListYear : FlowRateModalProps[]; - upHeadListFlowRateModalYear : TableUpperProps[]; + FlowRateModal: { + isInit: boolean; + modalFlowRateListYear: FlowRateModalProps[]; + upHeadListFlowRateModalYear: TableUpperProps[]; } } export type FlowRateSearchStore = FlowRateSearchType & FlowRateSearchActions; -const dataFormSetting=(item : flowRateListProps | FlowRateModalProps)=> { +export const dataFormSetting = (item: flowRateListProps | FlowRateModalProps | FlowRateModalInterface) => { DataForm({ type: 'date', column: 'msrDt', item: item as unknown as Record }); - DataForm({ type: 'float0', column: 'totInflAmnt', item: item as unknown as Record}); - DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record}); - DataForm({ type: 'float0', column: 'sumFlow', item: item as unknown as Record}); - DataForm({ type: 'float0', column: 'efflWqltBod', item: item as unknown as Record}); - DataForm({ type: 'float0', column: 'returnAmnt', item: item as unknown as Record}); - DataForm({ type: 'float0', column: 'efflAmnt', item: item as unknown as Record}); + DataForm({ type: 'float0', column: 'totInflAmnt', item: item as unknown as Record }); + DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record }); + DataForm({ type: 'float0', column: 'sumFlow', item: item as unknown as Record }); + DataForm({ type: 'float0', column: 'efflWqltBod', item: item as unknown as Record }); + DataForm({ type: 'float0', column: 'returnAmnt', item: item as unknown as Record }); + DataForm({ type: 'float0', column: 'efflAmnt', item: item as unknown as Record }); } -export const flowRateSearchInitState:FlowRateSearchType = { +export const flowRateSearchInitState: FlowRateSearchType = { FlowRateSearch: { isInit: false, flowRateSearchLabelArray: FlowRateSearchLabelArray, }, - FlowRateList : { - isInit : false, - upHeadList1 : upHeadList1, - upHeadList2 : upHeadList2, - upHeadList3 : upHeadList3, - flowRateList : flowRateList, - flowRateCount : 0, + FlowRateList: { + isInit: false, + upHeadList1: upHeadList1, + upHeadList2: upHeadList2, + upHeadList3: upHeadList3, + flowRateList: flowRateList, + flowRateCount: 0, excelList: [], isLoading: true, }, - FlowRateModal : { - isInit : false, - upHeadListFlowRateModalYear : upHeadListFlowRateModal, - modalFlowRateListYear : modalFlowRateListYear, + FlowRateModal: { + isInit: false, + upHeadListFlowRateModalYear: upHeadListFlowRateModal, + modalFlowRateListYear: modalFlowRateListYear, } } -export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => FlowRateSearchType) => void)=>FlowRateSearchActions=(set: (fn: (state: FlowRateSearchType) => FlowRateSearchType) => void) => { +export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => FlowRateSearchType) => void) => FlowRateSearchActions = (set: (fn: (state: FlowRateSearchType) => FlowRateSearchType) => void) => { return { searchFlowRateList: async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { set((state: FlowRateSearchType) => ({ @@ -288,7 +289,7 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow return item; }); - if(pageSize>5000){ + if (pageSize > 5000) { rtnData.forEach((item: flowRateListProps) => { excelDownList.push({ 시설코드: item.bscFctCd, @@ -312,15 +313,15 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow set((state: FlowRateSearchType) => ({ ...state, - FlowRateList: pageSize<5000?{ + FlowRateList: pageSize < 5000 ? { ...state.FlowRateList, flowRateList: rtnData, flowRateCount: res.count, - isLoading : false, - }:{ + isLoading: false, + } : { ...state.FlowRateList, excelList: excelDownList, - isLoading : false, + isLoading: false, }, })) }, @@ -329,44 +330,48 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow const inflData = CalcRainEffect(res.data); const res2 = await fetchFacilityWaterQltyListHist(searchYear, bscFctCd); - const wqltData = CalcRainEffect(res2?.data.wqltObjs); - + const wqltData = res2?.data.wqltObjs; + //const wqltData = CalcRainEffect(res2?.data.wqltObjs); /** - * [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]​ - /강우시 일별유입BOD) + * [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)] / 강우시 일별유입BOD */ - //let rainInflAmnt = 0; - let sunnyInflAmnt = 0; - let sunnyBod = 0; - //let rainDay = 0; + let sunnyInflAmnt = 0; // 청천시 일별유입유량 + let sunnyBod = 0; // 청천시 일별유입BOD let sunnyDay = 0; - - inflData.forEach(item => { - if(item.rainEffectDay == 1){ - //rainDay += 1; - //rainInflAmnt += Number(item.inflAmnt); + let rainEffectDay = 0; + wqltData?.forEach(item => { + if (item.infoRnDay == null) item.infoRnDay = 0; + if (Number(item.infoRnDay) >= 3) { + rainEffectDay = 2; } else { - const msrDt = item.msrDt.replaceAll('-',''); + rainEffectDay--; + } + if (rainEffectDay < 0) { //청천시 sunnyDay += 1; sunnyInflAmnt += Number(item.inflAmnt); - sunnyBod += Number(wqltData.filter((wqitem)=>wqitem.msrDt === msrDt)[0].inflAssctBfrWqltBod); + sunnyBod += Number(item.inflAssctBfrWqltBod); } }); - //const yearRainAmnt = rainInflAmnt===0?0:rainInflAmnt / rainDay; - const yearSunnyAmnt = sunnyInflAmnt===0?0:sunnyInflAmnt / sunnyDay; - const yearSunnyBod = sunnyBod===0?0:sunnyBod / sunnyDay; - + const yearSunnyAmnt = sunnyDay > 0 ? sunnyInflAmnt / sunnyDay : 0; // 청천시 연평균유입유량 + const yearSunnyBod = sunnyDay > 0 ? sunnyBod / sunnyDay : 0; // 청천시 연평균유입BOD + console.log(inflData); const rtnData = inflData.map((item: FlowRateModalProps) => { - const dayBod = Number(wqltData.filter(wqitem=>wqitem.msrDt === item.msrDt.replaceAll('-',''))[0].inflAssctBfrWqltBod); - const noProcessInflAmnt = roundNumber(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod, 0) - - item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0); - item.noProcessInflAmnt = noProcessInflAmnt && Number(noProcessInflAmnt.replaceAll(',','')) > 0 ? noProcessInflAmnt : ''; - dataFormSetting(item); - return item; + const targetWqItem = wqltData?.find(wqitem => wqitem.msrDt === item.msrDt.replaceAll('-', '')); + const dayBod = targetWqItem ? Number(targetWqItem.inflAssctBfrWqltBod) : 0; + const noProcessInflAmnt = Math.round(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod) + const totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0); + + return { + ...item, + totInflAmnt, + noProcessInflAmnt: noProcessInflAmnt && noProcessInflAmnt > 0 ? noProcessInflAmnt : '', + msrDt: (item.msrDt.length === 8 && !item.msrDt.includes('-')) ? + `${item.msrDt.slice(0, 4)}-${item.msrDt.slice(4, 6)}-${item.msrDt.slice(6, 8)}` + : item.msrDt, + }; }); - + console.log(rtnData); set((state: FlowRateSearchType) => ({ ...state, FlowRateModal: { diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx index e9857af71..1f4e8ce7e 100644 --- a/apps/fo/app/store/sewageOccur/index.tsx +++ b/apps/fo/app/store/sewageOccur/index.tsx @@ -29,7 +29,7 @@ export type SewageOccurProps = { mdmbsn: string, msrDt: string, } -export type modalTableType = { msrDt: string, waterUsage: number, swageChangePercent: number, estimationSewage: number }; +export type modalTableType = { msrDt: string, waterUsage: number, swageChangePercent: number, estimationSewage: number, } export type SewageOccurDetailProps = { cnt: number, sum: number, @@ -39,6 +39,8 @@ export type SewageOccurDetailProps = { sumWtrUsg: number, // 물사용량 합 avgWtrUsg: number, // 일평균 물사용량 monWtrUsg: number, // 월 물사용량 + maxEstSewerage: number, // 최대 오수발생량 추정 + minEstSewerage: number, // 최소 오수발생량 추정 } export type WtrUsgYmProps = { bscFctCd: string, // 처리구역시설코드 @@ -332,6 +334,7 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = // wtrUsgRes.data.forEach(fclt => { // wtrUsgMap[fclt.bscFctCd] = fclt.wtrUsg; // }); + let maxEstimationSewage = 0, minEstimationSewage = 999999999; for (const item of sewageOccurPropsList) { const detailList = soccurDetailRes?.data[item.bscFctCd]; @@ -367,18 +370,16 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = // console.log("totWaterUsage:", totWaterUsage); const count = detailList ? detailList.length : 0; - const avg = count == 0 ? 0 : totWaterUsage / count; // 일평균 유입량 - item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); // 물사용량 = 일평균 유입량 * 65% + const avg = count == 0 ? 0 : totWaterUsage / count; // 연간 하수유입량(m³/일) + item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); // 물사용량 = 연간 하수유입량(m³/일) * 65% : 실제 수용가의 물사용량 없는 경우 if (wtrUsgYearTotal > 0 && wtrUsgYearDays > 0) { - item.waterUsage = wtrUsgYearDays > 0 ? wtrUsgYearTotal / wtrUsgYearDays : 0; // 일평균 물사용량 + item.waterUsage = wtrUsgYearDays > 0 ? wtrUsgYearTotal / wtrUsgYearDays : 0; // 일평균 물사용량: 실제 수용가의 물사용량 } item.sewageInputYear = parseFloat(avg.toFixed(2)); // 연간 하수유입량(m³/일) item.sewageInputChungchun = parseFloat((chungcunSumFlow === 0 ? 0 : (chungcunSumFlow / sumChungcunDay)).toFixed(2)); // 청천시 하수유입량 item.estimationSewage = parseFloat((item.waterUsage * OSU_PERCENT).toFixed(2)); // 오수발생량 추정(m³/일) - if (item.bscFctCd === '11200PB001R') { - console.log('chungcunSumFlow:', chungcunSumFlow); - console.log('sumChungcunDay:', sumChungcunDay); - } + if (item.estimationSewage > maxEstimationSewage) maxEstimationSewage = item.estimationSewage; + if (item.estimationSewage < minEstimationSewage) minEstimationSewage = item.estimationSewage; // 반올림 처리 ["fctCpc", "waterUsage", "swageChangePercent", "estimationSewage", "sewageInputYear", "sewageInputChungchun"].forEach( (key) => (item[key] = roundNumber(item[key], 0)) @@ -427,93 +428,11 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = })); } - /* fetchSewageOccurList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm).then(async (res) => { - const excelDownList: ExcelType[] = []; - const data = res.data; - // Promise.all을 사용하여 모든 비동기 작업이 완료될 때까지 기다림 - const calData = await Promise.all(data.map(async (item: SewageOccurProps) => { - item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; - item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; - item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); - item.swageChangePercent = 90; - - const bscFctCd = item.bscFctCd; - const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as FlowResponse; - - let sumChungcunDay = 0; - let chungcunSumFlow = 0; - let totWaterUsage = 0; - - // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) - const rainEffectData = CalcRainEffect(res2.data); - - rainEffectData.forEach((item: FlowDataItem) => { - - if(Number(item.rainEffectDay) === 0){ - chungcunSumFlow += Number(item.inflAmnt); - sumChungcunDay += 1; - } - - totWaterUsage += Number(item.inflAmnt); - }); - const avg = totWaterUsage /res2.count; - item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); - item.sewageInputYear = parseFloat(avg.toFixed(2)); - item.sewageInputChungchun = parseFloat((chungcunSumFlow===0?0:(chungcunSumFlow / sumChungcunDay)).toFixed(2)); - item.estimationSewage = parseFloat((item.waterUsage * (item.swageChangePercent/100)).toFixed(2)); - return item; - })); - - calData.forEach((item: SewageOccurProps) => { - DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record }); - DataForm({ type: 'float0', column: 'waterUsage', item: item as unknown as Record }); - DataForm({ type: 'float0', column: 'swageChangePercent', item: item as unknown as Record }); - DataForm({ type: 'float0', column: 'estimationSewage', item: item as unknown as Record }); - DataForm({ type: 'float0', column: 'sewageInputYear', item: item as unknown as Record }); - DataForm({ type: 'float0', column: 'sewageInputChungchun', item: item as unknown as Record }); - }); - - if(pageSize>5000){ - calData.forEach((item: SewageOccurProps) => { - excelDownList.push({ - 시설코드: item.bscFctCd, - 권역: item.rvbsn, - 단위유역: item.lgbsn, - 중권역: item.mdmbsn, - 환경청: item.rgnNm, - 시설명: item.bscFctNm, - 시도: item.sidoNm, - 시군구: item.sggNm, - 주소: item.daddr, - "시설용량(m³/일)": item.fctCpc, - "물사용량(m³/일)": item.waterUsage, - "오수전환율(%)": item.swageChangePercent, - "오수발생량추정(m³/일)": item.estimationSewage, - "연간하수유입량(m³/일)": item.sewageInputYear, - "청천시하수유입량(m³/일)": item.sewageInputChungchun, - }); - }); - } - // 조회 데이터 설정 - set((state: any) => ({ - ...state, - SewageOccur: pageSize<5000?{ - ...state.SewageOccur, - sewageOccurList: calData, - sewageOccurCount: res.count, - isLoading : false, - }:{ - ...state.SewageOccur, - excelList: excelDownList, - isLoading : false, - }, - })) - }); */ }, searchSewageOccurDetailList: async (bscFctCd: string, searchYear: string, startYm?: string, endYm?: string) => { const fcltCdList = [bscFctCd]; - const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); + const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); // 수용가의 실제 물사용량 const res = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear); const monthData: SewageOccurDetailProps[] = []; let tot = 0, cnt = 0; @@ -554,15 +473,15 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = } else { monthData[monthIdx] = { cnt: 1, sum: Number(item.inflAmnt), yr: item.msrDt.substring(0, 4) - , usage: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0, monWtrUsg: 0 + , usage: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0, monWtrUsg: 0, maxEstSewerage: 0, minEstSewerage: 999999999 }; } } - tot += Number(item.inflAmnt) + tot += Number(item.inflAmnt); // 연간 유입량 cnt++ }); - // 물사용량 + // 수용가 실제 물사용량 let totWtrUsg = 0; let cntWtrUsg = 0; if (wtrUsgRes && wtrUsgRes.data && wtrUsgRes.data[bscFctCd]) { @@ -582,25 +501,23 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = const tableData: modalTableType[] = [] - let maxWaterUsage = 0; - let minWaterUsage = 9999999999; + let maxWaterUsage = 0, minWaterUsage = 9999999999; + let maxEstSewage = 0, minEstSewage = 9999999999; let avgWaterUsage = 0; monthData.forEach((item, index) => { - item.avgWtrUsg = item.sum / item.cnt * 0.65; // 일평균 물사용량 = 일평균유입수 * 0.65 - if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; + item.avgWtrUsg = item.sum / item.cnt * 0.65; // 일평균 물사용량 = 일평균유입수 * 0.65 : 수용가 실제 물사용량이 없으면 + if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; //수용가 실제 물사용량이 있는 경우 + const estSewage = Math.round(item.avgWtrUsg * OSU_PERCENT * 1) / 1; // 오수발생량 추정 tableData.push({ msrDt: item.yr + '-' + (index + 1 >= 10 ? String(index + 1) : '0' + (index + 1)), waterUsage: Math.round(item.avgWtrUsg * 1) / 1, - swageChangePercent: OSU_PERCENT * 100,//(Math.round((item.usage/item.usage*OSU_PERCENT) * 100) / 100) * 100, - estimationSewage: Math.round(item.avgWtrUsg * OSU_PERCENT * 1) / 1 + swageChangePercent: OSU_PERCENT * 100, //오수전환율 (Math.round((item.usage/item.usage*OSU_PERCENT) * 100) / 100) * 100, + estimationSewage: estSewage, }) - if (item.avgWtrUsg > maxWaterUsage) { - maxWaterUsage = item.avgWtrUsg; - } - - if (item.avgWtrUsg < minWaterUsage) { - minWaterUsage = item.avgWtrUsg; - } + if (item.avgWtrUsg > maxWaterUsage) maxWaterUsage = item.avgWtrUsg; // 물사용량 최대 + if (item.avgWtrUsg < minWaterUsage) minWaterUsage = item.avgWtrUsg; // 물사용량 최소 + if (maxEstSewage < estSewage) maxEstSewage = estSewage; // 오수발생량 최대 + if (minEstSewage > estSewage) minEstSewage = estSewage; // 오수발생량 최소 }); avgWaterUsage = tot / cnt * 0.65 @@ -617,13 +534,13 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = msrDt: '최대', waterUsage: roundNumber(Math.round(maxWaterUsage * 100) / 100, 0), swageChangePercent: OSU_PERCENT * 100, - estimationSewage: roundNumber(Math.round(maxWaterUsage * OSU_PERCENT * 1) / 1, 0), + estimationSewage: roundNumber(maxEstSewage / 1, 0), }, { msrDt: '최소', waterUsage: roundNumber(Math.round(minWaterUsage * 100) / 100, 0), swageChangePercent: OSU_PERCENT * 100, - estimationSewage: roundNumber(Math.round(minWaterUsage * OSU_PERCENT * 1) / 1, 0), + estimationSewage: roundNumber(minEstSewage / 1, 0), }, ...tableData ] diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx index c6a2167d8..0a0ce9537 100644 --- a/apps/fo/app/store/underWaterInput/index.tsx +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -5,20 +5,21 @@ import type { ExcelType, UnderWaterInputModalProps, UnderWaterProps, WtrUsgYmPro // import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { OSU_PERCENT } from "../common"; import { fetchFacilityListInit } from "../processFacility"; +import { getDaysInMonth } from "@/app/components/common/DataForm"; export type { TableUpperProps }; // SewageOccurDetailProps 타입을 여기에 정의 export type SewageOccurDetailProps = { - cnt : number, - sum : number, - yr:string, - usage:number, // 일평균 유입량 - sunnyCnt : number, - sunnyInflAmnt : number, - sunnyAvgInflAmnt : number, // 청천시 일평균 유입량 - cntWtrUsg : number, // 물사용량 일자수 - sumWtrUsg : number, // 물사용량 합 - avgWtrUsg:number, // 일평균 물사용량 + cnt: number, + sum: number, + yr: string, + usage: number, // 일평균 유입량 + sunnyCnt: number, + sunnyInflAmnt: number, + sunnyAvgInflAmnt: number, // 청천시 일평균 유입량 + cntWtrUsg: number, // 물사용량 일자수 + sumWtrUsg: number, // 물사용량 합 + avgWtrUsg: number, // 일평균 물사용량 } /**==================================== * Store - 타입 @@ -35,145 +36,145 @@ export type SewageOccurDetailProps = { /** * (1) 메인페이지 - */ + */ // 검색단 -const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; +const LabelArray: string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; // 리스트 헤더 -const upHeadList1:TableUpperProps[] = [ - { id: "A", title: "행정구역", row:0, colSpan:2 }, - { id: "sidoNm", title: "시도", row:1, widthPercent: 8 }, - { id: "sggNm", title: "시군구", row:1, widthPercent: 8 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 }, - { id: "daddr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 }, - { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 }, - { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, - { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 8 }, +const upHeadList1: TableUpperProps[] = [ + { id: "A", title: "행정구역", row: 0, colSpan: 2 }, + { id: "sidoNm", title: "시도", row: 1, widthPercent: 8 }, + { id: "sggNm", title: "시군구", row: 1, widthPercent: 8 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "C", title: "지하수 유입량 추정", align: "right", row: 0, colSpan: 3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "properYn", title: "적정여부", row: 0, rowSpan: 2, widthPercent: 8 }, ]; -const upHeadList2:TableUpperProps[] = [ - { id: "A", title: "유역", row:0, colSpan:3 }, - { id: "rvbsn", title: "권역", row:1, widthPercent: 5 }, - { id: "lgbsn", title: "단위유역", row:1, widthPercent: 5 }, - { id: "mdmbsn", title: "중권역", row:1, widthPercent: 5 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 }, - { id: "daddr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 }, - { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 }, - { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, - { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 8 }, +const upHeadList2: TableUpperProps[] = [ + { id: "A", title: "유역", row: 0, colSpan: 3 }, + { id: "rvbsn", title: "권역", row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", row: 1, widthPercent: 5 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "C", title: "지하수 유입량 추정", align: "right", row: 0, colSpan: 3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "properYn", title: "적정여부", row: 0, rowSpan: 2, widthPercent: 8 }, ]; -const upHeadList3:TableUpperProps[] = [ - { id: "A", title: "유역", row:0, colSpan:3 }, - { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1, widthPercent: 5 }, - { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1, widthPercent: 5 }, - { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1, widthPercent: 5 }, - { id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 8 }, - { id: "B", title: "행정구역", row:0, colSpan:2 }, - { id: "sidoNm", title: "시도", row:1, widthPercent: 6 }, - { id: "sggNm", title: "시군구", row:1, widthPercent: 6 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 }, - { id: "daddr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 }, - { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 }, - { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, - { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 6}, - { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 6 }, - { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 6 }, - { id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 6 }, +const upHeadList3: TableUpperProps[] = [ + { id: "A", title: "유역", row: 0, colSpan: 3 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe1", upSequnce: 1, row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe1", upSequnce: 2, row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe1", upSequnce: 3, row: 1, widthPercent: 5 }, + { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "B", title: "행정구역", row: 0, colSpan: 2 }, + { id: "sidoNm", title: "시도", row: 1, widthPercent: 6 }, + { id: "sggNm", title: "시군구", row: 1, widthPercent: 6 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 6 }, + { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "C", title: "지하수 유입량 추정", align: "right", row: 0, colSpan: 3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align: "right", row: 1, widthPercent: 6 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align: "right", row: 1, widthPercent: 6 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align: "right", row: 1, widthPercent: 6 }, + { id: "properYn", title: "적정여부", row: 0, rowSpan: 2, widthPercent: 6 }, ]; // 모달 -const upHeadListUnderWaterDetail:TableUpperProps[] = [ +const upHeadListUnderWaterDetail: TableUpperProps[] = [ { id: "msrDt", title: "날짜" }, - { id: "realSewageInput", title: "청천시 실제 하수유입량\n(m³/일)", align:"right" }, - { id: "sewageOccur", title: "오수발생량\n(m³/일)", align:"right" }, - { id: "underWaterInput", title: "지하수 유입량\n(m³/일)", align:"right" }, + { id: "realSewageInput", title: "청천시 실제 하수유입량\n(m³/일)", align: "right" }, + { id: "sewageOccur", title: "오수발생량\n(m³/일)", align: "right" }, + { id: "underWaterInput", title: "지하수 유입량\n(m³/일)", align: "right" }, ]; -const underWaterList:UnderWaterProps[] = [ +const underWaterList: UnderWaterProps[] = [ ] -const underWaterDetailList:UnderWaterInputModalProps[] = [ +const underWaterDetailList: UnderWaterInputModalProps[] = [ { - msrDt : "2024-01", - realSewageInput : 178007, - sewageOccur : 10.5, - underWaterInput : 80.6, + msrDt: "2024-01", + realSewageInput: 178007, + sewageOccur: 10.5, + underWaterInput: 80.6, }, { - msrDt : "2024-02", - realSewageInput : 123007, - sewageOccur : 10.7, - underWaterInput : 80.6, + msrDt: "2024-02", + realSewageInput: 123007, + sewageOccur: 10.7, + underWaterInput: 80.6, }, { - msrDt : "2024-03", - realSewageInput : 213007, - sewageOccur : 10.1, - underWaterInput : 80.6, + msrDt: "2024-03", + realSewageInput: 213007, + sewageOccur: 10.1, + underWaterInput: 80.6, }, { - msrDt : "2024-04", - realSewageInput : 83007, - sewageOccur : 9.57, - underWaterInput : 80.6, + msrDt: "2024-04", + realSewageInput: 83007, + sewageOccur: 9.57, + underWaterInput: 80.6, }, { - msrDt : "2024-05", - realSewageInput : 15007, - sewageOccur : 3.57, - underWaterInput : 80.6, + msrDt: "2024-05", + realSewageInput: 15007, + sewageOccur: 3.57, + underWaterInput: 80.6, }, { - msrDt : "2024-06", - realSewageInput : 123007, - sewageOccur : '', - underWaterInput : 80.6, + msrDt: "2024-06", + realSewageInput: 123007, + sewageOccur: '', + underWaterInput: 80.6, }, { - msrDt : "2024-07", - realSewageInput : 101007, - sewageOccur : 1, - underWaterInput : 80.6, + msrDt: "2024-07", + realSewageInput: 101007, + sewageOccur: 1, + underWaterInput: 80.6, }, { - msrDt : "2024-08", - realSewageInput : 103807, - sewageOccur : 10.57, - underWaterInput : '', + msrDt: "2024-08", + realSewageInput: 103807, + sewageOccur: 10.57, + underWaterInput: '', }, { - msrDt : "2024-09", - realSewageInput : 9007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-09", + realSewageInput: 9007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, { - msrDt : "2024-10", - realSewageInput : 163007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-10", + realSewageInput: 163007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, { - msrDt : "2024-11", - realSewageInput : 123007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-11", + realSewageInput: 123007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, { - msrDt : "2024-12", - realSewageInput : 1007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-12", + realSewageInput: 1007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, ] /**==================================== @@ -185,8 +186,8 @@ export interface FlowDataItem { inflAmnt: number | string; infoRnDay: number; msrDt: string; - rainEffectDay? : number; - sumFlow? : number | string | ''; + rainEffectDay?: number; + sumFlow?: number | string | ''; } export interface ApiResponse { @@ -216,9 +217,9 @@ const fetchUnderWaterList = async (pageNo: number, pageSize: number, searchYear: // } // 시설들 유량 정보 조회 -export const fetchDetailListFlow = async (searchYear: string|undefined, fcltCdList: string[]): Promise => { +export const fetchDetailListFlow = async (searchYear: string | undefined, fcltCdList: string[]): Promise => { try { - const res = await postFetch('fo', '/fclt/flow/'+searchYear, fcltCdList); + const res = await postFetch('fo', '/fclt/flow/' + searchYear, fcltCdList); return res; } catch (error) { console.error('시설정보 오수발생량 상세 데이터를 가져오는데 실패했습니다:', error); @@ -226,9 +227,9 @@ export const fetchDetailListFlow = async (searchYear: string|undefined, fcltCdLi } }; // 시설들 월별 물사용량 정보 조회 -export const fetchWtrUsgYmList = async (searchYear: string|undefined, fcltCdList: string[]): Promise => { +export const fetchWtrUsgYmList = async (searchYear: string | undefined, fcltCdList: string[]): Promise => { try { - const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/'+searchYear, fcltCdList); + const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/' + searchYear, fcltCdList); return res; } catch (error) { console.error('시설들 월별 물사용량 데이터를 가져오는데 실패했습니다:', error); @@ -241,16 +242,16 @@ export const fetchWtrUsgYmList = async (searchYear: string|undefined, fcltCdList ====================================*/ export type UnderWaterActions = { searchUnderWaterList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; - unserWaterModal:(bscFctCd:string, searchYear:string, startYm:string, endYm:string)=>void + underWaterModal: (bscFctCd: string, searchYear: string, startYm: string, endYm: string) => void } export type UnderWaterType = { UnderWaterSearch: { isInit: boolean; - labelArray:string[]; + labelArray: string[]; }, - UnderWater : { + UnderWater: { isInit: boolean; upHeadList1: TableUpperProps[]; upHeadList2: TableUpperProps[]; @@ -261,7 +262,7 @@ export type UnderWaterType = { isLoading: boolean; }, - UnderWaterDetail : { + UnderWaterDetail: { isInit: boolean; upHeadListUnderWaterDetail: TableUpperProps[]; gridListUnderWaterDetail: UnderWaterInputModalProps[]; @@ -274,30 +275,30 @@ export const underWaterInitState: UnderWaterType = { labelArray: LabelArray, }, - UnderWater : { - isInit : false, - upHeadList1 : upHeadList1, - upHeadList2 : upHeadList2, - upHeadList3 : upHeadList3, - underWaterList : underWaterList, - underWaterCount : 4, - excelList : [], - isLoading : true, + UnderWater: { + isInit: false, + upHeadList1: upHeadList1, + upHeadList2: upHeadList2, + upHeadList3: upHeadList3, + underWaterList: underWaterList, + underWaterCount: 4, + excelList: [], + isLoading: true, }, - UnderWaterDetail : { + UnderWaterDetail: { isInit: false, upHeadListUnderWaterDetail: upHeadListUnderWaterDetail, gridListUnderWaterDetail: underWaterDetailList, } } -const dataFormSetting=(item : UnderWaterProps)=> { +const dataFormSetting = (item: UnderWaterProps) => { DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record }); DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record }); - DataForm({ type: 'float0', column: 'underWaterInputYear', item: item as unknown as Record}); - DataForm({ type: 'float0', column: 'underWaterInputSummer', item: item as unknown as Record}); - DataForm({ type: 'float0', column: 'underWaterInputWinter', item: item as unknown as Record}); + DataForm({ type: 'float0', column: 'underWaterInputYear', item: item as unknown as Record }); + DataForm({ type: 'float0', column: 'underWaterInputSummer', item: item as unknown as Record }); + DataForm({ type: 'float0', column: 'underWaterInputWinter', item: item as unknown as Record }); } // 병렬 처리 제한용 헬퍼 @@ -310,47 +311,26 @@ const dataFormSetting=(item : UnderWaterProps)=> { // } // return results; // } -/** - * yyyymm 형태의 문자열을 받아 해당 월의 일수를 반환 - * @param {string} yyyymm - 예: "202502", "202412" - * @returns {number} 해당 월의 일수 (예: 28, 29, 30, 31) - */ -function getDaysInMonth(yyyymm) { - if (typeof yyyymm !== 'string' || yyyymm.length !== 6) { - throw new Error("입력은 'yyyymm' 형식의 문자열이어야 합니다. 예: '202502'"); - } - - const year = parseInt(yyyymm.slice(0, 4), 10); // "2025" -> 2025 - const month = parseInt(yyyymm.slice(4, 6), 10); // "02" -> 2 - - if (isNaN(year) || isNaN(month) || month < 1 || month > 12) { - throw new Error("유효한 년/월이 아닙니다."); - } - - // Date(year, month, 0) -> 전달의 마지막 날 - // month에 '다음달'을 넣고, 일(day)에 0을 주면 해당 월의 마지막 날짜가 됨 - return new Date(year, month, 0).getDate(); -} export type UnderWaterStore = UnderWaterType & UnderWaterActions; -export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterType) => void)=>UnderWaterActions=(set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => { +export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => UnderWaterActions = (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => { return { searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm); - - if(pageSize < 5000){ + + if (pageSize < 5000) { set((state: UnderWaterType) => ({ ...state, UnderWater: { ...state.UnderWater, - underWaterList : facilityInitData.data, - underWaterCount : facilityInitData.count, - isInit : true, + underWaterList: facilityInitData.data, + underWaterCount: facilityInitData.count, + isInit: true, isLoading: true, }, })); - }else{ + } else { set((state: UnderWaterType) => ({ ...state, UnderWater: { @@ -359,43 +339,43 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy }, })); } - + const fcltylist = facilityInitData.data; - const fcltCdList : string[] = []; // 시설코드목록 - const underWaterPropsList : UnderWaterProps[] = []; // 오수발생량시설목록 + const fcltCdList: string[] = []; // 시설코드목록 + const underWaterPropsList: UnderWaterProps[] = []; // 오수발생량시설목록 fcltylist.forEach(item => { fcltCdList.push(item.bscFctCd); underWaterPropsList.push({ - bscFctCd : item.bscFctCd, - sidoNm : item.sido, - sggNm : item.gugun, - lclgvrnmntNm : '', - bscFctNm : item.bscFctNm, - daddr : item.daddr, - fctCpc : parseFloat(item.fctCpc.toString().replace(/,/g, '')), - inflAmnt : 0, - waterUsage : 0, - underWaterInputYear : 0, - underWaterInputSummer : 0, - underWaterInputWinter : 0, - properYn : '', - infoRnDay : 0, - rgnNm : item.rgnNm, - rvbsn : item.rvbsn, - lgbsn : item.lgbsn, - mdmbsn : item.mdmbsn, - msrDt : '', + bscFctCd: item.bscFctCd, + sidoNm: item.sido, + sggNm: item.gugun, + lclgvrnmntNm: '', + bscFctNm: item.bscFctNm, + daddr: item.daddr, + fctCpc: parseFloat(item.fctCpc.toString().replace(/,/g, '')), + inflAmnt: 0, + waterUsage: 0, + underWaterInputYear: 0, + underWaterInputSummer: 0, + underWaterInputWinter: 0, + properYn: '', + infoRnDay: 0, + rgnNm: item.rgnNm, + rvbsn: item.rvbsn, + lgbsn: item.lgbsn, + mdmbsn: item.mdmbsn, + msrDt: '', }); }); - - const soccurDetailRes : any = await fetchDetailListFlow(searchYear, fcltCdList); - const wtrUsgYmRes : any = await fetchWtrUsgYmList(searchYear, fcltCdList); - + + const soccurDetailRes: any = await fetchDetailListFlow(searchYear, fcltCdList); + const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); + for (const item of underWaterPropsList) { - + const detailList = soccurDetailRes?.data[item.bscFctCd]; const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd]; - + let chungcunSumFlow = 0; // 청천유입량 let sumChungcunDay = 0; // 청천일수 let sumSummerChungcunDay = 0; // 하절기 청천일수 @@ -407,39 +387,39 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy let totWinterUsage = 0; // 동절기 하수유입량 let totSummerDays = 0; // 하절기 일수 let totWinterDays = 0; // 동절기 일수 - + const summerMonth = ['06', '07', '08']; const winterMonth = ['01', '02']; - + let rainEffectDay = 0; detailList?.forEach(item2 => { if (item2.infoRnDay == null || item2.infoRnDay.trim() == 'x') item2.infoRnDay = 0; - if(Number(item2.infoRnDay) >= 3) { + if (Number(item2.infoRnDay) >= 3) { rainEffectDay = 2; - }else{ + } else { rainEffectDay--; } - if(rainEffectDay<0){ //청천시 + if (rainEffectDay < 0) { //청천시 chungcunSumFlow += Number(item2.inflAmnt); sumChungcunDay += 1; - if(item2.msrDt.substring(4,6) ==='06' || item2.msrDt.substring(4,6) ==='07' || item2.msrDt.substring(4,6) ==='08'){ + if (item2.msrDt.substring(4, 6) === '06' || item2.msrDt.substring(4, 6) === '07' || item2.msrDt.substring(4, 6) === '08') { // 하절기 6,7,8월 sumSummerChungcunDay += 1; sumSummerChungcunFlow += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; - }else if(item2.msrDt.substring(4,6) ==='01' || item2.msrDt.substring(4,6) ==='02'){ + } else if (item2.msrDt.substring(4, 6) === '01' || item2.msrDt.substring(4, 6) === '02') { // 동절기 1,2월 sumWinterChungcunDay += 1; sumWinterChungcunFlow += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; } } totWaterUsage += Number(item2.inflAmnt); - if(item2.msrDt.substring(4,6) ==='06' || item2.msrDt.substring(4,6) ==='07' || item2.msrDt.substring(4,6) ==='08'){ + if (item2.msrDt.substring(4, 6) === '06' || item2.msrDt.substring(4, 6) === '07' || item2.msrDt.substring(4, 6) === '08') { // 하절기 6,7,8월 totSummerDays += 1; totSummerUsage += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; - }else if(item2.msrDt.substring(4,6) ==='01' || item2.msrDt.substring(4,6) ==='02'){ + } else if (item2.msrDt.substring(4, 6) === '01' || item2.msrDt.substring(4, 6) === '02') { // 동절기 1,2월 totWinterDays += 1; totWinterUsage += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; @@ -447,8 +427,8 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy }); const count = detailList ? detailList.length : 0; - const avg = count == 0 ? 0 : totWaterUsage / count; // 일평균 유입량 - + const avg = count == 0 ? 0 : totWaterUsage / count; // 연간 일평균 유입량 + let wtrUsgYearTotal = 0; // 연간 물사용량 let summerWtrUsgTot = 0; // 하절기 물사용량 let winterWtrUsgTot = 0; // 동절기 물사용량 @@ -459,52 +439,52 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy const days = getDaysInMonth(item3.levyYm); wtrUsgYearTotal += Number(item3.wtrUsg); wtrUsgYearDays += days; - if(summerMonth.includes(item3.levyYm.slice(-2))){ + if (summerMonth.includes(item3.levyYm.slice(-2))) { summerWtrUsgTot += Number(item3.wtrUsg); summerWtrUsgDays += days; - }else if(winterMonth.includes(item3.levyYm.slice(-2))){ + } else if (winterMonth.includes(item3.levyYm.slice(-2))) { winterWtrUsgTot += Number(item3.wtrUsg); winterWtrUsgDays += days; } }); - + if (wtrUsgYearTotal > 0) { // 물사용량이 있는 경우 - const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / sumChungcunDay:0; // 청천시 일평균 유입량 - const summerUsage = sumSummerChungcunFlow?sumSummerChungcunFlow / sumSummerChungcunDay:0; // 하절기 청천시 일평균 유입량 - const winterUsage = sumWinterChungcunFlow?sumWinterChungcunFlow / sumWinterChungcunDay:0; // 동절기 청천시 일평균 유입량 - const wtrUsg = wtrUsgYearDays>0? wtrUsgYearTotal / wtrUsgYearDays: 0; // 일평균 물사용량 - const summerWtrUsg = summerWtrUsgTot?summerWtrUsgTot / summerWtrUsgDays:0; // 하절기 일평균 물사용량 - const winterWtrUsg = winterWtrUsgTot?winterWtrUsgTot / winterWtrUsgDays:0; // 동절기 일평균 물사용량 - + const usage = chungcunSumFlow && chungcunSumFlow > 0 ? chungcunSumFlow / sumChungcunDay : 0; // 청천시 일평균 유입량 + const summerUsage = sumSummerChungcunFlow ? sumSummerChungcunFlow / sumSummerChungcunDay : 0; // 하절기 청천시 일평균 유입량 + const winterUsage = sumWinterChungcunFlow ? sumWinterChungcunFlow / sumWinterChungcunDay : 0; // 동절기 청천시 일평균 유입량 + const wtrUsg = wtrUsgYearDays > 0 ? wtrUsgYearTotal / wtrUsgYearDays : 0; // 일평균 물사용량 + const summerWtrUsg = summerWtrUsgTot ? summerWtrUsgTot / summerWtrUsgDays : 0; // 하절기 일평균 물사용량 + const winterWtrUsg = winterWtrUsgTot ? winterWtrUsgTot / winterWtrUsgDays : 0; // 동절기 일평균 물사용량 + item.inflAmnt = roundNumber(avg, 0); - item.underWaterInputYear = Math.round((usage-(wtrUsg*OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.underWaterInputSummer = Math.round((summerUsage-(summerWtrUsg*OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) - item.underWaterInputWinter = Math.round((winterUsage-(winterWtrUsg*OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) - item.properYn = Math.round( (Number(usage-(wtrUsg*OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1 ) / 1 > 20?'초과유입':'적정'; // 적정여부 + item.underWaterInputYear = Math.round((usage - (wtrUsg * OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.underWaterInputSummer = Math.round((summerUsage - (summerWtrUsg * OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) + item.underWaterInputWinter = Math.round((winterUsage - (winterWtrUsg * OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) + item.properYn = Math.round((Number(usage - (wtrUsg * OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1) / 1 > 20 ? '초과유입' : '적정'; // 적정여부 } else { // 물사용량이 없는 경우, 일평균 유입량으로 물사용량 추정(물사용량 = 유입량*0.65) - const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / sumChungcunDay:0; // 청천시 일평균 유입량 - const summerUsage = sumSummerChungcunFlow?sumSummerChungcunFlow / sumSummerChungcunDay:0; // 하절기 청천시 일평균 유입량 - const winterUsage = sumWinterChungcunFlow?sumWinterChungcunFlow / sumWinterChungcunDay:0; // 동절기 청천시 일평균 유입량 + const usage = chungcunSumFlow && chungcunSumFlow > 0 ? chungcunSumFlow / sumChungcunDay : 0; // 청천시 일평균 유입량 + const summerUsage = sumSummerChungcunFlow ? sumSummerChungcunFlow / sumSummerChungcunDay : 0; // 하절기 청천시 일평균 유입량 + const winterUsage = sumWinterChungcunFlow ? sumWinterChungcunFlow / sumWinterChungcunDay : 0; // 동절기 청천시 일평균 유입량 const wtrUsg = avg * 0.65; // 일평균 물사용량 - const summerWtrUsg = totSummerDays>0? (totSummerUsage / totSummerDays)*0.65:0; // 하절기 일평균 물사용량 - const winterWtrUsg = totWinterDays>0? (totWinterUsage / totWinterDays)*0.65:0; // 동절기 일평균 물사용량 - + const summerWtrUsg = totSummerDays > 0 ? (totSummerUsage / totSummerDays) * 0.65 : 0; // 하절기 일평균 물사용량 + const winterWtrUsg = totWinterDays > 0 ? (totWinterUsage / totWinterDays) * 0.65 : 0; // 동절기 일평균 물사용량 + item.inflAmnt = roundNumber(avg, 0); //item.underWaterInputYear = Math.round((usage-(usage*0.65*OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) - item.underWaterInputYear = Math.round((usage-(wtrUsg*OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.underWaterInputSummer = Math.round((summerUsage-(summerWtrUsg*OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.underWaterInputWinter = Math.round((winterUsage-(winterWtrUsg*OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.properYn = Math.round( (Number(usage-(wtrUsg*OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1 ) / 1 > 20?'초과유입':'적정'; // 적정여부 - // 반올림 처리 - // ["fctCpc", "inflAmnt", "underWaterInputYear", "underWaterInputSummer", "underWaterInputWinter"].forEach( - // (key) => (item[key] = roundNumber(item[key], 0)) - // ); + item.underWaterInputYear = Math.round((usage - (wtrUsg * OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.underWaterInputSummer = Math.round((summerUsage - (summerWtrUsg * OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.underWaterInputWinter = Math.round((winterUsage - (winterWtrUsg * OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.properYn = Math.round((Number(usage - (wtrUsg * OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1) / 1 > 20 ? '초과유입' : '적정'; // 적정여부 + // 반올림 처리 + // ["fctCpc", "inflAmnt", "underWaterInputYear", "underWaterInputSummer", "underWaterInputWinter"].forEach( + // (key) => (item[key] = roundNumber(item[key], 0)) + // ); } } - if(pageSize>= 5000){ + if (pageSize >= 5000) { const excelDownList: ExcelType[] = []; - underWaterPropsList.forEach((item : any) => { + underWaterPropsList.forEach((item: any) => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); excelDownList.push({ @@ -530,10 +510,10 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy UnderWater: { ...state.UnderWater, excelList: excelDownList, - isLoading : false, + isLoading: false, }, })); - }else{ + } else { set((state: UnderWaterType) => ({ ...state, UnderWater: { @@ -541,21 +521,21 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy underWaterList: underWaterPropsList, underWaterCount: facilityInitData.count, excelList: [], - isLoading : false, + isLoading: false, }, })); } }, - - unserWaterModal:async (bscFctCd, searchYear, startYm, endYm)=>{ + + underWaterModal: async (bscFctCd, searchYear, startYm, endYm) => { const fcltCdList = [bscFctCd]; - const wtrUsgRes : any = await fetchWtrUsgYmList(searchYear, fcltCdList); + const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); const res = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear); const monthData: SewageOccurDetailProps[] = []; let tot = 0, cnt = 0; let sunnyTot = 0, sunnyCnt = 0; - - if(startYm) { + + if (startYm) { res.data = res.data.filter((item: FlowDataItem) => { const month = item.msrDt?.substring(0, 6); return month >= startYm; @@ -567,7 +547,7 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy }); } } - if(endYm) { + if (endYm) { res.data = res.data.filter((item: FlowDataItem) => { const month = item.msrDt?.substring(0, 6); return month <= endYm; @@ -582,36 +562,40 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy let rainEffectDay = 0; res.data?.forEach(item2 => { if (item2.infoRnDay == null || item2.infoRnDay.trim() == 'x') item2.infoRnDay = 0; - if(Number(item2.infoRnDay) >= 3) { + if (Number(item2.infoRnDay) >= 3) { rainEffectDay = 2; - }else{ + } else { rainEffectDay--; } - + const month = item2.msrDt?.substring(4, 6); const monthIdx = month ? Number(month) - 1 : -1; - if (monthIdx >= 0 && (monthIdx>=Number(startYm.substring(4,6))-1 && monthIdx <= Number(endYm.substring(4, 6))-1)) { + if (monthIdx >= 0 && (monthIdx >= Number(startYm.substring(4, 6)) - 1 && monthIdx <= Number(endYm.substring(4, 6)) - 1)) { if (typeof monthData[monthIdx] === 'object') { monthData[monthIdx].sum += Number(item2.inflAmnt); // 유입량 합 monthData[monthIdx].cnt++; } else { - monthData[monthIdx] = {cnt:1, sum:Number(item2.inflAmnt), yr:item2.msrDt.substring(0,4) - , usage:0, sunnyCnt:0, sunnyInflAmnt:0, sunnyAvgInflAmnt: 0, cntWtrUsg:0, sumWtrUsg:0, avgWtrUsg:0}; + monthData[monthIdx] = { + cnt: 1, sum: Number(item2.inflAmnt), yr: item2.msrDt.substring(0, 4) + , usage: 0, sunnyCnt: 0, sunnyInflAmnt: 0, sunnyAvgInflAmnt: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0 + }; } - } - if(month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)){ + } + if (month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)) { cnt++; tot += item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; } - if(rainEffectDay<0) { // 청천시 + if (rainEffectDay < 0) { // 청천시 if (typeof monthData[monthIdx] === 'object') { monthData[monthIdx].sunnyInflAmnt += Number(item2.inflAmnt); // 청천 유입량 합 monthData[monthIdx].sunnyCnt++; - }else { - monthData[monthIdx] = {cnt:1, sum:Number(item2.inflAmnt), yr:item2.msrDt.substring(0,4) - , usage:0, sunnyCnt:0, sunnyInflAmnt:0, sunnyAvgInflAmnt: 0, cntWtrUsg:0, sumWtrUsg:0, avgWtrUsg:0}; + } else { + monthData[monthIdx] = { + cnt: 1, sum: Number(item2.inflAmnt), yr: item2.msrDt.substring(0, 4) + , usage: 0, sunnyCnt: 0, sunnyInflAmnt: 0, sunnyAvgInflAmnt: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0 + }; } - if (month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)){ + if (month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)) { sunnyCnt++; sunnyTot += item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; } @@ -630,75 +614,76 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy if (typeof monthData[monthIdx] === 'object') { monthData[monthIdx].sumWtrUsg += Number(item.wtrUsg); monthData[monthIdx].cntWtrUsg += days; - } + } } totWtrUsg += Number(item.wtrUsg); cntWtrUsg += days; }); } - - const tableData:UnderWaterInputModalProps[] = [] - - let maxWaterUsage = 0; - let minWaterUsage = 9999999999; - let avgWaterUsage = 0; - let maxSunnyInflAmnt = 0; - let minSunnyInflAmnt = 9999999999; - let avgSunnyInflAmnt = 0; + + const tableData: UnderWaterInputModalProps[] = [] + + let maxWaterUsage = 0, minWaterUsage = 9999999999, avgWaterUsage = 0; // 물사용량 + let maxSunnyInflAmnt = 0, minSunnyInflAmnt = 9999999999, avgSunnyInflAmnt = 0; // 청천 유입량 + let maxUnderWaterInput = 0, minUnderWaterInput = 9999999999; // 지하수 유입량 monthData.forEach((item, index) => { - item.usage = item.sum/item.cnt; // 일평균 유입량 - item.avgWtrUsg = item.sum/item.cnt * 0.65; // 일평균 물사용량 - if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; // 일평균 물사용량 + item.usage = item.sum / item.cnt; // 일평균 유입량 + item.avgWtrUsg = item.sum / item.cnt * 0.65; // 일평균 물사용량 : 수용가 물사용량이 없는 경우 + // 일평균 물사용량 : 수용가 물사용량이 있는 경우 + if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; item.sunnyAvgInflAmnt = item.sunnyInflAmnt / item.sunnyCnt; // 청천 일평균 유입량 + const underWtrInput = Math.round((item.sunnyAvgInflAmnt - (item.avgWtrUsg * OSU_PERCENT)) * 1) / 1; // 지하수 유입량 평균 tableData.push({ - msrDt: item.yr+'-'+(index+1>=10?String(index+1):'0'+(index+1)), - realSewageInput:Math.round(item.sunnyAvgInflAmnt*1) /1, // 청천 실제 하수유입량 - sewageOccur:Math.round(item.avgWtrUsg*OSU_PERCENT * 1) / 1,// 오수발생량 - underWaterInput:Math.round((item.sunnyAvgInflAmnt-(item.avgWtrUsg*OSU_PERCENT)) * 1) / 1, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + msrDt: item.yr + '-' + (index + 1 >= 10 ? String(index + 1) : '0' + (index + 1)), + realSewageInput: Math.round(item.sunnyAvgInflAmnt * 1) / 1, // 청천 실제 하수유입량 + sewageOccur: Math.round(item.avgWtrUsg * OSU_PERCENT * 1) / 1,// 오수발생량 + underWaterInput: underWtrInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) }) - if (item.avgWtrUsg > maxWaterUsage) maxWaterUsage = item.avgWtrUsg; + if (item.avgWtrUsg > maxWaterUsage) maxWaterUsage = item.avgWtrUsg; if (item.sunnyAvgInflAmnt > maxSunnyInflAmnt) maxSunnyInflAmnt = item.sunnyAvgInflAmnt; if (item.avgWtrUsg < minWaterUsage) minWaterUsage = item.avgWtrUsg; if (item.sunnyAvgInflAmnt < minSunnyInflAmnt) minSunnyInflAmnt = item.sunnyAvgInflAmnt; + if (underWtrInput > maxUnderWaterInput) maxUnderWaterInput = underWtrInput; + if (underWtrInput < minUnderWaterInput) minUnderWaterInput = underWtrInput; }); - if(monthData.length == 0){ - maxWaterUsage = 0; minWaterUsage = 0; avgWaterUsage = 0; + if (monthData.length == 0) { + maxWaterUsage = 0; minWaterUsage = 0; avgWaterUsage = 0; maxSunnyInflAmnt = 0; minSunnyInflAmnt = 0; avgSunnyInflAmnt = 0; } - - avgWaterUsage = cnt>0? tot/cnt * 0.65:0; // 일평균 물사용량 - if (totWtrUsg > 0 && cntWtrUsg > 0) avgWaterUsage = totWtrUsg / cntWtrUsg; // 일평균 물사용량 - avgSunnyInflAmnt = (sunnyCnt>0)?sunnyTot/sunnyCnt:0; // 청천 일평균 유입량 - const newData= [ - { - msrDt: '평균', - realSewageInput:Math.round(avgSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 - sewageOccur:Math.round(avgWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: Math.round((avgSunnyInflAmnt-(avgWaterUsage*OSU_PERCENT)) * 1) / 1 // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) - //underWaterInput:Math.round((avgWaterUsage-(avgWaterUsage*0.65*0.8)) * 100) / 100, - }, - { - msrDt: '최대', - realSewageInput: Math.round(maxSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 - sewageOccur: Math.round(maxWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: Math.round((maxSunnyInflAmnt-(maxWaterUsage*OSU_PERCENT)) * 1) / 1, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) - }, - { - msrDt: '최소', - realSewageInput: Math.round(minSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 - sewageOccur: Math.round(minWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: Math.round((minSunnyInflAmnt-(minWaterUsage*OSU_PERCENT)) * 1) / 1, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) - }, - ...tableData + avgWaterUsage = cnt > 0 ? tot / cnt * 0.65 : 0; // 일평균 물사용량 + if (totWtrUsg > 0 && cntWtrUsg > 0) avgWaterUsage = totWtrUsg / cntWtrUsg; // 일평균 물사용량 + avgSunnyInflAmnt = (sunnyCnt > 0) ? sunnyTot / sunnyCnt : 0; // 청천 일평균 유입량 + + const newData = [ + { + msrDt: '평균', + realSewageInput: Math.round(avgSunnyInflAmnt * 1) / 1, // 청천시 실제 하수유입량 + sewageOccur: Math.round(avgWaterUsage * OSU_PERCENT * 1) / 1, // 오수발생량 + underWaterInput: Math.round((avgSunnyInflAmnt - (avgWaterUsage * OSU_PERCENT)) * 1) / 1 // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + //underWaterInput:Math.round((avgWaterUsage-(avgWaterUsage*0.65*0.8)) * 100) / 100, + }, + { + msrDt: '최대', + realSewageInput: Math.round(maxSunnyInflAmnt * 1) / 1, // 청천시 실제 하수유입량 + sewageOccur: Math.round(maxWaterUsage * OSU_PERCENT * 1) / 1, // 오수발생량 + underWaterInput: maxUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + }, + { + msrDt: '최소', + realSewageInput: Math.round(minSunnyInflAmnt * 1) / 1, // 청천시 실제 하수유입량 + sewageOccur: Math.round(minWaterUsage * OSU_PERCENT * 1) / 1, // 오수발생량 + underWaterInput: minUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + }, + ...tableData ] set((state: UnderWaterType) => ({ ...state, UnderWaterDetail: { ...state.UnderWaterDetail, - gridListUnderWaterDetail:newData + gridListUnderWaterDetail: newData } })) } diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx index aedb32256..048a0cc42 100644 --- a/packages/common/business_components/src/ui/excel/index.tsx +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -6,6 +6,7 @@ type ExcelDownloadProps = { fileName: string; sheetNameArray: string[]; headerRange?: string; + headers?: readonly string[]|undefined; decimalArray0? : number[]; decimalArray1? : number[]; decimalArray2? : number[]; @@ -19,6 +20,15 @@ export const downloadExcel = ({ data, fileName = new Date().getTime().toString() excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); }; +export const downloadExcelHeaders = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3', headers}: ExcelDownloadProps) => { + const dataArray = Array.isArray(data) ? data : [data]; + // headers가 제공되면 열 순서를 강제함 + const worksheet = XLSX.utils.json_to_sheet(dataArray, headers ? { header: [...headers] } : undefined); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); + excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); +}; + export const downloadExcelFormat = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3', decimalArray0=[], decimalArray1=[], decimalArray2=[], decimalArray3=[]}: ExcelDownloadProps) => { const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]); const workbook = XLSX.utils.book_new();