From 94fa8eb7211e4c726944fdd3f11f649eaba0e27c Mon Sep 17 00:00:00 2001 From: dongsilove Date: Sat, 10 Jan 2026 20:43:46 +0900 Subject: [PATCH] =?UTF-8?q?fo:=20=EC=9C=A0=EB=9F=89=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=20=EA=B0=95=EC=9A=B0=EC=8B=9C=20=ED=8F=89=EA=B7=A0=20=EB=8B=A8?= =?UTF-8?q?=EC=88=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/components/common/DataForm.tsx | 42 +++++----- .../common/FacilityTermModalHeader.tsx | 82 +++++++++---------- .../(with-layout)/flowRate/modal/page.tsx | 24 ++++-- apps/fo/app/store/flowRate/index.tsx | 54 ++++++------ 4 files changed, 107 insertions(+), 95 deletions(-) diff --git a/apps/fo/app/components/common/DataForm.tsx b/apps/fo/app/components/common/DataForm.tsx index b58322458..2c99129b2 100644 --- a/apps/fo/app/components/common/DataForm.tsx +++ b/apps/fo/app/components/common/DataForm.tsx @@ -26,7 +26,7 @@ export const getDaysInMonth = (yyyymm: string) => { return new Date(year, month, 0).getDate(); } -export const roundNumber = (value : any, decimals: number) => { +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') { @@ -45,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 84d6353b6..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,28 +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 isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0); - const dateRanges:{start:Date, end:Date}[] = []; + const dateRanges: { start: Date, end: Date }[] = []; if (tabName.includes("_summer")) { dateRanges.push({ @@ -74,66 +74,66 @@ export default function FacilityTermModalHeader({ 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, isLeapYear ? 29 : 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) => { @@ -149,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; } @@ -172,7 +172,7 @@ export default function FacilityTermModalHeader({ }; const handleEndDateSelect = (day: Date | undefined) => { - if(day && day < startDate) { + if (day && day < startDate) { alert('종료일은 시작일 이후일 수 없습니다.'); return; } @@ -193,7 +193,7 @@ export default function FacilityTermModalHeader({ }); setCopySearchList(filteredData); }; - + const fncSetFilteredList = useCallback(() => { queryClick({ startDate: startDate, @@ -206,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; @@ -225,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" />
@@ -247,7 +247,7 @@ export default function FacilityTermModalHeader({
- handleStartDateSelect(date as Date)} @@ -261,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)/flowRate/modal/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx index 822b52979..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"; @@ -76,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; @@ -125,6 +126,12 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st } }); + const formattedData = filteredData.map((item: FlowRateModalInterface) => { + const newItem = { ...item }; + dataFormSetting(newItem); + return newItem; + }); + const newFilteredData = [ { msrDt: '평균', @@ -159,7 +166,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st infoRnDay: mininfoRnDay > 0 ? roundUp(mininfoRnDay, 1) : '0.0', rainEffectDay: 0, }, - ...filteredData + ...formattedData ]; return newFilteredData; } @@ -210,7 +217,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st - + {/* 연간 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -237,7 +244,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
- + {/* 하절기 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -264,7 +271,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
- + {/* 동절기 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -291,7 +298,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st - + {/* 청천시 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -318,7 +325,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st - + {/* 강우시 */} searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -329,7 +336,8 @@ 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/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 432bc5ba5..7bec0be97 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -237,7 +237,7 @@ export type FlowRateSearchType = { 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 }); @@ -330,44 +330,48 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl 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; // 청천시 일별유입BOD - //let rainDay = 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; // 청천시 연평균유입BOD - + 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 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); - item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0); - item.noProcessInflAmnt = noProcessInflAmnt && noProcessInflAmnt > 0 ? noProcessInflAmnt : ''; - dataFormSetting(item); - return item; + 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: {