중수도통계 테이블, 엑셀 수정

This commit is contained in:
jyha00
2025-07-22 20:38:42 +09:00
parent b4e3d922b1
commit 383e5f8382
5 changed files with 169 additions and 121 deletions
+37 -39
View File
@@ -31,7 +31,7 @@ export default function RainStat() {
searchRainStatList(searchYear);
}, [code.cityCd, code.sggCd, searchRainStatList])
const excelDetailDownLoad = () => {
const excelDetailDownLoad=() =>{
const sidoList = new Set<string>();
const sidoDataMap = new Map<string, (string | number)[]>(); // 시도별 데이터를 저장할 Map
const sidoDetailMap = new Map<string, (string | number)[][]>(); // 시도별 상세 데이터를 저장할 Map
@@ -49,7 +49,7 @@ export default function RainStat() {
sidoText = sido?.text || '';
sigunText = sigun?.text || '';
// 시도, 시군구 코드를 텍스트로 변환하여 데이터에 할당
if (item.length > 0) {
item[0] = sidoText as unknown as RainStatProps;
@@ -58,7 +58,7 @@ export default function RainStat() {
item[1] = sigunText as unknown as RainStatProps;
}
if (item.length > 2) {
item[2] = sidoText + ' ' + sigunText as unknown as RainStatProps;
item[2] = sidoText+' '+sigunText as unknown as RainStatProps;
}
// 시도별 상세 데이터 수집
@@ -89,32 +89,32 @@ export default function RainStat() {
const sidoData = sidoDataMap.get(sidoText)!;
// 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작)
for (let i = 1; i < item.length && i < sidoData.length; i++) {
if (i == 2) {
if(i == 2){
sidoData[i] = '합계';
} else if (i == 3) {
} else if(i == 3){
// 해당 시도의 데이터 개수를 계산
const sidoDataCount = rainDetailList.filter((data: unknown[]) =>
const sidoDataCount = rainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 0 && String(data[0]) === sidoText
).length;
sidoData[i] = sidoDataCount;
} else if (i == 4) {
} else if( i == 4){
sidoData[i] = '';
} else if (i == 6) {
} else if(i == 6){
// 법정 대상 건축물 개수 (인덱스 6이 'Y'인 경우)
const bumCnt = rainDetailList.filter((data: unknown[]) =>
const bumCnt = rainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 6 && String(data[0]) === sidoText
).filter((data: unknown[]) => String(data[6]) === '대상').length;
sidoData[i] = bumCnt;
} else if (i == 8) {
} else if(i==8){
const value = Number(item[8]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if (i == 11) {
} else if(i==11){
const value = Number(item[11]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if (i == 12) {
} else if(i==12){
const value = Number(item[12]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if (i == 14) {
} else if(i==14){
const value = Number(item[14]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
}
@@ -127,12 +127,12 @@ export default function RainStat() {
// 시도별로 합계와 상세 데이터를 순서대로 배치
const summaryExcelData: (string | number)[][] = [];
// 시도별로 순회하면서 합계와 상세 데이터를 추가
Array.from(sidoList).forEach((sidoText) => {
const sidoSummary = sidoDataMap.get(sidoText);
const sidoDetails = sidoDetailMap.get(sidoText) || [];
if (sidoSummary) {
// 시도 합계 데이터 추가
summaryExcelData.push(sidoSummary);
@@ -147,14 +147,14 @@ export default function RainStat() {
const sidoTotalSummary = [['전체', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '', 0]];
sidoSummaryList.forEach((item: (string | number)[]) => {
item.forEach((value: string | number, index: number) => {
if (typeof value === 'number') {
if(typeof value === 'number') {
if (sidoTotalSummary[0] && index < sidoTotalSummary[0].length) {
sidoTotalSummary[0][index] = Number(sidoTotalSummary[0][index]) + Number(value);
}
}
});
});
// sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성
const excelData = [...sidoTotalSummary, ...sidoSummaryList, ...summaryExcelData];
@@ -175,30 +175,28 @@ export default function RainStat() {
headerRange: "A1:M1"
})
}
useEffect(() => {
const transExcel = Array.isArray(excelList) ? excelList : [excelList];
const excelData = tableData(transExcel, { code });
const tbData = Array.isArray(excelData)
? excelData
.filter((item: RainStatProps) => item.cityText !== '없음')
.map((item: RainStatProps) => {
return {
"시도": item.cityText,
"개소": item.tmp,
"설치비(백만원)": item.instlCst,
"저류조용량(m³/년)": item.dtfcltCpct,
"연간사용량(m³/년)": item.wtrUsqty,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"세척살수용수": item.resn,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
})
? excelData.map((item: RainStatProps) => {
return {
"시도": item.cityText,
"개소": item.tmp,
"설치비(백만원)": item.instlCst,
"저류조용량(m³/년)": item.dtfcltCpct,
"연간사용량(m³/년)": item.wtrUsqty,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"세척살수용수": item.resn,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
})
: [];
setExData(tbData);
}, [code, excelList])
@@ -239,7 +237,7 @@ export default function RainStat() {
/>
</div>
<div className="flex flex-row space-x-2 items-center">
<Button className="" size={"sm"} onClick={() => { searchRainStatList(searchYear); }}>
<Button className="" size={"sm"} onClick={()=>{searchRainStatList(searchYear);}}>
조회
</Button>
<Button className="" size={"sm"} onClick={() => excelClick()}>
@@ -266,7 +264,7 @@ export default function RainStat() {
total={0}
headName={""}
cellClick={undefined}
onPageChange={() => { }}
onPageChange={() => {}}
></UiTable>
</ScrollArea>
</ListDiv>
+49 -48
View File
@@ -14,70 +14,70 @@ import {
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useEffect, useState } from "react";
import toast, { Toaster } from "react-hot-toast";
import { useTranslation } from "react-i18next";
export default function RswtStat() {
const { code, rswtStat, searchRswtStatList } = useWrStore((state) => state);
const { rswtStatList, excelList, rswtDetailList } = rswtStat;
const { rswtStatList, rswtDetailList } = rswtStat;
const [rswtTable, setRswtTable] = useState<RswtStatProps[]>();
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [excelData, setExceData] = useState<Record<string, string | number>[]>();
const { t } = useTranslation('base');
useEffect(() => {
searchRswtStatList(searchYear)
}, [searchRswtStatList])
searchRswtStatList(searchYear, code.cityCd)
}, [searchRswtStatList, code.cityCd])
const excelClick = () => {
downloadExcel({
data: (excelData as unknown as JSON[]) ?? [],
fileName: "중수도재이용통계",
sheetNameArray: ["Sheet1"],
headerRange: "A1:N1"
})
if (rswtTable) {
const data = rswtTable.map((item: RswtStatProps) => {
return {
"시도": item.cityText,
"개소": item.ctpvCnt,
// "건축연면적(m³)": item.archArea,
"처리용량(m³)": item.filtrTrtmfctCpct,
"물사용량(m³/년)": item.wtrUsqty,
"중수도+대체수이용량(m³/년)": item.rswtAltSum,
"중수도이용량(m³/년)": item.rswtrUsqty,
"대체수이용량(m³/년)": item.altUswtrUtztnQnt,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
})
downloadExcel({
data: (data as unknown as JSON[]) ?? [],
fileName: "중수도재이용통계",
sheetNameArray: ["Sheet1"],
headerRange: "A1:N1"
})
} else {
toast.error(t("excelDownErrMsg"))
}
}
useEffect(() => {
const transData = Array.isArray(rswtStatList) ? rswtStatList : [rswtStatList];
const data = tableData(transData, { code });
const tbData = Array.isArray(data)
? data.map((item: RswtStatProps) => {
const cityData = tableData(transData, { code });
const tbData = Array.isArray(cityData)
? cityData.map((item: RswtStatProps) => {
return {
...item,
ctpvCd: item.cityText
ctpvCd: item.cityText === '전체' ? '전국' : item.cityText,
cityText: item.cityText === '전체' ? '전국' : item.cityText
};
}).filter((item: RswtStatProps) => item.cityText !== '없음')
: [];
setRswtTable(tbData);
}, [code, rswtStatList])
}) : [];
useEffect(() => {
const transExcel = Array.isArray(excelList) ? excelList : [excelList];
const exData = tableData(transExcel, { code });
const tbData = Array.isArray(exData) ?
exData
.filter((item: RswtStatProps) => item.cityText !== '없음')
.map((item: RswtStatProps) => {
return {
"시도": item.cityText,
"개소": item.ctpvCnt,
// "건축연면적(m³)": item.archArea,
"처리용량(m³)": item.filtrTrtmfctCpct,
"물사용량(m³/년)": item.wtrUsqty,
"중수도+대체수이용량(m³/년)": item.rswtAltSum,
"중수도이용량(m³/년)": item.rswtrUsqty,
"대체수이용량(m³/년)": item.altUswtrUtztnQnt,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
}) : [];
setExceData(tbData);
}, [code, excelList])
setRswtTable(tbData);
}, [code, rswtStatList]);
const excelDetailDownLoad = () => {
const sidoList = new Set<string>();
@@ -199,7 +199,7 @@ export default function RswtStat() {
});
const sidoSummaryList = Array.from(sidoDataMap.values());
const sidoTotalSummary = [['전체', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '', 0]];
const sidoTotalSummary = [['전국', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '']];
sidoSummaryList.forEach((item: (string | number)[]) => {
item.forEach((value: string | number, index: number) => {
if (typeof value === 'number') {
@@ -217,7 +217,7 @@ export default function RswtStat() {
excelData as unknown as [][],
"중수도시설 통계",
"sample_rswtStats.xlsx",
"A1:Q3",
"A1:P3",
4
);
}
@@ -244,7 +244,7 @@ export default function RswtStat() {
className=""
size="sm"
onClick={() => {
searchRswtStatList(searchYear)
searchRswtStatList(searchYear, code.cityCd)
}}
>
조회
@@ -285,6 +285,7 @@ export default function RswtStat() {
</ListDiv>
</div>
</div>
<Toaster position="top-center"></Toaster>
</ContentsDiv>
</>
);
+2 -1
View File
@@ -1,4 +1,5 @@
import type { RswtStatProps } from ".";
import { bdstUsgCd } from "../../common/code/basicCode";
export const excelRswtStat = (excelList:RswtStatProps[]) : (string | number)[][] => {
const excelData: (string | number)[][] = [];
@@ -14,7 +15,7 @@ export const excelRswtStat = (excelList:RswtStatProps[]) : (string | number)[][]
String(item.bdstNm) ?? "",
//건축물용도코드(빈칸)
//String(item.bdstUsgCd) ?? "",
"",
bdstUsgCd.find((cd)=> cd.val === item.bdstUsgCd.toString())?.text ?? "", //건축물용도
//주소
String(item.daddr) ?? "",
//법적의무대상여부
+81 -33
View File
@@ -6,7 +6,7 @@ import { excelRswtStat } from "./excel";
export type RswtStatProps = {
cityText: string //시도명
ctpvCd: string //시도
sggCd : string //시군구
sggCd: string //시군구
areaNm: string //행정구역명
bdstNm: string //시설명
daddr: string //주소
@@ -26,9 +26,10 @@ export type RswtStatProps = {
ithlEtcUswtr: number //기타
anlOperCst: number //연간운영비
guideStats: GuideStatProps[]
utztnUsgCd : string //이용코드
lawTrgtYn : string //법적의무대상여부
instlCmptnDt : string //설치완료일자
utztnUsgCd: string //이용코드
lawTrgtYn: string //법적의무대상여부
instlCmptnDt: string //설치완료일자
bdstUsgCd: number
}
export type GuideStatProps = {
@@ -37,7 +38,7 @@ export type GuideStatProps = {
}
type rswtStatActions = {
searchRswtStatList: (year: string) => void;
searchRswtStatList: (year: string, city: { val: string; text: string }[]) => void;
}
export type ExcelType = {
@@ -71,36 +72,47 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = (
set: any
) => {
return {
searchRswtStatList: async (year: string) => {
searchRswtStatList: async (year: string, city: { val: string; text: string }[]) => {
const res = await getFetch(fetchType.WR, `/reuseChk/reuseWater/stat/${year}`)
console.log("city", city)
console.log("res", res)
const data = res.filter(item => {
const code = item.ctpvCd.trim();
return city.some(el => el.val === code);
});
console.log("data", data)
const cityArr: any[] = [];
res.forEach((item: RswtStatProps) => {
data.forEach((item: RswtStatProps) => {
let obj = cityArr.find((e) => {
return e.ctpvCd == item.ctpvCd
})
if (obj) {
obj.ctpvCnt += 1
obj.archArea += item.archArea
obj.filtrTrtmfctCpct += item.filtrTrtmfctCpct
obj.wtrUsqty += item.wtrUsqty
obj.rswtAltSum += (item.rswtrUsqty + item.altUswtrUtztnQnt)
obj.rswtrUsqty += item.rswtrUsqty
obj.altUswtrUtztnQnt += item.altUswtrUtztnQnt
obj.anlOperCst += item.anlOperCst
obj.ctpvCnt += 1 //개소
// obj.archArea += item.archArea 건축면적 삭제
obj.filtrTrtmfctCpct += item.filtrTrtmfctCpct //처리용량
obj.wtrUsqty += item.wtrUsqty //물사용량
obj.rswtAltSum += (item.rswtrUsqty + item.altUswtrUtztnQnt) //중수도+대체수
obj.rswtrUsqty += item.rswtrUsqty //중수도사용량
obj.altUswtrUtztnQnt += item.altUswtrUtztnQnt //대체수이용량
obj.anlOperCst += item.anlOperCst //연간운영비용
} else {
obj = {};
obj.ctpvCd = item.ctpvCd
obj.ctpvCnt = 1
obj.archArea = item.archArea
obj.filtrTrtmfctCpct = item.filtrTrtmfctCpct
obj.wtrUsqty = item.wtrUsqty
obj.rswtAltSum = item.rswtrUsqty + item.altUswtrUtztnQnt
obj.rswtrUsqty = item.rswtrUsqty
obj.altUswtrUtztnQnt = item.altUswtrUtztnQnt
obj.anlOperCst = item.anlOperCst
obj = {
ctpvCd: item.ctpvCd,
ctpvCnt: 1,
filtrTrtmfctCpct: item.filtrTrtmfctCpct,
wtrUsqty: item.wtrUsqty,
rswtAltSum: item.rswtrUsqty + item.altUswtrUtztnQnt,
rswtrUsqty: item.rswtrUsqty,
altUswtrUtztnQnt: item.altUswtrUtztnQnt,
anlOperCst: item.anlOperCst,
lndwtr: 0,
cleanToilUswtr: 0,
farmUswtr: 0,
indstUswtr: 0,
hydUswtr: 0,
ithlEtcUswtr: 0,
}
cityArr.push(obj)
}
@@ -120,11 +132,47 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = (
}
});
const total: any = {
ctpvCd: "0",
ctpvCnt: 0,
filtrTrtmfctCpct: 0,
wtrUsqty: 0,
rswtAltSum: 0,
rswtrUsqty: 0,
altUswtrUtztnQnt: 0,
anlOperCst: 0,
lndwtr: 0,
cleanToilUswtr: 0,
farmUswtr: 0,
indstUswtr: 0,
hydUswtr: 0,
ithlEtcUswtr: 0,
};
cityArr.forEach(item => {
total.ctpvCnt += item.ctpvCnt;
total.archArea += item.archArea;
total.filtrTrtmfctCpct += item.filtrTrtmfctCpct;
total.wtrUsqty += item.wtrUsqty;
total.rswtAltSum += item.rswtAltSum;
total.rswtrUsqty += item.rswtrUsqty;
total.altUswtrUtztnQnt += item.altUswtrUtztnQnt;
total.anlOperCst += item.anlOperCst;
total.lndwtr += item.lndwtr;
total.cleanToilUswtr += item.cleanToilUswtr;
total.farmUswtr += item.farmUswtr;
total.indstUswtr += item.indstUswtr;
total.hydUswtr += item.hydUswtr;
total.ithlEtcUswtr += item.ithlEtcUswtr;
});
cityArr.unshift(total);
cityArr.forEach(item => {
excelDownList.push({
ctpvCd: item.ctpvCd,
ctpvCnt: item.ctpvCnt,
archArea: item.archArea,
// archArea: item.archArea,
filtrTrtmfctCpct: item.filtrTrtmfctCpct,
wtrUsqty: item.wtrUsqty,
rswtAltSum: item.rswtAltSum,
@@ -139,21 +187,21 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = (
anlOperCst: item.anlOperCst,
})
})
console.log("엑셀다운리스트", excelDownList)
//상세
const rswtDetailList : RswtStatProps[] = [];
res.forEach((item:RswtStatProps) => {
const rswtDetailList: RswtStatProps[] = [];
res.forEach((item: RswtStatProps) => {
const utztnUsgArray = new Array<string>();
item.guideStats.forEach((guideStat) => {
utztnUsgArray.push(guideStat.utztnUsgCd);
})
rswtDetailList.push({
...item,
rswtAltSum : item.rswtrUsqty + item.altUswtrUtztnQnt,
utztnUsgCd : utztnUsgArray.join(', '),
rswtAltSum: item.rswtrUsqty + item.altUswtrUtztnQnt,
utztnUsgCd: utztnUsgArray.join(', '),
})
});
const excelDetailData = excelRswtStat(rswtDetailList);
set((state: rswtStatState) => ({
rswtStat: {
Binary file not shown.