Merge remote-tracking branch 'origin/iipbs/wr/prfSttn' into iipbs/wr/dev

This commit is contained in:
2025-07-26 16:42:59 +09:00
6 changed files with 264 additions and 179 deletions
@@ -117,6 +117,7 @@ export default function PbnstSttn() {
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
buttonOrder={["query", "init", "excel"]}
rightClassName="ml-auto mr-6 flex items-center space-x-1"
leftClassName="flex gap-5 w-9/12 m-4"
leftSelectClassName="w-1/4"
@@ -22,12 +22,13 @@ export default function PbnstPrfmncSttn() {
pbnstPrfmncSttn,
// pbnstPrfmncInit,
pbnstPrfmncSearch,
getFlcts,
prfmnc,
pbnstSttn,
pbnNmSearch
} = useWrStore((state) => state);
const { monthHeadList } = prfmnc
const { pbnstPrfHeadList, prfmncRes, rawData, selectYearList } = pbnstPrfmncSttn;
const { pbnstPrfHeadList, prfmncResCount, prfmncRes, rawData, selectYearList, fclts } = pbnstPrfmncSttn;
// const [isChHead, setIsChHead] = useState(false);
const [fromDate, setFromDate] = useState<string>(String(new Date().getFullYear()));
const [toDate, setToDate] = useState<string>(String(new Date().getFullYear()));
@@ -39,6 +40,8 @@ export default function PbnstPrfmncSttn() {
const { t } = useTranslation('base');
const searchYear = String(new Date().getFullYear());
const [excelData, setExcelData] = useState<any[]>([]);
const [pageNation, setPageNation] = useState(1);
const [resetPage, isResetPage] = useState(false);
const excelClick = useCallback(() => {
if (!excelData || excelData.length === 0) {
toast.error(t('excelDownErrMsg'));
@@ -489,17 +492,25 @@ export default function PbnstPrfmncSttn() {
sigunText: ""
}
tableHeadMaker(Number(searchYear), Number(searchYear));
pbnstPrfmncSearch(returnType, "", searchYear, searchYear)
getFlcts();
pbnstPrfmncSearch(1, returnType, "", searchYear, searchYear, fclts)
}, []);
useEffect(() => {
setbdstTable(prfmncRes.map((e, idx) => {
pbnstPrfmncSearch(pageNation, ref.current, pbnRuseNm, fromDate, toDate, pbnstPrfmncSttn.fclts);
isResetPage(false)
}, [fclts, pageNation]);
useEffect(() => {
const tableData = prfmncRes.map((e, idx) => {
return ({
...e,
number: String(idx + 1)
})
}))
})
setbdstTable(tableData)
if (prfmncRes?.[0]?.pbnstRuseFcltId) setChartId(prfmncRes[0].pbnstRuseFcltId)
}, [prfmncRes]);
@@ -533,6 +544,7 @@ export default function PbnstPrfmncSttn() {
rightClassName="ml-auto mr-6 flex items-center space-x-1"
leftClassName="flex gap-5 w-9/12 m-4"
leftSelectClassName="w-1/6"
buttonOrder={["query", "init", "excel"]}
leftChildren={<div className="col-span-5">
<div className="flex flex-row">
{/* <div className="flex flex-row items-center"> */}
@@ -548,7 +560,7 @@ export default function PbnstPrfmncSttn() {
selectArray={yearOptions}
value={fromDate}
onSelectValue={(val: string | number) => setFromDate(String(val))} />
<span> ~</span>
<span> ~</span>
<SelectBox
// className="w-full h-full text-2xl mx-4"
className="flex-none w-32 h-full text-2xl mr-4"
@@ -579,7 +591,7 @@ export default function PbnstPrfmncSttn() {
</div>
</div>}
queryClick={function (returnType: ReturnType): void {
pbnstPrfmncSearch(returnType, pbnRuseNm ?? "", fromDate, toDate);
pbnstPrfmncSearch(1, returnType, pbnRuseNm ?? "", fromDate, toDate, fclts);
if (fromDate && toDate) {
const fromNum = Number(fromDate);
const toNum = Number(toDate);
@@ -594,6 +606,7 @@ export default function PbnstPrfmncSttn() {
}
}
}
isResetPage(true)
}}
excelClick={excelClick}
initClick={function (): void { }}
@@ -608,13 +621,14 @@ export default function PbnstPrfmncSttn() {
headName={undefined}
tableData={bdstTable || []}
headlist={pbnstPrfHeadList}
pageSize={20}
total={10000}
pageSize={5}
total={prfmncResCount}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index ?? undefined, headId);
}}
onPageChange={() => { }}
onPageChange={setPageNation}
index={0}
resetPageNo={resetPage}
/>
<hr />
@@ -653,32 +667,8 @@ export default function PbnstPrfmncSttn() {
</div>
</div>
<h1 className="">하수재이용실적 현황 (단위: m³)</h1>
{/* <ListDiv className="col-span-8 pr-6 "> */}
{/* <ScrollArea className="h-[60vh]"> */}
{/* <div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수처리수재이용 실적(m³) 등록결과"}
</h3>
</div> */}
{/* <UiTable
headName={undefined}
tableData={prfData || []}
headlist={monthHeadList}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={()=>{}}>
</UiTable> */}
<ListDiv className="col-span-8 pr-6 ">
<ScrollArea className={prfData && prfData.length > 0 ? "h-[60vh]" : ""}>
{/* <div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수재이용실적 현황 (단위: m³)"}
</h3>
</div> */}
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(monthHeadList, [])}
@@ -690,10 +680,7 @@ export default function PbnstPrfmncSttn() {
</Table>
</ScrollArea>
</ListDiv>
{/* </ScrollArea> */}
</ListDiv>
{/* </ListDiv> */}
</div>
</div>
</ContentsDiv>
@@ -4,11 +4,12 @@ import { monthSttnHeadListExport, pbnstPrfmncSttnHeadListExport, pbnstYearHeadLi
import type { FcPrfType, PrfType } from "../../prfmncReg/pbnstPrfmncReg/type";
import type { pubHasuType, selectLabel } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
import type { ReturnType } from "@common/business_components";
import type { WaterReuseFacility } from "../../ruseFcltMng/fcltSttn/pbnstSttn/type";
type pbnstPrfmncSttnActions = {
tableHeadMaker: (startYear: number, endYear: number) => void;
pbnstPrfmncInit: (page: string, sggOrCity: string) => void;
pbnstPrfmncSearch: (returnType: ReturnType, swtrmtFcltNm: string, fromDate: string, toDate: string) => void;
// pbnstPrfmncInit: (page: string, sggOrCity: string) => void;
pbnstPrfmncSearch: (page: number, returnType: ReturnType, fcltNm: string, fromDate: string, toDate: string, fclts: string[]) => void;
}
const pbnstPrfmncRes: PrfType[] = [];
@@ -22,7 +23,9 @@ export type pbnstPrfmncSttnState = {
isInit: boolean;
rawData: any[];
selectYearList: selectLabel[]
monthSttnHeadList:TableUpperProps[];
monthSttnHeadList: TableUpperProps[];
fclts: string[];
prfmncResCount: number;
}
}
@@ -36,34 +39,75 @@ export const pbnstPrfmncSttnExport: pbnstPrfmncSttnState = {
isInit: false,
rawData: [],
selectYearList: [],
monthSttnHeadList:monthSttnHeadListExport
monthSttnHeadList: monthSttnHeadListExport,
fclts: [],
prfmncResCount: 1,
}
}
const checkWrRegList = async () => {
const wrRegList = await getFetch("wr", `/reuseFc/pubDetailList`);
return wrRegList;
};
const hasuListFetch = async (page: string, sggOrCity: string) => {
const checkWrRegListRes = await checkWrRegList();
const rainRes = await postFectch(
`/prcsFclt/ruseInfo/${page ? page : 1}/10/A/${sggOrCity ? sggOrCity : "11"}/0/1/SW`,
checkWrRegListRes?.fcltCds,
fetchType.COMMON
const hasuListFetch = async (
page: number,
returnType: ReturnType,
searchNm: string | undefined,
year: string,
flcts: string[]
) => {
let url = `/prcsFclt/ruseInfo/`;
if (returnType.partValue === "A") {
url += `${page}/5/${returnType.partValue}/${
// returnType.sidoValue ? returnType.sidoValue : returnType.sigunValue
returnType.sigunValue !== '0' ? returnType.sigunValue : returnType.sidoValue
}/0/1/SW`
} else if (returnType.partValue === "R") {
url += `${page}/5/${returnType.partValue}/${returnType.regionValue
? returnType.regionValue
: returnType.unitWaterShedValue
? returnType.unitWaterShedValue
: returnType.middleRegionValue
}/0/1/SW`
} else if (returnType.partValue === 'G') {
url += `${page}/5/${returnType.envPartValue}/${returnType.sigunValue !== '0' ? returnType.sigunValue : returnType.sidoValue}/0/1/SW`
} else {
url += `1/2/A/0/0/1/SW`
}
if (searchNm && searchNm?.length > 0) {
url += "/" + searchNm
}
const pbnList = await postFectch(url, flcts, fetchType.COMMON);
const getRuseList = await postFectch(
`/reuseFc/pubDetailList/${year}`,
flcts,
fetchType.WR
);
const data = checkWrRegListRes.fcPrfList.map((item: FcPrfType) => {
const findData = rainRes.data.find(
(fclt: pubHasuType) =>
fclt.bscFctCd === item.pbnstRuseFcltId.substring(0, 11)
);
return {
sido: findData?.sido,
gugun: findData?.gugun,
bscFctNm: findData?.bscFctNm,
ruseUtztnFcltNm: item.ruseUtztnFcltNm,
pbnstRuseFcltId: item.pbnstRuseFcltId,
};
});
let count = 0;
const checkWrRegListRes = getRuseList.data;
const data: WaterReuseFacility[] = checkWrRegListRes.map(
(item: FcPrfType) => {
if (!item.prfList || item.prfList.length === 0) {
return null;
}
const findData = pbnList.data.find(
(fclt: pubHasuType) =>
fclt.bscFctCd === item.pbnstRuseFcltId.substring(0, 11)
);
if (findData) {
count++;
return {
sido: findData?.sido || '-',
gugun: findData?.gugun || '-',
bscFctNm: findData?.bscFctNm || '-',
ruseUtztnFcltNm: item?.ruseUtztnFcltNm || '-',
pbnstRuseFcltId: item?.pbnstRuseFcltId || '-',
bscFctCd: findData?.bscFctCd || '-',
count
}
}
}
).filter(Boolean);
return data;
}
@@ -71,6 +115,15 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions
set: any
) => {
return {
getFlcts: async () => {
const fclts = await getFetch(fetchType.WR, '/reuseFc/pubFc')
return set((state: pbnstPrfmncSttnState) => ({
pbnstPrfmncSttn: {
...state.pbnstPrfmncSttn,
fclts: fclts
},
}));
},
tableHeadMaker: (startYear: number, endYear: number) => {
let yearHeader: TableUpperProps[] = [...pbnstPrfmncSttnHeadListExport];
const selectList = [] as unknown as selectLabel[]
@@ -79,7 +132,7 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions
if (yearHead) {
yearHead.forEach((item: { id?: string; }) => {
if (item.id) {
if(item.id === "year") {item.id = ""; return;}
if (item.id === "year") { item.id = ""; return; }
item.id = i + item.id;
}
})
@@ -100,117 +153,144 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions
};
});
},
pbnstPrfmncInit: async (page: string, sggOrCity: string) => {
// pbnstPrfmncInit: async (page: string, sggOrCity: string) => {
// try {
// const prfmncRes = await hasuListFetch(page, sggOrCity);
// return set((state: pbnstPrfmncSttnState) => ({
// ...state,
// pbnstPrfmncSttn: {
// ...state.pbnstPrfmncSttn,
// prfmncRes: prfmncRes,
// isInit: true,
// },
// }));
// } catch (e) {
// console.log(e)
// }
// },
pbnstPrfmncSearch: async (page: number, returnType: ReturnType, fcltNm: string, fromDate: string, toDate: string, fclts: string[]) => {
try {
const prfmncRes = await hasuListFetch(page, sggOrCity);
const prfmncRes = await hasuListFetch(
page,
returnType,
fcltNm,
toDate,
fclts);
// const bscFctCdList = prfmncRes.map((item: any) => {
// return item.bscFctCd;
// })
const bscFctCdList = prfmncRes
.map((item: any) => item.bscFctCd)
.filter((value, index, self) => self.indexOf(value) === index);
// const bscFctCdList = [...new Set(prfmncRes.map((item: any) => item.bscFctCd))];
const res = await postFectch(
`/reuseFc/pubDetailList/${fromDate}/${toDate}`,
bscFctCdList,
`wr`,
)
let inUsageSum = 0;
let outUsageSum = 0;
let year = "";
const yearsData = [] as any
res.data.forEach((item: any) => {
if (item.prfList.length === 0) {
const year: string = ""; // 연도 정보가 없으면 빈 문자열, 필요시 item에서 추출.
const yearVal: { [key: string]: any } = { year: year, pbnstRuseFcltId: item.pbnstRuseFcltId ?? "", ruseUtztnFcltNm: item.ruseUtztnFcltNm ?? "" };
yearVal[`${year}inUsage`] = 0;
yearVal[`${year}outUsage`] = 0;
yearVal[`${year}total`] = 0;
yearsData.push(yearVal);
}
item.prfList.forEach((acc) => {
year = acc.ym?.substring(0, 4) ?? "";
inUsageSum =
(acc.wshwtr ?? 0) + //조경용수
(acc.coolUswtr ?? 0) + //냉각수
(acc.cleanUswtr ?? 0) + //청소수
(acc.drwtUswtr ?? 0) + //식수대
(acc.dltnUswtr ?? 0) + //희석용수
(acc.ithlRswtr ?? 0) + //중수도
(acc.ithlEtcUswtr ?? 0) //기타
outUsageSum =
(acc.cleanToilUswtr ?? 0) + //청소화장실용수
(acc.resn ?? 0) + //세척살수용도
(acc.lndwtr ?? 0) + //조경용수
(acc.hydUswtr ?? 0) + //친수용수
(acc.ugwtChr ?? 0) + //지하수충전
(acc.farmUswtr ?? 0) + //농업용수
(acc.rvrKeepUswtr ?? 0) + //하천등유지용수
(acc.indstUswtr ?? 0); //공업용수
const yearData = yearsData.find(
(yearItem) =>
yearItem.year === year &&
yearItem.pbnstRuseFcltId == acc.pbnstRuseFcltId
);
if (yearData) {
yearData[`${year}inUsage`] += inUsageSum;
yearData[`${year}outUsage`] += outUsageSum;
yearData[`${year}total`] += (inUsageSum + outUsageSum);
} else {
const yearVal: { [key: string]: any } = { year: year, pbnstRuseFcltId: acc.pbnstRuseFcltId, ruseUtztnFcltNm: item.ruseUtztnFcltNm ?? "" };
yearVal[`${year}inUsage`] = inUsageSum;
yearVal[`${year}outUsage`] = outUsageSum;
yearVal[`${year}total`] = inUsageSum + outUsageSum;
yearsData.push(yearVal);
}
});
});
// 연도 필터링
const from = Number(fromDate);
const to = Number(toDate);
// 연도별 실적을 시설별로 병합
const mergedMap: { [key: string]: any } = {};
yearsData.forEach((acc) => {
const facilityId = acc.pbnstRuseFcltId;
const year = acc.year;
// 연도 필터 범위 안에만 포함
if (!year || Number(year) < from || Number(year) > to) return;
if (!mergedMap[facilityId]) {
mergedMap[facilityId] = {
pbnstRuseFcltId: facilityId,
ruseUtztnFcltNm: acc.ruseUtztnFcltNm,
};
}
// 해당 연도 데이터 추가
mergedMap[facilityId][`${year}inUsage`] = acc[`${year}inUsage`] ?? 0;
mergedMap[facilityId][`${year}outUsage`] = acc[`${year}outUsage`] ?? 0;
mergedMap[facilityId][`${year}total`] = acc[`${year}total`] ?? 0;
});
// prfmncRes 정보 merge
const resData = Object.values(mergedMap).map((item: any) => {
const match = prfmncRes.find((res) => res.pbnstRuseFcltId === item.pbnstRuseFcltId);
return match ? { ...item, ...match } : item;
});
return set((state: pbnstPrfmncSttnState) => ({
...state,
pbnstPrfmncSttn: {
...state.pbnstPrfmncSttn,
prfmncRes: prfmncRes,
isInit: true,
// prfmncRes: prfmncRes,
prfmncResCount: fclts.length - 5,
isInit: false,
prfmncRes: resData,
rawData: res.data
},
}));
} catch (e) {
console.log(e)
} catch (errorHasu) {
console.log(errorHasu);
}
},
pbnstPrfmncSearch: async (returnType: ReturnType, swtrmtFcltNm: string, fromDate: string, toDate: string) => {
let searchUrl = "";
if (returnType.sigunValue !== "0") {
if (swtrmtFcltNm !== "") {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sigunValue}/0/1/SW${'/' + swtrmtFcltNm}`;
} else {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sigunValue}/0/1/SW`;
}
} else {
if (swtrmtFcltNm !== "") {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sidoValue}/0/1/SW${'/' + swtrmtFcltNm}`;
} else {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sidoValue}/0/1/SW`;
}
}
const pbnstRes = await getFetch(
fetchType.COMMON,
searchUrl
);
const bscFctCdList = pbnstRes.map((item: any) => {
return item.bscFctCd;
})
const res = await postFectch(
`/reuseFc/pubDetailList/${fromDate}/${toDate}`,
bscFctCdList,
`wr`,
)
let inUsageSum = 0;
let outUsageSum = 0;
let year = "";
const yearsData = [] as any
res.data.forEach((item : any) => {
if (item.prfList.length === 0) {
const year: string = ""; // 연도 정보가 없으면 빈 문자열, 필요시 item에서 추출.
const yearVal: { [key: string]: any } = { year: year, pbnstRuseFcltId: item.pbnstRuseFcltId ?? "", ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" };
yearVal[`${year}inUsage`] = 0;
yearVal[`${year}outUsage`] = 0;
yearVal[`${year}total`] = 0;
yearsData.push(yearVal);
}
item.prfList.forEach((acc) => {
year = acc.ym?.substring(0, 4) ?? "";
inUsageSum =
(acc.wshwtr ?? 0) + //조경용수
(acc.coolUswtr ?? 0) + //냉각수
(acc.cleanUswtr ?? 0) + //청소수
(acc.drwtUswtr ?? 0) + //식수대
(acc.dltnUswtr ?? 0) + //희석용수
(acc.ithlRswtr ?? 0) + //중수도
(acc.ithlEtcUswtr ?? 0) //기타
outUsageSum =
(acc.cleanToilUswtr ?? 0) + //청소화장실용수
(acc.resn ?? 0)+ //세척살수용도
(acc.lndwtr ?? 0) + //조경용수
(acc.hydUswtr ?? 0) + //친수용수
(acc.ugwtChr ?? 0) + //지하수충전
(acc.farmUswtr ?? 0) + //농업용수
(acc.rvrKeepUswtr ?? 0) + //하천등유지용수
(acc.indstUswtr ?? 0); //공업용수
const yearData = yearsData.find(
(yearItem) =>
yearItem.year === year &&
yearItem.pbnstRuseFcltId == acc.pbnstRuseFcltId
);
if (yearData) {
yearData[`${year}inUsage`] += inUsageSum;
yearData[`${year}outUsage`] += outUsageSum;
yearData[`${year}total`] += (inUsageSum + outUsageSum);
} else {
const yearVal: { [key: string]: any } = { year: year, pbnstRuseFcltId: acc.pbnstRuseFcltId, ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" };
yearVal[`${year}inUsage`] = inUsageSum;
yearVal[`${year}outUsage`] = outUsageSum;
yearVal[`${year}total`] = inUsageSum + outUsageSum;
yearsData.push(yearVal);
}
});
});
const resData: any[] = []
pbnstRes.forEach((acc) => {
const data = yearsData.find((item) => item.pbnstRuseFcltId.substring(0, 11) === acc.bscFctCd)
if (data) {
resData.push({ ...acc, ...data })
}
})
return set((state: pbnstPrfmncSttnState) => ({
...state,
pbnstPrfmncSttn: {
...state.pbnstPrfmncSttn,
prfmncRes: resData,
rawData: res.data
},
}));
}
}
}
@@ -48,10 +48,10 @@ export default function CoDetailModal({
return (
<div>
<ScrollArea className="h-[85vh]">
<ScrollArea className="h-[85vh] mx-8">
<Form {...form}>
<form onSubmit={form.handleSubmit(onFormSubmit)}>
<div className="grid grid-cols-12 flex items-center card-header">
<div className="grid grid-cols-12 items-center card-header">
<h1 className="text-2xl font-medium text-label col-span-10">
잠재수요처 상세정보
</h1>
@@ -83,7 +83,6 @@ export default function DoubleBarChart({chartConfig=undefined, chartData=[], cha
.map(key => item[key])
).flat());
};
console.log(chartData);
const barMaxValue = getMaxValue(chartData, 'barVal');
return (
<>
@@ -24,6 +24,7 @@ type SearchBaseType = {
rightClassName?: string;
leftClassName?: string;
leftSelectClassName?: string;
buttonOrder?: ("query" | "init" | "excel")[];
}
export type ReturnType = {
partValue: string;
@@ -55,7 +56,8 @@ function SearchBaseForm ({
isAdmin=false,
rightClassName,
leftClassName,
leftSelectClassName
leftSelectClassName,
buttonOrder
}: SearchBaseType) {
const [partValue, setPartValue] = useState<string>("A");
const [sidoValue, setSidoValue] = useState<string>("0");
@@ -67,6 +69,30 @@ function SearchBaseForm ({
const [middleRegionValue, setMiddleRegionValue] = useState<string>("0");
const [envPartValue, setEnvPartValue] = useState<string>("0");
const [resetTrigger, setResetTrigger] = useState(false);
const renderButton = (type: "query" | "init" | "excel") => {
switch (type) {
case "query":
return (
<Button className={btnClass} onClick={queryVal} key="query">
조회
</Button>
);
case "init":
return (
<Button className={btnClass} onClick={initVal} key="init">
초기화
</Button>
);
case "excel":
return (
<Button className={btnClass} color="green" onClick={excelDownload} key="excel">
{excelName ? excelName : "엑셀다운로드"}
</Button>
);
default:
return null;
}
};
const queryVal = () => {
console.log("조회버튼 클릭");
queryClick({
@@ -145,16 +171,8 @@ function SearchBaseForm ({
{leftChildren}
</SearchFormLeft>
<SearchFormRight className={rightClassName}>
<Button className={btnClass} color="green" onClick={excelDownload}>
{excelName?excelName:"엑셀다운로드"}
</Button>
<div>
<Button className={btnClass} onClick={initVal}>
초기화
</Button>
<Button className={btnClass} onClick={queryVal}>
조회
</Button>
{(buttonOrder ?? ["excel", "init", "query"]).map(renderButton)}
</div>
{rightChildren}
</SearchFormRight>