329 lines
11 KiB
TypeScript
329 lines
11 KiB
TypeScript
import { useWrStore } from "@/app/store";
|
|
import type { TableUpperProps } from "@/app/store/common/type/header";
|
|
import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
|
|
import type { rswtrPolutionsZode } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList";
|
|
import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable";
|
|
import { ScrollArea, Title } from "@common/business_components/ui";
|
|
import { Button } from "@common/components/ui";
|
|
import React, { useEffect, useState } from "react";
|
|
import type { z } from "zod";
|
|
|
|
export default function ChkgdModal({ type, obj, setIsModal, readonly }: { type: string; obj: any, setIsModal: (open: boolean) => void, readonly: boolean }) {
|
|
const {
|
|
rainChkgdn,
|
|
rswtChkgdn,
|
|
rainChkSttn,
|
|
rswtChkSttn,
|
|
rainChkGuidUpdate,
|
|
rwstPolAndGuideUpdate,
|
|
} = useWrStore((state) => state);
|
|
const [guidData, setGuidData] = useState<splRuseWaterType[]>();
|
|
const [headList, setHeadList] = useState<{
|
|
splHeadList: TableUpperProps[];
|
|
ruseHeadList: TableUpperProps[];
|
|
rswtDetailHeadList: TableUpperProps[];
|
|
}>({ splHeadList: [], ruseHeadList: [], rswtDetailHeadList: [] });
|
|
|
|
const [polutionData, setPolutionData] = useState<Record<string, any[]>>({
|
|
"1": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
"2": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
"3": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
"4": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
});
|
|
const [upPolutionData, setUpPolutionData] = useState<Record<string, any[]>>({
|
|
"1": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
"2": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
"3": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
"4": [] as z.infer<typeof rswtrPolutionsZode>[],
|
|
});
|
|
|
|
const [updateData, setUpdateData] = useState<splRuseWaterType[]>();
|
|
|
|
const initStats = (): z.infer<typeof rswtrPolutionsZode> => ({
|
|
grssClfgUswtr: 0,
|
|
combResdch: 0,
|
|
trbt: 0,
|
|
bod: 0,
|
|
smll: 0,
|
|
crmty: 0,
|
|
tph: 0,
|
|
tn: 0,
|
|
ph: 0,
|
|
clIonQnt: 0,
|
|
});
|
|
|
|
///현황일 경우 input 비활성화 한다.
|
|
useEffect(() => {
|
|
if (rainChkSttn.isSttn) {
|
|
setHeadList({
|
|
splHeadList: rainChkSttn.splHeadList,
|
|
ruseHeadList: rainChkSttn.ruseHeadList,
|
|
rswtDetailHeadList: type === "RNB" ? [] : rswtChkSttn.rswtDetailSttnHeadList,
|
|
});
|
|
} else {
|
|
setHeadList({
|
|
splHeadList: rainChkgdn.splHeadList,
|
|
ruseHeadList: rainChkgdn.ruseHeadList,
|
|
rswtDetailHeadList:
|
|
type === "RNB" ? [] : rswtChkgdn.rswtDetailHeadList,
|
|
});
|
|
}
|
|
}, [
|
|
rainChkSttn.isSttn,
|
|
rainChkgdn.splHeadList,
|
|
rainChkSttn.splHeadList,
|
|
rswtChkgdn.rswtDetailHeadList,
|
|
rswtChkSttn.rswtDetailSttnHeadList
|
|
]);
|
|
|
|
useEffect(() => {
|
|
const result = obj.guideDetails?.reduce((acc: any, cur: any) => {
|
|
const code = cur.utztnUsgCd;
|
|
const month = cur.ym?.slice(4); // "MM"
|
|
const ruseMonthKey = `ruse${month}`;
|
|
const splMonthKey = `spl${month}`;
|
|
|
|
const ruseValue = cur.ruseFcltUtztnQnt;
|
|
const splValue = cur.splyUswtrUtztnQnt;
|
|
|
|
// 해당 utztnUsgCd 객체가 없으면 새로 생성
|
|
let target = acc.find(
|
|
(it: { utztnUsgCd: string }) => it?.utztnUsgCd === code
|
|
);
|
|
if (!target) {
|
|
target = { utztnUsgCd: code, ruseTotal: 0, splTotal: 0 };
|
|
acc.push(target);
|
|
}
|
|
// 월별 값 누적
|
|
target[ruseMonthKey] = (target[ruseMonthKey] ?? 0) + ruseValue;
|
|
target[splMonthKey] = (target[splMonthKey] ?? 0) + splValue;
|
|
// total 누적
|
|
target.ruseTotal += ruseValue;
|
|
target.splTotal += splValue;
|
|
return acc;
|
|
}, []);
|
|
|
|
if (result) {
|
|
// '기타' 항목을 배열의 맨 뒤로 정렬합니다.
|
|
result.sort((a: splRuseWaterType, b: splRuseWaterType) => {
|
|
if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다.
|
|
if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다.
|
|
return 0; // 순서를 유지합니다.
|
|
});
|
|
}
|
|
|
|
setGuidData(result as splRuseWaterType[]);
|
|
|
|
if (obj.rswtrPollutions) {
|
|
const resultPolution: Record<string, any[]> = {
|
|
"1": [],
|
|
"2": [],
|
|
"3": [],
|
|
"4": [],
|
|
};
|
|
obj.rswtrPollutions.forEach(
|
|
(item: z.infer<typeof rswtrPolutionsZode>) => {
|
|
const nodeKey = String(item.node);
|
|
resultPolution[nodeKey]?.push(item);
|
|
}
|
|
);
|
|
|
|
// 각 노드에 대해 합계/평균 추가
|
|
Object.entries(resultPolution).forEach(([nodeKey, items]) => {
|
|
const onlyData = items as z.infer<typeof rswtrPolutionsZode>[];
|
|
if (onlyData.length === 0) return;
|
|
|
|
const total = initStats();
|
|
onlyData.forEach((item) => {
|
|
total.grssClfgUswtr += item.grssClfgUswtr;
|
|
total.combResdch += item.combResdch;
|
|
total.trbt += item.trbt;
|
|
total.bod += item.bod;
|
|
total.smll += item.smll;
|
|
total.crmty += item.crmty;
|
|
total.tph += item.tph;
|
|
total.tn += item.tn;
|
|
total.ph += item.ph;
|
|
total.clIonQnt += item.clIonQnt;
|
|
});
|
|
|
|
const average = {
|
|
utztnUsgCd: "평균",
|
|
edit: false,
|
|
grssClfgUswtr: (total.grssClfgUswtr / onlyData.length).toFixed(1),
|
|
combResdch: (total.combResdch / onlyData.length).toFixed(1),
|
|
trbt: (total.trbt / onlyData.length).toFixed(1),
|
|
bod: (total.bod / onlyData.length).toFixed(1),
|
|
smll: (total.smll / onlyData.length).toFixed(1),
|
|
crmty: (total.crmty / onlyData.length).toFixed(1),
|
|
tph: (total.tph / onlyData.length).toFixed(1),
|
|
tn: (total.tn / onlyData.length).toFixed(1),
|
|
ph: (total.ph / onlyData.length).toFixed(1),
|
|
clIonQnt: (total.clIonQnt / onlyData.length).toFixed(1),
|
|
};
|
|
|
|
if (!resultPolution[nodeKey]) {
|
|
resultPolution[nodeKey] = [];
|
|
}
|
|
|
|
// '기타' 항목을 배열의 맨 뒤로 정렬합니다.
|
|
resultPolution[nodeKey].sort((a: any, b: any) => {
|
|
if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다.
|
|
if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다.
|
|
return 0; // 순서를 유지합니다.
|
|
});
|
|
|
|
resultPolution[nodeKey].push(average);
|
|
});
|
|
|
|
setPolutionData(resultPolution);
|
|
}
|
|
}, [obj]);
|
|
|
|
const setChGuidData = (data: splRuseWaterType[]) => {
|
|
if (data.length > 0) {
|
|
setUpdateData(data);
|
|
}
|
|
};
|
|
|
|
const allDataUpdate = () => {
|
|
const realGuideDetail = obj.guideDetails;
|
|
|
|
if (updateData === undefined || updateData.length === 0) return;
|
|
realGuideDetail.map((item: any) => {
|
|
const findObj = updateData.find(
|
|
(ch: any) => ch.utztnUsgCd === item.utztnUsgCd
|
|
);
|
|
|
|
const month = item.ym?.slice(4);
|
|
if (findObj) {
|
|
const ruseMonthKey = `ruse${month}` as keyof splRuseWaterType;
|
|
const splMonthKey = `spl${month}` as keyof splRuseWaterType;
|
|
|
|
if (
|
|
findObj[ruseMonthKey] !== undefined &&
|
|
findObj[splMonthKey] !== undefined
|
|
) {
|
|
item.splyUswtrUtztnQnt = findObj[splMonthKey];
|
|
item.ruseFcltUtztnQnt = findObj[ruseMonthKey];
|
|
|
|
return item;
|
|
}
|
|
}
|
|
});
|
|
obj.guideDetails = realGuideDetail;
|
|
if (type === "RNB") {
|
|
|
|
rainChkGuidUpdate(obj);
|
|
setIsModal(false)
|
|
} else {
|
|
const polution = Object.values(upPolutionData)
|
|
.flat()
|
|
.filter((item) => item.utztnUsgCd !== "평균");
|
|
obj.rswtrPollutions = polution;
|
|
rwstPolAndGuideUpdate([obj]);
|
|
setIsModal(false)
|
|
}
|
|
};
|
|
|
|
const getPolutionData = (data: z.infer<typeof rswtrPolutionsZode>[]) => {
|
|
const getNode = Number(data[0]?.node);
|
|
setUpPolutionData((prevPolutionData) => ({
|
|
...prevPolutionData,
|
|
[getNode]: data,
|
|
}));
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div>
|
|
<div>
|
|
<div className="flex justify-between">
|
|
<Title
|
|
title={
|
|
type === "RNB"
|
|
? "빗물이용시설 " + "지도점검 결과"
|
|
: "중수도 이용시설 " + "지도점검 결과"
|
|
}
|
|
></Title>
|
|
{!rainChkSttn.isSttn ? (
|
|
<Button className="mt-8 mr-7" onClick={allDataUpdate} disabled={!readonly}>
|
|
저장
|
|
</Button>
|
|
) : (
|
|
<></>
|
|
)}
|
|
</div>
|
|
<h3 className="text-2xl font-bold text-gray-900 mt-2 ml-6">
|
|
{type === "RNB"
|
|
? `시설명 : (${obj.bdstNm})` : `시설명 : (${obj.building.bdstNm})`}
|
|
</h3>
|
|
</div>
|
|
|
|
<ScrollArea className="h-[60vh]">
|
|
<div className="card-header">
|
|
<h3 className="text-2xl font-medium text-label">
|
|
{`연간대체수이용량`}
|
|
</h3>
|
|
</div>
|
|
<GuideDetailsTable
|
|
chgRes={guidData || []}
|
|
headList={headList.splHeadList}
|
|
upheadList={type === "RNB" ? rainChkgdn.rainSplHeadNm : rswtChkgdn.rswtSplHeadNm}
|
|
type={""}
|
|
setChGuidData={(data) => {
|
|
setChGuidData(data);
|
|
}}
|
|
readonly={readonly}
|
|
/>
|
|
<div className="card-header">
|
|
<h3 className="text-2xl font-medium text-label">
|
|
{type === "RNB" ? `연간빗물 이용량` : "연간중수도 이용량"}
|
|
</h3>
|
|
</div>
|
|
<GuideDetailsTable
|
|
chgRes={guidData || []}
|
|
headList={headList.ruseHeadList}
|
|
upheadList={type === "RNB" ? rainChkgdn.rainRuseHeadNm : rswtChkgdn.rswtRuseHeadNm}
|
|
type={""}
|
|
setChGuidData={(data) => {
|
|
setChGuidData(data);
|
|
}}
|
|
readonly={readonly}
|
|
/>
|
|
|
|
{type !== "RNB" && polutionData !== undefined ? (
|
|
<div key={"polutionData"}>
|
|
{Object.entries(polutionData).map(([key, value]) => {
|
|
const keyNum = Number(key);
|
|
|
|
return (
|
|
<React.Fragment key={`polutionData_fragment_${keyNum}`}>
|
|
<div className="card-header">
|
|
<h3 className="text-2xl font-medium text-label">
|
|
{`연간이용수질 ${keyNum}분기`}
|
|
</h3>
|
|
</div>
|
|
<GuideDetailsTable
|
|
chgRes={value}
|
|
headList={headList?.rswtDetailHeadList}
|
|
upheadList={rswtChkgdn.rswtSplHeadNm}
|
|
type={""}
|
|
setChGuidData={(data) => {
|
|
getPolutionData(data);
|
|
}}
|
|
readonly={readonly}
|
|
/>
|
|
</React.Fragment>
|
|
);
|
|
})}
|
|
</div>
|
|
) : (
|
|
<></>
|
|
)}
|
|
</ScrollArea>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|