Merge branch 'iipbs/sn/dev' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/sn/dev

This commit is contained in:
swcho
2025-11-07 10:50:56 +09:00
6 changed files with 117 additions and 104 deletions
@@ -99,7 +99,7 @@ const Map = () => {
if (feature) {
foundFeature = feature;
return;
}
}
}
}
});
@@ -132,6 +132,8 @@ const Map = () => {
},
{ width: 30 }
);
} else {
alert("수요처의 좌표정보를 찾을수 없으므로, 상단 조회조건의 시설명을 입력하여 위치를 조회하시기 바랍니다.");
}
const formatNumber = (val: any) => {
@@ -16,7 +16,7 @@ export default function CalcRainEffect(data : any, weather='ALL') {
for(let idx = 0; idx < data.length; idx++) {
const item = data[idx];
if(item){
if(item.infoRnDay && Number(item.infoRnDay) >= 3) {
if(item.infoRnDay && Number(item.infoRnDay) >= 3) { // 강우량이 3 이상인 경우
item.rainEffectDay = 1;
} else {
item.rainEffectDay = 0;
@@ -49,11 +49,13 @@ export default function CalcRainEffect(data : any, weather='ALL') {
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;
}
+12 -14
View File
@@ -11,20 +11,18 @@ export default function Home() {
const checkToken = getCookie(AUTH_USER_ID);
useEffect(() => {
const hostname = window.location.hostname;
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") {
if (!checkToken) {
async function doLogin() {
try {
await LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" });
window.location.href = "/pages/dashboard";
} catch (err) {
console.error("로그인 실패", err);
}
if (!checkToken) {
async function doLogin() {
try {
await LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" });
location.href = "/pages/dashboard";
} catch (err) {
console.error("로그인 실패", err);
}
doLogin();
} else router.push("/pages/dashboard");
} else router.push("/pages/dashboard");
}
doLogin();
} else {
router.push("/pages/dashboard");
}
}, []);
}
+20 -1
View File
@@ -1,4 +1,4 @@
import { getFetch } from "@/app/components/api";
import { getFetch, postFetch } from "@/app/components/api";
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
@@ -15,6 +15,15 @@ export type { TableUpperProps };
/**
* (1) 메인페이지
*/
// RDII 상세 타입
export interface FacilityRdiiDetailProps {
msrDt: string, // 측정일
inflAssctBfrWqltBod: string | '', // 유입연계전수질_BOD(mg/L)
inflAmnt: number | '', // 실제유입량(반류수제거)(m³/일)
infoRnDay: number | string | '', // 강수량 (mm/일)
}
// 시설수질리스트 타입
export interface FacilityWaterQltyProps {
bscFctCd: string,
@@ -306,6 +315,16 @@ export const fetchFacilityWaterQltyListHist = async (searchYear: string|undefine
return null;
}
};
// 시설정보 RDII 상세 [{BOD - inflAssctBfrWqltBod, 유입유량 inflAmnt, 강우량 infoRnDay, 측정일 msrDt}]
export const fetchFacilityRdiiDetailList = async (searchYear: string|undefined, swtrmtFcltCdList: string[]): Promise<FacilityRdiiDetailProps | null> => {
try {
const res = await postFetch('fo', '/rdii/detail/'+searchYear, swtrmtFcltCdList);
return res;
} catch (error) {
console.error('시설정보 RDII 상세 데이터를 가져오는데 실패했습니다:', error);
return null;
}
};
/**====================================
* Store - export
+73 -82
View File
@@ -1,9 +1,10 @@
import { getFetch } from "@/app/components/api";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
//import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty";
import type { FlowResponse } from "../sewageOccur";
//import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty";
import { fetchFacilityRdiiDetailList } from "../facilityWaterQlty";
//import type { FlowResponse } from "../sewageOccur";
export type { TableUpperProps };
/**====================================
* Store - 타입
@@ -245,15 +246,15 @@ const dataFormSetting=(item : RdiProps)=> {
type SetStateFunction = (state: RdiType | ((state: RdiType) => RdiType)) => void;
// 병렬 처리 제한용 헬퍼
async function processInBatches(items, batchSize, callback) {
const results:any = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(callback));
results.push(...batchResults);
}
return results;
}
// async function processInBatches(items, batchSize, callback) {
// const results:any = [];
// for (let i = 0; i < items.length; i += batchSize) {
// const batch = items.slice(i, i + batchSize);
// const batchResults = await Promise.all(batch.map(callback));
// results.push(...batchResults);
// }
// return results;
// }
export type RdiStore = RdiType & RdiActions;
@@ -302,44 +303,30 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
}));
}
const data = res.data;
const reData = await processInBatches(data, 15, async (item: any, index: number) => {
const bscFctCd = item.bscFctCd;
const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as FlowResponse;
const calData = CalcRainEffect(res2.data, 'SUNNY');
let avgChungcunSumFlow = 0;
let chungcunSumFlow = 0;
calData.forEach((flowItem: any) => {
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;
} */
});
avgChungcunSumFlow = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / calData.length : 0;
item.chungchunFlow = avgChungcunSumFlow;
item.rainCalInflAmnt = Number(avgChungcunSumFlow) + Number(item.rdiiValue);
return {...item, index:index}
});
const excelDownList: ExcelType[] = [];
const rtnData = reData.map((item: RdiProps) => {
const rtnData = res.data.map((item: RdiProps) => {
return {
...item,
sido: item.lclgvrnmntNm.split(' ')[0]?.toString() || '',
sigungo: item.lclgvrnmntNm.split(' ')[1]?.toString() || '',
inflAmnt: item.inflAmnt?Number(item.inflAmnt).toFixed(1): ''
inflAmnt: item.inflAmnt?Number(item.inflAmnt).toFixed(1): '' // 유입유량 (강우량)
}
})
// 청천히 동절기 유입bod를 새로 구하기 위해서 재 호출
const fcltCdList : string[]= [];
rtnData.forEach(item => {
fcltCdList.push(item.bscFctCd);
});
const rdiiDetailListRes : any = await fetchFacilityRdiiDetailList(searchYear, fcltCdList);
console.log(rdiiDetailListRes);
for (const item of rtnData) {
const fcltyCd = item.bscFctCd;
const res: any = await fetchFacilityWaterQltyListHist(searchYear, fcltyCd);
//const fcltyCd = item.bscFctCd;
//const res: any = await fetchFacilityWaterQltyListHist(searchYear, fcltyCd);
//const rdiiDetailList = res.data.wqltObjs;
const rdiiDetailList = rdiiDetailListRes?.data[item.bscFctCd];
//console.log(rdiiDetailListRes);
let rtnWinterInflBod = 0;
let rtnSummerBodInfl = 0;
@@ -348,50 +335,53 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
let rtnRdiRain = 0;
let chungchunFlow = 0;
if (res?.data) {
const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? [];
const rtnWqltData = res.data.wqltObjs;
const wqltDataTot = CalcRainEffect(clone(rtnWqltData));
const wqltDataSunny = CalcRainEffect(clone(rtnWqltData), 'SUNNY');
if (rdiiDetailList) {
let chungchunInfl = 0;
let chungchunInfl = 0; // 청천시 유입
let chungchunCnt = 0;
let minSummerBod = 99999999;
let minSummerBodInfl = 99999999;
let winterCnt = 0;
let winterBodSunny = 0;
let rdiRain = 0;
let rdiRain = 0;
const summerMonth = ['06', '07', '08'];
const winterMonth = ['01', '02'];
wqltDataTot.forEach(item2 => {
if(item2.rainEffectDay == 0){
chungchunCnt ++;
chungchunInfl += Number(item2.inflAmnt);
}
if(summerMonth.includes(item2.msrDt.toString().replaceAll('-','').substring(4,6))){
if(Number(item2.infoRnDay)>=3){
//const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? [];
let rainEffectDay = 0;
rdiiDetailList.forEach(item2 => {
if (item2.infoRnDay == null) item2.infoRnDay = 0;
if(item2.infoRnDay >= 3) {
rainEffectDay = 2;
//강우시
if(summerMonth.includes(item2.msrDt.toString().replaceAll('-','').substring(4,6))){
//하절기
const inflBod = Number(item2.inflAssctBfrWqltBod);
const infl = Number(item2.inflAmnt);
const rain = Number(item2.infoRnDay);
if(inflBod < minSummerBod){
minSummerBodInfl = infl;
minSummerBod = inflBod;
rdiRain = rain;
minSummerBodInfl = infl; // 강우일 하절기 최저 유입 BOD 일때의 유입유량
minSummerBod = inflBod; // 강우일 하절기 최저 유입 BOD
rdiRain = rain; // 강우일 하절기 최저 유입 BOD 일때의 강우량
}
}
}else{
rainEffectDay--;
}
if(rainEffectDay<0){
//청천시
chungchunInfl += item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0;
chungchunCnt ++;
if(winterMonth.includes(item2.msrDt.toString().replaceAll('-','').substring(4,6))){
winterBodSunny += Number(item2.inflAssctBfrWqltBod); // 동절기 청천시 유입BOD 합계
winterCnt += 1;
}
}
});
wqltDataSunny.filter(item=>winterMonth.includes(item.msrDt.toString().replaceAll('-','').substring(4,6))).forEach(item2 => {
winterBodSunny += Number(item2.inflAssctBfrWqltBod);
winterCnt += 1;
});
minSummerBod = minSummerBod === 99999999 ? 0 : minSummerBod;
minSummerBodInfl = minSummerBodInfl === 99999999 ? 0 : minSummerBodInfl;
minSummerBod = minSummerBod === 99999999 ? 0 : minSummerBod; // 강우일 최저 유입 BOD
minSummerBodInfl = minSummerBodInfl === 99999999 ? 0 : minSummerBodInfl; // 강우일 최저 유입 BOD일때 유입유량
const roundMinSummerBodInfl = Number(roundNumber(minSummerBodInfl, 0).toString().replaceAll(',',''));
const roundMinSummerBod = Number(roundNumber(minSummerBod, 1).toString().replaceAll(',',''));
@@ -401,23 +391,24 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
// 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD))
const winMinusSum = winterBodAvg - roundMinSummerBod;
const rdiValue = winMinusSum===0 ? 0 : roundMinSummerBodInfl * (winMinusSum / winterBodAvg );
const rdiValue = winMinusSum===0 ? 0 : roundMinSummerBodInfl * (winMinusSum / winterBodAvg ); // RDII 추정
rtnWinterInflBod = winterBodAvg;
rtnSummerBodInfl = minSummerBodInfl;
rtnSummerBod = minSummerBod;
rtnRdiValue = rdiValue;
rtnRdiRain = rdiRain;
chungchunFlow = chungchunInfl == 0? 0 : chungchunInfl / chungchunCnt;
rtnWinterInflBod = winterBodAvg; // 동절기 청천시 유입BOD
rtnSummerBodInfl = minSummerBodInfl; // 하절기(6~8월) 중 최저 유입 BOD일때 유입유량
rtnSummerBod = minSummerBod; // 하절기(6~8월) 중 최저 유입 BOD
rtnRdiValue = rdiValue; // RDII 추정
rtnRdiRain = rdiRain; // RDII 추정시 일강수량
chungchunFlow = chungchunInfl == 0? 0 : chungchunInfl / chungchunCnt; // 청천시 유입하수량
}
item.summerMinBodValue = roundNumber(rtnSummerBod,1);
item.inflAmnt = roundNumber(rtnSummerBodInfl.toString(), 0);
item.winterAvgBodLowRainfall = rtnWinterInflBod?roundNumber(rtnWinterInflBod, 1):0;
item.rdiiValue = rtnRdiValue?roundNumber(rtnRdiValue, 0):0;
item.infoRnDay = roundNumber(rtnRdiRain, 0);
item.chungchunFlow = roundNumber(chungchunFlow, 0);
item.rainCalInflAmnt = roundNumber(Number(item.chungchunFlow.toString().replaceAll(',','')) + Number(item.rdiiValue.toString().replaceAll(',','')), 0) || 0;
item.summerMinBodValue = roundNumber(rtnSummerBod,1); // 하절기강우일최저유입BOD(mg/L)
item.inflAmnt = roundNumber(rtnSummerBodInfl.toString(), 0); // 하절기최저유입BOD유입유량(m³/일)
item.winterAvgBodLowRainfall = rtnWinterInflBod?roundNumber(rtnWinterInflBod, 1):0; // 동절기청천시유입BOD(mg/L)
item.rdiiValue = rtnRdiValue?roundNumber(rtnRdiValue, 0):0; // RDII추정
item.infoRnDay = roundNumber(rtnRdiRain, 0); // RDII추정시일강수량(mm)
item.chungchunFlow = roundNumber(chungchunFlow, 0); //청천시유입하수량(m³/일)
item.rainCalInflAmnt = roundNumber(Number(item.chungchunFlow.toString().replaceAll(',',''))
+ Number(item.rdiiValue.toString().replaceAll(',','')), 0) || 0; // 강우시총추정유입량(m³/일)
item.properYn = Number(item.rainCalInflAmnt.toString().replaceAll(',','')) > Number(item.fctCpc.toString().replaceAll(',','')) ? '초과유입' : '적정';
}
@@ -1,7 +1,8 @@
"use client";
import { useEffect } from "react";
import { useRouter, usePathname } from "next/navigation";
import { useRouter } from "next/navigation";
//import { usePathname } from "next/navigation";
import { client } from "@/src/shared/api";
import type { IUserInfo } from "@/src/shared/store";
import { useUserStore, getCookie } from "@/src/shared/lib";
@@ -12,7 +13,7 @@ const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://loca
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
const router = useRouter();
const pathname = usePathname();
//const pathname = usePathname();
const { userInfo, setUserInfo } = useUserStore((state) => state);
async function authCheck() {
@@ -41,7 +42,7 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
console.error("Token refresh failed:", refreshError);
setUserInfo(null);
const hostname = window.location.hostname;
const hostname = location.hostname;
// 개발 환경에서는 localhost 도메인 사용
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
@@ -49,11 +50,11 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
// 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용
// router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용
if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
if (hostname.includes("hasuon.or.kr")) location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
}
}
})();
}, [pathname]);
}, []);
return <>{children}</>;
};