From 97b6ac481e812a793d10e788e3f626463e386f32 Mon Sep 17 00:00:00 2001 From: jyha00 Date: Tue, 17 Jun 2025 10:51:37 +0900 Subject: [PATCH 01/25] =?UTF-8?q?=EC=9E=A0=EC=9E=AC=EC=88=98=EC=9A=94?= =?UTF-8?q?=EC=B2=98=20=EC=83=81=EC=84=B8=EC=A0=95=EB=B3=B4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/store/matDmd/ldrmntCoSttn/index.tsx | 20 ++++++++++++++----- .../sttn/sttnDetailModal/coDatailModal.tsx | 9 ++++++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx index 958668b10..a54e5a1e7 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx @@ -10,9 +10,9 @@ import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headLis const ldrmntHeadList = ldrmntHeadListExport; const ldrmntNodeList = ldrmntNodeListExport; -export type customLdrmntBdst = z.infer; +export type customLdrmnt = z.infer; -const ldrmntRes: customLdrmntBdst[] = []; +const ldrmntRes: customLdrmnt[] = []; export type ldrmntState = { ldrmnt: { @@ -20,7 +20,7 @@ export type ldrmntState = { ldrmntNodeList: CommonTableProps[]; excelList: []; isInit: boolean; - ldrmntRes: customLdrmntBdst[]; + ldrmntRes: customLdrmnt[]; }; }; @@ -28,6 +28,7 @@ type ldrmntActions = { ldrmntRegData: (data: any[]) => void, ldrmntInit: () => void; ldrmntSearch: (sggCd: string, coNm: string) => void; + ldrmntUpdate: (ldrmntRes: customLdrmnt) => void; }; export type ldrmntType = ldrmntState & ldrmntActions; @@ -124,14 +125,23 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( console.log(e) } }, - ldrmntUpdate: async (ldrmntRes: customLdrmntBdst[]) => { + ldrmntUpdate: async (ldrmntRes: customLdrmnt) => { try { - + console.log("ldrmntRes", ldrmntRes) const response = await putFectch( `/reuseFc/request/temp`, ldrmntRes ); + return set((state: ldrmntState) => ({ + ...state, + ldrmnt: { + ...state.ldrmnt, + ldrmntRes: ldrmntRes, + isInit: false, + }, + })); + } catch (error) { console.error("Error ldrmntUpdate:", error); } diff --git a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx index 708cb4b3c..75df712a8 100644 --- a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx +++ b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx @@ -1,4 +1,6 @@ "use client"; +import { useWrStore } from "@/app/store"; +import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; import { ldrmntZod } from "@/app/store/matDmd/ldrmntCoSttn/headList"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { handleCommaNumberChange } from "@/components/lib/func/commom"; @@ -14,14 +16,19 @@ export default function SttnDetailModal({ }: { formObj: any; }) { + const { ldrmntUpdate } = useWrStore( + (state) => state + ); const defaultValues: z.infer = ldrmntZod.parse({}); const form = useForm>({ resolver: zodResolver(ldrmntZod), defaultValues: defaultValues, }); - const onSubmit = (values: z.infer) => { + const onSubmit = (values: customLdrmnt) => { console.log("values", values) + if (values) + ldrmntUpdate(values) }; useEffect(() => { From 84be05a35c49969b7adc0a11a068624d545b95ce Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Tue, 17 Jun 2025 15:42:27 +0900 Subject: [PATCH 02/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=9E=AC=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=EC=8B=9C=EC=84=A4=20=ED=86=B5=EA=B3=84=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C=EC=A7=84=ED=96=89=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 51 +++++++++-------- apps/wr/app/store/stats/rainStat/index.tsx | 64 +++++++++++++++++++--- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index f4d42e033..ec7802428 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -1,27 +1,29 @@ "use client"; + import { useWrStore } from "@/app/store"; import { yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, SearchDiv, - SearchFormLeft, SelectBox, Title, - UiTable, + UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; -import { useState } from "react"; +import { useEffect, useState } from "react"; -export default function rainStat() { - const { code, rainStat } = useWrStore((state) => { - return state; - }); - const [pageNation, setPageNation] = useState(1); +export default function RainStat() { + const { rainStat, searchRainStatList } = useWrStore((state) => state) + const [ pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState( String(new Date().getFullYear()) ); + useEffect(() => { + searchRainStatList(searchYear) + }, [searchRainStatList, searchYear]) + return ( <> @@ -29,17 +31,19 @@ export default function rainStat() {
<SearchDiv> - <SearchFormLeft> - <SelectBox - className="w-full h-full text-2xl" - label="통계년도" - selectClass={""} - selectArray={yearOptions} - value={searchYear} - onSelectValue={(val: string | number) => - setSearchYear(String(val)) - } - /> + <div className="grid grid-cols-12 gap-5 m-4"> + <div className="col-span-2"> + <SelectBox + className="w-full h-full text-2xl" + label="통계년도" + selectClass={""} + selectArray={yearOptions} + value={searchYear} + onSelectValue={(val: string | number) => + setSearchYear(String(val)) + } + /> + </div> <div className="flex flex-row space-x-2 items-center"> <Button className="" size={"sm"} onClick={(e) => {}}> 조회 @@ -51,11 +55,10 @@ export default function rainStat() { 전체통계다운로드 </Button> </div> - </SearchFormLeft> - {/* <SearchFormRight> - - </SearchFormRight> */} + </div> </SearchDiv> + {/* <SearchFormRight> + </SearchFormRight> */} </div> </div> <div className="grid grid-cols-6 gap-4"> @@ -78,4 +81,4 @@ export default function rainStat() { </ContentsDiv> </> ); -} +} \ No newline at end of file diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index a50d54d58..e9a9d3a3d 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -1,13 +1,39 @@ import type { TableUpperProps } from "../../common/type/header"; import { rainStatHeadListExport } from "./headList"; -type rainStatActions = { +export type RainStatProps = { + ctpvCd : string //시도 + sggCd : string //시군구 + areaNm : string //행정구역명 + archArea : number //건축연면적 + dtfcltCpct : number //처리용량 + annRnwtQty : number //물사용량 + jungsudo : number //중수도​이용량 + dachae : number //대체수​이용량 + way1 : number //방법1 + way2 : number //방법2 + way3 : number //방법3 + way4 : number //방법4 + way5 : number //방법5 + way6 : number //방법6 + way7 : number //방법7 + yearMoney : number //연간운영비 } +const fetchRainStatList = async (year:string) => { + const res = await fetch(`/api/stats/rainStat?year=${year}`) + const data = await res.json() + return data +} + +type rainStatActions = { + searchRainStatList : (year:string) => void +} export type rainStatState = { rainStat: { - rainStatHeadList:TableUpperProps[] + rainStatHeadList:TableUpperProps[], + rainStatList : RainStatProps[] } } @@ -15,14 +41,38 @@ export type rainStatType = rainStatState & rainStatActions; export const rainStatExport: rainStatState = { rainStat: { - rainStatHeadList:rainStatHeadListExport + rainStatHeadList:rainStatHeadListExport, + rainStatList : [] } } - -export const rainStatActionsExport: (set: any) => rainStatActions = ( - set: any +export const rainStatActionsExport = ( + set: (fn: (state: rainStatState) => rainStatState) => void ) => { return { - + searchRainStatList : async (year:string) => { + console.log(year); + //const data = await fetchRainStatList(year) + const rainStatList: never[] = []; + /* 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) => ({...state, rainStat: {rainStatList:rainStatList}})) + } } } \ No newline at end of file From c6d75babe315008bb27adbf667237b3e956c3db8 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Wed, 18 Jun 2025 10:24:23 +0900 Subject: [PATCH 03/25] =?UTF-8?q?=EC=9E=A0=EC=9E=AC=EC=88=98=EC=9A=94?= =?UTF-8?q?=EC=B2=98=20=EB=93=B1=EB=A1=9D,=20=EC=83=81=EC=84=B8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wr/app/matMng/coMng/ldrmntCoSttn/page.tsx | 18 ++++------- .../app/store/matDmd/ldrmntCoSttn/excel.tsx | 32 +++++++++++++------ .../store/matDmd/ldrmntCoSttn/headList.tsx | 5 ++- .../app/store/matDmd/ldrmntCoSttn/index.tsx | 15 ++++++++- .../coReg/coRegExcel/coRegExcelModal.tsx | 9 +++--- .../sttn/sttnDetailModal/coDatailModal.tsx | 28 ++++++++++++---- 6 files changed, 75 insertions(+), 32 deletions(-) diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx index 4b2fe4416..2fe3cd93a 100644 --- a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx @@ -2,7 +2,7 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; -import { type customLdrmntBdst } from "@/app/store/matDmd/ldrmntCoSttn"; +import { type customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; import { ldrmntNodeListExport } from "@/app/store/matDmd/ldrmntCoSttn/headList"; import { excelDownload, @@ -34,23 +34,18 @@ export default function LdrmntCoSttn() { (state) => state ); const { ldrmntRes } = ldrmnt; - const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customLdrmntBdst | undefined }>({ data: undefined, isOpen: false }) + const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customLdrmnt | undefined }>({ data: undefined, isOpen: false }) const [pageNation, setPageNation] = useState(1); const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); - const ref = useRef<ReturnType>({} as ReturnType); - const [bdstTable, setBdstTable] = useState<customLdrmntBdst[]>(); - const [codeData, setCodeData] = useState<string>(); + const [bdstTable, setBdstTable] = useState<customLdrmnt[]>(); const [searchTxt, setSearchTxt] = useState<string>(); - const [bdstChgProps, setBdstChgProps] = useState<{ - isOpen: boolean; - data: customLdrmntBdst[]; - }>({ isOpen: false, data: [] }); + const excelClick = useCallback(() => { excelDownload( [[]], "잠재수요처 관리", - "sample_ldrmnt.xlsx", + "sample_ldrmntCoSttn.xlsx", "A1:AL1", 2 ); @@ -86,8 +81,9 @@ export default function LdrmntCoSttn() { useEffect(() => { const data = tableData(ldrmntRes, { code }); + console.log("data", data) const tbData = Array.isArray(data) - ? data.map((item: customLdrmntBdst) => ({ + ? data.map((item: customLdrmnt) => ({ ...item, ctpvCd: item.fctryAddr.split(" ")[0] || "", sggCd: item.fctryAddr.split(" ")[1] || "" diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx index 5c0936357..dc0601127 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx @@ -46,16 +46,30 @@ export const names: nameMap = { } -export const excelToLdrmntData = (excelData: File[],) => { +export const excelPbnstSttnParsing = (data: any[]): string[][] => { - const ldrmntData = Object.values(excelData); - const data = ldrmntData.map((item) => { + const excelExportData: string[][] = []; - return ({ - ...(item as object), - rgtr: TEST_UUID, - mdfr: TEST_UUID, - }) + data.forEach((item) => { + excelExportData.push([ + item.rvbsn, + String(item.lgbsn), + item.mdmbsn ?? "", + item.rgnNm ?? "", + String(item.sido ?? ""), + String(item.gugun ?? ""), + String(item.bscFctNm ?? ""), + String(item.efflWqltStndrdNm ?? ""), + String(item.fctCpc ?? ""), + String(item.tel ?? ""), + String(item.ruseUtztnFcltNm ?? ""), + String(item.fcltCpct ?? ""), + String(item.splyExtraCpct ?? ""), + String(item.ruseCpct ?? ""), + String(item.usageTotal ?? ""), + String(item.inUsage ?? ""), + String(item.outUsage ?? ""), + ]) }) - return data; + return excelExportData; }; \ No newline at end of file diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx index d9159e1b5..67c02cabf 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx @@ -1,10 +1,12 @@ import { z } from "zod"; import type { CommonTableProps } from "../../common/type/header"; +import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg"; export const ldrmntZod = z.object({ + fctryMngSn: z.string().default(''), ctpvCd: z.string().default(''), sggCd: z.string().default(''), - mngInst: z.string().default('').nullish(), + mngInstNm: z.string().default('').nullish(), dmdCoNm: z.string().default(''), fctrySe: z.string().default(''), cmpxNm: z.string().default(''), @@ -40,6 +42,7 @@ export const ldrmntZod = z.object({ fctryAddr: z.string().default(''), fctryLotnoAddr: z.string().default(''), fctryMngNo: z.string().default(''), + rgtr:z.string().default(TEST_UUID).nullish() }) export const ldrmntHeadListExport: CommonTableProps[] = [ diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx index a54e5a1e7..cf6c316a4 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx @@ -1,8 +1,9 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; -import { fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api"; +import { deleteFectch, fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api"; import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { z } from "zod"; import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList"; +import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg"; @@ -29,6 +30,7 @@ type ldrmntActions = { ldrmntInit: () => void; ldrmntSearch: (sggCd: string, coNm: string) => void; ldrmntUpdate: (ldrmntRes: customLdrmnt) => void; + ldrmntDelete: () => void; }; export type ldrmntType = ldrmntState & ldrmntActions; @@ -127,6 +129,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( }, ldrmntUpdate: async (ldrmntRes: customLdrmnt) => { try { + ldrmntRes.rgtr = TEST_UUID; console.log("ldrmntRes", ldrmntRes) const response = await putFectch( `/reuseFc/request/temp`, @@ -146,5 +149,15 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( console.error("Error ldrmntUpdate:", error); } }, + ldrmntDelete: async () => { + try { + const response = await deleteFectch( + `/reuseFc/request/temp`, + ); + + } catch (error) { + console.error("Error ldrmntDelete:", error); + } + }, } } \ No newline at end of file diff --git a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx index ffd255579..1fa8fa8f3 100644 --- a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx +++ b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx @@ -1,6 +1,6 @@ import { useWrStore } from "@/app/store"; import { coRegExcel } from "@/app/store/matDmd/coSttn/headList"; -import type { customLdrmntBdst } from "@/app/store/matDmd/ldrmntCoSttn"; +import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; import { excelToLdrmntData, names } from "@/app/store/matDmd/ldrmntCoSttn/excel"; import { filePicked, FileUpload, FormUi, Title } from "@common/business_components/ui"; import { Form, FormField } from "@common/business_components/ui/form"; @@ -16,13 +16,14 @@ export default function CoRegExcel() { const form = useForm<z.infer<typeof coRegExcel>>({ resolver: zodResolver(coRegExcel), }); - const { ldrmntRegData } = useWrStore((state) => state); - const [excelData, setExcelData] = useState<customLdrmntBdst[]>(); + const { ldrmntRegData, ldrmntDelete } = useWrStore((state) => state); + const [excelData, setExcelData] = useState<customLdrmnt[]>(); const [file, setFiles] = useState<File | undefined>(); const onSubmit = (values: z.infer<typeof coRegExcel>) => { + ldrmntDelete(); if (file) { filePicked(file, 0).then((res) => { try { @@ -50,7 +51,7 @@ export default function CoRegExcel() { } }) ldrmntRegData(array); - console.log("array22", array) + console.log("array끝", array) } catch (e) { console.log(e) } diff --git a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx index 75df712a8..edffcc71d 100644 --- a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx +++ b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx @@ -17,8 +17,8 @@ export default function SttnDetailModal({ formObj: any; }) { const { ldrmntUpdate } = useWrStore( - (state) => state - ); + (state) => state + ); const defaultValues: z.infer<typeof ldrmntZod> = ldrmntZod.parse({}); const form = useForm<z.infer<typeof ldrmntZod>>({ resolver: zodResolver(ldrmntZod), @@ -35,7 +35,6 @@ export default function SttnDetailModal({ if (ldrmntZod) form.reset(formObj); }, [formObj]); - return ( <div> <ScrollArea className="h-[85vh]"> @@ -50,6 +49,23 @@ export default function SttnDetailModal({ </Button> </div> + <FormField + control={form.control} + name="fctryMngSn" + render={({ field }) => ( + <FormUi label=""> + <Input + className={selectClass} + placeholder="" + type="hidden" + onChange={(e) => { + }} + value={field.value ?? ""} + /> + </FormUi> + )} + /> + <div className="grid grid-cols-4 gap-2 mt-4"> <div className="col-span-2"> <FormField @@ -73,7 +89,7 @@ export default function SttnDetailModal({ <div className="col-span-2"> <FormField control={form.control} - name="mngInst" + name="mngInstNm" render={({ field }) => ( <FormUi label="관리기관"> <Input @@ -90,7 +106,7 @@ export default function SttnDetailModal({ /> </div> </div> - + <div className="grid grid-cols-4 gap-2 mt-4"> <div className="col-span-2"> <FormField @@ -716,7 +732,7 @@ export default function SttnDetailModal({ <FormField control={form.control} name="fctryMngNo" - render={({ field }) => ( + render={({ field, fieldState }) => ( <FormUi label="공장관리번호"> <Input className={selectClass} From 76c8ebd2adf3bc608750fdd37bc512a0a52de6c4 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Wed, 18 Jun 2025 13:20:57 +0900 Subject: [PATCH 04/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=8B=9C=EC=84=A4?= =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EC=8B=9C=EC=9E=91!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 2 +- apps/wr/app/stats/rswtStat/page.tsx | 129 ++++++++++-------- apps/wr/app/store/stats/rainStat/headList.tsx | 7 +- apps/wr/app/store/stats/rainStat/index.tsx | 23 ++-- 4 files changed, 95 insertions(+), 66 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index ec7802428..7b822875a 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -21,7 +21,7 @@ export default function RainStat() { ); useEffect(() => { - searchRainStatList(searchYear) + searchRainStatList(searchYear); }, [searchRainStatList, searchYear]) return ( diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index 7514f98b1..d1a0f6353 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -1,75 +1,92 @@ 'use client' + import { useWrStore } from "@/app/store"; import { yearOptions } from "@/components/lib/func/commom"; -import { ContentsDiv, SearchDiv, SearchFormLeft, SelectBox, Title, UiTable } from "@common/business_components/ui"; +import { + ContentsDiv, + SearchDiv, + SearchFormLeft, + SelectBox, + Title, + UiTable +} from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; import { useState } from "react"; export default function RswtStat() { - const { code, rswtStat } = useWrStore((state) => { - return state; - }); + const { code, rswtStat } = useWrStore((state) => state); const [pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); - return( - <> - <ContentsDiv> + const testData = [1,2,3] + testData.map((item) => { + console.log('test ',item); + }) + + return ( + <> + <ContentsDiv> <div className="grid grid-cols-4 gap-4"> <div className="col-span-4"> - <Title title={"재이용 통계"} /> - <SearchDiv> - <SearchFormLeft> + <Title title="재이용 통계" /> + <SearchDiv> + <div className="grid grid-cols-12 gap-5 m-4"> + <div className="col-span-2"> <SelectBox - className="w-full h-full text-2xl" - label="통계년도" - selectClass={""} - selectArray={yearOptions} - value={searchYear} - onSelectValue={(val: string | number) => - setSearchYear(String(val)) - } - /> - <div className="flex flex-row space-x-2 items-center"> - <Button className="" size={"sm"} onClick={(e) => {}}> - 조회 - </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> - 다운로드 - </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> - 전체통계다운로드 - </Button> - </div> - </SearchFormLeft> - {/* <SearchFormRight> - - </SearchFormRight> */} - </SearchDiv> - </div> + className="w-full h-full text-2xl" + label="통계년도" + selectClass="" + selectArray={yearOptions} + value={searchYear} + onSelectValue={(val: string | number) => setSearchYear(String(val))} + /> + </div> + <div className="flex flex-row space-x-2 items-center"> + <Button + className="" + size="sm" + onClick={() => {}} + > + 조회 + </Button> + <Button + className="" + size="sm" + onClick={() => {}} + > + 다운로드 + </Button> + <Button + className="" + size="sm" + onClick={() => {}} + > + 전체통계다운로드 + </Button> + </div> + </div> + </SearchDiv> </div> - <div className="grid grid-cols-6 gap-4"> - <div className="col-span-6 h-full min-h-0"> - <ListDiv className="min-h-0"> - {/* <ScrollArea className="h-[60vh]"> */} - <UiTable - tableData={[]} - headlist={rswtStat.rswtStatHeadList} - pageSize={20} - total={10000} - headName={"건축물 목록"} - cellClick={(val, headId) => {}} - onPageChange={setPageNation} - ></UiTable> - {/* </ScrollArea> */} - </ListDiv> - </div> + </div> + <div className="grid grid-cols-6 gap-4"> + <div className="col-span-6 h-full min-h-0"> + <ListDiv className="min-h-0"> + <UiTable + tableData={[]} + headlist={rswtStat.rswtStatHeadList} + pageSize={20} + total={10000} + headName="건축물 목록" + cellClick={() => {}} + onPageChange={setPageNation} + /> + </ListDiv> </div> - </ContentsDiv> - </> - ) - + </div> + </ContentsDiv> + </> + ); } \ No newline at end of file diff --git a/apps/wr/app/store/stats/rainStat/headList.tsx b/apps/wr/app/store/stats/rainStat/headList.tsx index cc5386589..e1c427fdf 100644 --- a/apps/wr/app/store/stats/rainStat/headList.tsx +++ b/apps/wr/app/store/stats/rainStat/headList.tsx @@ -29,7 +29,7 @@ export const rainStatHeadListExport: TableUpperProps[] = [ id: "이용용도", title: "이용용도", row:0, - colSpan:6 + colSpan:7 }, { id: "조경용수", @@ -41,6 +41,11 @@ export const rainStatHeadListExport: TableUpperProps[] = [ title: "청소화장실용수", row:1, }, + { + id:"세척살수용수", + title:"세척살수용수", + row:1, + }, { id: "농업용수", title: "농업용수", diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index e9a9d3a3d..032ad100b 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -1,3 +1,4 @@ +import { fetchType, getFetch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; import { rainStatHeadListExport } from "./headList"; @@ -5,8 +6,11 @@ export type RainStatProps = { ctpvCd : string //시도 sggCd : string //시군구 areaNm : string //행정구역명 + instlCst : number //설치비용 archArea : number //건축연면적 - dtfcltCpct : number //처리용량 + dtfcltCpct : number //처리용량(저류조용량) + wtrUsqty : number //연간사용량 + anlOperCst : number //연간운영비 annRnwtQty : number //물사용량 jungsudo : number //중수도​이용량 dachae : number //대체수​이용량 @@ -17,13 +21,12 @@ export type RainStatProps = { way5 : number //방법5 way6 : number //방법6 way7 : number //방법7 - yearMoney : number //연간운영비 } const fetchRainStatList = async (year:string) => { - const res = await fetch(`/api/stats/rainStat?year=${year}`) - const data = await res.json() - return data + const res = await getFetch(fetchType.WR,`/reuseChk/reuseWater/sttn/${year}`) + console.log(res); + return []; } type rainStatActions = { @@ -50,8 +53,7 @@ export const rainStatActionsExport = ( ) => { return { searchRainStatList : async (year:string) => { - console.log(year); - //const data = await fetchRainStatList(year) + const res = await fetchRainStatList(year); const rainStatList: never[] = []; /* const rainStatHeadList = data.map((item:RainStatProps) => ({ ...item, @@ -72,7 +74,12 @@ export const rainStatActionsExport = ( way7:item.way7, yearMoney:item.yearMoney, })) */ - set((state:rainStatState) => ({...state, rainStat: {rainStatList:rainStatList}})) + set((state: rainStatState) => ({ + rainStat: { + ...state.rainStat, + rainStatList: rainStatList, + } + })); } } } \ No newline at end of file From d9984da6f7b89aaa9c7f493a0af66912f0b7aeba Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Wed, 18 Jun 2025 13:22:31 +0900 Subject: [PATCH 05/25] =?UTF-8?q?=EC=9E=A0=EC=9E=AC=EC=88=98=EC=9A=94?= =?UTF-8?q?=EC=B2=98=20=EC=83=81=EC=84=B8=EC=A0=95=EB=B3=B4=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx | 12 ++++++++---- apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx | 11 ++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx index 2fe3cd93a..9e8d91bcf 100644 --- a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx @@ -7,6 +7,7 @@ import { ldrmntNodeListExport } from "@/app/store/matDmd/ldrmntCoSttn/headList"; import { excelDownload, getCity, + getCityOrSgg, tableData } from "@/components/lib/func/commom"; import CoRegExcel from "@/components/ui/modal/coReg/coRegExcel/coRegExcelModal"; @@ -40,6 +41,8 @@ export default function LdrmntCoSttn() { const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); const [bdstTable, setBdstTable] = useState<customLdrmnt[]>(); const [searchTxt, setSearchTxt] = useState<string>(); + const ref = useRef<ReturnType>({} as ReturnType); + const codeData = getCityOrSgg(ref); const excelClick = useCallback(() => { excelDownload( @@ -75,18 +78,19 @@ export default function LdrmntCoSttn() { useEffect(() => { if (!ldrmnt.isInit) { - ldrmntInit(); + ldrmntInit(codeData ?? "0"); } }, [ldrmnt.isInit, ldrmntInit]); useEffect(() => { - const data = tableData(ldrmntRes, { code }); - console.log("data", data) + const transData = Array.isArray(ldrmntRes) ? ldrmntRes : [ldrmntRes]; + const data = tableData(transData, { code }); const tbData = Array.isArray(data) ? data.map((item: customLdrmnt) => ({ ...item, - ctpvCd: item.fctryAddr.split(" ")[0] || "", + ctpvCd: item.fctryAddr.split(" ")[0] || "", sggCd: item.fctryAddr.split(" ")[1] || "" + })) : []; diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx index cf6c316a4..d95e179c9 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx @@ -27,7 +27,7 @@ export type ldrmntState = { type ldrmntActions = { ldrmntRegData: (data: any[]) => void, - ldrmntInit: () => void; + ldrmntInit: (con:string) => void ldrmntSearch: (sggCd: string, coNm: string) => void; ldrmntUpdate: (ldrmntRes: customLdrmnt) => void; ldrmntDelete: () => void; @@ -49,12 +49,14 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( set: any ) => { return { - ldrmntInit: async () => { + ldrmntInit: async (con:string) => { try { + console.log("con", con) const ldrmntRes = await getFetch( fetchType.WR, - `/reuseFc/request/temp/1/20/0` + `/reuseFc/request/temp/1/20/${con}` ); + console.log("initres",) return set((state: ldrmntState) => ({ ...state, rain: { @@ -130,7 +132,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( ldrmntUpdate: async (ldrmntRes: customLdrmnt) => { try { ldrmntRes.rgtr = TEST_UUID; - console.log("ldrmntRes", ldrmntRes) + console.log("ldrmntRes", ldrmntRes); const response = await putFectch( `/reuseFc/request/temp`, ldrmntRes @@ -141,7 +143,6 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( ldrmnt: { ...state.ldrmnt, ldrmntRes: ldrmntRes, - isInit: false, }, })); From 9b49f1218818dc291a6db4cd41021ea9d936839f Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Wed, 18 Jun 2025 13:32:59 +0900 Subject: [PATCH 06/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=8B=9C=EC=84=A4=20ur?= =?UTF-8?q?l=EC=88=98=EC=A0=95=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/store/stats/rainStat/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 032ad100b..2a1a5bc5a 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -24,7 +24,7 @@ export type RainStatProps = { } const fetchRainStatList = async (year:string) => { - const res = await getFetch(fetchType.WR,`/reuseChk/reuseWater/sttn/${year}`) + const res = await getFetch(fetchType.WR,`/reuseChk/rainy/stat/${year}`) console.log(res); return []; } From c5503681f03aaf2118c522755295d8a4ac010d1b Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Wed, 18 Jun 2025 14:32:52 +0900 Subject: [PATCH 07/25] =?UTF-8?q?return=20res=20=EC=B6=94=EA=B0=80,=20type?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/store/stats/rainStat/headList.tsx | 70 +++++++++++++++++++ apps/wr/app/store/stats/rainStat/index.tsx | 4 +- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/apps/wr/app/store/stats/rainStat/headList.tsx b/apps/wr/app/store/stats/rainStat/headList.tsx index e1c427fdf..412b79178 100644 --- a/apps/wr/app/store/stats/rainStat/headList.tsx +++ b/apps/wr/app/store/stats/rainStat/headList.tsx @@ -73,3 +73,73 @@ export const rainStatHeadListExport: TableUpperProps[] = [ rowSpan:2 }, ]; + +export const rainStatDetailHeadListExport: TableUpperProps[] = [ + { + id: "ctpvCd", + title: "시도", + row:0, + }, + { + id: "sggCd", + title: "시군구", + row:0, + }, + { + id: "areaNm", + title: "행정구역명", + row:0, + }, + { + id: "", + title: "시설명", + row:0, + }, + { + id: "이용용도", + title: "이용용도", + row:0, + colSpan:7 + }, + { + id: "조경용수", + title: "조경용수", + row:1, + }, + { + id: "청소화장실용수", + title: "청소화장실용수", + row:1, + }, + { + id:"세척살수용수", + title:"세척살수용수", + row:1, + }, + { + id: "농업용수", + title: "농업용수", + row:1, + }, + { + id: "공업용수", + title: "공업용수", + row:1, + }, + { + id: "친수용수", + title: "친수용수", + row:1, + }, + { + id: "기타", + title: "기타", + row:1, + }, + { + id: "연간운영비", + title: "연간운영비(백만원/년)", + row:0, + rowSpan:2 + }, +]; \ No newline at end of file diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 2a1a5bc5a..a2c9f45a7 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -6,6 +6,7 @@ export type RainStatProps = { ctpvCd : string //시도 sggCd : string //시군구 areaNm : string //행정구역명 + bdstNm : string //시설명 instlCst : number //설치비용 archArea : number //건축연면적 dtfcltCpct : number //처리용량(저류조용량) @@ -25,8 +26,7 @@ export type RainStatProps = { const fetchRainStatList = async (year:string) => { const res = await getFetch(fetchType.WR,`/reuseChk/rainy/stat/${year}`) - console.log(res); - return []; + return res; } type rainStatActions = { From 7235999ecd3da2db23ee847f4402ba4fd991fff9 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Wed, 18 Jun 2025 14:35:48 +0900 Subject: [PATCH 08/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=8B=9C=EC=84=A4?= =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EC=8B=9C=EB=8F=84=20groupby?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/store/stats/rainStat/index.tsx | 95 +++++++++++++++------- 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 2a1a5bc5a..447c2d54a 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -3,40 +3,40 @@ import type { TableUpperProps } from "../../common/type/header"; import { rainStatHeadListExport } from "./headList"; export type RainStatProps = { - ctpvCd : string //시도 - sggCd : string //시군구 - areaNm : string //행정구역명 - instlCst : number //설치비용 - archArea : number //건축연면적 - dtfcltCpct : number //처리용량(저류조용량) - wtrUsqty : number //연간사용량 - anlOperCst : number //연간운영비 - annRnwtQty : number //물사용량 - jungsudo : number //중수도​이용량 - dachae : number //대체수​이용량 - way1 : number //방법1 - way2 : number //방법2 - way3 : number //방법3 - way4 : number //방법4 - way5 : number //방법5 - way6 : number //방법6 - way7 : number //방법7 + ctpvCd: string //시도 + sggCd: string //시군구 + areaNm: string //행정구역명 + instlCst: number //설치비용 + archArea: number //건축연면적 + dtfcltCpct: number //처리용량(저류조용량) + wtrUsqty: number //연간사용량 + anlOperCst: number //연간운영비 + annRnwtQty: number //물사용량 + jungsudo: number //중수도​이용량 + dachae: number //대체수​이용량 + way1: number //방법1 + way2: number //방법2 + way3: number //방법3 + way4: number //방법4 + way5: number //방법5 + way6: number //방법6 + way7: number //방법7 } -const fetchRainStatList = async (year:string) => { - const res = await getFetch(fetchType.WR,`/reuseChk/rainy/stat/${year}`) - console.log(res); - return []; +const fetchRainStatList = async (year: string) => { + const res = await getFetch(fetchType.WR, `/reuseChk/rainy/stat/${year}`) + // console.log(res); + return res; } type rainStatActions = { - searchRainStatList : (year:string) => void + searchRainStatList: (year: string) => void } export type rainStatState = { rainStat: { - rainStatHeadList:TableUpperProps[], - rainStatList : RainStatProps[] + rainStatHeadList: TableUpperProps[], + rainStatList: RainStatProps[] } } @@ -44,17 +44,56 @@ export type rainStatType = rainStatState & rainStatActions; export const rainStatExport: rainStatState = { rainStat: { - rainStatHeadList:rainStatHeadListExport, - rainStatList : [] + rainStatHeadList: rainStatHeadListExport, + rainStatList: [] } } export const rainStatActionsExport = ( set: (fn: (state: rainStatState) => rainStatState) => void ) => { return { - searchRainStatList : async (year:string) => { + searchRainStatList: async (year: string) => { const res = await fetchRainStatList(year); const rainStatList: never[] = []; + + const grouped = Object.groupBy(res, (item: RainStatProps) => item.ctpvCd); + console.log("grouped", grouped); + + Object.values(grouped).forEach((item) => { + if (!item) return; + let instlCst = 0; + let dtfcltCpct = 0; + let wtrUsqty = 0; + let anlOperCst = 0; + let way1 = 0; + let way2 = 0; + let way3 = 0; + let way4 = 0; + let way5 = 0; + let way6 = 0; + let way7 = 0; + + item.forEach((element) => { + instlCst += element.instlCst; + dtfcltCpct += element.dtfcltCpct; + wtrUsqty += element.wtrUsqty; + anlOperCst += element.anlOperCst; + way1 += element.way1; + way2 += element.way2; + way3 += element.way3; + way4 += element.way4; + way5 += element.way5; + way6 += element.way6; + way7 += element.way7; + }) + + console.log("instlCst", instlCst) + console.log("dtfcltCpct", dtfcltCpct) + + }) + + + /* const rainStatHeadList = data.map((item:RainStatProps) => ({ ...item, ctpvCd:item.ctpvCd, From 77ce7ed4065ceb99eed5837698567f2bd528bf17 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Wed, 18 Jun 2025 16:14:43 +0900 Subject: [PATCH 09/25] =?UTF-8?q?=EC=97=91=EC=85=80=20=EB=A7=8C=EB=93=9C?= =?UTF-8?q?=EB=8A=94=20=EC=86=8C=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/store/stats/rainStat/excel.tsx | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 apps/wr/app/store/stats/rainStat/excel.tsx diff --git a/apps/wr/app/store/stats/rainStat/excel.tsx b/apps/wr/app/store/stats/rainStat/excel.tsx new file mode 100644 index 000000000..f79de9abd --- /dev/null +++ b/apps/wr/app/store/stats/rainStat/excel.tsx @@ -0,0 +1,29 @@ +import type { RainStatProps } from "."; + +export const excelRainStat = (excelList:RainStatProps[]) => { + const excelData: string[][] = []; + excelList.forEach((item) => { + excelData.push([ + String(item.ctpvCd) ?? "", + String(item.sggCd) ?? "", + String(item.areaNm) ?? "", + String(item.bdstNm) ?? "", + String(item.instlCst) ?? "", + String(item.archArea) ?? "", + String(item.dtfcltCpct) ?? "", + String(item.wtrUsqty) ?? "", + String(item.anlOperCst) ?? "", + String(item.annRnwtQty) ?? "", + String(item.jungsudo) ?? "", + String(item.dachae) ?? "", + String(item.way1) ?? "", + String(item.way2) ?? "", + String(item.way3) ?? "", + String(item.way4) ?? "", + String(item.way5) ?? "", + String(item.way6) ?? "", + String(item.way7) ?? "", + ]); + }); + return excelData; +} \ No newline at end of file From f5ac9bc126268e5f8f772c3ef95c11d980a77236 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Wed, 18 Jun 2025 16:39:08 +0900 Subject: [PATCH 10/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=9E=AC=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=20=EC=8B=9C=EC=84=A4=20=ED=83=80=EC=9E=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/store/stats/rainStat/index.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index a2c9f45a7..4a9e3c86b 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -7,10 +7,17 @@ export type RainStatProps = { sggCd : string //시군구 areaNm : string //행정구역명 bdstNm : string //시설명 + bdstUsgCd : string //건축물용도코드 + daddr : string //주소 + lawTrgtYn : string //법적의무대상여부 + instlCmptnDt : string //설치완료일자 instlCst : number //설치비용 + pntfColKnd : string //접수면종류 + filtrTrtmfctYn : string //여과등처리시설유무 archArea : number //건축연면적 dtfcltCpct : number //처리용량(저류조용량) wtrUsqty : number //연간사용량 + utztnUsgCd : string //이용용도코드 anlOperCst : number //연간운영비 annRnwtQty : number //물사용량 jungsudo : number //중수도​이용량 From d52f0137ca8782af64fe85bcea1ae69c2a1fa8c5 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Wed, 18 Jun 2025 16:48:03 +0900 Subject: [PATCH 11/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=ED=86=B5=EA=B3=84=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 10 ++- apps/wr/app/store/stats/rainStat/headList.tsx | 16 +++-- apps/wr/app/store/stats/rainStat/index.tsx | 62 ++++++++++--------- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index 7b822875a..26fc6340a 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useWrStore } from "@/app/store"; +import type { RainStatProps } from "@/app/store/stats/rainStat"; import { yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, @@ -14,7 +15,9 @@ import { Button } from "@common/components/ui"; import { useEffect, useState } from "react"; export default function RainStat() { - const { rainStat, searchRainStatList } = useWrStore((state) => state) + const { rainStat, searchRainStatList } = useWrStore((state) => state); + const { rainStatHeadList, rainStatList } = rainStat; + const [ pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) @@ -22,6 +25,7 @@ export default function RainStat() { useEffect(() => { searchRainStatList(searchYear); + console.log("rainStatList", rainStatList) }, [searchRainStatList, searchYear]) return ( @@ -66,11 +70,11 @@ export default function RainStat() { <ListDiv className="min-h-0"> {/* <ScrollArea className="h-[60vh]"> */} <UiTable - tableData={[]} + tableData={rainStatList || []} headlist={rainStat.rainStatHeadList} pageSize={20} total={10000} - headName={"건축물 목록"} + headName={""} cellClick={(val, headId) => {}} onPageChange={setPageNation} ></UiTable> diff --git a/apps/wr/app/store/stats/rainStat/headList.tsx b/apps/wr/app/store/stats/rainStat/headList.tsx index 412b79178..3b01c40c5 100644 --- a/apps/wr/app/store/stats/rainStat/headList.tsx +++ b/apps/wr/app/store/stats/rainStat/headList.tsx @@ -2,29 +2,35 @@ import type { TableUpperProps } from "../../common/type/header"; export const rainStatHeadListExport: TableUpperProps[] = [ { - id: "시도", + id: "ctpvCd", title: "시도", row:0, rowSpan:2 }, { - id: "개소", + id: "tmp", title: "개소", row:0, rowSpan:2 }, { - id: "설치비", + id: "instlCst", title: "설치비(백만원)", row:0, rowSpan:2 }, { - id: "저류조용량", + id: "dtfcltCpct", title: "저류조용량(m³/년)", row:0, rowSpan:2 }, + { + id: "wtrUsqty", + title: "연간사용량(㎥/년)", + row:0, + rowSpan:2 + }, { id: "이용용도", title: "이용용도", @@ -67,7 +73,7 @@ export const rainStatHeadListExport: TableUpperProps[] = [ row:1, }, { - id: "연간운영비", + id: "anlOperCst", title: "연간운영비(백만원/년)", row:0, rowSpan:2 diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 08e17b2ce..d22ae7a1a 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -22,6 +22,7 @@ export type RainStatProps = { way5 : number //방법5 way6 : number //방법6 way7 : number //방법7 + tmp : number //개소 } const fetchRainStatList = async (year:string) => { @@ -54,17 +55,19 @@ export const rainStatActionsExport = ( return { searchRainStatList: async (year: string) => { const res = await fetchRainStatList(year); - const rainStatList: never[] = []; + const rainStatList: RainStatProps[] = []; const grouped = Object.groupBy(res, (item: RainStatProps) => item.ctpvCd); console.log("grouped", grouped); Object.values(grouped).forEach((item) => { if (!item) return; + let ctpvCd = ""; let instlCst = 0; - let dtfcltCpct = 0; - let wtrUsqty = 0; - let anlOperCst = 0; + let tmp = 0; //개소 + let dtfcltCpct = 0; //설치비용 + let wtrUsqty = 0; //연간사용량 + let anlOperCst = 0; //연간운영비 let way1 = 0; let way2 = 0; let way3 = 0; @@ -74,7 +77,9 @@ export const rainStatActionsExport = ( let way7 = 0; item.forEach((element) => { + ctpvCd = element.ctpvCd; instlCst += element.instlCst; + tmp += 1; dtfcltCpct += element.dtfcltCpct; wtrUsqty += element.wtrUsqty; anlOperCst += element.anlOperCst; @@ -85,34 +90,33 @@ export const rainStatActionsExport = ( way5 += element.way5; way6 += element.way6; way7 += element.way7; + + }) + + rainStatList.push({ + instlCst, + tmp, + dtfcltCpct, + wtrUsqty, + anlOperCst, + way1, + way2, + way3, + way4, + way5, + way6, + way7, + ctpvCd, + // sggCd: "", + // areaNm: "", + // bdstNm: "", + // archArea: 0, + // annRnwtQty: 0, + // jungsudo: 0, + // dachae: 0 }) - - console.log("instlCst", instlCst) - console.log("dtfcltCpct", dtfcltCpct) - }) - - - /* 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, From 421eedb6f28259df34e7c3c89eaefa9b273a85ff Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Wed, 18 Jun 2025 20:18:53 +0900 Subject: [PATCH 12/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=9E=AC=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=86=B5=EA=B3=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=82=98=ED=83=80=EB=82=B4=EA=B8=B0=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/store/stats/rainStat/headList.tsx | 16 +- apps/wr/app/store/stats/rainStat/index.tsx | 164 ++++++++---------- 2 files changed, 84 insertions(+), 96 deletions(-) diff --git a/apps/wr/app/store/stats/rainStat/headList.tsx b/apps/wr/app/store/stats/rainStat/headList.tsx index 3b01c40c5..664e060c4 100644 --- a/apps/wr/app/store/stats/rainStat/headList.tsx +++ b/apps/wr/app/store/stats/rainStat/headList.tsx @@ -32,43 +32,43 @@ export const rainStatHeadListExport: TableUpperProps[] = [ rowSpan:2 }, { - id: "이용용도", + id: "a", title: "이용용도", row:0, colSpan:7 }, { - id: "조경용수", + id: "lndwtr", title: "조경용수", row:1, }, { - id: "청소화장실용수", + id: "cleanToilUswtr", title: "청소화장실용수", row:1, }, { - id:"세척살수용수", + id:"resn", title:"세척살수용수", row:1, }, { - id: "농업용수", + id: "farmUswtr", title: "농업용수", row:1, }, { - id: "공업용수", + id: "indstUswtr", title: "공업용수", row:1, }, { - id: "친수용수", + id: "hydUswtr", title: "친수용수", row:1, }, { - id: "기타", + id: "ithlEtcUswtr", title: "기타", row:1, }, diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 67baed954..c7c073bca 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -3,37 +3,43 @@ import type { TableUpperProps } from "../../common/type/header"; import { rainStatHeadListExport } from "./headList"; export type RainStatProps = { - ctpvCd : string //시도 - sggCd : string //시군구 - areaNm : string //행정구역명 - bdstNm : string //시설명 - bdstUsgCd : string //건축물용도코드 - daddr : string //주소 - lawTrgtYn : string //법적의무대상여부 - instlCmptnDt : string //설치완료일자 - instlCst : number //설치비용 - pntfColKnd : string //접수면종류 - filtrTrtmfctYn : string //여과등처리시설유무 - archArea : number //건축연면적 - dtfcltCpct : number //처리용량(저류조용량) - wtrUsqty : number //연간사용량 - utztnUsgCd : string //이용용도코드 - anlOperCst : number //연간운영비 - annRnwtQty : number //물사용량 - jungsudo : number //중수도​이용량 - dachae : number //대체수​이용량 - way1 : number //방법1 - way2 : number //방법2 - way3 : number //방법3 - way4 : number //방법4 - way5 : number //방법5 - way6 : number //방법6 - way7 : number //방법7 - tmp : number //개소 + ctpvCd: string //시도 + sggCd: string //시군구 + areaNm: string //행정구역명 + bdstNm: string //시설명 + bdstUsgCd: string //건축물용도코드 + daddr: string //주소 + lawTrgtYn: string //법적의무대상여부 + instlCmptnDt: string //설치완료일자 + instlCst: number //설치비용 + pntfColKnd: string //접수면종류 + filtrTrtmfctYn: string //여과등처리시설유무 + archArea: number //건축연면적 + dtfcltCpct: number //처리용량(저류조용량) + wtrUsqty: number //연간사용량 + utztnUsgCd: string //이용용도코드 + anlOperCst: number //연간운영비 + annRnwtQty: number //물사용량 + jungsudo: number //중수도​이용량 + dachae: number //대체수​이용량 + lndwtr: number //조경용수 + cleanToilUswtr: number //청소화장실용수 + resn: number //세척살수용수 + farmUswtr: number //농업용수 + indstUswtr: number //공업용수 + hydUswtr: number //친수용수 + ithlEtcUswtr: number //기타 + tmp: number //개소 + guideStats: GuideStatProps[] } -const fetchRainStatList = async (year:string) => { - const res = await getFetch(fetchType.WR,`/reuseChk/rainy/stat/${year}`) +export type GuideStatProps = { + utztnUsgCd: string + ruseFcltUtztnQnt: number +} + +const fetchRainStatList = async (year: string) => { + const res = await getFetch(fetchType.WR, `/reuseChk/rainy/stat/${year}`) return res; } @@ -62,74 +68,56 @@ export const rainStatActionsExport = ( return { searchRainStatList: async (year: string) => { const res = await fetchRainStatList(year); - const rainStatList: RainStatProps[] = []; - const grouped = Object.groupBy(res, (item: RainStatProps) => item.ctpvCd); - console.log("grouped", grouped); - - Object.values(grouped).forEach((item) => { - if (!item) return; - let ctpvCd = ""; - let instlCst = 0; - let tmp = 0; //개소 - let dtfcltCpct = 0; //설치비용 - let wtrUsqty = 0; //연간사용량 - let anlOperCst = 0; //연간운영비 - let way1 = 0; - let way2 = 0; - let way3 = 0; - let way4 = 0; - let way5 = 0; - let way6 = 0; - let way7 = 0; - - item.forEach((element) => { - ctpvCd = element.ctpvCd; - instlCst += element.instlCst; - tmp += 1; - dtfcltCpct += element.dtfcltCpct; - wtrUsqty += element.wtrUsqty; - anlOperCst += element.anlOperCst; - way1 += element.way1; - way2 += element.way2; - way3 += element.way3; - way4 += element.way4; - way5 += element.way5; - way6 += element.way6; - way7 += element.way7; - - }) + let cityArr: any[] = []; + res.forEach((item: RainStatProps) => { - rainStatList.push({ - instlCst, - tmp, - dtfcltCpct, - wtrUsqty, - anlOperCst, - way1, - way2, - way3, - way4, - way5, - way6, - way7, - ctpvCd, - // sggCd: "", - // areaNm: "", - // bdstNm: "", - // archArea: 0, - // annRnwtQty: 0, - // jungsudo: 0, - // dachae: 0 + let obj = cityArr.find((e) => { + return e.ctpvCd == item.ctpvCd }) + + if (obj) { + obj.instlCst += item.instlCst + obj.dtfcltCpct += item.dtfcltCpct + obj.wtrUsqty += item.wtrUsqty + obj.anlOperCst += item.anlOperCst + obj.tmp += 1 + } else { + obj = {}; + obj.ctpvCd = item.ctpvCd + obj.instlCst = item.instlCst + obj.tmp = 1 + obj.dtfcltCpct = item.dtfcltCpct + obj.wtrUsqty = item.wtrUsqty + obj.anlOperCst = item.anlOperCst + + cityArr.push(obj) + } + + if (item.guideStats && item.guideStats.length > 0) { + item.guideStats.forEach((guide: GuideStatProps) => { + rainStatHeadListExport.forEach((headItem: TableUpperProps) => { + + if (headItem.title == guide.utztnUsgCd) { + if (!obj[headItem.id] || typeof obj[headItem.id] !== "number") obj[headItem.id] = 0; + if (typeof obj[headItem.id] === "number") { + + obj[headItem.id] += guide.ruseFcltUtztnQnt; + console.log("obj", obj) + } + } + }); + }) + } + }) set((state: rainStatState) => ({ rainStat: { ...state.rainStat, - rainStatList: rainStatList, + rainStatList: cityArr, } })); } } -} \ No newline at end of file +} From f00128b5b8d6e2a3eb470a103b6844bc07dd2c9a Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 19 Jun 2025 09:37:11 +0900 Subject: [PATCH 13/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=8B=9C=EC=84=A4?= =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EC=97=91=EC=85=80=EB=8B=A4=EC=9A=B4?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=96=91=EC=8B=9D=20=EB=B0=8F=20=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=EB=A1=9C=EB=93=9C=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 23 ++++++++++++++++--- apps/wr/app/store/stats/rainStat/excel.tsx | 20 +++++++---------- apps/wr/app/store/stats/rainStat/index.tsx | 25 +++++++++++++++++++-- apps/wr/public/sample_rainStats.xlsx | Bin 0 -> 10809 bytes 4 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 apps/wr/public/sample_rainStats.xlsx diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index 7b822875a..ab855be1c 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useWrStore } from "@/app/store"; -import { yearOptions } from "@/components/lib/func/commom"; +import { excelDownload, yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, SearchDiv, @@ -14,7 +14,9 @@ import { Button } from "@common/components/ui"; import { useEffect, useState } from "react"; export default function RainStat() { + const { code } = useWrStore((state) => state) const { rainStat, searchRainStatList } = useWrStore((state) => state) + const { rainDetailList } = rainStat; const [ pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) @@ -22,7 +24,22 @@ export default function RainStat() { useEffect(() => { searchRainStatList(searchYear); - }, [searchRainStatList, searchYear]) + }, [code.cityCd, code.sggCd, searchRainStatList, searchYear]) + + const excelDownLoad=() =>{ + rainDetailList.forEach((item) => { + item.forEach((item2) => { + console.log(item2); + }) + }) + excelDownload( + rainDetailList, + "빗물이용시설 통계", + "sample_rainStats.xlsx", + "A1:V3", + 4 + ); + } return ( <> @@ -51,7 +68,7 @@ export default function RainStat() { <Button className="" size={"sm"} onClick={(e) => {}}> 다운로드 </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> + <Button className="" size={"sm"} onClick={() => excelDownLoad()}> 전체통계다운로드 </Button> </div> diff --git a/apps/wr/app/store/stats/rainStat/excel.tsx b/apps/wr/app/store/stats/rainStat/excel.tsx index f79de9abd..d4bb0b07c 100644 --- a/apps/wr/app/store/stats/rainStat/excel.tsx +++ b/apps/wr/app/store/stats/rainStat/excel.tsx @@ -1,6 +1,6 @@ import type { RainStatProps } from "."; -export const excelRainStat = (excelList:RainStatProps[]) => { +export const excelRainStat = (excelList:RainStatProps[]) : string[][] => { const excelData: string[][] = []; excelList.forEach((item) => { excelData.push([ @@ -8,21 +8,17 @@ export const excelRainStat = (excelList:RainStatProps[]) => { 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.archArea) ?? "", + String(item.pntfColKnd) ?? "", + String(item.filtrTrtmfctYn) ?? "", String(item.dtfcltCpct) ?? "", String(item.wtrUsqty) ?? "", + String(item.utztnUsgCd) ?? "", String(item.anlOperCst) ?? "", - String(item.annRnwtQty) ?? "", - String(item.jungsudo) ?? "", - String(item.dachae) ?? "", - String(item.way1) ?? "", - String(item.way2) ?? "", - String(item.way3) ?? "", - String(item.way4) ?? "", - String(item.way5) ?? "", - String(item.way6) ?? "", - String(item.way7) ?? "", ]); }); return excelData; diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 4a9e3c86b..801162093 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -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 //시도 @@ -22,6 +23,11 @@ export type RainStatProps = { annRnwtQty : number //물사용량 jungsudo : number //중수도​이용량 dachae : number //대체수​이용량 + guideStats : [{ + utztnUsgCd : string, + splyUswtrUtztnQnt : number, + ruseFcltUtztnQnt : number, + }] way1 : number //방법1 way2 : number //방법2 way3 : number //방법3 @@ -43,7 +49,8 @@ type rainStatActions = { export type rainStatState = { rainStat: { rainStatHeadList:TableUpperProps[], - rainStatList : RainStatProps[] + rainStatList : RainStatProps[], + rainDetailList : [][] } } @@ -52,7 +59,8 @@ export type rainStatType = rainStatState & rainStatActions; export const rainStatExport: rainStatState = { rainStat: { rainStatHeadList:rainStatHeadListExport, - rainStatList : [] + rainStatList : [], + rainDetailList : [] } } export const rainStatActionsExport = ( @@ -62,6 +70,18 @@ export const rainStatActionsExport = ( searchRainStatList : async (year:string) => { const res = await fetchRainStatList(year); const rainStatList: never[] = []; + 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, @@ -85,6 +105,7 @@ export const rainStatActionsExport = ( rainStat: { ...state.rainStat, rainStatList: rainStatList, + rainDetailList: excelDetailData as [][] } })); } diff --git a/apps/wr/public/sample_rainStats.xlsx b/apps/wr/public/sample_rainStats.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c8f8e69b5fd4bfa9578f1300356c8b4535494232 GIT binary patch literal 10809 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 Xin0jMuL}S?gZ_M>B|$FzZ_@t*FYYFb literal 0 HcmV?d00001 From 042117939156202692f1f199eb02dd859e0769c6 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 19 Jun 2025 09:37:56 +0900 Subject: [PATCH 14/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=8B=9C=EC=84=A4?= =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wr/app/matMng/coMng/ldrmntCoSttn/page.tsx | 4 +- .../store/matDmd/ldrmntCoSttn/headList.tsx | 2 +- .../app/store/matDmd/ldrmntCoSttn/index.tsx | 24 +++++----- apps/wr/app/store/stats/rainStat/index.tsx | 44 +++++++++++++++++++ 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx index 9e8d91bcf..bd48782aa 100644 --- a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx @@ -3,7 +3,7 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import { type customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; -import { ldrmntNodeListExport } from "@/app/store/matDmd/ldrmntCoSttn/headList"; +import { ldrmntHeadListExport, ldrmntNodeListExport } from "@/app/store/matDmd/ldrmntCoSttn/headList"; import { excelDownload, getCity, @@ -202,7 +202,7 @@ export default function LdrmntCoSttn() { <UiTable headName={[]} tableData={bdstTable || []} - headlist={ldrmntNodeListExport} + headlist={ldrmntHeadListExport} pageSize={20} total={10000} cellClick={(index: number | undefined, headId: string) => { cellClick(index ?? undefined, headId) }} diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx index 67c02cabf..7a1695039 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/headList.tsx @@ -114,7 +114,7 @@ export const ldrmntNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "mngInst", + id: "mngInstNm", title: "관리기관", visible: true, row: 1, diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx index d95e179c9..f5005654d 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx @@ -27,7 +27,7 @@ export type ldrmntState = { type ldrmntActions = { ldrmntRegData: (data: any[]) => void, - ldrmntInit: (con:string) => void + ldrmntInit: (con: string) => void ldrmntSearch: (sggCd: string, coNm: string) => void; ldrmntUpdate: (ldrmntRes: customLdrmnt) => void; ldrmntDelete: () => void; @@ -49,22 +49,24 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( set: any ) => { return { - ldrmntInit: async (con:string) => { + ldrmntInit: async (con: string) => { try { console.log("con", con) const ldrmntRes = await getFetch( fetchType.WR, `/reuseFc/request/temp/1/20/${con}` ); - console.log("initres",) - return set((state: ldrmntState) => ({ - ...state, - rain: { - ...state.ldrmnt, - ldrmntRes: ldrmntRes, - isInit: false, - }, - })); + console.log("initres", ldrmntRes) + set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + ldrmntRes: ldrmntRes, + isInit: false, + }, + } + }); } catch (e) { console.log(e) } diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 4a9e3c86b..ed34c539e 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -61,6 +61,7 @@ export const rainStatActionsExport = ( return { searchRainStatList : async (year:string) => { const res = await fetchRainStatList(year); +<<<<<<< Updated upstream const rainStatList: never[] = []; /* const rainStatHeadList = data.map((item:RainStatProps) => ({ ...item, @@ -81,6 +82,49 @@ export const rainStatActionsExport = ( way7:item.way7, yearMoney:item.yearMoney, })) */ +======= + + let cityArr: any[] = []; + res.forEach((item: RainStatProps) => { + + let obj = cityArr.find((e) => { + return e.ctpvCd == item.ctpvCd + }) + + if (obj) { + obj.instlCst += item.instlCst + obj.dtfcltCpct += item.dtfcltCpct + obj.wtrUsqty += item.wtrUsqty + obj.anlOperCst += item.anlOperCst + obj.tmp += 1 + } else { + obj = {}; + obj.ctpvCd = item.ctpvCd + obj.instlCst = item.instlCst + obj.tmp = 1 + obj.dtfcltCpct = item.dtfcltCpct + obj.wtrUsqty = item.wtrUsqty + obj.anlOperCst = item.anlOperCst + + cityArr.push(obj) + } + + if (item.guideStats && item.guideStats.length > 0) { + item.guideStats.forEach((guide: GuideStatProps) => { + rainStatHeadListExport.forEach((headItem: TableUpperProps) => { + + if (headItem.title == guide.utztnUsgCd) { + if (!obj[headItem.id] || typeof obj[headItem.id] !== "number") obj[headItem.id] = 0; + if (typeof obj[headItem.id] === "number") { + + obj[headItem.id] += guide.ruseFcltUtztnQnt; + } + } + }); + }) + } + }) +>>>>>>> Stashed changes set((state: rainStatState) => ({ rainStat: { ...state.rainStat, From b6177964835be2c0af42ba320f5fe5a01054ddb5 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 19 Jun 2025 13:35:30 +0900 Subject: [PATCH 15/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=EC=8B=9C=EC=84=A4?= =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EC=97=91=EC=85=80=20=EB=8B=A4=EC=9A=B4?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 73 ++++++++++++++++++---- apps/wr/app/store/stats/rainStat/index.tsx | 35 +++++++++-- 2 files changed, 92 insertions(+), 16 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index 26fc6340a..b2f2006bf 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -2,7 +2,8 @@ import { useWrStore } from "@/app/store"; import type { RainStatProps } from "@/app/store/stats/rainStat"; -import { yearOptions } from "@/components/lib/func/commom"; +import { tableData, yearOptions } from "@/components/lib/func/commom"; +import { downloadExcel } from "@common/business_components"; import { ContentsDiv, SearchDiv, @@ -12,22 +13,72 @@ import { } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; export default function RainStat() { - const { rainStat, searchRainStatList } = useWrStore((state) => state); - const { rainStatHeadList, rainStatList } = rainStat; + const { code, rainStat, searchRainStatList } = useWrStore((state) => state); + const { rainStatHeadList, rainStatList, excelList } = rainStat; - const [ pageNation, setPageNation] = useState(1); + const [pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); + const [exData, setExData] = useState<Array<Record<string, string | number>>>(); + const [bdstTable, setBdstTable] = useState<RainStatProps[]>(); useEffect(() => { searchRainStatList(searchYear); - console.log("rainStatList", rainStatList) }, [searchRainStatList, searchYear]) + const excelClick = () => { + downloadExcel({ + data: (exData as unknown as JSON[]) ?? [], + fileName: "재이용통계", + sheetNameArray: ["Sheet1"], + headerRange: "A1:M1" + }) + } + + + useEffect(() => { + const transExcel = Array.isArray(excelList) ? excelList : [excelList]; + const excelData = tableData(transExcel, { code }); + const tbData = Array.isArray(excelData) + ? 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); + }, [excelList]) + + useEffect(() => { + const transData = Array.isArray(rainStatList) ? rainStatList : [rainStatList]; + const data = tableData(transData, { code }); + const tbData = Array.isArray(data) + ? data.map((item: RainStatProps) => { + return { + ...item, + ctpvCd: item.cityText + }; + }) + : []; + setBdstTable(tbData); + }, [rainStatList]); + return ( <> <ContentsDiv> @@ -49,13 +100,13 @@ export default function RainStat() { /> </div> <div className="flex flex-row space-x-2 items-center"> - <Button className="" size={"sm"} onClick={(e) => {}}> + <Button className="" size={"sm"} onClick={(e) => { }}> 조회 </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> + <Button className="" size={"sm"} onClick={() => excelClick()}> 다운로드 </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> + <Button className="" size={"sm"} onClick={(e) => { }}> 전체통계다운로드 </Button> </div> @@ -70,12 +121,12 @@ export default function RainStat() { <ListDiv className="min-h-0"> {/* <ScrollArea className="h-[60vh]"> */} <UiTable - tableData={rainStatList || []} + tableData={bdstTable || []} headlist={rainStat.rainStatHeadList} pageSize={20} total={10000} headName={""} - cellClick={(val, headId) => {}} + cellClick={(val, headId) => { }} onPageChange={setPageNation} ></UiTable> {/* </ScrollArea> */} diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index c7c073bca..edb5ab0d5 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -38,6 +38,12 @@ export type GuideStatProps = { ruseFcltUtztnQnt: number } +type ExcelType = { + [key: string]: string | number | undefined; +}; + +const excelDownList: ExcelType[] = []; + const fetchRainStatList = async (year: string) => { const res = await getFetch(fetchType.WR, `/reuseChk/rainy/stat/${year}`) return res; @@ -50,7 +56,8 @@ type rainStatActions = { export type rainStatState = { rainStat: { rainStatHeadList: TableUpperProps[], - rainStatList: RainStatProps[] + rainStatList: RainStatProps[], + excelList: ExcelType[] } } @@ -59,7 +66,8 @@ export type rainStatType = rainStatState & rainStatActions; export const rainStatExport: rainStatState = { rainStat: { rainStatHeadList: rainStatHeadListExport, - rainStatList: [] + rainStatList: [], + excelList: [] } } export const rainStatActionsExport = ( @@ -71,7 +79,7 @@ export const rainStatActionsExport = ( let cityArr: any[] = []; res.forEach((item: RainStatProps) => { - + let obj = cityArr.find((e) => { return e.ctpvCd == item.ctpvCd }) @@ -101,21 +109,38 @@ export const rainStatActionsExport = ( if (headItem.title == guide.utztnUsgCd) { if (!obj[headItem.id] || typeof obj[headItem.id] !== "number") obj[headItem.id] = 0; if (typeof obj[headItem.id] === "number") { - + obj[headItem.id] += guide.ruseFcltUtztnQnt; - console.log("obj", obj) } } }); }) } + }) + cityArr.forEach(item => { + excelDownList.push({ + ctpvCd: item.ctpvCd, + tmp: item.tmp, + instlCst: item.instlCst, //설치비 + dtfcltCpct: item.dtfcltCpct, //저류조용량 + bdstUsgCd: item.bdstUsgCd, //연간사용량 + lndwtr: item.lndwtr, //조경용수 + cleanToilUswtr: item.cleanToilUswtr, //청소화장실용수 + resn: item.resn, //세척살수용수 + farmUswtr: item.farmUswtr, //농업용수 + indstUswtr: item.indstUswtr, //공업용수 + hydUswtr: item.hydUswtr, //친수용수 + ithlEtcUswtr: item.ithlEtcUswtr, //기타 + anlOperCst: item.anlOperCst, //연간운영비 + }) }) set((state: rainStatState) => ({ rainStat: { ...state.rainStat, rainStatList: cityArr, + excelList: excelDownList } })); } From b39969f7e60819a97dd5a5ef0407fa5cf473ffcc Mon Sep 17 00:00:00 2001 From: truthwing <truthplumage@gmail.com> Date: Thu, 19 Jun 2025 13:38:57 +0900 Subject: [PATCH 16/25] =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20headlist=EC=97=90=20=ED=82=A4=EA=B0=92=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80.=20API=20=ED=98=B8=EC=B6=9C=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rswtStat/page.tsx | 33 ++++++++----------- apps/wr/app/store/stats/rswtStat/headList.tsx | 28 ++++++++-------- apps/wr/app/store/stats/rswtStat/index.tsx | 16 ++++++++- 3 files changed, 43 insertions(+), 34 deletions(-) diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index d1a0f6353..de96b29ea 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -1,33 +1,25 @@ -'use client' - +"use client"; import { useWrStore } from "@/app/store"; import { yearOptions } from "@/components/lib/func/commom"; -import { - ContentsDiv, - SearchDiv, - SearchFormLeft, - SelectBox, - Title, - UiTable +import { + ContentsDiv, + SearchDiv, + SelectBox, + Title, + UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; import { useState } from "react"; export default function RswtStat() { - const { code, rswtStat } = useWrStore((state) => state); + const { code, rswtStat, searchRswtStatList } = useWrStore((state) => state); const [pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); - const testData = [1,2,3] - testData.map((item) => { - console.log('test ',item); - }) - - return ( - <> + return ( <> <ContentsDiv> <div className="grid grid-cols-4 gap-4"> <div className="col-span-4"> @@ -48,7 +40,10 @@ export default function RswtStat() { <Button className="" size="sm" - onClick={() => {}} + onClick={() => { + console.log('searchYear', searchYear ); + searchRswtStatList(searchYear) + }} > 조회 </Button> @@ -89,4 +84,4 @@ export default function RswtStat() { </ContentsDiv> </> ); -} \ No newline at end of file +} diff --git a/apps/wr/app/store/stats/rswtStat/headList.tsx b/apps/wr/app/store/stats/rswtStat/headList.tsx index 2c8aebec9..2ed9f6bad 100644 --- a/apps/wr/app/store/stats/rswtStat/headList.tsx +++ b/apps/wr/app/store/stats/rswtStat/headList.tsx @@ -2,13 +2,13 @@ import type { TableUpperProps } from "../../common/type/header"; export const rswtStatHeadListExport :TableUpperProps[]=[ { - id: "시도", + id: "ctpvCd", title: "시도", row:0, rowSpan:2 }, { - id: "개소", + id: "ctpvCnt", title: "개소", row:0, rowSpan:2 @@ -20,17 +20,17 @@ export const rswtStatHeadListExport :TableUpperProps[]=[ colSpan:2 }, { - id: "건축연면적(m³)", + id: "archArea", title: "건축연면적(m³)", row:1, }, { - id: "처리용량", + id: "filtrTrtmfctCpct", title: "처리용량(m³)", row:1, }, { - id: "물사용량", + id: "wtrUsqty", title: "물사용량(m³/년)", row:0, rowSpan:2 @@ -42,13 +42,13 @@ export const rswtStatHeadListExport :TableUpperProps[]=[ rowSpan:2 }, { - id: "중수도이용량", + id: "rswtrUsqty", title: "중수도이용량(m³/년)", row:0, rowSpan:2 }, { - id: "대체수이용량", + id: "altUswtrUtztnQnt", title: "대체수이용량(m³/년)", row:0, rowSpan:2 @@ -61,37 +61,37 @@ export const rswtStatHeadListExport :TableUpperProps[]=[ colSpan:6 }, { - id: "조경용수", + id: "lndwtr", title: "조경용수", row:1, }, { - id: "청소화장실용수", + id: "cleanToilUswtr", title: "청소화장실용수", row:1, }, { - id: "농업용수", + id: "farmUswtr", title: "농업용수", row:1, }, { - id: "공업용수", + id: "indstUswtr", title: "공업용수", row:1, }, { - id: "친수용수", + id: "hydUswtr", title: "친수용수", row:1, }, { - id: "기타", + id: "ithlEtcUswtr", title: "기타", row:1, }, { - id: "연간운영비", + id: "anlOperCst", title: "연간운영비(백만원/년)", row:0, rowSpan:2 diff --git a/apps/wr/app/store/stats/rswtStat/index.tsx b/apps/wr/app/store/stats/rswtStat/index.tsx index 652917bc3..b4d58a448 100644 --- a/apps/wr/app/store/stats/rswtStat/index.tsx +++ b/apps/wr/app/store/stats/rswtStat/index.tsx @@ -1,13 +1,16 @@ +import { fetchType, getFetch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; import { rswtStatHeadListExport } from "./headList"; type rswtStatActions = { + searchRswtStatList: (year: string) => void; } export type rswtStatState = { rswtStat: { rswtStatHeadList:TableUpperProps[] + rswtStatList: never[]; // Replace with actual type when available } } @@ -23,6 +26,17 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = ( set: any ) => { return { - + searchRswtStatList: async (year: string) => { + const res = await getFetch(fetchType.WR,`/reuseChk/reuseWater/stat/${year}`) + console.log('res', res); + const rswtStatList: never[] = []; + set((state: rswtStatState) => ({ + rswtStat: { + ...state.rswtStat, + rswtStatList, + // rswtStatHeadList + } + })); + } } } \ No newline at end of file From 68a3d45f3bae3b169a79f56a4cf86855f3a4864b Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 19 Jun 2025 14:39:50 +0900 Subject: [PATCH 17/25] =?UTF-8?q?=EC=97=91=EC=85=80=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=20=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 104 ++++++++++++++++++--- apps/wr/app/store/stats/rainStat/excel.tsx | 17 +++- 2 files changed, 109 insertions(+), 12 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index ab855be1c..bb6184600 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useWrStore } from "@/app/store"; +import type { RainStatProps } from "@/app/store/stats/rainStat"; import { excelDownload, yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, @@ -17,7 +18,6 @@ export default function RainStat() { const { code } = useWrStore((state) => state) const { rainStat, searchRainStatList } = useWrStore((state) => state) const { rainDetailList } = rainStat; - const [ pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); @@ -27,13 +27,95 @@ export default function RainStat() { }, [code.cityCd, code.sggCd, searchRainStatList, searchYear]) const excelDownLoad=() =>{ - rainDetailList.forEach((item) => { - item.forEach((item2) => { - console.log(item2); - }) - }) + 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( - rainDetailList, + excelData, "빗물이용시설 통계", "sample_rainStats.xlsx", "A1:V3", @@ -62,10 +144,10 @@ export default function RainStat() { /> </div> <div className="flex flex-row space-x-2 items-center"> - <Button className="" size={"sm"} onClick={(e) => {}}> + <Button className="" size={"sm"} onClick={() => {}}> 조회 </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> + <Button className="" size={"sm"} onClick={() => {}}> 다운로드 </Button> <Button className="" size={"sm"} onClick={() => excelDownLoad()}> @@ -88,8 +170,8 @@ export default function RainStat() { pageSize={20} total={10000} headName={"건축물 목록"} - cellClick={(val, headId) => {}} - onPageChange={setPageNation} + cellClick={() => {}} + onPageChange={() => {}} ></UiTable> {/* </ScrollArea> */} </ListDiv> diff --git a/apps/wr/app/store/stats/rainStat/excel.tsx b/apps/wr/app/store/stats/rainStat/excel.tsx index d4bb0b07c..35a918d83 100644 --- a/apps/wr/app/store/stats/rainStat/excel.tsx +++ b/apps/wr/app/store/stats/rainStat/excel.tsx @@ -4,20 +4,35 @@ 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.instlCmptnDt) ?? "", + //설치비용 String(item.instlCst) ?? "", + //접수면종류 String(item.pntfColKnd) ?? "", + //여과등처리시설유무 String(item.filtrTrtmfctYn) ?? "", + //처리용량(저류조용량) String(item.dtfcltCpct) ?? "", + //연간사용량 String(item.wtrUsqty) ?? "", + //이용용도코드 String(item.utztnUsgCd) ?? "", + //연간운영비 String(item.anlOperCst) ?? "", ]); }); From 08d5ca48f33eb69eb390eeee908f45e420bf60f1 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 19 Jun 2025 15:30:54 +0900 Subject: [PATCH 18/25] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=A0=9C=EA=B1=B0,=20merge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 4 ++-- apps/wr/app/store/stats/rainStat/index.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index 20ecf3ae9..f9d2a1350 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -2,7 +2,7 @@ import { useWrStore } from "@/app/store"; import type { RainStatProps } from "@/app/store/stats/rainStat"; -import { tableData, yearOptions, excelDownload } from "@/components/lib/func/commom"; +import { excelDownload, tableData, yearOptions } from "@/components/lib/func/commom"; import { downloadExcel } from "@common/business_components"; import { @@ -14,7 +14,7 @@ import { } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; export default function RainStat() { const { code, rainStat, searchRainStatList } = useWrStore((state) => state); diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 68b1a051d..059de2b65 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -1,7 +1,7 @@ import { fetchType, getFetch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; -import { rainStatHeadListExport } from "./headList"; import { excelRainStat } from "./excel"; +import { rainStatHeadListExport } from "./headList"; export type RainStatProps = { ctpvCd: string //시도 From 84d39c4d447a88fce55bc65d1d8b48e199ab172d Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 19 Jun 2025 15:37:50 +0900 Subject: [PATCH 19/25] =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84=ED=86=B5?= =?UTF-8?q?=EA=B3=84=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rswtStat/page.tsx | 110 +++++++++------- apps/wr/app/store/stats/rswtStat/headList.tsx | 6 +- apps/wr/app/store/stats/rswtStat/index.tsx | 119 ++++++++++++++++-- 3 files changed, 180 insertions(+), 55 deletions(-) diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index de96b29ea..74a8a3c82 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useWrStore } from "@/app/store"; -import { yearOptions } from "@/components/lib/func/commom"; +import type { ExcelType, RswtStatProps } from "@/app/store/stats/rswtStat"; +import { tableData, yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, SearchDiv, @@ -10,58 +11,81 @@ import { } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; -import { useState } from "react"; +import { useEffect, useState } from "react"; export default function RswtStat() { const { code, rswtStat, searchRswtStatList } = useWrStore((state) => state); + const { rswtStatList, excelList } = rswtStat; + const [rswtTable, setRswtTable] = useState<RswtStatProps[]>(); const [pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); + const [excelData, setExceData] = useState<ExcelType[]>(); - return ( <> - <ContentsDiv> - <div className="grid grid-cols-4 gap-4"> - <div className="col-span-4"> + useEffect(() => { + const transData = Array.isArray(rswtStatList) ? rswtStatList : [rswtStatList]; + const data = tableData(transData, { code }); + const tbData = Array.isArray(data) + ? data.map((item: RswtStatProps) => { + return { + ...item, + ctpvCd: item.cityText + }; + }) + : []; + setRswtTable(tbData); + }, [rswtStatList]) + + useEffect(() => { + const transExcel = Array.isArray(excelList) ? excelList : [excelList]; + const exData = tableData(transExcel, { code }); + const tbData = Array.isArray(excelData) + }, [excelList]) + + return (<> + <ContentsDiv> + <div className="grid grid-cols-4 gap-4"> + <div className="col-span-4"> <Title title="재이용 통계" /> <SearchDiv> <div className="grid grid-cols-12 gap-5 m-4"> <div className="col-span-2"> <SelectBox - className="w-full h-full text-2xl" - label="통계년도" - selectClass="" - selectArray={yearOptions} - value={searchYear} - onSelectValue={(val: string | number) => setSearchYear(String(val))} - /> - </div> - <div className="flex flex-row space-x-2 items-center"> - <Button - className="" - size="sm" - onClick={() => { - console.log('searchYear', searchYear ); - searchRswtStatList(searchYear) - }} - > - 조회 - </Button> - <Button - className="" - size="sm" - onClick={() => {}} - > - 다운로드 - </Button> - <Button - className="" - size="sm" - onClick={() => {}} - > - 전체통계다운로드 - </Button> - </div> + className="w-full h-full text-2xl" + label="통계년도" + selectClass="" + selectArray={yearOptions} + value={searchYear} + onSelectValue={(val: string | number) => setSearchYear(String(val))} + /> + </div> + <div className="flex flex-row space-x-2 items-center"> + <Button + className="" + size="sm" + onClick={() => { + console.log("searchYear", searchYear) + searchRswtStatList(searchYear) + }} + > + 조회 + </Button> + <Button + className="" + size="sm" + onClick={() => { }} + > + 다운로드 + </Button> + <Button + className="" + size="sm" + onClick={() => { }} + > + 전체통계다운로드 + </Button> + </div> </div> </SearchDiv> </div> @@ -70,18 +94,18 @@ export default function RswtStat() { <div className="col-span-6 h-full min-h-0"> <ListDiv className="min-h-0"> <UiTable - tableData={[]} + tableData={rswtTable || []} headlist={rswtStat.rswtStatHeadList} pageSize={20} total={10000} headName="건축물 목록" - cellClick={() => {}} + cellClick={() => { }} onPageChange={setPageNation} /> </ListDiv> </div> </div> </ContentsDiv> - </> + </> ); } diff --git a/apps/wr/app/store/stats/rswtStat/headList.tsx b/apps/wr/app/store/stats/rswtStat/headList.tsx index 2ed9f6bad..877089092 100644 --- a/apps/wr/app/store/stats/rswtStat/headList.tsx +++ b/apps/wr/app/store/stats/rswtStat/headList.tsx @@ -14,7 +14,7 @@ export const rswtStatHeadListExport :TableUpperProps[]=[ rowSpan:2 }, { - id: "시설현황", + id: "a", title: "시설현황", row:0, colSpan:2 @@ -36,7 +36,7 @@ export const rswtStatHeadListExport :TableUpperProps[]=[ rowSpan:2 }, { - id: "청소화장실용수", + id: "rswtAltSum", title: "중수도+대체수이용량(m³/년)", row:0, rowSpan:2 @@ -55,7 +55,7 @@ export const rswtStatHeadListExport :TableUpperProps[]=[ }, { - id: "용도", + id: "b", title: "용도", row:0, colSpan:6 diff --git a/apps/wr/app/store/stats/rswtStat/index.tsx b/apps/wr/app/store/stats/rswtStat/index.tsx index b4d58a448..f1b09354e 100644 --- a/apps/wr/app/store/stats/rswtStat/index.tsx +++ b/apps/wr/app/store/stats/rswtStat/index.tsx @@ -2,15 +2,47 @@ import { fetchType, getFetch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; import { rswtStatHeadListExport } from "./headList"; +export type RswtStatProps = { + ctpvCd: string //시도 + ctpvCnt: string //개소 + archArea: number //건축연면적 + filtrTrtmfctCpct: number //처리용량 + wtrUsqty: number //물사용량 + rswtAltSum: number //중수도+대체수이용량 + rswtrUsqty: number //중수도이용량 + altUswtrUtztnQnt: number //대체수이용량 + lndwtr: number //조경용수 + cleanToilUswtr: number //청소화장실용수 + resn: number //세척살수용수 + farmUswtr: number //농업용수 + indstUswtr: number //공업용수 + hydUswtr: number //친수용수 + ithlEtcUswtr: number //기타 + anlOperCst: number //연간운영비 + guideStats: GuideStatProps[] +} + +export type GuideStatProps = { + utztnUsgCd: string + ruseFcltUtztnQnt: number +} + type rswtStatActions = { searchRswtStatList: (year: string) => void; } +export type ExcelType = { + [key: string]: string | number | undefined; +}; + +const excelDownList: ExcelType[] = []; + export type rswtStatState = { rswtStat: { - rswtStatHeadList:TableUpperProps[] - rswtStatList: never[]; // Replace with actual type when available + rswtStatHeadList: TableUpperProps[] + rswtStatList: RswtStatProps[]; + excelList: ExcelType[] } } @@ -18,7 +50,9 @@ export type rswtStatType = rswtStatState & rswtStatActions; export const rswtStatExport: rswtStatState = { rswtStat: { - rswtStatHeadList:rswtStatHeadListExport + rswtStatHeadList: rswtStatHeadListExport, + rswtStatList: [], + excelList: [] } } @@ -26,15 +60,82 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = ( set: any ) => { return { - searchRswtStatList: async (year: string) => { - const res = await getFetch(fetchType.WR,`/reuseChk/reuseWater/stat/${year}`) - console.log('res', res); - const rswtStatList: never[] = []; + searchRswtStatList: async (year: string) => { + const res = await getFetch(fetchType.WR, `/reuseChk/reuseWater/stat/${year}`) + + const rswtStatList: RswtStatProps[] = []; + + let cityArr: any[] = []; + res.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 + } 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 + + cityArr.push(obj) + } + + if (item.guideStats && item.guideStats.length > 0) { + item.guideStats.forEach((guide: GuideStatProps) => { + rswtStatHeadListExport.forEach((headItem: TableUpperProps) => { + + if (headItem.title == guide.utztnUsgCd) { + if (!obj[headItem.id] || typeof obj[headItem.id] !== "number") obj[headItem.id] = 0; + if (typeof obj[headItem.id] === "number") { + + obj[headItem.id] += guide.ruseFcltUtztnQnt; + } + } + }); + }) + } + }); + + cityArr.forEach(item => { + excelDownList.push({ + ctpvCd: item.ctpvCd, + ctpvCnt: item.ctpvCnt, + archArea: item.archArea, + filtrTrtmfctCpct: item.filtrTrtmfctCpct, + wtrUsqty: item.wtrUsqty, + rswtAltSum: item.rswtAltSum, + rswtrUsqty: item.rswtrUsqty, + altUswtrUtztnQnt: item.altUswtrUtztnQnt, + lndwtr: item.lndwtr, + cleanToilUswtr: item.cleanToilUswtr, + farmUswtr: item.farmUswtr, + indstUswtr: item.indstUswtr, + hydUswtr: item.hydUswtr, + ithlEtcUswtr: item.ithlEtcUswtr, + anlOperCst: item.anlOperCst, + }) + }) + set((state: rswtStatState) => ({ rswtStat: { ...state.rswtStat, - rswtStatList, - // rswtStatHeadList + rswtStatList: cityArr, + excelList: excelDownList } })); } From 7f966c9d874be8231805f713e78f664583f3b155 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 19 Jun 2025 16:34:36 +0900 Subject: [PATCH 20/25] =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84=ED=86=B5?= =?UTF-8?q?=EA=B3=84=20=EC=A1=B0=ED=9A=8C,=20=EC=97=91=EC=85=80=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rswtStat/page.tsx | 43 +++++++++++++++++++--- apps/wr/app/store/stats/rswtStat/index.tsx | 2 - 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index 74a8a3c82..37e48a308 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -1,9 +1,10 @@ "use client"; import { useWrStore } from "@/app/store"; -import type { ExcelType, RswtStatProps } from "@/app/store/stats/rswtStat"; +import type { RswtStatProps } from "@/app/store/stats/rswtStat"; import { tableData, yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, + downloadExcel, SearchDiv, SelectBox, Title, @@ -21,7 +22,20 @@ export default function RswtStat() { const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); - const [excelData, setExceData] = useState<ExcelType[]>(); + const [excelData, setExceData] = useState<any[]>(); + + useEffect(() => { + searchRswtStatList(searchYear) + }, [searchRswtStatList, searchYear]) + + const excelClick = () => { + downloadExcel({ + data: (excelData as unknown as JSON[]) ?? [], + fileName: "중수도재이용통계", + sheetNameArray: ["Sheet1"], + headerRange: "A1:O1" + }) + } useEffect(() => { const transData = Array.isArray(rswtStatList) ? rswtStatList : [rswtStatList]; @@ -40,7 +54,27 @@ export default function RswtStat() { useEffect(() => { const transExcel = Array.isArray(excelList) ? excelList : [excelList]; const exData = tableData(transExcel, { code }); - const tbData = Array.isArray(excelData) + const tbData = Array.isArray(exData) ? + exData.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); }, [excelList]) return (<> @@ -65,7 +99,6 @@ export default function RswtStat() { className="" size="sm" onClick={() => { - console.log("searchYear", searchYear) searchRswtStatList(searchYear) }} > @@ -74,7 +107,7 @@ export default function RswtStat() { <Button className="" size="sm" - onClick={() => { }} + onClick={() => excelClick()} > 다운로드 </Button> diff --git a/apps/wr/app/store/stats/rswtStat/index.tsx b/apps/wr/app/store/stats/rswtStat/index.tsx index f1b09354e..b270d31aa 100644 --- a/apps/wr/app/store/stats/rswtStat/index.tsx +++ b/apps/wr/app/store/stats/rswtStat/index.tsx @@ -62,8 +62,6 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = ( return { searchRswtStatList: async (year: string) => { const res = await getFetch(fetchType.WR, `/reuseChk/reuseWater/stat/${year}`) - - const rswtStatList: RswtStatProps[] = []; let cityArr: any[] = []; res.forEach((item: RswtStatProps) => { From f5fb50a488a7c997b938043c583516372c95b3d5 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 19 Jun 2025 17:08:07 +0900 Subject: [PATCH 21/25] =?UTF-8?q?=EB=B9=97=EB=AC=BC=ED=86=B5=EA=B3=84/?= =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84=20=ED=86=B5=EA=B3=84=20-=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=95=20=EC=A0=9C=EA=B1=B0,=20=EC=85=80?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=A0=9C=EA=B1=B0,=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 25 +++++++++++++------------ apps/wr/app/stats/rswtStat/page.tsx | 23 +++++++++++++---------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index b2f2006bf..49ef16e1a 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -6,6 +6,7 @@ import { tableData, yearOptions } from "@/components/lib/func/commom"; import { downloadExcel } from "@common/business_components"; import { ContentsDiv, + ScrollArea, SearchDiv, SelectBox, Title, @@ -118,18 +119,18 @@ export default function RainStat() { </div> <div className="grid grid-cols-6 gap-4"> <div className="col-span-6 h-full min-h-0"> - <ListDiv className="min-h-0"> - {/* <ScrollArea className="h-[60vh]"> */} - <UiTable - tableData={bdstTable || []} - headlist={rainStat.rainStatHeadList} - pageSize={20} - total={10000} - headName={""} - cellClick={(val, headId) => { }} - onPageChange={setPageNation} - ></UiTable> - {/* </ScrollArea> */} + <ListDiv className=""> + <ScrollArea className="h-[67vh]"> + <UiTable + tableData={bdstTable || []} + headlist={rainStat.rainStatHeadList} + pageSize={10} + total={0} + headName={""} + cellClick={undefined} + onPageChange={setPageNation} + ></UiTable> + </ScrollArea> </ListDiv> </div> </div> diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index 37e48a308..6b7a99fbd 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -5,6 +5,7 @@ import { tableData, yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, downloadExcel, + ScrollArea, SearchDiv, SelectBox, Title, @@ -125,16 +126,18 @@ export default function RswtStat() { </div> <div className="grid grid-cols-6 gap-4"> <div className="col-span-6 h-full min-h-0"> - <ListDiv className="min-h-0"> - <UiTable - tableData={rswtTable || []} - headlist={rswtStat.rswtStatHeadList} - pageSize={20} - total={10000} - headName="건축물 목록" - cellClick={() => { }} - onPageChange={setPageNation} - /> + <ListDiv className=""> + <ScrollArea className="h-[67vh]"> + <UiTable + tableData={rswtTable || []} + headlist={rswtStat.rswtStatHeadList} + pageSize={10} + total={0} + headName="" + cellClick={undefined} + onPageChange={() => { }} + /> + </ScrollArea> </ListDiv> </div> </div> From 1b81ca10b92d2e4b6dc63ac2184f83ac10bd9927 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 19 Jun 2025 19:03:12 +0900 Subject: [PATCH 22/25] =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84=EC=8B=9C?= =?UTF-8?q?=EC=84=A4=ED=86=B5=EA=B3=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 4 +- apps/wr/app/stats/rswtStat/page.tsx | 109 ++++++++++++++++++++- apps/wr/app/store/stats/rainStat/index.tsx | 2 +- apps/wr/app/store/stats/rswtStat/excel.tsx | 46 +++++++++ apps/wr/app/store/stats/rswtStat/index.tsx | 37 +++++-- apps/wr/public/sample_rswtStats.xlsx | Bin 0 -> 10897 bytes 6 files changed, 186 insertions(+), 12 deletions(-) create mode 100644 apps/wr/app/store/stats/rswtStat/excel.tsx create mode 100644 apps/wr/public/sample_rswtStats.xlsx diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index f9d2a1350..26faf2616 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -31,7 +31,7 @@ export default function RainStat() { searchRainStatList(searchYear); }, [code.cityCd, code.sggCd, searchRainStatList, searchYear]) - const excelDownLoad=() =>{ + const excelDetailDownLoad=() =>{ const sidoList = new Set(); const sidoDataMap = new Map(); // 시도별 데이터를 저장할 Map @@ -203,7 +203,7 @@ export default function RainStat() { <Button className="" size={"sm"} onClick={() => excelClick()}> 다운로드 </Button> - <Button className="" size={"sm"} onClick={() => excelDownLoad()}> + <Button className="" size={"sm"} onClick={() => excelDetailDownLoad()}> 전체통계다운로드 </Button> </div> diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index 74a8a3c82..cd5fa667c 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useWrStore } from "@/app/store"; import type { ExcelType, RswtStatProps } from "@/app/store/stats/rswtStat"; -import { tableData, yearOptions } from "@/components/lib/func/commom"; +import { excelDownload, tableData, yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, SearchDiv, @@ -15,7 +15,7 @@ import { useEffect, useState } from "react"; export default function RswtStat() { const { code, rswtStat, searchRswtStatList } = useWrStore((state) => state); - const { rswtStatList, excelList } = rswtStat; + const { rswtStatList, excelList, rswtDetailList } = rswtStat; const [rswtTable, setRswtTable] = useState<RswtStatProps[]>(); const [pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( @@ -43,6 +43,109 @@ export default function RswtStat() { const tbData = Array.isArray(excelData) }, [excelList]) + const excelDetailDownLoad=() =>{ + const sidoList = new Set(); + const sidoDataMap = new Map(); // 시도별 데이터를 저장할 Map + + console.log("rswtDetailList : ", rswtDetailList); + rswtDetailList.forEach((item: RswtStatProps[]) => { + 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 RswtStatProps; + } + if (item.length > 1) { + item[1] = sigunText as unknown as RswtStatProps; + } + if (item.length > 2) { + item[2] = sidoText+' '+sigunText as unknown as RswtStatProps; + } + + // 시도별 데이터 수집 + 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); + } + }); + // 시도별 합계 계산 + rswtDetailList.forEach((item: RswtStatProps[]) => { + 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 = rswtDetailList.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 = rswtDetailList.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==9){ + const value = Number(item[9]) || 0; + sidoData[i] = (Number(sidoData[i]) + value) as string | number; + } else if(i==10){ + const value = Number(item[10]) || 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==13){ + const value = Number(item[13]) || 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 if(i==16){ + const value = Number(item[16]) || 0; + sidoData[i] = (Number(sidoData[i]) + value) as string | number; + } else { + sidoData[i] = ''; + } + } + } + }); + // Map을 배열로 변환 + const sidoSummaryList = Array.from(sidoDataMap.values()); + console.log("sidoSummaryList : ", sidoSummaryList) + // sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성 + const excelData = [...sidoSummaryList, ...rswtDetailList]; + + excelDownload( + excelData, + "중수도시설 통계", + "sample_rswtStats.xlsx", + "A1:V3", + 4 + ); + } + return (<> <ContentsDiv> <div className="grid grid-cols-4 gap-4"> @@ -81,7 +184,7 @@ export default function RswtStat() { <Button className="" size="sm" - onClick={() => { }} + onClick={() => { excelDetailDownLoad() }} > 전체통계다운로드 </Button> diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 059de2b65..d6e48a53e 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -139,7 +139,7 @@ export const rainStatActionsExport = ( }) }) - //상세세 + //상세 const rainDetailList : RainStatProps[] = []; res.forEach((item:RainStatProps) => { const utztnUsgArray = new Array<string>(); diff --git a/apps/wr/app/store/stats/rswtStat/excel.tsx b/apps/wr/app/store/stats/rswtStat/excel.tsx new file mode 100644 index 000000000..d47e0e3fe --- /dev/null +++ b/apps/wr/app/store/stats/rswtStat/excel.tsx @@ -0,0 +1,46 @@ +import type { RswtStatProps } from "."; + +export const excelRswtStat = (excelList:RswtStatProps[]) : 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.archArea) ?? "", + //처리용량 + String(item.filtrTrtmfctCpct) ?? "", + //물사용량 + String(item.wtrUsqty) ?? "", + //중수도+대체수이용량 + String(item.rswtAltSum) ?? "", + //중수도이용량 + String(item.rswtrUsqty) ?? "", + //대체수이용량 + String(item.altUswtrUtztnQnt) ?? "", + //중수도용도 + String(item.utztnUsgCd) ?? "", + //연간운영비 + String(item.anlOperCst) ?? "", + ]); + }); + return excelData; +} \ No newline at end of file diff --git a/apps/wr/app/store/stats/rswtStat/index.tsx b/apps/wr/app/store/stats/rswtStat/index.tsx index f1b09354e..4e2a7ecc8 100644 --- a/apps/wr/app/store/stats/rswtStat/index.tsx +++ b/apps/wr/app/store/stats/rswtStat/index.tsx @@ -1,9 +1,14 @@ import { fetchType, getFetch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; import { rswtStatHeadListExport } from "./headList"; +import { excelRswtStat } from "./excel"; export type RswtStatProps = { ctpvCd: string //시도 + sggCd : string //시군구 + areaNm: string //행정구역명 + bdstNm: string //시설명 + daddr: string //주소 ctpvCnt: string //개소 archArea: number //건축연면적 filtrTrtmfctCpct: number //처리용량 @@ -20,6 +25,9 @@ export type RswtStatProps = { ithlEtcUswtr: number //기타 anlOperCst: number //연간운영비 guideStats: GuideStatProps[] + utztnUsgCd : string //이용코드 + lawTrgtYn : string //법적의무대상여부 + instlCmptnDt : string //설치완료일자 } export type GuideStatProps = { @@ -40,9 +48,10 @@ const excelDownList: ExcelType[] = []; export type rswtStatState = { rswtStat: { - rswtStatHeadList: TableUpperProps[] + rswtStatHeadList: TableUpperProps[]; rswtStatList: RswtStatProps[]; - excelList: ExcelType[] + excelList: ExcelType[]; + rswtDetailList: RswtStatProps[][]; } } @@ -52,7 +61,8 @@ export const rswtStatExport: rswtStatState = { rswtStat: { rswtStatHeadList: rswtStatHeadListExport, rswtStatList: [], - excelList: [] + excelList: [], + rswtDetailList: [] } } @@ -62,10 +72,9 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = ( return { searchRswtStatList: async (year: string) => { const res = await getFetch(fetchType.WR, `/reuseChk/reuseWater/stat/${year}`) - const rswtStatList: RswtStatProps[] = []; - let cityArr: any[] = []; + const cityArr: any[] = []; res.forEach((item: RswtStatProps) => { let obj = cityArr.find((e) => { return e.ctpvCd == item.ctpvCd @@ -131,11 +140,27 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = ( }) }) + //상세 + 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(', '), + }) + }); + + const excelDetailData = excelRswtStat(rswtDetailList); set((state: rswtStatState) => ({ rswtStat: { ...state.rswtStat, rswtStatList: cityArr, - excelList: excelDownList + excelList: excelDownList, + rswtDetailList: excelDetailData } })); } diff --git a/apps/wr/public/sample_rswtStats.xlsx b/apps/wr/public/sample_rswtStats.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..702c4cec0da4eefb5c10e37547be86a7579c4cc9 GIT binary patch literal 10897 zcmeHtg<D+7^7h~^gFC@pgS!j_cL?qf+%@>%?hxF91(yU5u7g8@y9I&<C&<U{@9y2* z?EU_Nd(S-6{mh)M>gV)%tE#KtQjv#&#R0$r5CH%H1;F$;$I1{207!rZ0I&gw(0Y=N z4sI3>Zblm3P8O~PtX}qZFA8Cy>GJ{5&*T4h{THu5WeP;8mmO2;TIODIn?-K9UJQ}@ z2t0_zs4CLcmpt&nOfT2k`YAW^C#FOJt_^P;*2J<8=h>K5y@UNHaKu2H8ftXVP?x45 zF)v&H;2}*XK4FrJuFgq54zU;qp^;InWftI_b5pMx7idFVu9C<K7f&Q`D`#;~3%EAW zg8D(XjDKjUdtFIu705SIK7+Y6g*|Iy&ER8rzQrO78%^o6jOSrktU{r!&S0w6;&PWR z|Jjwk`Q;a5Gw4<Ju!IiumGL$Bw$Hp|id;nX<xv+ObO#b_nL2&-ecyJ{$3<VL+_m!H zS{bqE<%$JSfT!mHDz?#$cvYMZ6MlW7xJ3$()1DVAKWR3wN&41^&0BNh6U>zeDD9co ziwAQ-%KW^HVE@vg;by)r<s&l^Ux$(@gl$-<n<tzr;C}0Qmjvc;7X`In_|f{%zM#+H z<c?nO@mbn_0Oun-0Pyq#15o*!S$@=Hr@DB?n!>Zyp*)+Vk&A_$D;w)??f=a2zt{%< z^5~UGipst0s9`5E_u)g=Use(@CFDKDW!fk-`~zi|F+Ro?Q4_Cp(ve_l5Cy}$3h3~^ zA6Z%viai*jxZ32ZjK;zdr26Dp6_$SI?2f=l>yjqzT)EK)^!Rf5<tpQqoHxBkM?7Oi zb6J7>@EVo$%o(T-bAt6X5fXMWNf@4RMv(4+qRy)6O*PaP3H76@u-Ycx{Db6)tbn<+ zl6^GM2!4gb=?vT<SJO8O)xJY^6qmO|n(9{k*0rX&E&`O^M&@>1=b)@k><3>KrR*U! zN-nG$&WTrpH2IeSx{X|CkR0zmUZmcNq0?b-G<n(TbA<Y*kpzjPq@O>pNb9qa5CIUO zyzJQi&rUoYU2IJq9c_P$UVqpO)N=@X*7DzdRjMh<_pxJkpge}NduDmy0vFuaC=WHi zV;~MUGAz+jy!5|VBW7$h(EcjV2ICm!eKI!aam|gs34?vv%~TeJ1^X7;?nDsIaqN5y z2GR7WiVXY;4jb$6;Csap3VNn1c8f^T5OXdL-|h`P4Pkgu2_@*FWjc(@W}Mxf)5dj@ zbmSQ`kjCx6yAbumDsW>{(~C?7%blkd$)zj!Jg_(U)HxxNtPq+vVCvf}1=CHp)D_~7 z_Ipc3?{VAiqC3<bk_vgU58T4OVQw$NhhC8fFeJI|6lSz(o@}^D{2XEET>8Nbxj3=h z9v=L%_WY**37JsbIEIa97)-zb02t3Bo+0yBu)I%JjGtl0{LQ8iAlLSp^(>g&I^C=h zhARDo$23?j*|KH_Yy;@lPr}I|^=%jR5%QJ;N@VeCybYfP2*&)O;dkuDXBM(w)=qyJ zId*xxg#3(togGSV$I{r4a83p5uPGGp>6rAGY40iqz_Z;RJM~5u%N#{IB;(xJy42YU z^d8Go_7t%YokfgGKxcHXq7TvH7BqCqfI7z|*AttZ14T@S2*yiX#HjkQ0ebm^fse{* z?G|M}h7MHR7&QnS$w*wVd_x)~H}er={|Bh#0@XeRgs+eNCPc1;cH%f|Jeez}TECLG zc*7$p2kAr<`DJz?{|sfH=f^0OJzuHf?;BIl9*_2=Tt_A8>CybkQKDLQiO2^(W8(s~ zK+PUJNeZ2Ck4Cc6SMJ}309Q!<ZpcBt<S7haFK{@qHRq$|>(SlE9qT!ByxrEs2h<ph zLLJf6B;$WL!`T@m!519XT^JOnGLuKJjOW}Vw1kr2$jPLZpEEq^6_^U&k2E3QIkD}j z)c5ApfBf$HXew3Y++M@?eK1E*bC72*dIz$z*?0vtTOGTt((2nmFcA<)ju03}NYzku zmKR=-FHYQJS)2B96o;m{d<N)rCx^_^G!(|(&UcrWZCQ5%_n*+v^oG-w^x1hBA^-q5 z|Az)wD-#zBb9FZtYlk<kzxj{K)Cq?fG0cIJ#2@HibE8!1Dei$1pM1(f`eI>(0&&}7 zi@iwe^*|0td=VdjEa8}R)P;pC^h1ce&6<=u_RSV_Ctb~~ns9@$%49wdS&o*SX9rm| z?U`58)=qP8;9Jz0fnz4PYaR=6;<=(e`d%_ztjv~r+<E-))&kjfnYY>FEt98u188cv zg^v+xhUEge{n7p_CO4K#j$Ub9wRMu-9UIy_H3D&`HjVm>!uh#7oQ0bA2DGRyPh?Xb z89z<u7DmWYAbqnfwg)}!dLd`1;C>s?w1#T<SHibUQ|0XLnXJwFAV+xG!}x7+r<V7I zQeS$igzT-BM6i|Zf{jB9bq3Ymb?!7&Ob-Wy?0B~e#cRB%i1(q#qnLc6==A&=s`kMa zr%Pybk7wNr%CW6UL)&FBxQHi4l8`3z@YA{?@m*rO6@>^&`8_}6I0Z}G30!D`Ikd$Z zgMX`!T?5|3wbPS*YG*5gi@_#Pn&fzAfeT;J4GL`$l3y<j*IqvHjbq(PjCplRL^`SJ zCRW0ZE0mqz@)XpY9w&sBnli}Z%`Vn$U3kgu{Scc&{Y{{8{^YvUraCk1hi!_-`MF_O zk#^G}2!z72a+syCfHZ5K>l^4vaeQ;+mQ;cSf2(h)i<9dSRLv6VG1g%d!Fa3tV{!Pj ziDiM0{sH^v87I2&JF)pR*X&9(!n|QegB!Q9N!_TuqT6S{{L{JYm(Vm@K5ysLiGRzb zes?ZzRu=XaY`?c0zoF?+XUu_^7xOdzH$hAvW#)w>Q^G_T`Ls<QXVZDPD3Wpmn{=RO z%L@j<R@~t_v7kchDfyt)xAcqfGJ%HErOsJ}ib3rX;oEY$x*B$L@OSv6b}ZLh_Y+QG zt#6OSM<ywNNk1xaHP~K5gX$AraYgHO=lGvYzYTofqZ2|nA;a_zlTd%j_o<`8OOl3~ z2Jz~R3rrIjRPJkLAr)2|vtyB)jJk@}B2x!`1*`!<lS8efR8?v*#-`%TFpCi?1sxu3 zB!t0Uat|B3%C$q*In>qILKH}>ru!C5YNyIR09_~r74juVb)ilpZ&dSyRG>_?8NH^E z8F#TO?F<dNiTi0w(hgaUzGo=c)y!kYYN06uF)S4-I&{xRu3|nzv44#C?$MUx;4VD@ za3TPgXr*zE={j~S=1wyQ9nMKD=E!xZxt`J7*`jdrE**Jv=nR=g5+yw7>UGt;Ci+;V ziQp)PXJphhx2Tt+)Z0y*(9er^+QBp?J=RaG(qqM=D`p#h^%m}u(0phi4*xUy>7^W0 zUeOC8%c)`=RPU0se%+`O*D07lc+N_zuvuz4NfHShPbUFP99wv=;Pq+ZHk^@AnlY4N zl}Y`NU<_AOLXOhwgWKzxTv4g#FTelI;mwBfU_2SA=>62R3(xU7GpnQT?a`Y6{|An{ zt$kiL@_>y&2<PJ*xybF#-o%60P<{)D?X&NXr3N~-&vzHsCuBbBde9gnry`1xpr#?< z;vT~{OVlknCHPHW!8@dqarA6}J;r{u9LahWlBI}#R`Wm`Q@+<t;N0LfsSXAfht_QG zt#pz=m%+GB7D^42gOwo-%Jrbm;TzTgi)E34aFJEgZ2sz_IM=ewnS3|9HQ5NNU9#Sc z9**G%i91qq;O5jZS#g|!r!{@^wq)qB>g>R*ZITEnUl7+?qon#Nq_6a4^J3lDvBB)_ zXz3*nzguDg<~#3@6YSl0X98qQ*>^Hm&Lbo6ospWG*guRZdpN6^aJ>X*V~QL=?=Oy8 zSj5(nW*m*nUK=)@)XN@Fh89whk7d0(=XA-67eG>Str_K#ADPG4MwGxQ60Y_=H8{46 z@P`*&w<~WuQQK_(c_HBxJ`g8!4w!NrC@fo4dQh~!YBe3D*Vyvx_j)T}-#xW0ADM$q z<3)IEr0vyo#<xU;`8^t8qOJ93^)dX@ZEG8I`h>3i9voigwzrX8>$aP9ve5e&(lR6} z-s1ga8WKEJ3_L{`$CBoS$rQTNkMzgrta$T>;^2z-GC6dtY{_^7ZYm>Yl<7JUe>(e8 zhQ&+YB<#j9KG}jXo@5h)3Di$yGL;_Q=IL`I4I42r88~Jy1C$7>tfAjneDc^idZ$^X zAwRbJL5sUELv62&N1f2Oxr~T;yb{R(5xfdlxf}>IfS@-ZSyE4XG`XJ7vSeO{w#v}* zQHI7hu11S|Afi(=vmlZtBj4vg!68p==H^~#TKB-COI`SqR-5(q#J-)2)M3wX+S`Yc zR7XomDXpMLYqGNDD-6zNJ1(k8WoV5xx?y_jSub-~TY(A^@l`2p1JYazZ`NaNWshR$ z$DiOHCDNf#jU{bb9<I>}N?2{nFej=f8`9CYs>t&)0Wb_-zfur9@-TG8Rof0b$w+8= zcv$x@s}hK*%H3)MofAN>thxqF$%B8omw`oqsZN3>&pB~m1(&`3`3TFn)O0FaE$Vo+ zSsGn4eUpGxX@=bfZTuU~cXUiuKn%C@5r-7PPDa`tHknixf~N_MsXZip{7R`s7>ea> z<QTWlpP*SadJ2$tkkEXfSz8p20<D6+YkQ%I!(9*WcD@L|>m1{k?|sj$;AfLJAfv(; zuR)2p5L|Cwc!Fd4W%IC}T1R{cq#>)Hp;w2nolyI^Itb1069RpZ3h$Tq^f2(AoR7<U zl)><I4la-7Iq{0S=bsQ-1#4N-RsseL-)k}66&L023;$G5=4L{u;h&%Io?VRkn15#T zF#5_KJzYfRDd;>tDq(?~?jmS$@283$@cygu5)-Vd-!KoE48DvW8Nwvrf)uerW{SOb z)bUl%5`A+btH27O(a<#SzT1TLp^ocry{pUF<;vb|jDhxioqNm7<vXIJEAyy>D=UE^ zg28u2A4f!m&bs}aE_n3M;xm%2Y@VR>&$?4g0;mJGo5s2Ic%Pp4GXD%qD&7H~agYE2 zusi^O_OD%zo41|C@7tSgeZBal0bGBK$tN+)Z$+bR)U4ESX&y+hGSL8!pwBKea*%iU zLGMZI!O+%3_*RS1XvRhO^PzgpGN#)mz$S6SAK}c$0Ye!Z7M6|EHkCV3T*%#q&VBs% zyS{roFR6V_SpAf}zJcn9;r&!wsG`BxF};z*qj#G%$9h%O^nH<}3U+L$*`K|R`!?Hx z^EzgtlU*lTJa_pb0hHiowp^Owdzqxovy82!vmB>m*i#5sjIUr&uN7_o`A{7l$HBHw z5+lTZxM@Xfl$zw$jEv$lsj&8_-qvK^Ql!tpTL+goi%77j$XiFekVL-&sM+GeB{P%q zMyij^&<?FGz%|lWCL~J9f-f|XOVvFO_4{q)O3dRUsWIE~sQVMlxruM`dC`KY@dh?1 zWyBux?NHCYiDUZXXn*6i!flv=@3=ABC^!<2rj!d_<-6#Skr7*B*Ive&|D2ptcXt4} zSSaoJ{(9ndd|rNX>8F#odkgW5$9|TtI1<v4G!$pU${{p2tn^sia)_odK)0H2Vv;PW z2VIX&!RShfCCIcfF!}RCu))yr*>&Lu?sdfdniWErQHuV+F{Ph{7UD6g<}EJ0>mG3= zVf;x@vM|PtvG7)s4O|tjFYMX<C3LKmP{D;d;S`n#INu%inxVEyum*Tyw`HsRJEfqu zRkEAi3|nl<Nm2X`KF$u{5H~pxHXlS596AfvR8DZArJ7E1eiJ{+;8Qj34oV2<3=j#I zU=HNuXUaPD797u&x@sxhq?8y@TA89i7xo0Jj7m4(Lwe`S{7hq&PTd*I%e=P4>!ivo zVg;IBT$o$MeRw6n>5Rmr$>;k8tlTeiLiA1j_B80jh+C#$iy`iiT5dwKRT|aW{=1R| z&BYamxmj+hxw<4}*JzL6$OboBzdD1A%xX$@Kv22+*e7H$^NwgXcNJJ7z&8TvITZ!X z@BqH`H4*R!cbf?J204ndNKIsM#mY_H)~LyJAGtOUEe2Tby5Ii)qSOy;Ru`<m0cUC# zW6t(58a92Hd~GsTyW9S6F)c0MUEq9W&hI+Z5FJJta}m3JkGW!KYnN23n<4D!Ba86D z6B)GZ2=U7cgm+mXt~XCy3Rv^F1Q)c`!YD9HlJc8U7;(9^KG4K8ejNO+gBa_kqm1@i zW^dA)tC&)z#9wJPtxoO4Ig}mQnW|3}`@Pv@y{{-@s_94+RiT<bIu247KplzRerZ(C zOiA(Ra>wUm{DEU8o3x7-IeGn1wVz;^lIDb<oXpqky?|3(;(=-+u3`_I-EtMSosNOd zKtmDlr}Q!Cnz`L^k=K_k4G{R)<3sh(6;#cOZcXY^M-}0l!?1%cYhI1`heOMvEskis zw#%_>f6^GCS;<`j!CX&_{vSrlkP9d#{NPm=Mp%@!AIaCoQ_xovQ~uUxxLRvJYIHsf zp~DL=xxNWHfvtTy07VK)x3!w_xz)4G?YOmR&yPw+za{QNzVbcJd2-pv6G#kgTHzpD zj>2Ocp2B=1?&8}ND48h|(bGprck>C5LhTr+y#&?<-U8QHCHzn%Cb^rG9PueCIqb|y z-Ikm})`4gr<=<`K3&0gxBXppjnfM{>R=`Q;w`LHSTxlA^zOtc}ekYGZ(4C4X4e*V1 zU#(VVqSx6jAhAmfgbuk30++P|HL5Zf(=Np9(U1a=Q+K+okuscA$TOC(^jw2EE&MTG zM-XkS3zQV>3TW^b*+Kfzv=~zl05nsKA^jyc7^(XJ&6f>`7TNS(yyVmX2YQ((hvK>~ z=@LbDb`Mf|7G@~yMAYg*2ISlrdiF1UU()E9sd9dlE>cMnz*?DGz1Ln?u9TFb_}F3{ zF1@haE;)9amE}R7Fg7N@wKk?G$ThONOB!{$TSAI#?%IGp=IJ_v9{a=o-I0}JuiYyj zCQCuxBkNa%P4)G$EH=s&9dl`Ewb@#=O;Rio)x`P~qIxy?c$QOJiM;dKt+zB2Jwp!! zU-Qa@+j-Z%2x6jc6b<FBd8U0cQEzAST~XS4;-Ga)#!y4^z;!~m`I)|Q&tf1ehLL+E zrTN%0iDhUcB>Uu^_;`$gnaJ6zsgh#UOt$<X{2sP{=8Q6|%_vOAY<v*i`J1@q;TuLq z6b5INfFla@knK$sk<vc#&1FfFz@fekF@?Tv)?1Oyd|gO?L2E1)0`4@~xBS<vam79B z?<LlHm~#_VTVY1LC#xc<Mhn$4u@KDGBuPy0zKEsp5&R_EL~Nk<R@LZozruX=PO6`k z27S~C!<nW*K#mBM-7PESL)=i7o9{MgJz)Dhw35&^+p?WDjvbQ8K_nP|{Iw5gxe!t4 zDxJdZ9HPTh_$?b~p-5tq_S@X1k|dT7P^&&&#UIr$O_DERy|_-tV1Z;h<db}U`5+L1 zd6m&#<D(kpMjV>Bz#BwHxI`HUqu!q8m8WPS{%hZ#k{LoeVyAZ~A_kpzLJx<9I6avO zBi0fX6OU<+SKlQNZND(my{>R1t1(RDoP4Cf)tZ#Xir=a>e7OE`{lpYlnZZ%&Q=HeS z-Qi2EFLLL4*B=dGiva5obMeLU`(2bf-Con}zod+ar7Tm}Ak@2?i=JCEsC@jP0Z61V zsSGdA1~NPhZe0w=7bkEJ@Y(Y}>=k`Ef5MTNmx;y_naj@=HR!l6f$d2ekA{I@j&LSv zM)qV#Oe@F{wrM9#mLNQNg>X7m@zc~GS!$1zecVOOrl5SdCZBl|z~~0itr@9EJ;_re z*?Q1VI^6J9U@g}7zvc2%&15DHI+HvwuSZLc7*1Lij0#YktcW@_DBfv=Hdn|l?>J5R zxfAb~==%isd5)}kbmFedkAPMiWJJBT_6ma|(60*wZ|QR~=wv2zkBgVMgfGfZ=rOv5 zEpP9>W71S?8#l!nyWtF(eAT;U21(KMz93d%eOogFY)|+G@2Jpo;t9^u!F`~=TJMlk z6`3cw7oPr#UmlDql3M_6N7PpSX{RlWvWZzyOZV;4@uyb%F)N+0Lb9gIjYtzh91pVz zPp;vlLYxyTUB&^`&AYfgc(~Val5R{1u;Fv45{&N>h9C{_qW|%fxtUx54(j>%C<zMy zAo%mh(ACPq!p)WK_wM)9K1Ex{^@9wKf8K{%44jkKuuU@MO<V(ghd*;Nc>A=<0b^oW z7XA;}lEEWEw5viPSAz0vYjfca@S>tHMm}$xH_x2PvSLfB>n3;P+4M0k)1P+>*aq?; z*sP>^;dW&Kb)YByyYu*Ng!r{2G&6}{R1?lwUJ1}A6YAqIIHl=zAWC=rrt>=D4Pi|z zbyP-!LNN4NZRS`tkk7CTg6iR`fc{z6n>EYDleku8h??V^6lzPE$1r7k0s8u#TM%}q zeGxe;2Bl2hsjsqcv8+3b)6uQKc3s1%$!ebElJoiUe!SXUm#bOsX{wc&fFydO(B9`M z-WM}gwHL<l&4;?9T9STti^&aX4l(fi&>e3NsrapIdvt_2@>;+wL39Samqt#HVR5d3 znF*Y-r0m68$R{~DoNMF<4P+`ej*CcK1u$lFy(WSu_Gz3R<hJskTt0pF+9t;z)pLY( zTe5Au3l-G{>J#|fa$7{A#B_-f*&p`ph?s{w>8=;l8;j>C^Sd}Q@JM#7@$Kg|>UG3b zw=989*VFsPm~{tqbV!6mIeosDb!p)tPWTzutO?(i^m^bSOfZjg5`VpRW{-6PpN{_g z&Yk&S*fjI;pmctWawFq<-q9^C64rD^WTPd1bg<Pp@}2jP?h$nFqmt_d#()8_u|#Bo zhJ;yXV-?j9mnWkb)EhSsG4-|YU8A9au|gM48FAUw8Q-CaJNfVQiFOT%YpDX4&3=w^ zn;s+eTE^awWs}+6?>YrdrO;K>n%XcByFg0%O%4#>a7EmP!)p=_$x$NMwp)7|x2Nin zT?yR9O?j8~A_x7zDw91adhGHFm)No-!``2gZQ>8hRx_3hdWk$r@1zujf;`ILBpbwp ztgpTv2Hk|yT+}5DM@Idkf<);l5n36?tE3AB&XD00C6E-#GBL2z#x7uP{;|9+Hqlcv z-0Z!+HRvu?It4r(QLjRzN-0M*B4rKQr;nwlDhARNa}~CyNNc1`M=+`rsXEJ1eNeUr z(J;oA$rS@}KX4W5rb=s6Ki||M`i>)9oqW-(G_xh3s(b(vW{7B&wb9QhqjN9Jr3cxI zv8>{n(|-#ER|;ee<3o-wt`v6$DkVu*RRz%n%(Yq&$WEq56oblP(JMM-({?L+LUGD; z7K-&qhP@YxUSBlR`()z?@8ZJLMX{#ivQ`yBG>?;NhTWx52_F<gQ3xOHpPMIxP!#Vk ztLX;J5`&VVC<R-pt%qyce=Gn-AUI_MM=QytV&xmI1L0Z@Kl`vsIIG794M=H(EM#z| z{#D!1g~r>%2^J^4WMbM<f9W7sWPKH5Rw!??9u{{7sGH835c3zWaaqkv4QKov=$+() z1d*53*EawOBqP!9g_z)(4NLLIL9VxWY+y@-xBx-zRTpw*;^{6h@P4(vppz55$<!-c zb3M(^Msr;q0-rnb_$G~oZSMVAh6RkR#gi)p{>R8os0B>8#r<Nv$r$7&)}nVh{Y(!6 z4?l8~V*vxS@O4;tk;>_By`T~V;Jx}TN(3Ul(V`N<XFX#gL%#JE!!`o?4k6w$U^HNe z5D@U&dTjOCvMF%oRRuO#!qg1awf}&SgJ11)8+XI$&(7?^i|nvt+F`SaF^x+-QbBI} z`go=(=}ga(ugTp|=YV8Br;#rnv|i3qkwwp+fduYW=H5>|Jv+sJW}VOiWTjfq4%O#5 zCj~x}bLNg_DlU#ru54zGE*AePEBPNM_q=p5N!`l9>;(NMw2v6?J*`X}9AH~PV@j+X zz@oFSjcWwR#n#^mo;u)o%%_5p(yuxm?^a(YUDh#nz*woza!Q$qB_Jft6()E`8P>;k zf^zE=khQ*Ism+4LZQuH(I^mw{_9j>3TImIzk;rDgtH3#`(&QKjJ1H=wbwc0oGpJ&+ zTv6N8=6D=-=>k%q=m%MVb;1PmYosX!DB#Ew59HH@#hg%SG+tD7n_zB|*T5NMh+<rf z^y%P!(yX3gI8I@?c@cM9#2{@p!zKRmyIJ!+h5wR>$hGE!gh#_>pcSRpC^x&F?c(L@ zqdJ9C^9Ew$;h2?HofBkCPnHLEmSk^m08@@mZ^1Xi$nm#>&2GGx{bAq5yjX37a0HoZ z8h(b`1zUj%Ta@wqn@5KjJ&ZuBZ7TSCZQpvO-J`C^HyNp#&V*tddyvjh^Zhm<YoY$n z#NI!_sEY`*xAqLij_13We+8q7lhgmO_zc2-UD@j04zthvFx44`>hX#>%7@7j+0ak< zWZHGpB}WT<$$dR_EIvd>E?da=P`(nPf$=s^LC%#cV`@svtL+&vYwa1e5c`@WsO)rU z{C(fFQY0%AoAM>fj`G#K4q5DY{W*O?G^tjYJi|0LquP%z@kr!Okv>j-mJtNC4RNvw zd~3;5)m1OysNRz)uzfkhrPh@SycV_^9Y4RP3}yjW7l<^3hglys6PyNQeU*mwd;GMh zgQZ_T^5S*sVZo@52kLxg(>jD7LTT(d@I_=6)Rji+ssG{@dq}o#Rkz~(y3FTPCWh>@ zlJ4yltw7TSu3@WHv<M$MXZ%bB$t!W2w|Vo3GVxngTc3!BW&5-$ijzFvUnkhZzOH>Q z4hdtzU>3wWB=XYU%#@!Vhu24aG1=S)VQU;X=eq3^hV_YZTUT<4HCLyP?v6;k{5CR} zCz|_NM9BZ?^5TdWQbs*Zm93>*=S!+ktP5Ql8Wf{O@61@ARMr(>XJvOEzI&^2UPi$f z=fXn@5J~18SHO7qlDYhN=xAqA&DXQquI^HQCm6Xh-~!}z7Xl+q@VL>d%s60F@L?Wi z>U%H>$*vvX9r%r%gZL_zZg|tqqjeq`OPAg`xs`>ly}$prQ9wbnJTsmDx%lr75d6{q zhf+Wl`M)dpdzsQ7g1`0Y&r|-TXz5qMzn5<ORj~b;K>Pm}a{Q|2S3dtwO()OwjlZz_ zzY70K|Nbfbfc(4gKgi%;HT=r>{i#9W`K0xE`d|6KUlsg%Hv6Z7t!D=DS%K@nPilV^ z{WUN7Q<ReQ-;e%}Eag`%e-G1t>Hq+AC;@<f1npnN|L$1-D!xno7x90&SrvJ>=eG+0 RAU}TspZ5hn>3;k5{{W-jJnR4f literal 0 HcmV?d00001 From 60e3eb4a8be6e268153be78a37925fd67de07e01 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 19 Jun 2025 19:16:22 +0900 Subject: [PATCH 23/25] =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84=EC=8B=9C?= =?UTF-8?q?=EC=84=A4=20=EC=97=91=EC=85=80=EB=B2=94=EC=9C=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rswtStat/page.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index 8582822fc..6b51f53f5 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -1,7 +1,6 @@ "use client"; import { useWrStore } from "@/app/store"; - -import type { ExcelType, RswtStatProps } from "@/app/store/stats/rswtStat"; +import type { RswtStatProps } from "@/app/store/stats/rswtStat"; import { excelDownload, tableData, yearOptions } from "@/components/lib/func/commom"; import { ContentsDiv, @@ -177,7 +176,7 @@ export default function RswtStat() { excelData, "중수도시설 통계", "sample_rswtStats.xlsx", - "A1:V3", + "A1:Q3", 4 ); } From 8cccf62a918ee03e4e0e04af593c10cefa8bbeb3 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Fri, 20 Jun 2025 10:28:21 +0900 Subject: [PATCH 24/25] =?UTF-8?q?-=20=EB=B2=95=EC=A0=81=EB=8C=80=EC=83=81?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20(Y/N=20>=20=EB=8C=80=EC=83=81/=EB=AF=B8?= =?UTF-8?q?=EB=8C=80=EC=83=81)=20-=20=EC=84=A4=EC=B9=98=EC=99=84=EB=A3=8C?= =?UTF-8?q?=EC=9D=BC=EC=9E=90=20NULL=EC=9D=B4=EB=A9=B4=20=EB=B9=88?= =?UTF-8?q?=EC=B9=B8=EC=9C=BC=EB=A1=9C=20-=20=EC=A4=91=EC=88=98=EB=8F=84+?= =?UTF-8?q?=EB=8C=80=EC=B2=B4=EC=88=98=20=EC=9D=B4=EC=9A=A9=EB=9F=89=20?= =?UTF-8?q?=EC=8B=9C=EB=8F=84,=EC=8B=9C=EA=B5=B0=EA=B5=AC=20=ED=95=A9?= =?UTF-8?q?=EA=B3=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 4 ++-- apps/wr/app/stats/rswtStat/page.tsx | 13 ++++++----- apps/wr/app/store/stats/rainStat/excel.tsx | 27 +++++++++++----------- apps/wr/app/store/stats/rswtStat/excel.tsx | 22 +++++++++--------- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index da593e073..8da063a90 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -93,7 +93,7 @@ export default function RainStat() { // 법정 대상 건축물 개수 (인덱스 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; + ).filter((data: unknown[]) => String(data[6]) === '대상').length; sidoData[i] = bumCnt; } else if(i==8){ const value = Number(item[8]) || 0; @@ -182,7 +182,7 @@ export default function RainStat() { <ContentsDiv> <div className="grid grid-cols-4 gap-4"> <div className="col-span-4"> - <Title title={"재이용 통계"} /> + <Title title={"빗물이용시설 통계"} /> <SearchDiv> <div className="grid grid-cols-12 gap-5 m-4"> <div className="col-span-2"> diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index 6b51f53f5..bd1c3f363 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -82,11 +82,10 @@ export default function RswtStat() { const sidoList = new Set(); const sidoDataMap = new Map(); // 시도별 데이터를 저장할 Map - console.log("rswtDetailList : ", rswtDetailList); rswtDetailList.forEach((item: RswtStatProps[]) => { const sidoVal = item.at(0)?.toString().trim(); const sigunVal = item.at(1)?.toString().trim(); - + const bdstVal = item.at(2)?.toString().trim(); let sidoText = ''; let sigunText = ''; @@ -140,7 +139,7 @@ export default function RswtStat() { // 법정 대상 건축물 개수 (인덱스 6이 'Y'인 경우) const bumCnt = rswtDetailList.filter((data: unknown[]) => Array.isArray(data) && data.length > 6 && String(data[0]) === sidoText - ).filter((data: unknown[]) => String(data[6]) === 'Y').length; + ).filter((data: unknown[]) => String(data[6]) === '대상').length; sidoData[i] = bumCnt; } else if(i==9){ const value = Number(item[9]) || 0; @@ -151,7 +150,10 @@ export default function RswtStat() { } else if(i==11){ const value = Number(item[11]) || 0; sidoData[i] = (Number(sidoData[i]) + value) as string | number; - } else if(i==13){ + } else if(i==12){ + const value = Number(item[12]) || 0; + sidoData[i] = (Number(sidoData[i]) + value) as string | number; + }else if(i==13){ const value = Number(item[13]) || 0; sidoData[i] = (Number(sidoData[i]) + value) as string | number; } else if(i==14){ @@ -168,7 +170,6 @@ export default function RswtStat() { }); // Map을 배열로 변환 const sidoSummaryList = Array.from(sidoDataMap.values()); - console.log("sidoSummaryList : ", sidoSummaryList) // sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성 const excelData = [...sidoSummaryList, ...rswtDetailList]; @@ -185,7 +186,7 @@ export default function RswtStat() { <ContentsDiv> <div className="grid grid-cols-4 gap-4"> <div className="col-span-4"> - <Title title="재이용 통계" /> + <Title title="중수도시설 통계" /> <SearchDiv> <div className="grid grid-cols-12 gap-5 m-4"> <div className="col-span-2"> diff --git a/apps/wr/app/store/stats/rainStat/excel.tsx b/apps/wr/app/store/stats/rainStat/excel.tsx index 35a918d83..db2099d9a 100644 --- a/apps/wr/app/store/stats/rainStat/excel.tsx +++ b/apps/wr/app/store/stats/rainStat/excel.tsx @@ -1,39 +1,40 @@ import type { RainStatProps } from "."; -export const excelRainStat = (excelList:RainStatProps[]) : string[][] => { - const excelData: string[][] = []; +export const excelRainStat = (excelList:RainStatProps[]) : (string | number)[][] => { + const excelData: (string | number)[][] = []; excelList.forEach((item) => { excelData.push([ //시도 - String(item.ctpvCd) ?? "", + item.ctpvCd ?? "", //시군구 - String(item.sggCd) ?? "", + item.sggCd ?? "", //행정구역명 String(item.areaNm) ?? "", //시설명 String(item.bdstNm) ?? "", - //건축물용도코드 - String(item.bdstUsgCd) ?? "", + //건축물용도코드 (값 없음) + //String(item.bdstUsgCd) ?? "", + "", //주소 String(item.daddr) ?? "", //법적의무대상여부 - String(item.lawTrgtYn) ?? "", + String(item.lawTrgtYn)==="Y" ? "대상" : "미대상", //설치완료일자 - String(item.instlCmptnDt) ?? "", + String(item.instlCmptnDt).substring(0, 10) ?? "", //설치비용 - String(item.instlCst) ?? "", + item.instlCst ?? "", //접수면종류 String(item.pntfColKnd) ?? "", //여과등처리시설유무 String(item.filtrTrtmfctYn) ?? "", //처리용량(저류조용량) - String(item.dtfcltCpct) ?? "", + item.dtfcltCpct ?? "", //연간사용량 - String(item.wtrUsqty) ?? "", + item.wtrUsqty ?? "", //이용용도코드 - String(item.utztnUsgCd) ?? "", + item.utztnUsgCd ?? "", //연간운영비 - String(item.anlOperCst) ?? "", + item.anlOperCst ?? "", ]); }); return excelData; diff --git a/apps/wr/app/store/stats/rswtStat/excel.tsx b/apps/wr/app/store/stats/rswtStat/excel.tsx index d47e0e3fe..35f567253 100644 --- a/apps/wr/app/store/stats/rswtStat/excel.tsx +++ b/apps/wr/app/store/stats/rswtStat/excel.tsx @@ -1,7 +1,7 @@ import type { RswtStatProps } from "."; -export const excelRswtStat = (excelList:RswtStatProps[]) : string[][] => { - const excelData: string[][] = []; +export const excelRswtStat = (excelList:RswtStatProps[]) : (string | number)[][] => { + const excelData: (string | number)[][] = []; excelList.forEach((item) => { excelData.push([ //시도 @@ -18,28 +18,28 @@ export const excelRswtStat = (excelList:RswtStatProps[]) : string[][] => { //주소 String(item.daddr) ?? "", //법적의무대상여부 - String(item.lawTrgtYn) ?? "", + String(item.lawTrgtYn)==="Y" ? "대상" : "미대상", //설치완료일자 - String(item.instlCmptnDt) ?? "", + item.instlCmptnDt ? String(item.instlCmptnDt).substring(0, 10) : "", //가동개시일(빈칸) //String(item.instlCst) ?? "", "", //건축물면적 - String(item.archArea) ?? "", + item.archArea ?? "", //처리용량 - String(item.filtrTrtmfctCpct) ?? "", + item.filtrTrtmfctCpct ?? "", //물사용량 - String(item.wtrUsqty) ?? "", + item.wtrUsqty ?? "", //중수도+대체수이용량 - String(item.rswtAltSum) ?? "", + item.rswtAltSum ?? "", //중수도이용량 - String(item.rswtrUsqty) ?? "", + item.rswtrUsqty ?? "", //대체수이용량 - String(item.altUswtrUtztnQnt) ?? "", + item.altUswtrUtztnQnt ?? "", //중수도용도 String(item.utztnUsgCd) ?? "", //연간운영비 - String(item.anlOperCst) ?? "", + item.anlOperCst ?? "", ]); }); return excelData; From 10ebd8cbef5e5f60749bfa73a22e12cea2267e9e Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Fri, 20 Jun 2025 11:03:38 +0900 Subject: [PATCH 25/25] =?UTF-8?q?=EC=97=91=EC=85=80=20=EC=8B=9C=EB=8F=84?= =?UTF-8?q?=EB=B3=84=EB=A1=9C=20=EC=86=8C=EA=B3=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/stats/rainStat/page.tsx | 51 +++++++++++++++++++------- apps/wr/app/stats/rswtStat/page.tsx | 55 +++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index 8da063a90..d1b2f54cc 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -19,9 +19,8 @@ import { useEffect, useState } from "react"; export default function RainStat() { const { code, rainStat, searchRainStatList } = useWrStore((state) => state); - const { rainStatHeadList, rainStatList, excelList, rainDetailList } = rainStat; + const { rainStatList, excelList, rainDetailList } = rainStat; - const [pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); @@ -33,9 +32,11 @@ export default function RainStat() { }, [code.cityCd, code.sggCd, searchRainStatList, searchYear]) const excelDetailDownLoad=() =>{ - const sidoList = new Set(); - const sidoDataMap = new Map(); // 시도별 데이터를 저장할 Map + const sidoList = new Set<string>(); + const sidoDataMap = new Map<string, (string | number)[]>(); // 시도별 데이터를 저장할 Map + const sidoDetailMap = new Map<string, (string | number)[][]>(); // 시도별 상세 데이터를 저장할 Map + // 먼저 시도별 상세 데이터를 그룹화 rainDetailList.forEach((item: RainStatProps[]) => { const sidoVal = item.at(0)?.toString().trim(); const sigunVal = item.at(1)?.toString().trim(); @@ -60,7 +61,15 @@ export default function RainStat() { item[2] = sidoText+' '+sigunText as unknown as RainStatProps; } - // 시도별 데이터 수집 + // 시도별 상세 데이터 수집 + if (sidoText) { + if (!sidoDetailMap.has(sidoText)) { + sidoDetailMap.set(sidoText, []); + } + sidoDetailMap.get(sidoText)!.push(item as unknown as (string | number)[]); + } + + // 시도별 합계 데이터 수집 if (sidoText && !sidoList.has(sidoText)) { sidoList.add(sidoText); // 시도별 초기 데이터 구조 생성 (예: [시도명, 0, 0, 0, ...]) @@ -72,11 +81,12 @@ export default function RainStat() { sidoDataMap.set(sidoText, initialData); } }); + // 시도별 합계 계산 rainDetailList.forEach((item: RainStatProps[]) => { const sidoText = item[0]?.toString(); if (sidoText && sidoDataMap.has(sidoText)) { - const sidoData = sidoDataMap.get(sidoText); + const sidoData = sidoDataMap.get(sidoText)!; // 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작) for (let i = 1; i < item.length && i < sidoData.length; i++) { if(i == 2){ @@ -115,13 +125,30 @@ export default function RainStat() { } }); - // Map을 배열로 변환 + // 시도별로 합계와 상세 데이터를 순서대로 배치 + const summaryExcelData: (string | number)[][] = []; + + // 시도별로 순회하면서 합계와 상세 데이터를 추가 + Array.from(sidoList).forEach((sidoText) => { + const sidoSummary = sidoDataMap.get(sidoText); + const sidoDetails = sidoDetailMap.get(sidoText) || []; + + if (sidoSummary) { + // 시도 합계 데이터 추가 + summaryExcelData.push(sidoSummary); + // 해당 시도의 상세 데이터들 추가 + sidoDetails.forEach(detail => { + summaryExcelData.push(detail); + }); + } + }); + const sidoSummaryList = Array.from(sidoDataMap.values()); // sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성 - const excelData = [...sidoSummaryList, ...rainDetailList]; + const excelData = [...sidoSummaryList, ...summaryExcelData]; excelDownload( - excelData, + excelData as unknown as [][], "빗물이용시설 통계", "sample_rainStats.xlsx", "A1:V3", @@ -144,7 +171,7 @@ export default function RainStat() { const tbData = Array.isArray(excelData) ? excelData.map((item: RainStatProps) => { return { - "시도": item.cityText, + "시도": item.ctpvCd, "개소": item.tmp, "설치비(백만원)": item.instlCst, "저류조용량(m³/년)": item.dtfcltCpct, @@ -170,7 +197,7 @@ export default function RainStat() { ? data.map((item: RainStatProps) => { return { ...item, - ctpvCd: item.cityText + ctpvCd: item.ctpvCd }; }) : []; @@ -198,7 +225,7 @@ export default function RainStat() { /> </div> <div className="flex flex-row space-x-2 items-center"> - <Button className="" size={"sm"} onClick={(e) => { }}> + <Button className="" size={"sm"} onClick={() => { }}> 조회 </Button> <Button className="" size={"sm"} onClick={() => excelClick()}> diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index bd1c3f363..ce9a9c0f0 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -19,11 +19,10 @@ export default function RswtStat() { const { code, rswtStat, searchRswtStatList } = useWrStore((state) => state); const { rswtStatList, excelList, rswtDetailList } = rswtStat; const [rswtTable, setRswtTable] = useState<RswtStatProps[]>(); - const [pageNation, setPageNation] = useState(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); - const [excelData, setExceData] = useState<any[]>(); + const [excelData, setExceData] = useState<Record<string, string | number>[]>(); useEffect(() => { searchRswtStatList(searchYear) @@ -45,12 +44,12 @@ export default function RswtStat() { ? data.map((item: RswtStatProps) => { return { ...item, - ctpvCd: item.cityText + ctpvCd: item.ctpvCd }; }) : []; setRswtTable(tbData); - }, [rswtStatList]) + }, [code, rswtStatList]) useEffect(() => { const transExcel = Array.isArray(excelList) ? excelList : [excelList]; @@ -58,7 +57,7 @@ export default function RswtStat() { const tbData = Array.isArray(exData) ? exData.map((item: RswtStatProps) => { return { - "시도": item.cityText, + "시도": item.ctpvCd, "개소": item.ctpvCnt, "건축연면적(m³)": item.archArea, "처리용량(m³)": item.filtrTrtmfctCpct, @@ -76,16 +75,17 @@ export default function RswtStat() { }; }) : []; setExceData(tbData); - }, [excelList]) + }, [code, excelList]) const excelDetailDownLoad=() =>{ - const sidoList = new Set(); - const sidoDataMap = new Map(); // 시도별 데이터를 저장할 Map + const sidoList = new Set<string>(); + const sidoDataMap = new Map<string, (string | number)[]>(); // 시도별 데이터를 저장할 Map + const sidoDetailMap = new Map<string, (string | number)[][]>(); // 시도별 상세 데이터를 저장할 Map + // 먼저 시도별 상세 데이터를 그룹화 rswtDetailList.forEach((item: RswtStatProps[]) => { const sidoVal = item.at(0)?.toString().trim(); const sigunVal = item.at(1)?.toString().trim(); - const bdstVal = item.at(2)?.toString().trim(); let sidoText = ''; let sigunText = ''; @@ -106,7 +106,15 @@ export default function RswtStat() { item[2] = sidoText+' '+sigunText as unknown as RswtStatProps; } - // 시도별 데이터 수집 + // 시도별 상세 데이터 수집 + if (sidoText) { + if (!sidoDetailMap.has(sidoText)) { + sidoDetailMap.set(sidoText, []); + } + sidoDetailMap.get(sidoText)!.push(item as unknown as (string | number)[]); + } + + // 시도별 합계 데이터 수집 if (sidoText && !sidoList.has(sidoText)) { sidoList.add(sidoText); // 시도별 초기 데이터 구조 생성 (예: [시도명, 0, 0, 0, ...]) @@ -118,11 +126,12 @@ export default function RswtStat() { sidoDataMap.set(sidoText, initialData); } }); + // 시도별 합계 계산 rswtDetailList.forEach((item: RswtStatProps[]) => { const sidoText = item[0]?.toString(); if (sidoText && sidoDataMap.has(sidoText)) { - const sidoData = sidoDataMap.get(sidoText); + const sidoData = sidoDataMap.get(sidoText)!; // 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작) for (let i = 1; i < item.length && i < sidoData.length; i++) { if(i == 2){ @@ -168,13 +177,31 @@ export default function RswtStat() { } } }); - // Map을 배열로 변환 + + // 시도별로 합계와 상세 데이터를 순서대로 배치 + const summaryExcelData: (string | number)[][] = []; + + // 시도별로 순회하면서 합계와 상세 데이터를 추가 + Array.from(sidoList).forEach((sidoText) => { + const sidoSummary = sidoDataMap.get(sidoText); + const sidoDetails = sidoDetailMap.get(sidoText) || []; + + if (sidoSummary) { + // 시도 합계 데이터 추가 + summaryExcelData.push(sidoSummary); + // 해당 시도의 상세 데이터들 추가 + sidoDetails.forEach(detail => { + summaryExcelData.push(detail); + }); + } + }); + const sidoSummaryList = Array.from(sidoDataMap.values()); // sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성 - const excelData = [...sidoSummaryList, ...rswtDetailList]; + const excelData = [...sidoSummaryList, ...summaryExcelData]; excelDownload( - excelData, + excelData as unknown as [][], "중수도시설 통계", "sample_rswtStats.xlsx", "A1:Q3",