import DataForm from "@/app/components/common/DataForm"; import type { TableUpperProps } from "../dashboard"; import { getFetch } from "@/app/components/api"; import type { ExcelType, UnderWaterInputModalProps, UnderWaterProps } from "./types"; export type { TableUpperProps }; // SewageOccurDetailProps 타입을 여기에 정의 export type SewageOccurDetailProps = { cnt : number, sum : number, yr:string, usege:number } /**==================================== * Store - 타입 ====================================*/ /** * (1) 메인페이지 */ // 시설별 강수현황 /**==================================== * Store - data ====================================*/ /** * (1) 메인페이지 */ // 검색단 const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; // 리스트 헤더 const upHeadList1:TableUpperProps[] = [ { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, { id: "A", title: "행정구역", row:0, colSpan:2 }, { id: "sidoNm", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 }, { id: "sggNm", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 }, { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, { id: "daddr", title: "주소", row:0, rowSpan:2 }, { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 }, { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 }, { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 }, ]; const upHeadList2:TableUpperProps[] = [ { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, { id: "A", title: "유역", row:0, colSpan:3 }, { id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1 }, { id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1 }, { id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1 }, { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, { id: "daddr", title: "주소", row:0, rowSpan:2 }, { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 }, { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 }, { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 }, ]; const upHeadList3:TableUpperProps[] = [ { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, { id: "A", title: "유역", row:0, colSpan:3 }, { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1 }, { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1 }, { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1 }, { id: "rgnNm", title: "환경청", row:0, rowSpan:2 }, { id: "B", title: "행정구역", row:0, colSpan:2 }, { id: "sidoNm", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 }, { id: "sggNm", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 }, { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, { id: "daddr", title: "주소", row:0, rowSpan:2 }, { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 }, { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 }, { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 }, ]; // 모달 const upHeadListUnderWaterDetail:TableUpperProps[] = [ { id: "msrDt", title: "날짜" }, { id: "realSewageInput", title: "청천시 실제 하수유입량\n(m³/일)" }, { id: "sewageOccur", title: "오수발생량\n(m³/일)" }, { id: "underWaterInput", title: "지하수 유입량\n(m³/일)" }, ]; const underWaterList:UnderWaterProps[] = [ ] const underWaterDetailList:UnderWaterInputModalProps[] = [ { msrDt : "2024-01", realSewageInput : 178007, sewageOccur : 10.5, 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-04", realSewageInput : 83007, sewageOccur : 9.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-07", realSewageInput : 101007, sewageOccur : 1, underWaterInput : 80.6, }, { msrDt : "2024-08", realSewageInput : 103807, sewageOccur : 10.57, underWaterInput : '', }, { msrDt : "2024-09", realSewageInput : 9007, 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-12", realSewageInput : 1007, sewageOccur : 10.57, underWaterInput : 80.6, }, ] /**==================================== * Store - API ====================================*/ // API response types export interface FlowDataItem { inflAmnt: number | string; infoRnDay: number; msrDt: string; rainEffectDay? : number; sumFlow? : number | string | ''; } export interface ApiResponse { data: FlowDataItem[]; count: number; } const fetchUnderWaterList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { 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 } /* const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; const res = await getFetch('fo', url); return { data: res.data, count: res.count } */ //return { data: underWaterList, count: 2 }; } /**==================================== * Store - expaort ====================================*/ 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)=>void } export type UnderWaterType = { UnderWaterSearch: { isInit: boolean; labelArray:string[]; }, UnderWater : { isInit: boolean; upHeadList1: TableUpperProps[]; upHeadList2: TableUpperProps[]; upHeadList3: TableUpperProps[]; underWaterList: UnderWaterProps[]; // Changed from facilityAreaProps to ProcessAreaProps underWaterCount: number; excelList: ExcelType[]; isLoading: boolean; }, UnderWaterDetail : { isInit: boolean; upHeadListUnderWaterDetail: TableUpperProps[]; gridListUnderWaterDetail: UnderWaterInputModalProps[]; } } export const underWaterInitState: UnderWaterType = { UnderWaterSearch: { isInit: false, labelArray: LabelArray, }, UnderWater : { isInit : false, upHeadList1 : upHeadList1, upHeadList2 : upHeadList2, upHeadList3 : upHeadList3, underWaterList : underWaterList, underWaterCount : 4, excelList : [], isLoading : true, }, UnderWaterDetail : { isInit: false, upHeadListUnderWaterDetail: upHeadListUnderWaterDetail, gridListUnderWaterDetail: underWaterDetailList, } } const dataFormSetting=(item : UnderWaterProps)=> { DataForm({ type: 'float1', column: 'fctCpc', item: item as unknown as Record }); DataForm({ type: 'float1', column: 'underWaterInputYear', item: item as unknown as Record}); DataForm({ type: 'float2', column: 'underWaterInputSummer', item: item as unknown as Record}); DataForm({ type: 'float2', column: 'underWaterInputWinter', item: item as unknown as Record}); } export type UnderWaterStore = UnderWaterType & UnderWaterActions; export const calRainEffectDay = (data: FlowDataItem[], weather: string) => { // 강우영향일 계산 (강우량이 3 이상이면 무조건 강우영향일) for(let idx = 0; idx < data.length; idx++) { const item = data[idx]; if(item){ if(item.infoRnDay && Number(item.infoRnDay.toString().trim()) >= 3) { item.rainEffectDay = 1; } else { item.rainEffectDay = 0; } } } // 이틀 전, 하루 전이 강우영향일(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.toString().trim()) >= 3) { data[idx]!.rainEffectDay = 1; } // 이틀 전이 강우영향일(3 이상)인 경우 if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) { data[idx]!.rainEffectDay = 1; } } } for(let idx = 0; idx < data.length; idx++) { if(data[idx] && data[idx]?.rainEffectDay === 1) { if(idx > 1){ if(data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) { data[idx]!.infoRnDay = data[idx-1]!.infoRnDay; } } if(idx > 2){ if(data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) { data[idx]!.infoRnDay = data[idx-2]!.infoRnDay; } } } } let rtnData : FlowDataItem[] = []; if (weather === 'ALL') { rtnData = data; } else if (weather === 'SUNNY') { rtnData = data.filter((item: FlowDataItem) => item.rainEffectDay === 0); } else { rtnData = data.filter((item: FlowDataItem) => item.rainEffectDay === 1); } return rtnData; } 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) => { set((state: UnderWaterType) => ({ ...state, UnderWater: { ...state.UnderWater, isLoading: true, }, })); const res = await fetchUnderWaterList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); const data = res.data; const calData = await Promise.all(data.map(async (item: UnderWaterProps) => { item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); const bscFctCd = item.bscFctCd; const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as ApiResponse; const calData = calRainEffectDay(res2.data, 'SUNNY'); let chungcunSumFlow = 0; let sumSummerChungcunDay = 0; let sumSummerChungcunFlow = 0; let sumWinterChungcunDay = 0; let sumWinterChungcunFlow = 0; calData.forEach((flowItem: FlowDataItem) => { chungcunSumFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; if(flowItem.msrDt.substring(4,6) ==='06' || flowItem.msrDt.substring(4,6) ==='07' || flowItem.msrDt.substring(4,6) ==='08'){ sumSummerChungcunDay += 1; sumSummerChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; }else if(flowItem.msrDt.substring(4,6) ==='01' || flowItem.msrDt.substring(4,6) ==='02'){ sumWinterChungcunDay += 1; sumWinterChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; } }); const usage = chungcunSumFlow / calData.length; const summerUsage = sumSummerChungcunFlow / sumSummerChungcunDay; const winterUsage = sumWinterChungcunFlow / sumWinterChungcunDay; item.underWaterInputYear = Math.round((usage-(usage*0.65*0.8)) * 100) / 100; item.underWaterInputSummer = Math.round((summerUsage-(summerUsage*0.65*0.8)) * 100) / 100; item.underWaterInputWinter = Math.round((winterUsage-(winterUsage*0.65*0.8)) * 100) / 100; return item; })); const excelDownList: ExcelType[] = []; if(pageSize>5000){ calData.forEach(item => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); /* item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; */ excelDownList.push({ 시설코드: item.bscFctCd, 권역: item.rvbsn, 단위유역: item.lgbsn, 중권역: item.mdmbsn, 환경청: item.rgnNm, 시도: item.sidoNm, 시군구: item.sggNm, 시설명: item.bscFctNm, 주소: item.daddr, 시설용량: item.fctCpc, 연간지하수유입량: item.underWaterInputYear, 하절기지하수유입량: item.underWaterInputSummer, 동절기지하수유입량: item.underWaterInputWinter, }); }); }else{ data.forEach((item: UnderWaterProps) => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); /* item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; */ }); } set((state: UnderWaterType) => ({ ...state, UnderWater: pageSize<5000?{ ...state.UnderWater, underWaterList: calData, underWaterCount: res.count, isLoading : false, }:{ ...state.UnderWater, isLoading : false, excelList: excelDownList }, })) }, unserWaterModal:async (bscFctCd, searchYear)=>{ console.log('searchYear : ', searchYear); const res = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear); const monthData: SewageOccurDetailProps[] = []; const calData = calRainEffectDay(res.data, 'SUNNY'); let tot = 0, cnt= 0; let tmpTot = 0; calData.forEach((item: FlowDataItem) => { tmpTot += Number(item.inflAmnt); }) console.log('tmpTot : ', tmpTot/calData.length); calData.forEach((item: FlowDataItem) => { const month = item.msrDt?.substring(4, 6); const monthIdx = month ? Number(month) - 1 : -1; if (monthIdx >= 0) { if (typeof monthData[monthIdx] === 'object') { monthData[monthIdx].sum += Number(item.inflAmnt); monthData[monthIdx].cnt++; } else { monthData[monthIdx] = {cnt:1, sum:Number(item.inflAmnt), yr:item.msrDt.substring(0,4), usege:0}; } } tot += Number(item.inflAmnt) cnt++ }) const tableData:UnderWaterInputModalProps[] = [] let maxWaterUsage = 0; let minWaterUsage = 9999999999; let avgWaterUsage = 0; monthData.forEach((item, index) => { item.usege = item.sum/item.cnt tableData.push({ msrDt: item.yr+'-'+(index+1>=10?String(index+1):'0'+(index+1)), realSewageInput:Math.round(item.usege*100) /100, sewageOccur:Math.round(item.usege*0.65*0.8 * 100) / 100, underWaterInput:Math.round((item.usege-(item.usege*0.65*0.8)) * 100) / 100, }) if (item.usege > maxWaterUsage) { maxWaterUsage = item.usege; } if (item.usege < minWaterUsage) { minWaterUsage = item.usege; } }); avgWaterUsage = tot/cnt const newData= [ { msrDt: '평균', realSewageInput:Math.round(avgWaterUsage*100) /100, sewageOccur:Math.round(avgWaterUsage*0.65*0.8 * 100) / 100, underWaterInput:Math.round((avgWaterUsage-(avgWaterUsage*0.65*0.8)) * 100) / 100, }, { msrDt: '최대', realSewageInput: Math.round(maxWaterUsage*100) /100, sewageOccur: Math.round(maxWaterUsage*0.65*0.8 * 100) / 100, underWaterInput: Math.round((maxWaterUsage-(maxWaterUsage*0.65*0.8)) * 100) / 100, }, { msrDt: '최소', realSewageInput: Math.round(minWaterUsage*100) /100, sewageOccur: Math.round(minWaterUsage*0.65*0.8 * 100) / 100, underWaterInput: Math.round((minWaterUsage-(minWaterUsage*0.65*0.8)) * 100) / 100, }, ...tableData ] set((state: UnderWaterType) => ({ ...state, UnderWaterDetail: { ...state.UnderWaterDetail, gridListUnderWaterDetail:newData } })) } } }