diff --git a/apps/wr/app/page.tsx b/apps/wr/app/page.tsx index 63c97952b..c173173ff 100644 --- a/apps/wr/app/page.tsx +++ b/apps/wr/app/page.tsx @@ -76,6 +76,13 @@ export default function Home() { +
+ +
diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx new file mode 100644 index 000000000..960edd227 --- /dev/null +++ b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx @@ -0,0 +1,76 @@ +'use client' + +import { useWrStore } from "@/app/store"; +import { btnClass } from "@/app/store/common/code"; +import type { chgBuilding, customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { getCityOrSgg } from "@/components/lib/func/commom"; +import { ContentsDiv, SearchBaseForm, Title ,type ReturnType, } from "@common/business_components/ui" +import { Button } from "@common/components/ui"; +import { useCallback, useRef, useState } from "react"; + +export default function HtdflSttn(){ +const { code } = useWrStore( + (state) => state + ); +const ref = useRef({} as ReturnType); + + const [pageNation, setPageNation] = useState(1); + const [isChHead, setIsChHead] = useState(false); + const [bdstTable, setBdstTable] = useState(); + const [detailModal, setDetailModal] = useState<{isOpen:boolean,data:customRainBdst|undefined}>({data:undefined,isOpen:false }) + const [bdstChgProps, setBdstChgProps] = useState<{ + isOpen: boolean; + chBuilding: chgBuilding[]; + }>({ isOpen: false, chBuilding: [] }); + + const codeData = getCityOrSgg(ref); + + const excelClick = useCallback(() => { + // if (codeData) rainSttnSearch(1, "10000", codeData); + }, []); + + return( + <> + +
+
+ + <SearchBaseForm + selectSidoData={code.cityCd} + selectSigunData={code.sggCd} + selectRegionData={code.rvbsnCd} + selectUnitWaterShedData={code.lgbsnCd} + selectMiddleRegionData={code.mdmbsnCd} + selectEnvPartData={code.lclgvrnmntCd} + rightChildren={ + <Button + className={btnClass} + onClick={() => { + setIsChHead(true); + }} + > + 조회항목설정 + </Button> + } + leftChildren={undefined} + queryClick={function (returnType: ReturnType): void { + // '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}' + let con; + if (returnType.sigunValue != "0") { + con = returnType.sigunValue; + } else { + con = returnType.sidoValue; + } + // rainSttnSearch(1, "20", con); + }} + excelClick={excelClick} + initClick={function (): void {}} + btnClass={btnClass} + ref={ref} + /> + </div> + </div> + </ContentsDiv> + </> + ) +} \ No newline at end of file diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx index 8ed57f120..66dd6ba3d 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx @@ -73,7 +73,7 @@ export default function RainSttn() { ...item, ...item.reuseBuilding[0], ...item.reuseBuilding[0].rainyObj, - chBuildingYn:item.chgBuilding[0].bdstChgNm!==null?'Y':'N' + chBuildingYn:item.chgBuilding[0]?.bdstChgNm!==null?'Y':'N' })) .filter((item: any) => item.rainyObj !== undefined); diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx index d13cf8a12..3608cddab 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx @@ -1,9 +1,16 @@ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; +import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import { excelDownload, getCityOrSgg, tableData } from "@/components/lib/func/commom"; +import { + excelDownload, + getCityOrSgg, + tableData, +} from "@/components/lib/func/commom"; +import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal"; +import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; import { ContentsDiv, SearchBaseForm, @@ -18,21 +25,43 @@ import { Button } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; export default function RswtSttn() { - const { code, rswtSttn, rswtSttnSearch ,rswtSttnInit} = useWrStore((state) => state); + const { code, rswtSttn, rswtSttnSearch, rswtSttnInit } = useWrStore( + (state) => state + ); const [pageNation, setPageNation] = useState(1); const { rswtSttnRes } = rswtSttn; const [isChHead, setIsChHead] = useState(false); const ref = useRef<ReturnType>({} as ReturnType); const [bdstTable, setBdstTable] = useState<customRswtBdst[]>(); + const [detailModal, setDetailModal] = useState<{isOpen:boolean,data:customRswtBdst|undefined}>({data:undefined,isOpen:false }) + const [bdstChgProps, setBdstChgProps] = useState<{ + isOpen: boolean; + chBuilding: chgBuilding[]; + }>({ isOpen: false, chBuilding: [] }); const codeData = getCityOrSgg(ref); +const cellClick=(index:number|undefined, headId: string)=>{ + + if(headId!=='chBuildingYn' && index!==undefined && bdstTable!==undefined){ + setDetailModal({isOpen:true ,data:bdstTable[index] }) + }else if( headId==='chBuildingYn' && index!==undefined && bdstTable!==undefined){ + if ( + bdstTable[index] && + bdstTable[index]?.chgBuilding[0]?.bdstChgNm!==null + + ) { + setBdstChgProps({ isOpen:true , chBuilding: bdstTable[index].chgBuilding}); + } + } + + } + useEffect(() => { if (!rswtSttn.isInit) { - - rswtSttnInit('0') + rswtSttnInit("0"); } }, [rswtSttn.isInit, rswtSttnInit]); @@ -40,20 +69,21 @@ export default function RswtSttn() { if (rswtSttnRes.length > 0 && code.cityCd.length > 0) { const data = tableData(rswtSttnRes, { code }); const chData = data - .map((item: customRswtBdst) => ({ + .map((item: customRswtBdst) => ({ ...item, ...item.reuseBuilding[0], ...item.reuseBuilding[0]?.rswtrObj, - chBuildingYn:item.chgBuilding.length>0?'Y':'N' + chBuildingYn:item?.chgBuilding[0]?.bdstChgNm!==null?'Y':'N' })) - .filter((item: customRswtBdst) => item.reuseBuilding[0]?.rswtrObj !== undefined); + .filter( + (item: customRswtBdst) => + item.reuseBuilding[0]?.rswtrObj !== undefined + ); - console.log("chData ", chData) setBdstTable(chData); } }, [code, rswtSttnRes]); - useEffect(() => { if (rswtSttn.excelList.length > 0) { if (rswtSttn.excelList.length === 0) return; @@ -82,7 +112,6 @@ export default function RswtSttn() { if (codeData != null) rswtSttnSearch(pageNation, "20", codeData); }, [pageNation]); - return ( <> <ContentsDiv> @@ -136,9 +165,8 @@ export default function RswtSttn() { headlist={rswtSttn.rswtSttHeadList} pageSize={20} total={10000} - cellClick={undefined} + cellClick={(index: number | undefined,headId:string)=>{cellClick(index ?? undefined,headId)} } onPageChange={setPageNation} - ></UiTable> </ListDiv> </div> @@ -149,7 +177,34 @@ export default function RswtSttn() { setIsChHead(!isChHead); }} bodyClass={""} - body={<HeadChModal headList={(rswtSttn.rswtSttHeadList||[]).map(item => ({ ...item, visible: item.visible ?? false }))} type={"RST"} />} + body={ + <HeadChModal + headList={(rswtSttn.rswtSttHeadList || []).map((item) => ({ + ...item, + visible: item.visible ?? false, + }))} + type={"RST"} + /> + } + /> + <UiModal + open={detailModal.isOpen} + onOpenChange={() => { + setDetailModal({ ...detailModal, isOpen: !detailModal.isOpen }); + }} + bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"} + body={<SttnDetailModal type={"RST"} formObj={detailModal.data} />} + /> + + <UiModal + bodyClass={""} + open={bdstChgProps.isOpen} + body={ + <BdstChgModal chgBuilding={bdstChgProps.chBuilding}></BdstChgModal> + } + onOpenChange={(open) => { + setBdstChgProps({ ...bdstChgProps, isOpen: open }); + }} /> </ContentsDiv> </> diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx index 0d21b08e8..978805d9d 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx @@ -1,4 +1,4 @@ -import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { TableHead, TableRow } from "@common/components/ui"; diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index abf3dcc8f..b83284c32 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -1,11 +1,12 @@ "use client"; import { useWrStore } from "@/app/store"; +import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { - fcltDiv, - type rainChkZodType -} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import { excelDownload } from "@/components/lib/func/commom"; + excelArrayDownload, + excelDownload, +} from "@/components/lib/func/commom"; import ChkgdExcel from "@/components/ui/modal/chkgd/chkgdExcel/chkgdExcel"; import ChkgdModal from "@/components/ui/modal/chkgd/chkgdModal/chkgdModal"; import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable"; @@ -18,7 +19,7 @@ import { SearchInput, SelectBox, Title, - UiModal + UiModal, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; @@ -27,59 +28,97 @@ import { Toaster } from "react-hot-toast"; //----------------------- export default function Page() { - - const { code, rainChkgdn, rainChkInit,rainChkDetilUpdate, rainChkDelete , rainChkExcelDownload, rswtrChkExcelDownload } = useWrStore((state) => { + const { + code, + rainChkgdn, + rswtChkgdn, + rainChkInit, + rainChkDetilUpdate, + rainChkDelete, + rainChkExcelDownload, + rswtrChkExcelDownload, + + rswtChkgdnInit + } = useWrStore((state) => { return state; }); const [isRegExcel, setIsRegExcel] = useState(false); const [searchTxt, setSearchTxt] = useState<string>(); - const [updateRainDetail, setUpdateRainDetail] = useState<rainChkZodType[]>([]); - const [deleteIdx, setDeleteIdx ] = useState<number[]> ([]); + const [updateRainDetail, setUpdateRainDetail] = useState<rainChkZodType[]>( + [] + ); + const [deleteIdx, setDeleteIdx] = useState<number[]>([]); const [selFcltDiv, setSelFcltDiv] = useState("RNB"); const [isModal, setIsModal] = useState({ open: false, data: {}, }); const cellClick = () => { - if(searchTxt) - rainChkInit(searchTxt,'0') - + if (searchTxt) rainChkInit(searchTxt, "0"); }; - useEffect(() => { + useEffect(() => { if (!rainChkgdn.isInit) { - rainChkInit('2024','0'); - setIsModal({data:{}, open:rainChkgdn.isModalClose }) - setIsRegExcel(false) + rainChkInit("2024", "0"); + setIsModal({ data: {}, open: rainChkgdn.isModalClose }); + setIsRegExcel(false); + } + + if (!rswtChkgdn.isInit) { + rswtChkgdnInit("2024", "0"); + setIsModal({ data: {}, open: rainChkgdn.isModalClose }); + setIsRegExcel(false); } }, [rainChkgdn.isInit, rainChkInit]); + useEffect(() => { + console.log("rswtChkgdn.excelList ", rswtChkgdn.excelList); + + if (rswtChkgdn.excelList[0]?.data.length > 1) + excelArrayDownload( + "중수도_점검결과_이용량현황", + "sample_rs_chk.xlsx", + rswtChkgdn.excelList + ); + }, [rswtChkgdn.excelList]); useEffect(() => { - excelDownload(rainChkgdn.excelList ,'빗물이용시설 지도점검','sample_rainy.xlsx', 'A1:AN1'); + excelDownload( + rainChkgdn.excelList, + "빗물이용시설 지도점검", + "sample_rainy.xlsx", + "A1:AN1" + ); }, [rainChkgdn.excelList]); - const excelClick= useCallback(()=>{ - if(selFcltDiv === "RNB") { + const excelClick = useCallback(() => { + console.log("selFcltDiv ", selFcltDiv); + if (selFcltDiv === "RNB") { rainChkExcelDownload(code.cityCd, code.sggCd); } else { rswtrChkExcelDownload(code.cityCd, code.sggCd); } - }, [rainChkExcelDownload, rswtrChkExcelDownload, code.cityCd, code.sggCd]); + }, [ + rainChkExcelDownload, + rswtrChkExcelDownload, + code.cityCd, + code.sggCd, + selFcltDiv, + ]); + const handleClick = useCallback( + (data: any) => { + if (data) setIsModal({ open: true, data: data }); + }, + [isModal] + ); - - const handleClick = useCallback((data:any) => { - if(data) setIsModal({ open: true, data: data }); - }, [isModal]); - - const clickDelete=(data:number[])=>{ - if(data.length>0){ - rainChkDelete( data ) + const clickDelete = (data: number[]) => { + if (data.length > 0) { + rainChkDelete(data); } - } + }; - return ( <ContentsDiv> <div className="grid grid-cols-4 gap-4 "> @@ -90,16 +129,20 @@ export default function Page() { <SearchInput className="col-span-3 my-7 !text-xl" label=" 지도점검년도" - textValue={searchTxt??''} - setText={(e) => {setSearchTxt(e);}} + textValue={searchTxt ?? ""} + setText={(e) => { + setSearchTxt(e); + }} /> <SelectBox className={"col-span-3 w-full h-full text-2xl"} label={"시설구분"} selectClass={""} - selectArray={fcltDiv} - onSelectValue={setSelFcltDiv} - value={selFcltDiv ?? fcltDiv[0]?.val} + selectArray={rainChkgdn.fcltDiv} + onSelectValue={(val: string | number) => + setSelFcltDiv(String(val)) + } + value={selFcltDiv ?? rainChkgdn.fcltDiv[0]?.val} /> </SearchFormLeft> <SearchFormRight> @@ -113,22 +156,33 @@ export default function Page() { > 조회 </Button> - <Button size={"sm"} onClick={() => { clickDelete(deleteIdx) }}> + <Button + size={"sm"} + onClick={() => { + clickDelete(deleteIdx); + }} + > 삭제 </Button> - <Button size={"sm"} onClick={() => { rainChkDetilUpdate( updateRainDetail as rainChkZodType[]) }}> + <Button + size={"sm"} + onClick={() => { + rainChkDetilUpdate(updateRainDetail as rainChkZodType[]); + }} + > 저장 </Button> </div> <div className="flex flex-row space-x-2 pt-3"> - <Button size={"sm"} onClick={() => {setIsRegExcel(!isRegExcel)}}> + <Button + size={"sm"} + onClick={() => { + setIsRegExcel(!isRegExcel); + }} + > 결과등록 </Button> - <Button - color="green" - size={"sm"} - onClick={excelClick} - > + <Button color="green" size={"sm"} onClick={excelClick}> 양식받기 </Button> </div> @@ -140,18 +194,30 @@ export default function Page() { <div className="grid grid-cols-6 gap-4 "> <div className="col-span-6"> <ListDiv> - {selFcltDiv === "RNB" ? <RainChkgdTable deleteData={setDeleteIdx} detailUp={setUpdateRainDetail} handleClick={handleClick} /> : <RswtChkgdTable />} + {selFcltDiv === "RNB" ? ( + <RainChkgdTable + deleteData={setDeleteIdx} + detailUp={setUpdateRainDetail} + handleClick={handleClick} + /> + ) : ( + <RswtChkgdTable detaiRswtlUpdate={function (data: rswtChkZodType[]): void { + throw new Error("Function not implemented."); + } } deleteRswtData={function (selectedIds: number[]): void { + throw new Error("Function not implemented."); + } } /> + )} </ListDiv> </div> </div> <UiModal - open={isModal.open} - onOpenChange={() => { - setIsModal({ open: !open, data: {} }); - }} - bodyClass={"w-[80vw] max-w-none"} - body={<ChkgdModal type={"RNB"} obj={isModal.data} />} - ></UiModal> + open={isModal.open} + onOpenChange={() => { + setIsModal({ open: !open, data: {} }); + }} + bodyClass={"w-[80vw] max-w-none"} + body={<ChkgdModal type={"RNB"} obj={isModal.data} />} + ></UiModal> <UiModal open={isRegExcel} onOpenChange={setIsRegExcel} diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx index c34d0b9fc..c39456095 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -1,8 +1,8 @@ import type { SelectDataType } from "@common/business_components"; import type { rainChkZodType } from "."; import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { buildingType } from '../../../common/code/index'; -const useTypes = [ +import { buildingType } from "../../../common/code/index"; +export const useTypes = [ "조경용수", "청소화장실용수", "세척살수용수", @@ -30,31 +30,61 @@ export const buildingToExcelType = ( buildings: Buildingtype[], sidoCode: SelectDataType[], sggCdoe: SelectDataType[], - bdType: string, ) => { const excelData: string[][] = []; - if(bdType===buildingType.RNB){ buildings.forEach((building) => { useTypes.forEach((useType) => { excelData.push([ building.bdstInfoPk.toString(), sidoCode.find((sido) => sido.val === building.ctpvCd.toString()) ?.text || "", - sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text || "",building.daddr,building.bdstNm,"","","","",useType,"","","","","","","","","","","","","","","","","","","","","","","","","","","","","","", + sggCdoe.find((sido) => sido.val === building.sggCd.toString()) + ?.text || "", + building.daddr, + building.bdstNm, + "", + "", + "", + "", + useType, + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", ]); }); }); return excelData; - }else if(bdType===buildingType.RST){ - - } + }; -export const excelToRainChkData = ( - excelData: any, - year: string, -) => { - +export const excelToRainChkData = (excelData: any, year: string) => { const rainChkgdData: rainChkZodType[] = excelData.map((item: any) => { const makeGuidDetail = Array.from({ length: 12 }, (_, i) => { let month = `${i + 1}`; @@ -64,33 +94,33 @@ export const excelToRainChkData = ( return { utztnUsgCd: item["이용용도"], ym: year + month, - chckYmd: item["점검일"] , + chckYmd: item["점검일"], splyUswtrUtztnQnt: splyData !== "" ? splyData : 0, - ruseFcltUtztnQnt: ruseData !== "" ? ruseData : 0, + ruseFcltUtztnQnt: ruseData !== "" ? ruseData : 0, flg: "RNB", }; }); return { - bdstRuseFcltFk: Number(item["NO"]), - chckYmd: item["점검일"] , - spwtPositn: item["유량측정방법"], - rgtr: TEST_UUID, - oilqMeasMthd: item["운영관리형태"], - anlOperCst: Number(item["연간운영비(원/년)"])??0, - operMngCd: item["유량측정방법"], - guideDetails: makeGuidDetail, - rainyDetails: [ - { - utztnUsgCd: item["이용용도"], - ph: Number(item["PH"])??0, - trbt: Number(item["탁도"])??0, - grssClfg: Number(item["총대장균군수"])??0, - etc: item["기타"] ?? "", // 필드 누락 방지 - vltnDt: item["과태료 부과일(위반일)"], - vltnMttr: item["위반사항"], - levyAmt: Number(item["과태료부과금액(천원)"])??0, - rgtr: TEST_UUID, + bdstRuseFcltFk: Number(item["NO"]), + chckYmd: item["점검일"], + spwtPositn: item["유량측정방법"], + rgtr: TEST_UUID, + oilqMeasMthd: item["운영관리형태"], + anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0, + operMngCd: item["유량측정방법"], + guideDetails: makeGuidDetail, + rainyDetails: [ + { + utztnUsgCd: item["이용용도"], + ph: Number(item["PH"]) ?? 0, + trbt: Number(item["탁도"]) ?? 0, + grssClfg: Number(item["총대장균군수"]) ?? 0, + etc: item["기타"] ?? "", // 필드 누락 방지 + vltnDt: item["과태료 부과일(위반일)"], + vltnMttr: item["위반사항"], + levyAmt: Number(item["과태료부과금액(천원)"]) ?? 0, + rgtr: TEST_UUID, }, ], }; diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx new file mode 100644 index 000000000..e16da6329 --- /dev/null +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx @@ -0,0 +1,282 @@ +import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { z } from "zod"; + + + + +export const chkgdRegExcel = z.object({ + bdstInfoPk: z.number().default(111111111), + chckYr: z.string() + .default("") + .refine( + (year) => year.length === 0 || /^\d{4}$/.test(year), + { message: "4자리 연도만 입력하세요" } + ) + .refine( + (year) => { + if (year.length === 0) return true; // 빈 문자열은 통과 + const numYear = Number(year); + return !isNaN(numYear) && numYear <= new Date().getFullYear(); + }, + { message: "현재 년도보다 높은 수를 입력할 수 없습니다." } + ), + file: z.instanceof(File).optional(), + }); + + +export const guideDetail = z.object({ + chkgdnFk: z.number().nullable(), + utztnUsgCd: z.string(), + chckYmd: z.string(), + ym: z.string(), + splyUswtrUtztnQnt: z.number(), + ruseFcltUtztnQnt: z.number(), + flg: z.string(), +}) +export const rainChkZod = z.object({ + chkgdnPk: z.number().nullable(), + bdstRuseFcltFk: z.number(), + chckYmd: z.string(), + prcsCpct: z.number().nullable(), + spwtPositn: z.string().nullable(), + regDt: z.string().nullable(), + rgtr: z.string().nullable(), + mdfcnDt: z.string().nullable(), + mdfr: z.string().nullable(), + flg: z.string().nullable(), + guideDetails: z.array( + guideDetail + ), + building: z.object({ + bdstInfoPk: z.number(), + ctpvCd: z.number(), + sggCd: z.number(), + daddr: z.string().nullable(), + bdstNm: z.string(), + frstArchPrmsnDt: z.string().nullable(), + archArea: z.number(), + regDt: z.string().nullable(), + rgtr: z.string().nullable(), + mdfcnDt: z.string().nullable(), + mdfr: z.string().nullable(), + }).nullable(), + rainyDetails: z.array( + z.object({ + chkgdnFk: z.number().nullable(), + utztnUsgCd: z.string(), + ph: z.number().nullable(), + trbt: z.number().nullable(), + grssClfg: z.number().nullable(), + etc: z.string().nullable(), + vltnDt: z.string().nullable(), + vltnMttr: z.string().nullable(), + levyAmt: z.number().nullable(), + regDt: z.string().nullable(), + rgtr: z.string().nullable(), + mdfcnDt: z.string().nullable(), + mdfr: z.string().nullable(), + }) + ), +}); + + + +export type chHeadType = { + headNm: string; + text: string; + length: number; + rows?: number; + }; + + + + +export type splRuseWaterType = { + utztnUsgCd: string; + splTotal: number; + spl01: number; + spl02: number; + spl03: number; + spl04: number; + spl05: number; + spl06: number; + spl07: number; + spl08: number; + spl09: number; + spl10: number; + spl11: number; + spl12: number; + ruseTotal: number; + ruse01: number; + ruse02: number; + ruse03: number; + ruse04: number; + ruse05: number; + ruse06: number; + ruse07: number; + ruse08: number; + ruse09: number; + ruse10: number; + ruse11: number; + ruse12: number; + }; + +export const rainHeadNmExport: chHeadType[] = [ + { headNm: "useQuilty", text: "이용수질(필요시)", length: 4 }, + { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, + { headNm: "ruseWater", text: "연간보급수 이용량(m³)", length: 13 }, + { headNm: "detailQulity", text: "분기", length: 11 }, + { headNm: "splWater", text: "연간빗물 이용량(m³)", length: 13 }, + +]; + + +export const rainChkgdnHeadListExport: TableUpperProps[] = [ + { id: "order", title: "순번", rowSpan: true }, + { id: "cityText", title: "시도", rowSpan: true }, + { id: "sggText", title: "시군구", rowSpan: true }, + { id: "bdstNm", title: "시설명", rowSpan: true }, + { id: "operMngCd", title: "운영관리형태", rowSpan: true }, + { id: "oilqMeasMthd", title: "유량측정방법", rowSpan: true }, + { id: "anlOperCst", title: "연간운영비(원/년)", rowSpan: true }, + { id: "dtfcltCpct", title: "빗물저류조용량(m³)", rowSpan: true }, + { id: "chckYmd", title: "점검일", rowSpan: true }, + { id: "utztnUsgCd", title: "이용용도" }, + { id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, + { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" }, + { id: "ph", title: "PH", upName: "useQuilty", upSequnce: 1, type: "number" }, + { + id: "trbt", + title: "탁도", + upName: "useQuilty", + upSequnce: 2, + type: "number", + }, + { + id: "grssClfg", + title: "총대장균군수", + upName: "useQuilty", + upSequnce: 3, + type: "number", + }, + { + id: "etc", + title: "기타", + upName: "useQuilty", + upSequnce: 4, + type: "number", + }, + { + id: "vltnDt", + title: "부과일(위반일)", + upName: "feeHist", + upSequnce: 1, + type: "text", + }, + { + id: "vltnMttr", + title: "위반사항", + upName: "feeHist", + upSequnce: 2, + type: "text", + }, + { + id: "levyAmt", + title: "부과금액(천원)", + upName: "feeHist", + upSequnce: 3, + type: "number", + }, +]; + +export const ruseHeadListExport: TableUpperProps[] = [ + { id: "utztnUsgCd", title: "이용용도" }, + { id: "ruseTotal", title: "계", upName: "ruseWater", upSequnce: 1 }, + { id: "ruse01", title: "1월", upName: "ruseWater", upSequnce: 2 }, + { id: "ruse02", title: "2월", upName: "ruseWater", upSequnce: 3 }, + { id: "ruse03", title: "3월", upName: "ruseWater", upSequnce: 4 }, + { id: "ruse04", title: "4월", upName: "ruseWater", upSequnce: 5 }, + { id: "ruse05", title: "5월", upName: "ruseWater", upSequnce: 6 }, + { id: "ruse06", title: "6월", upName: "ruseWater", upSequnce: 7 }, + { id: "ruse07", title: "7월", upName: "ruseWater", upSequnce: 8 }, + { id: "ruse08", title: "8월", upName: "ruseWater", upSequnce: 9 }, + { id: "ruse09", title: "9월", upName: "ruseWater", upSequnce: 10 }, + { id: "ruse10", title: "10월", upName: "ruseWater", upSequnce: 11 }, + { id: "ruse11", title: "11월", upName: "ruseWater", upSequnce: 12 }, + { id: "ruse12", title: "12월", upName: "ruseWater", upSequnce: 13 }, +]; + +export const splHeadListExport: TableUpperProps[] = [ + { id: "utztnUsgCd", title: "이용용도" }, + { id: "splTotal", title: "계", upName: "splWater", upSequnce: 1 }, + { id: "spl01", title: "1월", upName: "splWater", upSequnce: 2 }, + { id: "spl02", title: "2월", upName: "splWater", upSequnce: 3 }, + { id: "spl03", title: "3월", upName: "splWater", upSequnce: 4 }, + { id: "spl04", title: "4월", upName: "splWater", upSequnce: 5 }, + { id: "spl05", title: "5월", upName: "splWater", upSequnce: 6 }, + { id: "spl06", title: "6월", upName: "splWater", upSequnce: 7 }, + { id: "spl07", title: "7월", upName: "splWater", upSequnce: 8 }, + { id: "spl08", title: "8월", upName: "splWater", upSequnce: 9 }, + { id: "spl09", title: "9월", upName: "splWater", upSequnce: 10 }, + { id: "spl10", title: "10월", upName: "splWater", upSequnce: 11 }, + { id: "spl11", title: "11월", upName: "splWater", upSequnce: 12 }, + { id: "spl12", title: "12월", upName: "splWater", upSequnce: 13 }, +]; + +export const rswtDetailHeadListExport: TableUpperProps[] = [ + { id: "utztnUsgTest", title: "이용용도" }, + { + id: "avre", + title: "평균", + upName: "detailQulity", + upSequnce: 1, + edit: true, + }, + { + id: "grssClfg", + title: "총대장균군수", + upName: "detailQulity", + upSequnce: 2, + edit: true, + }, + { + id: "combResdch", + title: "결합잔류염소", + upName: "detailQulity", + upSequnce: 3, + edit: true, + }, + { + id: "trbt", + title: "탁도", + upName: "detailQulity", + upSequnce: 4, + edit: true, + }, + { id: "bod", title: "BOD", upName: "detailQulity", upSequnce: 5, edit: true }, + { + id: "smll", + title: "냄새", + upName: "detailQulity", + upSequnce: 6, + edit: true, + }, + { + id: "crmty", + title: "색도", + upName: "detailQulity", + upSequnce: 7, + edit: true, + }, + { id: "tn", title: "T-N", upName: "detailQulity", upSequnce: 8, edit: true }, + { id: "tph", title: "T-P", upName: "detailQulity", upSequnce: 9, edit: true }, + { id: "ph", title: "PH", upName: "detailQulity", upSequnce: 10, edit: true }, + { + id: "clIonQnt", + title: "염화물", + upName: "detailQulity", + upSequnce: 11, + edit: true, + }, +]; + diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index d544013d6..d3cc745ae 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -8,288 +8,20 @@ import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import type { SelectDataType } from "@common/business_components/ui"; import { z } from "zod"; import { buildingToExcelType } from "./excel"; +import { rainChkgdnHeadListExport, rainChkZod, rainHeadNmExport, rswtDetailHeadListExport, ruseHeadListExport, splHeadListExport, type chHeadType } from "./headList"; -const guideDetail = z.object({ - chkgdnFk: z.number().nullable(), - utztnUsgCd: z.string(), - chckYmd: z.string(), - ym: z.string(), - splyUswtrUtztnQnt: z.number(), - ruseFcltUtztnQnt: z.number(), - flg: z.string(), -}) -export const rainChkZod = z.object({ - chkgdnPk: z.number().nullable(), - bdstRuseFcltFk: z.number(), - chckYmd: z.string(), - prcsCpct: z.number().nullable(), - spwtPositn: z.string().nullable(), - regDt: z.string().nullable(), - rgtr: z.string().nullable(), - mdfcnDt: z.string().nullable(), - mdfr: z.string().nullable(), - flg: z.string().nullable(), - guideDetails: z.array( - guideDetail - ), - building: z.object({ - bdstInfoPk: z.number(), - ctpvCd: z.number(), - sggCd: z.number(), - daddr: z.string().nullable(), - bdstNm: z.string(), - frstArchPrmsnDt: z.string().nullable(), - archArea: z.number(), - regDt: z.string().nullable(), - rgtr: z.string().nullable(), - mdfcnDt: z.string().nullable(), - mdfr: z.string().nullable(), - }).nullable(), - rainyDetails: z.array( - z.object({ - chkgdnFk: z.number().nullable(), - utztnUsgCd: z.string(), - ph: z.number().nullable(), - trbt: z.number().nullable(), - grssClfg: z.number().nullable(), - etc: z.string().nullable(), - vltnDt: z.string().nullable(), - vltnMttr: z.string().nullable(), - levyAmt: z.number().nullable(), - regDt: z.string().nullable(), - rgtr: z.string().nullable(), - mdfcnDt: z.string().nullable(), - mdfr: z.string().nullable(), - }) - ), -}); export type rainChkZodType = z.infer<typeof rainChkZod>; - -export const rainRegExcel = z.object({ - bdstInfoPk: z.number().default(111111111), - chckYr: z.string() - .default("") - .refine( - (year) => year.length === 0 || /^\d{4}$/.test(year), - { message: "4자리 연도만 입력하세요" } - ) - .refine( - (year) => { - if (year.length === 0) return true; // 빈 문자열은 통과 - const numYear = Number(year); - return !isNaN(numYear) && numYear <= new Date().getFullYear(); - }, - { message: "현재 년도보다 높은 수를 입력할 수 없습니다." } - ), - file: z.instanceof(File).optional(), -}); - -export const fcltDiv = [ + const fcltDiv = [ { val: "RST", text: "중수도시설" }, { val: "RNB", text: "빗물이용시설" }, ]; -export type chHeadType = { - headNm: string; - text: string; - length: number; - rows?: number; -}; - -export const rainHeadNm: chHeadType[] = [ - { headNm: "useQuilty", text: "이용수질(필요시)", length: 4 }, - { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, - { headNm: "ruseWater", text: "연간보급수 이용량(m³)", length: 13 }, - { headNm: "detailQulity", text: "분기", length: 11 }, - { headNm: "splWater", text: "연간빗물 이용량(m³)", length: 13 }, - -]; - - -export const rainChkgdnHeadList: TableUpperProps[] = [ - { id: "order", title: "순번", rowSpan: true }, - { id: "cityText", title: "시도", rowSpan: true }, - { id: "sggText", title: "시군구", rowSpan: true }, - { id: "bdstNm", title: "시설명", rowSpan: true }, - { id: "operMngCd", title: "운영관리형태", rowSpan: true }, - { id: "oilqMeasMthd", title: "유량측정방법", rowSpan: true }, - { id: "anlOperCst", title: "연간운영비(원/년)", rowSpan: true }, - { id: "dtfcltCpct", title: "빗물저류조용량(m³)", rowSpan: true }, - { id: "chckYmd", title: "점검일", rowSpan: true }, - { id: "utztnUsgCd", title: "이용용도" }, - { id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, - { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" }, - { id: "ph", title: "PH", upName: "useQuilty", upSequnce: 1, type: "number" }, - { - id: "trbt", - title: "탁도", - upName: "useQuilty", - upSequnce: 2, - type: "number", - }, - { - id: "grssClfg", - title: "총대장균군수", - upName: "useQuilty", - upSequnce: 3, - type: "number", - }, - { - id: "etc", - title: "기타", - upName: "useQuilty", - upSequnce: 4, - type: "number", - }, - { - id: "vltnDt", - title: "부과일(위반일)", - upName: "feeHist", - upSequnce: 1, - type: "text", - }, - { - id: "vltnMttr", - title: "위반사항", - upName: "feeHist", - upSequnce: 2, - type: "text", - }, - { - id: "levyAmt", - title: "부과금액(천원)", - upName: "feeHist", - upSequnce: 3, - type: "number", - }, -]; - -export const ruseHeadList: TableUpperProps[] = [ - { id: "utztnUsgCd", title: "이용용도" }, - { id: "ruseTotal", title: "계", upName: "ruseWater", upSequnce: 1 }, - { id: "ruse01", title: "1월", upName: "ruseWater", upSequnce: 2 }, - { id: "ruse02", title: "2월", upName: "ruseWater", upSequnce: 3 }, - { id: "ruse03", title: "3월", upName: "ruseWater", upSequnce: 4 }, - { id: "ruse04", title: "4월", upName: "ruseWater", upSequnce: 5 }, - { id: "ruse05", title: "5월", upName: "ruseWater", upSequnce: 6 }, - { id: "ruse06", title: "6월", upName: "ruseWater", upSequnce: 7 }, - { id: "ruse07", title: "7월", upName: "ruseWater", upSequnce: 8 }, - { id: "ruse08", title: "8월", upName: "ruseWater", upSequnce: 9 }, - { id: "ruse09", title: "9월", upName: "ruseWater", upSequnce: 10 }, - { id: "ruse10", title: "10월", upName: "ruseWater", upSequnce: 11 }, - { id: "ruse11", title: "11월", upName: "ruseWater", upSequnce: 12 }, - { id: "ruse12", title: "12월", upName: "ruseWater", upSequnce: 13 }, -]; - -export const splHeadList: TableUpperProps[] = [ - { id: "utztnUsgCd", title: "이용용도" }, - { id: "splTotal", title: "계", upName: "splWater", upSequnce: 1 }, - { id: "spl01", title: "1월", upName: "splWater", upSequnce: 2 }, - { id: "spl02", title: "2월", upName: "splWater", upSequnce: 3 }, - { id: "spl03", title: "3월", upName: "splWater", upSequnce: 4 }, - { id: "spl04", title: "4월", upName: "splWater", upSequnce: 5 }, - { id: "spl05", title: "5월", upName: "splWater", upSequnce: 6 }, - { id: "spl06", title: "6월", upName: "splWater", upSequnce: 7 }, - { id: "spl07", title: "7월", upName: "splWater", upSequnce: 8 }, - { id: "spl08", title: "8월", upName: "splWater", upSequnce: 9 }, - { id: "spl09", title: "9월", upName: "splWater", upSequnce: 10 }, - { id: "spl10", title: "10월", upName: "splWater", upSequnce: 11 }, - { id: "spl11", title: "11월", upName: "splWater", upSequnce: 12 }, - { id: "spl12", title: "12월", upName: "splWater", upSequnce: 13 }, -]; - -export const rswtDetailHeadList: TableUpperProps[] = [ - { id: "utztnUsgTest", title: "이용용도" }, - { - id: "avre", - title: "평균", - upName: "detailQulity", - upSequnce: 1, - edit: true, - }, - { - id: "grssClfg", - title: "총대장균군수", - upName: "detailQulity", - upSequnce: 2, - edit: true, - }, - { - id: "combResdch", - title: "결합잔류염소", - upName: "detailQulity", - upSequnce: 3, - edit: true, - }, - { - id: "trbt", - title: "탁도", - upName: "detailQulity", - upSequnce: 4, - edit: true, - }, - { id: "bod", title: "BOD", upName: "detailQulity", upSequnce: 5, edit: true }, - { - id: "smll", - title: "냄새", - upName: "detailQulity", - upSequnce: 6, - edit: true, - }, - { - id: "crmty", - title: "색도", - upName: "detailQulity", - upSequnce: 7, - edit: true, - }, - { id: "tn", title: "T-N", upName: "detailQulity", upSequnce: 8, edit: true }, - { id: "tph", title: "T-P", upName: "detailQulity", upSequnce: 9, edit: true }, - { id: "ph", title: "PH", upName: "detailQulity", upSequnce: 10, edit: true }, - { - id: "clIonQnt", - title: "염화물", - upName: "detailQulity", - upSequnce: 11, - edit: true, - }, -]; - - - -export type splRuseWaterType = { - utztnUsgCd: string; - splTotal: number; - spl01: number; - spl02: number; - spl03: number; - spl04: number; - spl05: number; - spl06: number; - spl07: number; - spl08: number; - spl09: number; - spl10: number; - spl11: number; - spl12: number; - ruseTotal: number; - ruse01: number; - ruse02: number; - ruse03: number; - ruse04: number; - ruse05: number; - ruse06: number; - ruse07: number; - ruse08: number; - ruse09: number; - ruse10: number; - ruse11: number; - ruse12: number; -}; - - - + const rainHeadNm=rainHeadNmExport; + const rainChkgdnHeadList=rainChkgdnHeadListExport; + const ruseHeadList=ruseHeadListExport; + const splHeadList=splHeadListExport; + const rswtDetailHeadList=rswtDetailHeadListExport; const rainChk: rainChkZodType[] = []; @@ -303,6 +35,7 @@ export type rainChkgdnState = { rswtDetailHeadList: TableUpperProps[]; isInit: boolean; isModalClose: boolean; + fcltDiv:SelectDataType[] excelList: []; }; }; @@ -328,7 +61,8 @@ export const rainChkgdnStateExport: rainChkgdnState = { rswtDetailHeadList: rswtDetailHeadList, isInit: false, isModalClose: false, - excelList: [] + excelList: [], + fcltDiv:fcltDiv }, }; @@ -354,12 +88,7 @@ const initFetch = async (txt: string | undefined, sgg: string | undefined) => { "wr", `/reuseChk/rainy` + (txt ? `/${txt}` : "2024") + (sgg ? `/${sgg}` : "/0") ); - const chRainRes = rainRes.map((item: rainChkZodType) => { - return { - ...item, - }; - }); - return chRainRes; + return rainRes; }; export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( @@ -370,7 +99,7 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( // 로그인한 아이디의 시도 or 시군구로 들어가야하는데 현재는 그냥 0으로 하드코딩 const data = await getFetch(fetchType.WR, `/reuseFc/buildingFlg/${buildingType.RNB}/41`) - const excelList = buildingToExcelType(data, sidoCode, sggCode, buildingType.RNB); + const excelList = buildingToExcelType(data, sidoCode, sggCode); set((state: rainChkgdnState) => ({ rainChkgdn: { ...state.rainChkgdn, diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx new file mode 100644 index 000000000..5827dcbf5 --- /dev/null +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx @@ -0,0 +1,225 @@ +import type { SelectDataType } from "@common/business_components/ui"; +import { useTypes, type Buildingtype } from "../rainChkgdn/excel"; +import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import type { rswtChkZodType } from "."; + +export const rswtMakeExcelSample = ( + buildings: Buildingtype[], + sidoCode: SelectDataType[], + sggCdoe: SelectDataType[] +) => { + const excelSite = { + guideDetail: [] as string[][], + polutions: [] as string[][], + }; + //첫번째 시트 데이터 이용량 현황 양식만들기 + buildings.forEach((building) => { + useTypes.forEach((useType) => { + excelSite.guideDetail.push([ + building.bdstInfoPk.toString(), + sidoCode.find((sido) => sido.val === building.ctpvCd.toString()) + ?.text || "", + sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text || + "", + building.bdstNm, + building.daddr, + "", + "", + "", + "", + "", + useType, + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ]); + }); + }); + + //두번째 시트 양식 만들기 오염도 + buildings.forEach((building) => { + useTypes.forEach((useType) => { + excelSite.polutions.push([ + building.bdstInfoPk.toString(), + sidoCode.find((sido) => sido.val === building.ctpvCd.toString()) + ?.text || "", + sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text || + "", + building.bdstNm, + building.daddr, + "", + "", + "", + "", + useType, + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ]); + }); + }); + + return excelSite; +}; + +export const excelToRswtGuideData = (excelData: any, year: string) => { + const rainChkgdData: rswtChkZodType[] = excelData + .map((item: any) => { + if (item["점검일"] !== undefined) { + const makeGuidDetail = Array.from({ length: 12 }, (_, i) => { + let month = `${i + 1}`; + const splyData = item[`대체수_${month}월`]; + const rswtData = item[`중수_${month}월`]; + if (month.length < 2) month = "0" + month; + return { + ym: year + month, + chckYmd: item["점검일"], + splyUswtrUtztnQnt: splyData !== "" ? splyData : 0, + ruseFcltUtztnQnt: rswtData !== "" ? rswtData : 0, + }; + }); + + return { + bdstRuseFcltFk: Number(item["NO"]), + chckYmd: item["점검일"], + utztnUsgCd: item["이용용도"], + spwtPositn: item["유량측정방법"], + rgtr: TEST_UUID, + mdfr: TEST_UUID, + oilqMeasMthd: item["운영관리형태"], + anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0, + operMngCd: item["유량측정방법"], + guideDetails: makeGuidDetail, + + }; + } + }) + .filter((el: any) => el !== undefined); + return rainChkgdData; +}; + +export const excelToRswtPolution = (excelData: any, year: string) => { + const rainChkgdData: rswtChkZodType[] = excelData + .map((item: any) => { + if (item["점검일"] !== undefined) { + console.log("item ", item) + const makePoluttion = Array.from({ length: 4 }, (_, i) => { + let quarter = `${i+1}`; + const grssClfgUswtr = item[`${quarter}분기_총대장균군수`]; + const combResdch = item[`${quarter}분기_결합잔류염소`]; + const trbt = item[`${quarter}분기_탁도`]; + const bod = item[`${quarter}분기_BOD`]; + const smll = item[`${quarter}분기_냄새`]; + const crmty = item[`${quarter}분기_색도`]; + const tph = item[`${quarter}분기_T-P`]; + const tn = item[`${quarter}분기_T-N`]; + const ph = item[`${quarter}분기_PH`]; + const clIonQnt = item[`${quarter}분기_염화물`]; + + return { + + node: quarter, + chckYmd: item["점검일"], + grssClfgUswtr: grssClfgUswtr !== "" ? grssClfgUswtr : 0, + combResdch: combResdch !== "" ? combResdch : 0, + trbt: trbt !== "" ? trbt : 0, + bod: bod !== "" ? bod : 0, + smll: smll !== "" ? smll : 0, + crmty: crmty !== "" ? crmty : 0, + tph: tph !== "" ? tph : 0, + tn: tn !== "" ? tn : 0, + ph: ph !== "" ? ph : 0, + clIonQnt: clIonQnt !== "" ? clIonQnt : 0, + rgtr: TEST_UUID, + mdfr: TEST_UUID, + }; + }); + + return { + bdstRuseFcltFk: Number(item["NO"]), + chckYmd: item["점검일"], + utztnUsgCd: item["이용용도"], + spwtPositn: item["유량측정방법"], + rgtr: TEST_UUID, + mdfr: TEST_UUID, + oilqMeasMthd: item["운영관리형태"], + anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0, + operMngCd: item["유량측정방법"], + rswtrPolutions: makePoluttion, + rswtrDetails: [ + { + utztnUsgCd: item["이용용도"], + vltnDt: item["과태료 부과일(위반일)"], + vltnMttr: item["위반사항"], + levyAmt: Number(item["과태료 부과금액(천원)"]) ?? 0, + rgtr: TEST_UUID, + mdfr: TEST_UUID, + }, + ], + }; + } + }) + .filter((el: any) => el !== undefined); + return rainChkgdData; +}; diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx new file mode 100644 index 000000000..a23d168e7 --- /dev/null +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx @@ -0,0 +1,109 @@ +import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { z } from "zod"; +import { guideDetail, type chHeadType } from "../rainChkgdn/headList"; + + + + + +const rswtrPolutionsZode =z.object({ + chkgdnDtlFk: z.string().nullish(), + utztnUsgCd: z.string(), + node: z.string(), + grssClfgUswtr: z.string(), + combResdch: z.string(), + trbt: z.string(), + bod: z.string(), + smll: z.string(), + crmty: z.string(), + tph: z.string(), + tn: z.string(), + ph: z.string(), + clIonQnt: z.string(), + regDt: z.string(), + rgtr: z.string(), + mdfcnDt: z.string(), + mdfr: z.string(), +}) + +export const rswtChkgdZod = z.object({ + chkgdnPk: z.number().nullish(), + bdstRuseFcltFk: z.number().nullish(), + chckYmd: z.string(), + prcsCpct: z.number(), + dtfcltCpct: z.number(), + spwtPositn: z.string(), + regDt: z.string().nullish(), + rgtr: z.string().nullish(), + mdfcnDt: z.string().nullish(), + mdfr: z.string().nullish(), + flg: z.string().nullish(), + oilqMeasMthd: z.string().nullish(), + anlOperCst: z.number().nullish(), + operMngCd: z.string().nullish(), + utztnUsgCd: z.string(), + guideDetails: z.array( + guideDetail + ), + rswtrDetails: z.array( + z.object({ + chkgdnDtlPk: z.string().nullish(), + chkgdnFk: z.string().nullish(), + utztnUsgCd: z.string(), + vltnDt: z.string(), + vltnMttr: z.string(), + levyAmt: z.string(), + regDt: z.string().nullish(), + rgtr: z.string().nullish(), + mdfcnDt: z.string().nullish(), + mdfr: z.string().nullish(), + }) + ), + rswtrPolutions: z.array( + rswtrPolutionsZode + ), +}); + +export const rswtHeadNmExport: chHeadType[] = [ + { headNm: "useQuilty", text: "연간 평균 이용수질", length: 10 }, + { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, +]; + +export const rswtChkHeadListExport: TableUpperProps[] = [ + { id: "cityText", title: "시도" }, + { id: "sggText", title: "시군구" }, + { id: "bdstNm", title: "시설명" }, + { id: "operMngCd", title: "운영관리형태" }, + { id: "yearFee", title: "연간운영비(원/년)" }, + { id: "rainDtnbaOpct", title: "처리용량(m³)" }, + { id: "checkDay", title: "점검일" }, + { id: "checkPoint", title: "채수지점" }, + { id: "utztnUsg", title: "이용용도" }, + { id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, + { id: "rswtUsg", title: "연간중수도이용량(m³)" }, + + { + id: "grssClfgUswtr", + title: "총대장균군수", + upName: "useQuilty", + upSequnce: 1, + }, + { + id: "combResdch", + title: "결합잔류염소", + upName: "useQuilty", + upSequnce: 2, + }, + { id: "trbt", title: "탁도", upName: "useQuilty", upSequnce: 3 }, + { id: "bod", title: "BOD", upName: "useQuilty", upSequnce: 4 }, + { id: "smll", title: "냄새", upName: "useQuilty", upSequnce: 5 }, + { id: "crmty", title: "색도", upName: "useQuilty", upSequnce: 6 }, + { id: "tn", title: "T-N", upName: "useQuilty", upSequnce: 7 }, + { id: "tph", title: "T-P", upName: "useQuilty", upSequnce: 8 }, + { id: "ph", title: "PH", upName: "useQuilty", upSequnce: 9 }, + { id: "clIonQnt", title: "염화물", upName: "useQuilty", upSequnce: 10 }, + + { id: "dayFee", title: "부과일(위반일)", upName: "feeHist", upSequnce: 1 }, + { id: "guilty", title: "위반사항", upName: "feeHist", upSequnce: 2 }, + { id: "fee", title: "부과금액(천원)", upName: "feeHist", upSequnce: 3 }, +]; \ No newline at end of file diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx index 9ba3e1404..7ea3902f5 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx @@ -1,89 +1,135 @@ import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import type { chHeadType } from "../rainChkgdn"; -import type { SelectDataType } from "@common/business_components"; -import { fetchType, getFetch } from "@/components/lib/api"; -import { buildingToExcelType } from "../rainChkgdn/excel"; +import type { + SelectDataType, + sheetParameter, +} from "@common/business_components"; +import { fetchType, getFetch, postFectch } from "@/components/lib/api"; import { buildingType } from "@/app/store/common/code"; +import { rswtMakeExcelSample } from "./excel"; +import { + rswtChkgdZod, + rswtChkHeadListExport, + rswtHeadNmExport, +} from "./headList"; +import { z } from "zod"; +import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; +import { type chHeadType } from "../rainChkgdn/headList"; - - -export const rswtHeadNm:chHeadType[] = [ - {headNm:"useQuilty", text:"연간 평균 이용수질" , length: 10}, - {headNm:"feeHist", text:"과태료 부과내역" , length: 3}, -] -export const rswtChkgdnHeadList: TableUpperProps[] = [ - { id: "cityText", title: "시도" }, - { id: "sggText", title: "시군구" }, - { id: "bdstNm", title: "시설명" }, - { id: "operMngCd", title: "운영관리형태" }, - { id: "yearFee", title: "연간운영비(원/년)" }, - { id: "rainDtnbaOpct", title: "처리용량(m³)" }, - { id: "checkDay", title: "점검일" }, - {id: "checkPoint", title: "채수지점"}, - { id: "utztnUsg", title: "이용용도" }, - { id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, - { id: "rswtUsg", title: "연간중수도이용량(m³)" }, - - - { id: "grssClfgUswtr", title: "총대장균군수", upName: "useQuilty", upSequnce: 1 }, - { id: "combResdch", title: "결합잔류염소", upName: "useQuilty", upSequnce: 2 }, - { id: "trbt", title: "탁도", upName: "useQuilty", upSequnce: 3 }, - { id: "bod", title: "BOD", upName: "useQuilty", upSequnce: 4 }, - { id: "smll", title: "냄새", upName: "useQuilty", upSequnce: 5 }, - { id: "crmty", title: "색도", upName: "useQuilty", upSequnce: 6 }, - { id: "tn", title: "T-N", upName: "useQuilty", upSequnce: 7 }, - { id: "tph", title: "T-P", upName: "useQuilty", upSequnce: 8 }, - { id: "ph", title: "PH", upName: "useQuilty", upSequnce: 9 }, - { id: "clIonQnt", title: "염화물", upName: "useQuilty", upSequnce: 10 }, - - - - { id: "dayFee", title: "부과일(위반일)", upName: "feeHist", upSequnce: 1 }, - { id: "guilty", title: "위반사항", upName: "feeHist", upSequnce: 2 }, - { id: "fee", title: "부과금액(천원)", upName: "feeHist", upSequnce: 3 }, - - -]; +const rswtChkHeadList= rswtChkHeadListExport +const rswtHeadNm =rswtHeadNmExport +export type rswtChkZodType = z.infer<typeof rswtChkgdZod>; export type rswtChkgdnState = { rswtChkgdn: { - rswtChkgdnHeadList: TableUpperProps[]; - rswtHeadNm:chHeadType[]; + rswtChkHeadList: TableUpperProps[]; + rswtHeadNm: chHeadType[]; + excelList: [typeof sheetParameter]; + rswtChkRes:rswtChkZodType[] + isInit: boolean; }; }; type rswtChkgdnActions = { - rswtChkgdnInit: (sggCd: string, searchTxt: string, flag: string) => void; - rswtrChkExcelDownload(sidoCode: SelectDataType[],sggCode: SelectDataType[]): Promise<void> + rswtChkgdnInit: (year: string, sggCd: string) => void; + rswtrChkExcelDownload( + sidoCode: SelectDataType[], + sggCode: SelectDataType[] + ): Promise<void>; + rswtChkExceDataUpload: (excelData: rswtChkZodType[]) => void; }; export type rswtChkgdnType = rswtChkgdnState & rswtChkgdnActions; export const rswtChkgdnStateExport: rswtChkgdnState = { rswtChkgdn: { - rswtChkgdnHeadList: rswtChkgdnHeadList, - rswtHeadNm:rswtHeadNm + rswtChkHeadList: rswtChkHeadList, + rswtHeadNm: rswtHeadNm, + excelList: [{ data: [[]], headerNum: 0, headerRange: "A1:V3" }], + rswtChkRes:[], + isInit: false, + }, }; +const initFetch = async (year: string | undefined, sgg: string | undefined) => { + const rswtChkRes = await getFetch( + "wr", + `/reuseChk/reuseWater/` + (year ? `${year}` : "2024") + (sgg ? `/${sgg}` : "/0") + ); + return rswtChkRes; +}; + + export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( set: any ) => { - rswtrChkExcelDownload: async (sidoCode: SelectDataType[],sggCode: SelectDataType[]) => { - const data = await getFetch(fetchType.WR, `/reuseFc/buildingFlg/${buildingType.RST}/41`) - const excelList = buildingToExcelType(data, sidoCode, sggCode, buildingType.RST); - set((state: rswtChkgdnState) => ({ - rswtChkgdn: { - ...state.rswtChkgdn, - excelList:excelList - }, - })); - } - } return { - rswtChkgdnInit: async (sggCd: string, searchTxt: string, flg: string) => { + rswtrChkExcelDownload: async ( + sidoCode: SelectDataType[], + sggCode: SelectDataType[] + ) => { + const data = await getFetch( + fetchType.WR, + `/reuseFc/buildingFlg/${buildingType.RST}/41` + ); + const excelList: any = []; + const exceldata = rswtMakeExcelSample(data, sidoCode, sggCode); + excelList.push({ + data: exceldata.guideDetail, + headerNum: 0, + headerRange: "A1:AI1", + }); + excelList.push({ + data: exceldata.polutions, + headerNum: 0, + headerRange: "A1:AZ1", + }); + return set((state: rswtChkgdnState) => ({ + rswtChkgdn: { + ...state.rswtChkgdn, + excelList: excelList, + }, + })); + }, + rswtChkgdnInit: async (year: string, sggCd: string) => { + try { + const rswtChkRes = await initFetch( '2024',sggCd); + + return set((state: rswtChkgdnState) => ({ + ...state, + rswtChkgdn: { + ...state.rswtChkgdn, + rswtChkRes: rswtChkRes, + isInit:false, + }, + })); + } catch (error) { + console.log(error); + } + }, + rswtChkExceDataUpload: async (excelData: rswtChkZodType[]) => { + try { + const res = await postFectch("/reuseChk/reuseWater", excelData); + const rswtMessage: string[] = []; + if (res.ok) { + ToastFormUi({ + body: "지도점검 등록이 완료되었습니다.", + title: "지도점검 등록", + }); + } + // const rainChkRes = await initFetch('2024', '0'); + return set((state: rswtChkgdnState) => ({ + ...state, + rswtChkgdn: { + ...state.rswtChkgdn, + rswtMessage: rswtMessage, + // rainChk: rainChkRes, + }, + })); + } catch (error) { + console.log(error); + } }, - , }; }; diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index 08126336e..86a58d6c7 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -1,4 +1,5 @@ import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui"; @@ -7,9 +8,9 @@ import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui"; -export const rightTableData = (rainChk: rainChkZodType[]) => { +export const rainChkTableData = (chkData: rainChkZodType[]) => { // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 - const maketotal = rainChk.map((item: rainChkZodType) => { + const maketotal = chkData.map((item: rainChkZodType) => { const selectTotal = item.guideDetails.reduce((acc: any, cur: any) => { const code = cur.utztnUsgCd; const fk = cur.chkgdnFk; @@ -36,7 +37,7 @@ export const rightTableData = (rainChk: rainChkZodType[]) => { // 3. rainyDetails에 누계 정보 주입 const updatedRainyDetails: any[] = []; - rainChk.forEach((rd: rainChkZodType) => { + chkData.forEach((rd: rainChkZodType) => { rd.rainyDetails.forEach((rainyItem: any) => { const key = `${rainyItem.chkgdnFk}_${rainyItem.utztnUsgCd}`; const totals = flatTotalMap[key] || { @@ -57,6 +58,110 @@ export const rightTableData = (rainChk: rainChkZodType[]) => { return updatedRainyDetails; }; + + + + +export const rswtChkTableData = (chkData: rswtChkZodType[]) => { + // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 + const maketotal = makeTotalChk(chkData) + + // 2. 누계 정보들을 하나의 객체로 합치기 (평탄화) + const flatTotalMap = Object.assign({}, ...maketotal); + + // 3. rainyDetails에 누계 정보 주입 + + const updatedRainyDetails: any[] = []; + // chkData.forEach((rd: rswtChkZodType) => { + // rd.rswtrDetails.forEach((rswtItem: any) => { + // const keyGuide = `${rswtItem.chkgdnFk}_${rswtItem.utztnUsgCd}_guide`; + // const keyPolution = `${rswtItem.chkgdnFk}_${rswtItem.utztnUsgCd}_poliution`; + // const totalsGuide = flatTotalMap[keyGuide] || { + // totalSplyUswtrUtztnQnt: 0, + // totalRuseFcltUtztnQnt: 0, + // }; + + // updatedRainyDetails.push({ + // ...rd, + // ...rd.building, + // ...rswtItem, + // ...totalsGuide, + // averCombResdch:totalsGuide.averCombResdch/rswtItem + // totalsGuide.averTrbt:0, + // totalsGuide.averBod:0, + // totalsGuide.averSmll:0, + // totalsGuide.averCrmty:0, + // totalsGuide.averTph:0, + // totalsGuide.averTn:0, + // totalsGuide.averPh:0, + // totalsGuide.averClIonQnt:0, + // rowspan: rd.rswtrDetails?.length, + // }); + // }); + // }); + + return updatedRainyDetails; +}; + +const makeTotalChk=(chkData: rswtChkZodType[])=>{ + const maketotal = chkData.map((item: rswtChkZodType) => { + const selectTotalWater = item.guideDetails.reduce((acc: any, cur: any) => { + const code = cur.utztnUsgCd; + const fk = cur.chkgdnFk; + const flg = 'guide' + + const key = `${fk}_${code}_${flg}`; + acc[key] = acc[key] || { + totalSplyUswtrUtztnQnt: 0, + totalRuseFcltUtztnQnt: 0, + }; + + acc[key].totalSplyUswtrUtztnQnt += cur.splyUswtrUtztnQnt; + acc[key].totalRuseFcltUtztnQnt += cur.ruseFcltUtztnQnt; + + return acc; + }, {}); + const selectAverPolution = item.rswtrPolutions.reduce((acc: any, cur: any) => { + const code = cur.utztnUsgCd; + const fk = cur.chkgdnFk; + const flg = 'poliution' + + const key = `${fk}_${code}_${flg}`; + acc[key] = acc[key] || { + averCombResdch:0, + averTrbt:0, + averBod:0, + averSmll:0, + averCrmty:0, + averTph:0, + averTn:0, + averPh:0, + averClIonQnt:0, + node:0 + }; + + acc[key].averCombResdch+=cur.combResdch + acc[key].averTrbt+=cur.trbt + acc[key].averBod+=cur.bod + acc[key].averSmll+=cur.smll + acc[key].averCrmty+=cur.crmty + acc[key].averTph+=cur.tph + acc[key].averTn+=cur.tn + acc[key].averPh+=cur.ph + acc[key].averClIonQnt+=cur.clIonQnt + acc[key].nod+=1 + + return acc; + }, {}); + + + return {...selectTotalWater, ...selectAverPolution}; // 모든 키: `${chkgdnFk}_${utztnUsgCd}` 형태 + }); + return maketotal; +} + + + export const chRowspanTable = ( makeTableData: any[], headList: TableUpperProps[], @@ -90,7 +195,6 @@ export const chRowspanTable = ( renderedSet.add(rowIndex + i); } renderedMap.set(key, renderedSet); - return ( <TableCell key={key} diff --git a/apps/wr/components/lib/func/commom.tsx b/apps/wr/components/lib/func/commom.tsx index a91750fce..80b8ebf42 100644 --- a/apps/wr/components/lib/func/commom.tsx +++ b/apps/wr/components/lib/func/commom.tsx @@ -3,6 +3,8 @@ import { filePickedBlob, type SelectDataType, type ReturnType, + filePickedBlobArray, + sheetParameter, } from "@common/business_components/ui"; import type { RefObject } from "react"; @@ -62,7 +64,8 @@ export const excelDownload = ( excelList: [][], fileNm: string, sampleFile: string, - headerRange = "A1:V3" + headerRange = "A1:V3", + writeLine=4 ) => { if (excelList.length === 0) return; fetch(`/${sampleFile}`, {}).then(async (response) => { @@ -72,10 +75,29 @@ export const excelDownload = ( // 받은 파일 바인너리 처리 const blobRet = await response.arrayBuffer(); // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 - await filePickedBlob(blobRet, excelList, fileNm, 4, headerRange); + await filePickedBlob(blobRet, excelList, fileNm, writeLine, headerRange); }); }; +export const excelArrayDownload = ( + fileNm: string, + sampleFile: string, + sheetArray:[typeof sheetParameter] +) => { + if (!sheetArray) return; + fetch(`/${sampleFile}`, {}).then(async (response) => { + if (!response.ok) { + throw Error(response.statusText); + } + // 받은 파일 바인너리 처리 + const blobRet = await response.arrayBuffer(); + // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 + await filePickedBlobArray(blobRet, fileNm, sheetArray); + }); +}; + + + // onchange 텍스트를 숫자로 and ,제거 export const handleCommaNumberChange = ( e: React.ChangeEvent<HTMLInputElement>, diff --git a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx index ebbae3481..390e17318 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx @@ -1,14 +1,21 @@ import { useWrStore } from "@/app/store"; -import { rainRegExcel, type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import { excelToRainChkData } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel"; +import { chkgdRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; +import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; +import { + excelToRswtGuideData, + excelToRswtPolution, +} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel"; import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { filePicked, + filePickedArray, FileUpload, Form, FormField, FormUi, - Title + Title, } from "@common/business_components/ui"; import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -17,107 +24,199 @@ import { useForm } from "react-hook-form"; import type { z } from "zod"; export default function ChkgdExcel({ type }: { type: string }) { - const { rainChkExcelDataUPload } = useWrStore((state) => { - return state; - }); + const { + rswtChkgdn, + rainChkExcelDataUPload, + rswtChkExceDataUpload, + } = useWrStore((state) => { + return state; + }); const [files, setFiles] = useState<File[] | null>(null); - const [excelData , setExcelData] = useState<rainChkZodType[]>() - const defaultValues: z.infer<typeof rainRegExcel> = rainRegExcel.parse({}); + const [excelData, setExcelData] = useState< + rswtChkZodType[] | rainChkZodType[] + >(); + const [excelRswtData, setExcelRswtData] = useState<rswtChkZodType[]>(); - const form = useForm<z.infer<typeof rainRegExcel>>({ - resolver: zodResolver(rainRegExcel), + const defaultValues: z.infer<typeof chkgdRegExcel> = chkgdRegExcel.parse({}); + + const form = useForm<z.infer<typeof chkgdRegExcel>>({ + resolver: zodResolver(chkgdRegExcel), defaultValues: defaultValues, }); useEffect(() => { - if (files) { - const file = files[0]; - if(form.getValues("chckYr").length<1 ){ - ToastFormUi({body:"파일업로드 이전에 등록년도를 작성해주세요 " ,title:'지도점검 등록'}) - setFiles(null) - return - } - if (file) + if (files) { + const file = files[0]; + if (form.getValues("chckYr").length < 1) { + ToastFormUi({ + body: "파일업로드 이전에 등록년도를 작성해주세요 ", + title: "지도점검 등록", + }); + setFiles(null); + return; + } + if (file) + if (type === "RNB") { filePicked(file, 0).then((res) => { if (res !== undefined) - setExcelData(excelToRainChkData(res, form.getValues("chckYr"))) + setExcelData(excelToRainChkData(res, form.getValues("chckYr"))); }); - } + } else if (type === "RST") { + filePickedArray(file, 0).then((res) => { + if (res && res?.length > 1) { + const excelArray = []; + const guideData = excelToRswtGuideData( + res[0], + form.getValues("chckYr") + ); + const polutionData = excelToRswtPolution( + res[1], + form.getValues("chckYr") + ); + + + const keyGenerator = (item: rswtChkZodType) => + `${item.bdstRuseFcltFk}|${item.chckYmd}|${item.utztnUsgCd}`; + const totalData: rswtChkZodType[] = guideData.map((guide) => { + const fusion = polutionData.find( + (polution) => + guide.bdstRuseFcltFk === polution.bdstRuseFcltFk && + guide.chckYmd === polution.chckYmd && + guide.utztnUsgCd === polution.utztnUsgCd + ); + + if (fusion) { + return { + ...guide, + rswtrPolutions: fusion?.rswtrPolutions, + rswtrDetails:fusion?.rswtrDetails + }; + } else { + return { + ...guide, + }; + } + }); + const guideKey = new Set(guideData.map(keyGenerator)); + + const onlypolution = polutionData.filter( + (item) => !guideKey.has(keyGenerator(item)) + ); + + const listTotalData:rswtChkZodType[] =[ + ...totalData, + ...onlypolution + ] + + setExcelRswtData(listTotalData); + } + }); + } + } }, [files]); - - const onSubmit =(values: z.infer<typeof rainRegExcel>)=> { - if(values.chckYr ===''){ - ToastFormUi({body:"등록년도를 작성해주세요" ,title:'지도점검 등록'}) - return - }else if(excelData ===undefined || excelData?.length === 0 ){ - ToastFormUi({body:"빈 파일 및 파일 오류 입니다." ,title:'지도점검 등록'}) - return - } - if (excelData) { - rainChkExcelDataUPload(excelData); - } + + function findMatchingItems<T>( + arrayA: T[], + arrayB: T[], + keySelector: (item: T) => string, + condition?: (item: T) => boolean + ): T[] { + const bKeySet = new Set(arrayB.map(keySelector)); + return arrayA.filter( + (item) => + (!condition || condition(item)) && bKeySet.has(keySelector(item)) + ); } + + + const onSubmit = (values: z.infer<typeof chkgdRegExcel>) => { + if (values.chckYr === "") { + ToastFormUi({ body: "등록년도를 작성해주세요", title: "지도점검 등록" }); + return; + } + + if (type === "RNB") { + if (excelData === undefined || excelData?.length === 0) { + ToastFormUi({ + body: "빈 파일 및 파일 오류 입니다.", + title: "지도점검 등록", + }); + return; + } else { + rainChkExcelDataUPload(excelData as rainChkZodType[]); + } + } else if (type === "RST") { + if (excelRswtData === undefined || excelRswtData?.length === 0) { + ToastFormUi({ + body: "빈 파일 및 파일 오류 입니다.", + title: "중수지도점검 등록", + }); + return; + } else { + rswtChkExceDataUpload(excelRswtData as rswtChkZodType[]); + } + } + }; return ( <> <div> <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)}> - <div> - <Title - title={ - type === "RNB" - ? "빗물 이용시설" - : "중수도 이용시설" + "점검 결과등록" - } - > -
-
-

- {"○점검정보 입력"} -

+
+
+ +
+
+

+ {"○점검정보 입력"} +

- -
+ +
-
- ( - - - - )} - /> +
+ ( + + + + )} + /> - ( - - { - if(files) setFiles(files) - } } - fileTypes="xlsx" - > - - )} - /> -
- + ( + + { + if (files) setFiles(files); + }} + fileTypes="xlsx" + > + + )} + /> +
+
- ); } diff --git a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx index d6c332042..5e6727d56 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx @@ -2,9 +2,9 @@ import { useWrStore } from "@/app/store"; import { ScrollArea, Title, UiTable } from "@common/business_components/ui"; import { Button } from "@common/components/ui"; import { useEffect, useState } from "react"; -import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable"; +import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { const { rainChkgdn, rainChkDetilUpdate, rainChkGuidUpdate } = useWrStore( diff --git a/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx b/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx index 2ea483364..443757f98 100644 --- a/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx +++ b/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx @@ -7,7 +7,7 @@ import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import { useWrStore } from "@/app/store"; import { useEffect, useState } from "react"; import type { CommonTableProps } from "@/app/store/common/type/headder"; -import { rightTableData } from "@/components/lib/func/TableData"; +import { rainChkTableData } from "@/components/lib/func/TableData"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; export default function SttnDetailModal({ @@ -40,7 +40,7 @@ export default function SttnDetailModal({ formObj.reuseBuilding[0] && rainSttn.rainChkRes?.bdstRuseFcltFk ) { - const tableTotalData = rightTableData([rainSttn.rainChkRes]); + const tableTotalData = rainChkTableData([rainSttn.rainChkRes]); const data = tableTotalData.map((item) => { const obj = { totalSplyUswtrUtztnQnt: item.totalSplyUswtrUtztnQnt, @@ -72,7 +72,7 @@ export default function SttnDetailModal({ return (
- + 0?"h-[80vh]":"h-[70vh]"} > {type === "RNB" ? ( diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx index 4aa57fe5e..a26cf0541 100644 --- a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -5,7 +5,7 @@ import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn" import { tableData } from "@/components/lib/func/commom"; import { chRowspanTable, - rightTableData + rainChkTableData } from "@/components/lib/func/TableData"; import { Table, @@ -66,13 +66,11 @@ export default function RainChkgdTable({ rowspan: item.rainyDetails?.length, }; }); - const tableTotalData = rightTableData(rainChg) + const tableTotalData = rainChkTableData(rainChg) setMakeTableData(tableTotalData); }, [rainChkgdn.rainChk, code]); useEffect(() => { - - //데이터를 평탄화 한것중에 체크박스 선택한 테이블만 선택 const selectedData = makeTableData.filter((item) =>selectedIds.includes(item.chkgdnPk)); @@ -132,10 +130,6 @@ export default function RainChkgdTable({ } },[selectedIds]) - useEffect(() => { - - },[]) - return ( diff --git a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx index b378167cc..ebc7d020f 100644 --- a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx @@ -1,30 +1,79 @@ -'use client' +"use client"; import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; -import { UiTable } from "@common/business_components/ui"; +import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; +import { chRowspanTable } from "@/components/lib/func/TableData"; +import { Table, TableBody, TableHeader } from "@common/components/ui"; +import { useCallback, useState } from "react"; -export default function RswtChkgdTable() { +export default function RswtChkgdTable({ + detaiRswtlUpdate, + handleRswtClick = () => {}, + deleteRswtData, +}: { + detaiRswtlUpdate: (data: rswtChkZodType[]) => void; + handleRswtClick?: (data: any) => void; + deleteRswtData: (selectedIds: number[]) => void; +}) { + const { code, rswtChkgdn, rswtChkgdnInit } = useWrStore((state) => state); - const { rswtChkgdn} = useWrStore((state) => state); - const nodeList = headMakeprfmnc(rswtChkgdn?.rswtChkgdnHeadList , rswtChkgdn?.rswtHeadNm ); - + const [makeTableData, setMakeTableData] = useState([]); + const [selectedIds, setSelectedIds] = useState([]); + const [upRaintDetail, setUpRaintDetail] = useState([]); + const toggleSelection = (pk: number, checked: boolean) => { + setSelectedIds((prev) => + checked ? [...prev, pk] : prev.filter((item) => item !== pk) + ); + }; + const handleChange = ( + rowIndex: number, + field: keyof (typeof makeTableData)[0], + value: string | number + ) => { + setMakeTableData((prev) => + prev.map((row, idx) => { + return idx === rowIndex ? { ...row, [field]: value } : row; + }) + ); + }; - return( - <> - { } } onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - } } > - {nodeList} - - - ) -} \ No newline at end of file + + const handleCellClick = useCallback( + (index: number, headId: string) => { + if ( + headId === "totalSplyUswtrUtztnQnt" || + headId === "totalRuseFcltUtztnQnt" + ) { + handleRswtClick(makeTableData[index]); + } + }, + [makeTableData, handleRswtClick] + ); + + + + + return ( + <> +
+ + {headMakeprfmnc(rswtChkgdn?.rswtChkHeadList, rswtChkgdn?.rswtHeadNm)} + + + + {chRowspanTable( + makeTableData, + rswtChkgdn.rswtChkHeadList, + handleChange, + toggleSelection, + selectedIds, + handleCellClick + )} + +
+ + ); +} diff --git a/apps/wr/public/sample_rs_chk.xlsx b/apps/wr/public/sample_rs_chk.xlsx index e114862bd..1569fbbce 100644 Binary files a/apps/wr/public/sample_rs_chk.xlsx and b/apps/wr/public/sample_rs_chk.xlsx differ