Merge branch 'iipbs/wr/stats_excel' into iipbs/wr/stats

This commit is contained in:
YangJinSoo94
2025-06-19 15:29:32 +09:00
4 changed files with 187 additions and 14 deletions
+108 -11
View File
@@ -2,8 +2,9 @@
import { useWrStore } from "@/app/store";
import type { RainStatProps } from "@/app/store/stats/rainStat";
import { tableData, yearOptions } from "@/components/lib/func/commom";
import { tableData, yearOptions, excelDownload } from "@/components/lib/func/commom";
import { downloadExcel } from "@common/business_components";
import {
ContentsDiv,
SearchDiv,
@@ -17,7 +18,7 @@ import { useCallback, useEffect, useState } from "react";
export default function RainStat() {
const { code, rainStat, searchRainStatList } = useWrStore((state) => state);
const { rainStatHeadList, rainStatList, excelList } = rainStat;
const { rainStatHeadList, rainStatList, excelList, rainDetailList } = rainStat;
const [pageNation, setPageNation] = useState(1);
const [searchYear, setSearchYear] = useState<string>(
@@ -28,7 +29,104 @@ export default function RainStat() {
useEffect(() => {
searchRainStatList(searchYear);
}, [searchRainStatList, searchYear])
}, [code.cityCd, code.sggCd, searchRainStatList, searchYear])
const excelDownLoad=() =>{
const sidoList = new Set();
const sidoDataMap = new Map(); // 시도별 데이터를 저장할 Map
rainDetailList.forEach((item: RainStatProps[]) => {
const sidoVal = item.at(0)?.toString().trim();
const sigunVal = item.at(1)?.toString().trim();
let sidoText = '';
let sigunText = '';
const sido = code.cityCd.find((city) => city.val === sidoVal);
const sigun = code.sggCd.find((sgg) => sgg.val === sigunVal);
sidoText = sido?.text || '';
sigunText = sigun?.text || '';
// 시도, 시군구 코드를 텍스트로 변환하여 데이터에 할당
if (item.length > 0) {
item[0] = sidoText as unknown as RainStatProps;
}
if (item.length > 1) {
item[1] = sigunText as unknown as RainStatProps;
}
if (item.length > 2) {
item[2] = sidoText+' '+sigunText as unknown as RainStatProps;
}
// 시도별 데이터 수집
if (sidoText && !sidoList.has(sidoText)) {
sidoList.add(sidoText);
// 시도별 초기 데이터 구조 생성 (예: [시도명, 0, 0, 0, ...])
const initialData: (string | number)[] = [sidoText];
// 데이터의 나머지 컬럼들을 0으로 초기화 (실제 컬럼 수에 맞게 조정 필요)
for (let i = 1; i < item.length; i++) {
initialData.push(0);
}
sidoDataMap.set(sidoText, initialData);
}
});
// 시도별 합계 계산
rainDetailList.forEach((item: RainStatProps[]) => {
const sidoText = item[0]?.toString();
if (sidoText && sidoDataMap.has(sidoText)) {
const sidoData = sidoDataMap.get(sidoText);
// 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작)
for (let i = 1; i < item.length && i < sidoData.length; i++) {
if(i == 2){
sidoData[i] = '합계';
} else if(i == 3){
// 해당 시도의 데이터 개수를 계산
const sidoDataCount = rainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 0 && String(data[0]) === sidoText
).length;
sidoData[i] = sidoDataCount;
} else if( i == 4){
sidoData[i] = '';
} else if(i == 6){
// 법정 대상 건축물 개수 (인덱스 6이 'Y'인 경우)
const bumCnt = rainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 6 && String(data[0]) === sidoText
).filter((data: unknown[]) => String(data[6]) === 'Y').length;
sidoData[i] = bumCnt;
} else if(i==8){
const value = Number(item[8]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==11){
const value = Number(item[11]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==12){
const value = Number(item[12]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==14){
const value = Number(item[14]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
}
else {
sidoData[i] = '';
}
}
}
});
// Map을 배열로 변환
const sidoSummaryList = Array.from(sidoDataMap.values());
// sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성
const excelData = [...sidoSummaryList, ...rainDetailList];
excelDownload(
excelData,
"빗물이용시설 통계",
"sample_rainStats.xlsx",
"A1:V3",
4
);
}
const excelClick = () => {
downloadExcel({
@@ -38,8 +136,7 @@ export default function RainStat() {
headerRange: "A1:M1"
})
}
useEffect(() => {
const transExcel = Array.isArray(excelList) ? excelList : [excelList];
const excelData = tableData(transExcel, { code });
@@ -63,7 +160,7 @@ export default function RainStat() {
})
: [];
setExData(tbData);
}, [excelList])
}, [code, excelList])
useEffect(() => {
const transData = Array.isArray(rainStatList) ? rainStatList : [rainStatList];
@@ -77,7 +174,7 @@ export default function RainStat() {
})
: [];
setBdstTable(tbData);
}, [rainStatList]);
}, [code, rainStatList]);
return (
<>
@@ -106,7 +203,7 @@ export default function RainStat() {
<Button className="" size={"sm"} onClick={() => excelClick()}>
다운로드
</Button>
<Button className="" size={"sm"} onClick={(e) => { }}>
<Button className="" size={"sm"} onClick={() => excelDownLoad()}>
전체통계다운로드
</Button>
</div>
@@ -125,9 +222,9 @@ export default function RainStat() {
headlist={rainStat.rainStatHeadList}
pageSize={20}
total={10000}
headName={""}
cellClick={(val, headId) => { }}
onPageChange={setPageNation}
headName={"건축물 목록"}
cellClick={() => {}}
onPageChange={() => {}}
></UiTable>
{/* </ScrollArea> */}
</ListDiv>
@@ -0,0 +1,40 @@
import type { RainStatProps } from ".";
export const excelRainStat = (excelList:RainStatProps[]) : string[][] => {
const excelData: string[][] = [];
excelList.forEach((item) => {
excelData.push([
//시도
String(item.ctpvCd) ?? "",
//시군구
String(item.sggCd) ?? "",
//행정구역명
String(item.areaNm) ?? "",
//시설명
String(item.bdstNm) ?? "",
//건축물용도코드
String(item.bdstUsgCd) ?? "",
//주소
String(item.daddr) ?? "",
//법적의무대상여부
String(item.lawTrgtYn) ?? "",
//설치완료일자
String(item.instlCmptnDt) ?? "",
//설치비용
String(item.instlCst) ?? "",
//접수면종류
String(item.pntfColKnd) ?? "",
//여과등처리시설유무
String(item.filtrTrtmfctYn) ?? "",
//처리용량(저류조용량)
String(item.dtfcltCpct) ?? "",
//연간사용량
String(item.wtrUsqty) ?? "",
//이용용도코드
String(item.utztnUsgCd) ?? "",
//연간운영비
String(item.anlOperCst) ?? "",
]);
});
return excelData;
}
+39 -3
View File
@@ -1,6 +1,7 @@
import { fetchType, getFetch } from "@/components/lib/api";
import type { TableUpperProps } from "../../common/type/header";
import { rainStatHeadListExport } from "./headList";
import { excelRainStat } from "./excel";
export type RainStatProps = {
ctpvCd: string //시도
@@ -35,6 +36,7 @@ export type RainStatProps = {
export type GuideStatProps = {
utztnUsgCd: string
splyUswtrUtztnQnt : number,
ruseFcltUtztnQnt: number
}
@@ -58,6 +60,7 @@ export type rainStatState = {
rainStatHeadList: TableUpperProps[],
rainStatList: RainStatProps[],
excelList: ExcelType[]
rainDetailList : [][]
}
}
@@ -67,7 +70,8 @@ export const rainStatExport: rainStatState = {
rainStat: {
rainStatHeadList: rainStatHeadListExport,
rainStatList: [],
excelList: []
excelList: [],
rainDetailList : []
}
}
export const rainStatActionsExport = (
@@ -76,8 +80,7 @@ export const rainStatActionsExport = (
return {
searchRainStatList: async (year: string) => {
const res = await fetchRainStatList(year);
let cityArr: any[] = [];
const cityArr: any[] = [];
res.forEach((item: RainStatProps) => {
let obj = cityArr.find((e) => {
@@ -136,9 +139,42 @@ export const rainStatActionsExport = (
})
})
//상세세
const rainDetailList : RainStatProps[] = [];
res.forEach((item:RainStatProps) => {
const utztnUsgArray = new Array<string>();
item.guideStats.forEach((guideStat) => {
utztnUsgArray.push(guideStat.utztnUsgCd);
})
rainDetailList.push({
...item,
utztnUsgCd : utztnUsgArray.join(', '),
})
})
const excelDetailData = excelRainStat(rainDetailList);
/* const rainStatHeadList = data.map((item:RainStatProps) => ({
...item,
ctpvCd:item.ctpvCd,
sggCd:item.sggCd,
areaNm:item.areaNm,
archArea:item.archArea,
dtfcltCpct:item.dtfcltCpct,
annRnwtQty:item.annRnwtQty,
jungsudo:item.jungsudo,
dachae:item.dachae,
way1:item.way1,
way2:item.way2,
way3:item.way3,
way4:item.way4,
way5:item.way5,
way6:item.way6,
way7:item.way7,
yearMoney:item.yearMoney,
})) */
set((state: rainStatState) => ({
rainStat: {
...state.rainStat,
rainDetailList: excelDetailData as [][],
rainStatList: cityArr,
excelList: excelDownList
}
Binary file not shown.