diff --git a/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx index 233d2ed53..b252121dc 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx @@ -13,7 +13,6 @@ import { UiTable, } from "@common/business_components"; import { Button } from "@common/components"; -import { headMakeColSpan } from "../rainReg/page"; import ListDiv from "@common/business_components/ui/list_div"; import { useEffect, useState } from "react"; import { tableData } from "@/components/lib/func/commom"; @@ -22,6 +21,7 @@ import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import BdstChgModal from "@/components/ui/modal/bdstChgModal/bdstChgModal"; import { BdstReg } from "@/components/ui/modal/bdstRegModal/bdstRegModal"; import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +import { headMakeColSpan } from "../rainReg/TableHead"; export default function Home() { const { code, htdfl, initHtdfl } = useWrStore((state) => state); diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/TableHead.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/TableHead.tsx new file mode 100644 index 000000000..39137d364 --- /dev/null +++ b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/TableHead.tsx @@ -0,0 +1,30 @@ +import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { TableRow, TableHead } from "@common/components/ui"; + +export const headMakeColSpan = (upHeadList: TableUpperProps[]) => { + return ( + <> + + {upHeadList.map((head: TableUpperProps) => + !head.upSequnce ? ( + + {head.title} + + ) : head.upName === "upChangeRe" && head.upSequnce === 1 ? ( + + {"중축 개축 재축 "} + + ) : null + )} + + + {upHeadList.map((head: TableUpperProps) => + head.upName === "upChangeRe" ? ( + {head.title} + ) : null + )} + + + ); + }; + \ No newline at end of file diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx index 1434481be..30ddd1f4a 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx @@ -1,12 +1,11 @@ "use client"; import { useWrStore } from "@/app/store"; -import type { - chgBuilding, - customRainBdst, - TableUpperProps, +import { + type chgBuilding, + type customRainBdst, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { tableData } from "@/components/lib/func/commom"; -import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm"; +import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm"; import BdstChgModal from "@/components/ui/modal/bdstChgModal/bdstChgModal"; import { BdstReg } from "@/components/ui/modal/bdstRegModal/bdstRegModal"; import { @@ -21,46 +20,17 @@ import { UiTable, } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { Button, TableHead, TableRow } from "@common/components"; +import { Button } from "@common/components"; import { useEffect, useState } from "react"; -export const headMakeColSpan = (upHeadList: TableUpperProps[]) => { - return ( - <> - - {upHeadList.map((head: TableUpperProps) => - !head.upSequnce ? ( - - {head.title} - - ) : head.upName === "upChangeRe" && head.upSequnce === 1 ? ( - - {"중축 개축 재축 "} - - ) : null - )} - - - {upHeadList.map((head: TableUpperProps) => - head.upName === "upChangeRe" ? ( - {head.title} - ) : null - )} - - - ); -}; - -//------------------------------------------------------------------------------------------------------- - export default function Home() { - const { rain, code, init } = useWrStore((state) => { + const { rain, code, initRain, rainSearch, getRainData } = useWrStore((state) => { return state; }); const { rainRes } = rain; const [rainForm, setRainForm] = useState(); const [issNewReg, setIsNewReg] = useState(false); - + const [pageNation, setPageNation] = useState(1); const [bdstTable, setbdstTable] = useState(); const [searchTxt, setSearchTxt] = useState(); const [bdstChgProps, setBdstChgProps] = useState<{ @@ -68,16 +38,24 @@ export default function Home() { chgBuilding: chgBuilding[]; }>({ isOpen: false, chgBuilding: [] }); - const nodeList = headMakeColSpan(rain.upHeadList); useEffect(() => { if (!rain.isInit) { - init(undefined); + initRain('41'); } - }, [rain.isInit, init]); + }, [rain.isInit, initRain]); useEffect(() => { if (code.sggCd.length > 0) { - setbdstTable(tableData(rainRes, { code })); + const rainData = tableData(rainRes, { code }).map( + (item: customRainBdst) => { + return { + ...item, + bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N", + }; + } + ); + + setbdstTable(rainData); } }, [code, rainRes]); const cellClick: (val: number | undefined, headId: string) => void = ( @@ -103,8 +81,9 @@ export default function Home() { }; useEffect(() => { - console.log("rainForm", rainForm); - }, [rainForm]); + console.log("getPageNation", pageNation); + getRainData(pageNation, "41"); + }, [pageNation]); return ( <> @@ -115,7 +94,7 @@ export default function Home() { { @@ -123,24 +102,24 @@ export default function Home() { }} /> - +
- - + +
@@ -148,19 +127,19 @@ export default function Home() {
- + { cellClick(val, headId); }} + onPageChange={setPageNation} > - {nodeList} @@ -176,7 +155,7 @@ export default function Home() {
} - bodyClass="w-[90vw] max-w-none" + bodyClass="w-[30vw] max-w-none" open={issNewReg} onOpenChange={(open) => { setIsNewReg(open); diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx index bf15631d9..597973ac9 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx @@ -14,37 +14,46 @@ import { } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components"; -import { headMakeColSpan } from "../rainReg/page"; import { useEffect, useState } from "react"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import { tableData } from "@/components/lib/func/commom"; import RswtrRegForm from "@/components/ui/form/fcltReg/rswtrReg/rswtrRegForm"; import BdstChgModal from "@/components/ui/modal/bdstChgModal/bdstChgModal"; import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { headMakeColSpan } from "../rainReg/TableHead"; export default function Home() { - const { code, rswt, initRswt } = useWrStore((state) => state); - const nodeList = headMakeColSpan(rswt.upHeadList); + const { code, rswt, initRswt ,rswtBdstSearch,getRswtBdstData} = useWrStore((state) => state); const [rswtForm, setRswtForm] = useState(); const [searchTxt, setSearchTxt] = useState(); const [issNewReg, setIsNewReg] = useState(false); + const [pageNation, setPageNation] = useState(1); const [bdstTable, setbdstTable] = useState(); const [bdstChgProps, setBdstChgProps] = useState<{ isOpen: boolean; chgBuilding: chgBuilding[]; }>({ isOpen: false, chgBuilding: [] }); - const { rswtRes } = rswt; useEffect(() => { if (!rswt.isInit) { - initRswt(undefined); + initRswt('41'); } }, [rswt.isInit, initRswt]); useEffect(() => { if (code.sggCd.length > 0) { - setbdstTable(tableData(rswtRes, { code })); + const rswtData = tableData(rswtRes, { code }).map( + (item: customRswtBdst) => { + return { + ...item, + bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N", + bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd + }; + } + ); + console.log(rswtData) + setbdstTable(rswtData); } }, [code, rswtRes]); const cellClick: (val: number | undefined, headId: string) => void = ( @@ -69,6 +78,10 @@ export default function Home() { const bdstChgModal = (chgBuilding: chgBuilding[]) => { setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding }); }; + useEffect(() => { + getRswtBdstData(pageNation, "41"); + }, [pageNation]); + return ( <> @@ -93,7 +106,7 @@ export default function Home() { size={"sm"} className="mr-4 " onClick={(e) => { - initRswt(searchTxt || ""); + rswtBdstSearch(searchTxt || "",pageNation,'41'); }} > 조회 @@ -117,12 +130,12 @@ export default function Home() { - {nodeList} + cellClick={cellClick} + onPageChange={setPageNation} + >
diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx index b7f47f0ca..6c865932e 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx @@ -17,10 +17,10 @@ import HeadChModal from "@/components/ui/modal/headChModal/headChModal"; import { useState } from "react"; export default function PbnstSttn() { - const { code, sttnCommon } = useWrStore((state) => state); + const { code, rainSttn } = useWrStore((state) => state); const [isChHead, setIsChHead] = useState(false); - const nodeList = headMakeprfmnc(sttnCommon.pbnSttHeadList, sttnCommon.pbnSttHeadNm); + const nodeList = headMakeprfmnc(rainSttn.pbnSttHeadList, rainSttn.pbnSttHeadNm); return ( <> @@ -113,7 +113,7 @@ export default function PbnstSttn() { { - return ( - <> - {Array.from({ length: rowCount }).map((_, i) => ( - - - - - - { - upHeadList - .filter((head: TableTripleProps) => head.visible == true) - .map((head: TableTripleProps) => - !head.upSequnce[i] ? ( - - {head.title} - - ) : head.upSequnce[i] === 1 ? ( - ch.headNm === head.upName[i]) - ?.length - } - > - {makeHeadNm.find((ch) => ch.headNm === head.upName[i])?.text} - - ) : null - )} - - ))} - - {upHeadList - .map((head: TableTripleProps) => - makeHeadNm.find((ch) => ch.headNm === head?.upName[1] && head.visible ==true ) ? ( - - {head.title} - - ) : null - )} - - - ); -}; +import { Button } from "@common/components/ui"; +import { useCallback, useEffect, useRef, useState } from "react"; +import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; export default function RainSttn() { - const { code, rain, init, sttnCommon } = useWrStore((state) => state); - const { rainRes } = rain; - + const { code, rainSttn, rainSttnSearch } = + useWrStore((state) => state); + const { rainSttnRes } = rainSttn; const [isChHead, setIsChHead] = useState(false); - - const [bdstTable, setBdstTable] = useState(); - const [tableHead, setTableHead] = useState([]); - let nodeList = headMakeTriple( - sttnCommon.rainSttHeadList, - sttnCommon.rainSttHeadNm - ); + const ref = useRef({} as ReturnType); + const [bdstTable, setBdstTable] = useState(); useEffect(() => { - if (!rain.isInit) { - init(undefined); - } - }, [rain.isInit, init]); - - useEffect(() => { - if (code.sggCd.length > 0) { - const data = tableData(rainRes, { code }); - // data 는 위 JSON 객체라고 가정 - - console.log("sttnCommon " , sttnCommon.rainSttHeadList) - - const unVisibleHead = sttnCommon.rainSttHeadList.filter( - (item: TableTripleProps) => item.visible === false - ); - - console.log("unVisibleHead " , unVisibleHead) - const chData = data - .map((item:any) =>({ - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0].rainyObj - })).filter((item:any) => item.rainyObj !== undefined) - - console.log("chData " , chData) - - - setBdstTable( chData); - - - + if (!rainSttn.isInit) { + let con + if (ref.current.sigunValue != '0') { + con = ref.current.sigunValue + }else{ + con = ref.current.sidoValue } - - }, [code, rainRes,sttnCommon]); + rainSttnSearch('1', '20' ,con); + } + }, [rainSttn.isInit, rainSttnSearch]); + useEffect(() => { + + if (rainSttnRes.length > 0 && code.cityCd.length>0) { + const data = tableData(rainSttnRes, { code }); + const chData = data + .map((item: any) => ({ + + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].rainyObj, + // cityText:item.cityText, + // sggText:item.sggText, + // bdstNm: item.bdstNm, + // daddr:item.daddr, + // bdstUsgCd:item.bdstUsgCd, + // frstArchPrmsnDt:item.frstArchPrmsnDt, + // archArea:item.archArea, + // lawTrgtYn:item.lawTrgtYn, + // instlCmptnDt:item.instlCmptnDt, + // instlCst:item.instlCst, + + + + + })) + .filter((item: any) => item.rainyObj !== undefined); + + setBdstTable(chData); + } + }, [code, rainSttnRes, rainSttn.rainSttHeadList]); + + + useEffect(() =>{ +console.log(rainSttn.rainSttNodeList) + },[rainSttn.rainSttNodeList]) + + useEffect(() => { + if(rainSttn.excelList.length>0){ + + if (rainSttn.excelList.length === 0) return; + excelDownload(rainSttn.excelList , '빗물재이용시설 현황','sample_rainSttn.xlsx') + } + }, [rainSttn.excelList]); + const excelClick = useCallback((returnType:ReturnType) => { + + let con + if (returnType.sigunValue != '0') { + con = returnType.sigunValue + }else{ + con = returnType.sidoValue + } + rainSttnSearch('1', '10000' ,con); + },[rainSttnSearch]); return ( <>
- <SearchDiv> - <SearchFormLeft> - <SelectBox - className={"col-span-2 w-full h-full text-2xl"} - label={"권역"} - selectClass={""} - selectArray={code.yn} - onSelectValue={() => {}} - value={""} - /> - <SelectBox - className={"col-span-2 w-full h-full text-2xl"} - label={"단위유역"} - selectClass={""} - selectArray={code.yn} - onSelectValue={() => {}} - value={""} - /> - <SelectBox - className={"col-span-2 w-full h-full text-2xl"} - label={"중권역"} - selectClass={""} - selectArray={code.yn} - onSelectValue={() => {}} - value={""} - /> - <SelectBox - className={"col-span-2 w-full h-full text-2xl"} - label={"환경청"} - selectClass={""} - selectArray={code.yn} - onSelectValue={() => {}} - value={""} - /> - <SelectBox - className={"col-span-2 w-full h-full text-2xl"} - label={"시도"} - selectClass={""} - selectArray={code.yn} - onSelectValue={() => {}} - value={""} - /> - <SelectBox - className={"col-span-2 w-full h-full text-2xl"} - label={"시군구"} - selectClass={""} - selectArray={code.yn} - onSelectValue={() => {}} - value={""} - /> - </SearchFormLeft> - <SearchFormRight> - <div className="space-y"> - {/* 첫 줄: 버튼 3개 */} - <div className="flex flex-row space-x-2"> - <Button size={"sm"} onClick={(e) => {}}> - 조회 - </Button> - <Button size={"sm"} onClick={() => {}}> - 다운로드 - </Button> - </div> - <div className="flex flex-row space-x-2 pt-3"> - <Button - size={"sm"} - color="green" - onClick={() => { - setIsChHead(true); - }} - > - 조회항목설정 - </Button> - </div> - </div> - </SearchFormRight> - </SearchDiv> + <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> <div className="grid grid-cols-6 gap-4 "> @@ -220,7 +140,8 @@ export default function RainSttn() { <UiTable headName={[]} tableData={bdstTable || []} - headlist={sttnCommon.rainSttHeadList} + children={<HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList}/>} + headlist={rainSttn.rainSttHeadList} pageSize={0} total={0} cellClick={undefined} @@ -228,18 +149,17 @@ export default function RainSttn() { throw new Error("Function not implemented."); }} > - {nodeList} </UiTable> </ListDiv> </div> </div> - <UiModal + <UiModal open={isChHead} onOpenChange={() => { setIsChHead(!isChHead); }} bodyClass={""} - body={<HeadChModal type={'rain'}/>} + body={<HeadChModal type={"rain"} />} /> </ContentsDiv> </> diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx new file mode 100644 index 000000000..0d21b08e8 --- /dev/null +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx @@ -0,0 +1,53 @@ +import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { TableHead, TableRow } from "@common/components/ui"; + +export const headMakeprfmnc = ( + upHeadList: TableUpperProps[], + makeHeadNm: chHeadType[] + ) => { + return ( + <> + <TableRow> + {upHeadList + .map((head: TableUpperProps) => + !head.upSequnce ? ( + <TableHead + className={`border border-gray-600 px-2 py-1 `} + rowSpan={2} + key={head.id} + > + {head.title} + </TableHead> + ) : head.upSequnce === 1 ? ( + <TableHead + className={`border border-gray-600 px-2 py-1 `} + key={head.id} + rowSpan={1} + colSpan={ + makeHeadNm.find((ch) => ch.headNm === head.upName)?.length + } + > + {makeHeadNm.find((ch) => ch.headNm === head.upName)?.text} + </TableHead> + ) : null + )} + </TableRow> + + <TableRow> + {upHeadList + .filter((data) => data.visible != false) + .map((head: TableUpperProps) => + makeHeadNm.find((ch) => ch.headNm === head.upName) ? ( + <TableHead + className={`border border-gray-600 px-2 py-1 `} + key={head.id} + > + {head.title} + </TableHead> + ) : null + )} + </TableRow> + </> + ); + }; \ No newline at end of file diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index 7aef0b4e8..fc8fb1e0a 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -3,13 +3,13 @@ import { useWrStore } from "@/app/store"; import { fcltDiv, - type chHeadType, - type rainChkZodType, + type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { excelDownload } from "@/components/lib/func/commom"; import ChkgdExcel from "@/components/ui/modal/chkgdExcel/chkgdExcel"; import ChkgdModal from "@/components/ui/modal/chkgdModal/chkgdModal"; import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable"; +import RainChkgdTableModal from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTableModal"; import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable"; import { ContentsDiv, @@ -22,85 +22,63 @@ import { UiModal } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { TableHead, TableRow } from "@common/components"; import { Button } from "@common/components/ui"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; +import { Toaster } from "react-hot-toast"; -export const headMakeprfmnc = ( - upHeadList: TableUpperProps[], - makeHeadNm: chHeadType[] -) => { - return ( - <> - <TableRow> - {upHeadList - .map((head: TableUpperProps) => - !head.upSequnce ? ( - <TableHead - className={`border border-gray-600 px-2 py-1 `} - rowSpan={2} - key={head.id} - > - {head.title} - </TableHead> - ) : head.upSequnce === 1 ? ( - <TableHead - className={`border border-gray-600 px-2 py-1 `} - key={head.id} - rowSpan={1} - colSpan={ - makeHeadNm.find((ch) => ch.headNm === head.upName)?.length - } - > - {makeHeadNm.find((ch) => ch.headNm === head.upName)?.text} - </TableHead> - ) : null - )} - </TableRow> - - <TableRow> - {upHeadList - .filter((data) => data.visible != false) - .map((head: TableUpperProps) => - makeHeadNm.find((ch) => ch.headNm === head.upName) ? ( - <TableHead - className={`border border-gray-600 px-2 py-1 `} - key={head.id} - > - {head.title} - </TableHead> - ) : null - )} - </TableRow> - </> - ); -}; //----------------------- export default function Page() { - const { rainChkgdn, rainChkInit,rainChkDetilUpdate } = useWrStore((state) => { + const { code, rainChkgdn, rainChkInit,rainChkDetilUpdate, rainChkDelete , rainChkExcelDownload } = useWrStore((state) => { return state; }); - - const [isDetail, setIsDetail] = useState(false); - const [isExcel, setIsExcel] = useState(false); + const [isRegExcel, setIsRegExcel] = useState(false); const [searchTxt, setSearchTxt] = useState<string>(); - const [testObj, setTestObj] = useState({}); 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,'41') + rainChkInit(searchTxt,'0') }; useEffect(() => { if (!rainChkgdn.isInit) { rainChkInit('2024','0'); + setIsModal({data:{}, open:rainChkgdn.isModalClose }) + setIsRegExcel(false) } }, [rainChkgdn.isInit, rainChkInit]); + + useEffect(() => { + excelDownload(rainChkgdn.excelList ,'빗물이용시설 지도점검','sample_rainy.xlsx', 'A1:AN1'); + }, [rainChkgdn.excelList]); + + const excelClick= useCallback(()=>{ + rainChkExcelDownload(code.cityCd, code.sggCd); + }, [rainChkExcelDownload, code.cityCd, code.sggCd]); + + + + const handleClick = useCallback((data:any) => { + if(data) setIsModal({ open: true, data: data }); + }, [isModal]); + + const clickDelete=(data:number[])=>{ + if(data.length>0){ + data.forEach((data) =>{ + rainChkDelete( String(data) ) + }) + } + } + + return ( <ContentsDiv> <div className="grid grid-cols-4 gap-4 "> @@ -109,7 +87,7 @@ export default function Page() { <SearchDiv> <SearchFormLeft> <SearchInput - className="col-span-3 my-7" + className="col-span-3 my-7 !text-xl" label=" 지도점검년도" textValue={searchTxt??''} setText={(e) => {setSearchTxt(e);}} @@ -134,7 +112,7 @@ export default function Page() { > 조회 </Button> - <Button size={"sm"} onClick={() => {}}> + <Button size={"sm"} onClick={() => { clickDelete(deleteIdx) }}> 삭제 </Button> <Button size={"sm"} onClick={() => { rainChkDetilUpdate( updateRainDetail as rainChkZodType[]) }}> @@ -142,15 +120,13 @@ export default function Page() { </Button> </div> <div className="flex flex-row space-x-2 pt-3"> - <Button size={"sm"} onClick={() => {}}> + <Button size={"sm"} onClick={() => {setIsRegExcel(!isRegExcel)}}> 결과등록 </Button> <Button color="green" size={"sm"} - onClick={() => { - setIsExcel(!isDetail); - }} + onClick={excelClick} > 양식받기 </Button> @@ -163,24 +139,25 @@ export default function Page() { <div className="grid grid-cols-6 gap-4 "> <div className="col-span-6"> <ListDiv> - {selFcltDiv === "RNB" ? <RainChkgdTable detailUp={setUpdateRainDetail} /> : <RswtChkgdTable />} + {selFcltDiv === "RNB" ? <RainChkgdTable deleteData={setDeleteIdx} detailUp={setUpdateRainDetail} handleClick={handleClick} /> : <RswtChkgdTable />} </ListDiv> </div> </div> - <UiModal - open={isDetail} - onOpenChange={setIsDetail} - bodyClass={"w-[40vw] max-w-none"} - body={<ChkgdModal type={selFcltDiv} obj={testObj}></ChkgdModal>} - /> - + open={isModal.open} + onOpenChange={() => { + setIsModal({ open: !open, data: {} }); + }} + bodyClass={"w-[80vw] max-w-none"} + body={<ChkgdModal type={"RNB"} obj={isModal.data} />} + ></UiModal> <UiModal - open={isExcel} - onOpenChange={setIsExcel} + open={isRegExcel} + onOpenChange={setIsRegExcel} bodyClass={"w-[40vw] max-w-none"} body={<ChkgdExcel type={selFcltDiv}></ChkgdExcel>} /> + <Toaster position="top-center" /> </ContentsDiv> ); } diff --git a/apps/wr/app/store/common/code/index.ts b/apps/wr/app/store/common/code/index.ts index 2a9e77d8e..e5f25e318 100644 --- a/apps/wr/app/store/common/code/index.ts +++ b/apps/wr/app/store/common/code/index.ts @@ -1,38 +1,37 @@ import { getFetch } from "@/components/lib/api"; +import type { EnvPartSelectDataType, SelectDataType } from "@common/business_components/ui"; -// Description: 공통코드 -export type selectArray = { - text: string; - val: string | number; - adstDliStrCd?: string -}; -export const yn :selectArray[]=[ + +export const btnClass= "p-4 m-2 text-white rounded-sm text-lg font-medium " + + const yn :SelectDataType[]=[ {val:'Y', text:'Y'}, {val:'N', text:'N'}, ] //공통 건축물 용도 -export const bdstUsgCd: selectArray[] = [ - { val: 1, text: "운동장" }, - { val: 2, text: "체육관" }, - { val: 3, text: "공공업무시설" }, - { val: 4, text: "공공기관의청사" }, - { val: 5, text: "아파트" }, - { val: 6, text: "연립주택" }, - { val: 7, text: "다세대주택" }, - { val: 8, text: "기숙사" }, - { val: 9, text: "초등학교" }, - { val: 10, text: "중학교" }, - { val: 11, text: "고등학교" }, - { val: 12, text: "전문대학" }, - { val: 13, text: "대학및대학교" }, - { val: 14, text: "골프장" }, - { val: 15, text: "대규모점포" }, - { val: 16, text: "기타" }, + const bdstUsgCd: SelectDataType[] = [ + { val: '-1', text: "확인불가" }, + { val: '1', text: "운동장" }, + { val: '2', text: "체육관" }, + { val: '3', text: "공공업무시설" }, + { val: '4', text: "공공기관의청사" }, + { val: '5', text: "아파트" }, + { val: '6', text: "연립주택" }, + { val: '7', text: "다세대주택" }, + { val: '8', text: "기숙사" }, + { val: '9', text: "초등학교" }, + { val: '10', text: "중학교" }, + { val: '11', text: "고등학교" }, + { val: '12', text: "전문대학" }, + { val: '13', text: "대학및대학교" }, + { val: '14', text: "골프장" }, + { val: '15', text: "대규모점포" }, + { val: '16', text: "기타" }, ]; //빗물 집수면 종류 용도 -export const rainFcltCd = [ + const rainFcltCd = [ { val: "1", text: "지붕" }, { val: "2", text: "건물옥상" }, { val: "3", text: "골프장 연못" }, @@ -45,36 +44,36 @@ export const rainFcltCd = [ { val: "10", text: "확인불가" }, ]; // 중수도 필수 원수종류 -export const rswtBdstType: selectArray[] = [ - { text: "숙박업", val: 17 }, - { text: "목욕장업", val: 18 }, - { text: "공장", val: 19 }, - { text: "발전시설", val: 20 }, - { text: "관광단지개발사업", val: 21 }, - { text: "도시개발사업", val: 22 }, - { text: "산업단지개발사업", val: 23 }, - { text: "택지개발사업", val: 24 }, - { text: "대규모점포(대형마트)", val: 25 }, - { text: "대규모점포(전문점)", val: 26 }, - { text: "대규모점포(백화점)", val: 27 }, - { text: "대규모점포(쇼핑센터)", val: 28 }, - { text: "대규모점포(복합쇼핑몰)", val: 29 }, - { text: "물류시설", val: 30 }, - { text: "운수시설(여객자동차터미널)", val: 31 }, - { text: "운수시설(철도시설)", val: 32 }, - { text: "운수시설(공항시설)", val: 33 }, - { text: "운수시설(항만시설)", val: 34 }, - { text: "업무시설(공공업무시설)", val: 35 }, - { text: "업무시설(금융업소)", val: 36 }, - { text: "업무시설(사무소)", val: 37 }, - { text: "업무시설(결혼상담소 등 소개업소)", val: 38 }, - { text: "업무시설(출판사)", val: 39 }, - { text: "업무시설(신문사)", val: 40 }, - { text: "업무시설(오피스텔)", val: 41 }, - { text: "교정시설", val: 42 }, - { text: "방송국", val: 43 }, - { text: "전신전화국", val: 44 }, - { text: "기타", val: 45 }, + const rswtBdstType: SelectDataType[] = [ + { text: "숙박업", val: "17" }, + { text: "목욕장업", val: "18" }, + { text: "공장", val: "19" }, + { text: "발전시설", val: "20" }, + { text: "관광단지개발사업", val: "21" }, + { text: "도시개발사업", val: "22" }, + { text: "산업단지개발사업", val: "23" }, + { text: "택지개발사업", val: "24" }, + { text: "대규모점포(대형마트)", val: "25" }, + { text: "대규모점포(전문점)", val: "26" }, + { text: "대규모점포(백화점)", val: "27" }, + { text: "대규모점포(쇼핑센터)", val: "28" }, + { text: "대규모점포(복합쇼핑몰)", val: "29" }, + { text: "물류시설", val: "30" }, + { text: "운수시설(여객자동차터미널)", val: "31" }, + { text: "운수시설(철도시설)", val: "32" }, + { text: "운수시설(공항시설)", val: "33" }, + { text: "운수시설(항만시설)", val: "34" }, + { text: "업무시설(공공업무시설)", val: "35" }, + { text: "업무시설(금융업소)", val: "36" }, + { text: "업무시설(사무소)", val: "37" }, + { text: "업무시설(결혼상담소 등 소개업소)", val: "38" }, + { text: "업무시설(출판사)", val: "39" }, + { text: "업무시설(신문사)", val: "40" }, + { text: "업무시설(오피스텔)", val: "41" }, + { text: "교정시설", val: "42" }, + { text: "방송국", val: "43" }, + { text: "전신전화국", val: "44" }, + { text: "기타", val: "45" } ]; const orgwtKndCd = [ @@ -85,7 +84,7 @@ const orgwtKndCd = [ { text: "기타", val: "5" }, ]; -export const chBuCd = [ + const chBuCd = [ { val: "증축", text: "증축" }, { val: "개축", text: "개축" }, { val: "재축", text: "재축" }, @@ -96,23 +95,17 @@ export const chBuCd = [ export type comCodeState = { code: { isInit: boolean; - chBuCd:selectArray[] - rainFcltCd: selectArray[]; - bdstUsgCd: selectArray[]; - cityCd: selectArray[]; - sggCd: selectArray[]; - - rvbsnCd:selectArray[]; - mdmbsnCd:selectArray[]; - lgbsnCd:selectArray[]; - lclgvrnmntCd:selectArray[]; - - - - - - orgwtKndCd:selectArray[]; - yn:selectArray[]; + chBuCd:SelectDataType[] + rainFcltCd: SelectDataType[]; + bdstUsgCd: SelectDataType[]; + cityCd: SelectDataType[]; + sggCd: SelectDataType[]; + rvbsnCd:SelectDataType[]; + mdmbsnCd:SelectDataType[]; + lgbsnCd:SelectDataType[]; + lclgvrnmntCd:EnvPartSelectDataType[]; + orgwtKndCd:SelectDataType[]; + yn:SelectDataType[]; }; }; @@ -121,7 +114,7 @@ export type comCodeType = comCodeState & comCodeActions; export const getSggCd = async (set: any) => { const sgg = await getFetch("common", "/addr/sgg"); const sggCd = sgg.map((item: any) => ({ - val: Number(item.adstDstrCd), + val:item.adstDstrCd, text: item.gugun, })); set((state: comCodeState) => ({ @@ -134,10 +127,10 @@ export const getSggCd = async (set: any) => { export const getCityCd = async (set: any) => { const city = await getFetch("common", "/addr/city"); const cityCd = city.map((item: any) => ({ - val: Number(item.adstDstrCd), + val: item.adstDstrCd, text: item.sido, })); - cityCd.unshift({val:0,text:'전체'}) + cityCd.unshift({val:'0',text:'전체'}) set((state: comCodeState) => ({ code: { ...state.code, @@ -151,10 +144,10 @@ export const getRegionCd = async (set: any) => { try{ const rvbsn = await getFetch("common", "/addr/sarea"); const rvbsnCd = rvbsn.map((item: any) => ({ - val: Number(item.rvbsnCd), + val: item.rvbsnCd, text: item.rvbsn, })); - rvbsnCd.unshift({val:0,text:'전체'}) + rvbsnCd.unshift({val:'0',text:'전체'}) set((state: comCodeState) => ({ code: { ...state.code, @@ -171,10 +164,10 @@ export const getMiddleRegionCd = async (set: any) => { try{ const mdmbsn = await getFetch("common", "/addr/midArea"); const mdmbsnCd = mdmbsn.map((item: any) => ({ - val: Number(item.rvbsnCd), + val: item.rvbsnCd, text: item.mdmbsn, })); - mdmbsnCd.unshift({val:0,text:'전체'}) + mdmbsnCd.unshift({val:'0',text:'전체'}) set((state: comCodeState) => ({ code: { ...state.code, @@ -192,10 +185,10 @@ export const getUnitWaterShedCd =async (set: any) => { try{ const lgbsn = await getFetch("common", "/addr/largeArea"); const lgbsnCd = lgbsn.map((item: any) => ({ - val: Number(item.rvbsnCd), + val: item.rvbsnCd, text: item.lgbsn, })); - lgbsnCd.unshift({val:0,text:'전체'}) + lgbsnCd.unshift({val:'0',text:'전체'}) set((state: comCodeState) => ({ code: { ...state.code, @@ -214,11 +207,12 @@ export const getEnvPartCd =async (set: any) => { try{ const lclgvrnmnt = await getFetch('common', '/addr/govArea'); const lclgvrnmntCd = lclgvrnmnt.map((item: any) => ({ - val: Number(item.lclgvrnmntCd), + val: item.lclgvrnmntCd, text: item.lclgvrnmntNm, - adstDliStrCd:item.adstDliStrCd + adstDliStrCd: item.adstDliStrCd || '' + })); - lclgvrnmntCd.unshift({val:0,text:'전체' ,adstDliStrCd:''}) + lclgvrnmntCd.unshift({val:'0',text:'전체' ,adstDliStrCd: '' }) set((state: comCodeState) => ({ code: { ...state.code, @@ -245,7 +239,8 @@ export const comCodeStateExport: comCodeState = { mdmbsnCd:[], lgbsnCd:[], lclgvrnmntCd:[], - yn:yn + yn:yn, + }, }; @@ -262,13 +257,13 @@ export const codeActionExport: (set: any) => comCodeActions = (set: any) => { const sgg = await getFetch("common", "/addr/sgg"); const sggCd = sgg.map((item: any) => ({ - val: Number(item.adstDstrCd), + val: item.adstDstrCd, text: item.gugun, })); const city = await getFetch("common", "/addr/city"); const cityCd = city.map((item: any) => ({ - val: Number(item.adstDstrCd), + val: item.adstDstrCd, text: item.sido, })); @@ -281,11 +276,11 @@ export const codeActionExport: (set: any) => comCodeActions = (set: any) => { })); }, - divCityCd: async(cd: number) => { + divCityCd: async(cd: string) => { set((state: comCodeState) => ({ code: { ...state.code, - sggCd:state.code.sggCd.filter((item) => { return Number(item.val.toString().slice(0,2)) === cd }), + sggCd:state.code.sggCd.filter((item) => { return item.val.toString().slice(0,2) === cd }), }, })); }, diff --git a/apps/wr/app/store/common/type/headder.tsx b/apps/wr/app/store/common/type/headder.tsx new file mode 100644 index 000000000..e11fae01c --- /dev/null +++ b/apps/wr/app/store/common/type/headder.tsx @@ -0,0 +1,23 @@ +export type CommonTableProps = { + id: string; + title: string; + upName?: string; + upSequnce?: number; + row?: number; + rowSpan?: number; + colSpan?: number; + visible?: boolean; +}; + +export type TableUpperProps = { + id: string; + title: string; + upName?: string; + upSequnce?: number; + edit?:boolean; + visible?:boolean; + rowSpan?: true; + type?: string; + }; + + \ No newline at end of file diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx new file mode 100644 index 000000000..d6c8d8345 --- /dev/null +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -0,0 +1,133 @@ +import type { SelectDataType } from "@common/business_components"; +import type { rainChkZodType } from "."; +import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { excelSerialToDateString } from "@/components/lib/func/commom"; +const useTypes = [ + "조경용수", + "청소화장실용수", + "세척살수용수", + "농업용수", + "공업용수", + "친수용수", + "기타", +]; + +export type Buildingtype = { + bdstInfoPk: number; + ctpvCd: 1; + sggCd: 1001; + daddr: "string3"; + bdstNm: "string"; + frstArchPrmsnDt: "2025-03-25"; + archArea: 0; + regDt: "2025-04-16"; + rgtr: null; + mdfcnDt: "2025-04-16"; + mdfr: null; +}; + +export const buildingToExcelType = ( + buildings: Buildingtype[], + sidoCode: SelectDataType[], + sggCdoe: SelectDataType[] +) => { + const excelData: string[][] = []; + 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, + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ]); + }); + }); + return excelData; +}; + +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}`; + const splyData = item[`보급_${month}월`]; + const ruseData = item[`빗물_${month}월`]; + if (month.length < 2) month = "0" + month; + return { + utztnUsgCd: item["이용용도"], + ym: year + month, + chckYmd: item["점검일"] , + splyUswtrUtztnQnt: splyData !== "" ? splyData : 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, + }, + ], + }; + }); + + return rainChkgdData; +}; diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index 9b26b68f3..9f51eed50 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -2,30 +2,35 @@ import { TEST_UUID, type TableUpperProps, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { getFetch, postFectch, putFectch } from "@/components/lib/api"; +import { deleteFectch, fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api"; +import type { SelectDataType } from "@common/business_components/ui"; import { z } from "zod"; +import { buildingToExcelType, excelToRainChkData } from "./excel"; +import toast from "react-hot-toast"; +import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; +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(), + chkgdnPk: z.number().nullable(), bdstRuseFcltFk: z.number(), chckYmd: z.string(), - prcsCpct: z.number(), - spwtPositn: z.string(), - regDt: z.string(), - rgtr: 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(), + flg: z.string().nullable(), guideDetails: z.array( - z.object({ - chkgdnFk: z.number(), - utztnUsgCd: z.string(), - chckYmd: z.string(), - ym: z.string(), - splyUswtrUtztnQnt: z.number(), - ruseFcltUtztnQnt: z.number(), - flg: z.string(), - }) + guideDetail ), building: z.object({ bdstInfoPk: z.number(), @@ -39,20 +44,20 @@ export const rainChkZod = z.object({ rgtr: z.string().nullable(), mdfcnDt: z.string().nullable(), mdfr: z.string().nullable(), - }), + }).nullable() , rainyDetails: z.array( z.object({ - chkgdnFk: z.number(), + chkgdnFk: z.number().nullable(), utztnUsgCd: z.string(), - ph: z.number(), - trbt: z.number(), - grssClfg: z.number(), - etc: z.string(), - vltnDt: z.string(), - vltnMttr: z.string(), - levyAmt: z.number(), - regDt: z.string(), - rgtr: 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(), }) @@ -63,9 +68,22 @@ export type rainChkZodType = z.infer<typeof rainChkZod>; export const rainRegExcel = z.object({ bdstInfoPk: z.number().default(111111111), - chckYmd: z.date().default(new Date()), - file: z.instanceof(File).optional(), -}); + 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 = [ { val: "RST", text: "중수도시설" }, @@ -88,15 +106,16 @@ export const rainHeadNm: chHeadType[] = [ ]; + 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: "flowCheck", title: "유량측정방법", rowSpan: true }, - { id: "yearFee", title: "연간운영비(원/년)", rowSpan: true }, - { id: "rainDtnbaOpct", title: "빗물저류조용량(m³)", 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³)" }, @@ -283,6 +302,8 @@ export type rainChkgdnState = { splHeadList: TableUpperProps[]; rswtDetailHeadList: TableUpperProps[]; isInit: boolean; + isModalClose:boolean; + excelList:[]; }; }; @@ -290,6 +311,9 @@ type rainChkgdnActions = { rainChkInit: (sggCd: string, searchTxt: string) => void; rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise<void>; rainChkGuidUpdate(rainChk: rainChkZodType): Promise<void>; + rainChkExcelDownload(sidoCode: SelectDataType[],sggCode: SelectDataType[]): Promise<void> + rainChkExcelDataUPload(excelData:rainChkZodType[]) : Promise<void> + rainChkDelete(chkgdnPk:string) :Promise<void> }; export type rainChkgdnType = rainChkgdnState & rainChkgdnActions; @@ -303,6 +327,8 @@ export const rainChkgdnStateExport: rainChkgdnState = { ruseHeadList: ruseHeadList, rswtDetailHeadList: rswtDetailHeadList, isInit: false, + isModalClose:false, + excelList:[] }, }; @@ -340,6 +366,37 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( set: any ) => { return { + rainChkExcelDownload:async(sidoCode:SelectDataType[], sggCode:SelectDataType[])=>{ + const data = await getFetch(fetchType.WR, "/reuseFc/building/RNB/0") + // const excelList = buildingToExcelType(data, sidoCode, sggCode); + + const excelList = buildingToExcelType(data, sidoCode, sggCode); + set((state: rainChkgdnState) => ({ + rainChkgdn: { + ...state.rainChkgdn, + excelList:excelList + }, + })); + }, + rainChkExcelDataUPload: async(excelData:rainChkZodType[] ) =>{ + try{ + const res = await postFectch("/reuseChk/rainyExcel", excelData); + if (res.ok) { + ToastFormUi({body:"지도점검 등록이 완료되었습니다. " ,title:'지도점검 등록'}) + } + const rainChkRes = await initFetch('2024', '0'); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + }catch(error){ + console.log(error); + ToastFormUi({body:"지도점검 등록이 실패되었습니다." ,title:'지도점검 등록'}) + } + }, rainChkInit: async (searchTxt: string, sggCd: string) => { try { const rainChkRes = await initFetch(searchTxt, sggCd); @@ -361,11 +418,9 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( const res = await postFectch("/reuseChk/rainyExcel", rainChk); if (res.ok) { - alert(" 수정이 완료되었습니다."); + ToastFormUi({body:"지도점검 보급수 및 밋물이용량 수정이 완료되었습니다. " ,title:'지도점검 수정'}) } - const rainChkRes = await initFetch('2024', '0'); - return set((state: rainChkgdnState) => ({ ...state, rainChkgdn: { @@ -379,13 +434,11 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( } }, rainChkGuidUpdate: async (rainChk: rainChkZodType) => { - try{ - //const chData = await makeMdfrChk(rainChk, "guideDetails", "rainDetil"); const res = await putFectch("/reuseChk/rainy", rainChk); if (res.ok) { - alert(" 수정이 완료되었습니다."); + ToastFormUi({body:"지도점검 수질 및 과태료 수정이 완료되었습니다. " ,title:'지도점검 수정'}) } const rainChkRes = await initFetch('2024', '0'); return set((state: rainChkgdnState) => ({ @@ -400,6 +453,30 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( } + }, + rainChkDelete: async (chkgdnPk:string) =>{ + try{ + const res = await deleteFectch(`/reuseChk/rainy/${chkgdnPk}`,''); + + if(res.ok){ + ToastFormUi({body:"삭제가 완료되었습니다. " ,title:'지도점검 삭제'}) + } + const rainChkRes = await initFetch('2024', '0'); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + + + }catch(error){ + ToastFormUi({body:"삭제를 실패했습니다.. " ,title:'지도점검 삭제'}) + + } + + } diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx index f19962010..2ac27be5a 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx @@ -1,5 +1,5 @@ import { getFetch, postFectch, putFectch } from "@/components/lib/api"; -import { upHeadList, type bdstAll, type chgBuilding, type TableUpperProps } from "../rainReg"; +import { upHeadList, type chgBuilding, type TableUpperProps } from "../rainReg"; import { z } from "zod"; import { makeMdfr, makeRstr } from "../bdstReg"; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index 55f203c19..f857671a9 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -1,11 +1,8 @@ -import type { selectArray } from "@/app/store/common/code"; import { getFetch, postFectch, putFectch } from "@/components/lib/api"; import { z } from "zod"; import { makeMdfr, makeRstr } from "../bdstReg"; - export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e' - export const rainZod = z.object({ bdstInfoPk: z.number().optional(), ctpvCd: z.number().default(0), @@ -23,11 +20,11 @@ export const rainZod = z.object({ bdstRuseFcltPk: z.number().nullish(), bdstInfoFk:z.number().nullish(), instlCmptnDt: z.coerce.date().default(() => new Date()), - instlCst: z.number().default(0), + instlCst: z.number().nullish(), operMngCd: z.string().optional().default(""), anlOperCst: z.number().default(0), instlCstSprtYn: z.string().default(""), - instlCstSprtAmt: z.number().nullish(), + instlCstSprtAmt: z.number().nullish(), grntchBdstCertYn: z.enum(["Y", "N"]).nullish(), grntchBdstCertYr: z.string().default("") .refine((year)=> year.length===0 || /^\d{4}$/.test(year),{ @@ -35,7 +32,7 @@ export const rainZod = z.object({ }), grntchBdstCertNo: z.string().default(""), grntchBdstCertGrd: z.string().default(""), - crgRdctYn: z.enum(["Y", "N"]), // 안쓰는 값 + crgRdctYn: z.enum(["Y", "N"]).nullish(), // 안쓰는 값 crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값 crgRdctAmt: z.number().default(0), // 안쓰는 값 ruseFcltFlg: z.string().default(""), @@ -75,8 +72,6 @@ export const rainZod = z.object({ ).default([]) }); - - export type chgBuilding={ bdstInfoFk?: number|null, archChgPrmsnDt?: Date, @@ -85,11 +80,7 @@ export type chgBuilding={ rgtr?:string|null; mdfr?:string|null; } - - export type customRainBdst = z.infer<typeof rainZod> - - export type TableUpperProps = { id: string; title: string; @@ -101,54 +92,38 @@ export type TableUpperProps = { type?: string; }; -export type TableTripleProps = { - id: string; - title: string; - upName: string[]; - upSequnce: number[]; - edit?:boolean; - visible?:boolean; -}; - - export const upHeadList: TableUpperProps[] = [ { id: "cityText", title: "시도" }, { id: "sggText", title: "시군구" }, { id: "bdstNm", title: "시설명" }, { id: "daddr", title: "위치" }, { id: "bdsgUsgText", title: "건축물용도" }, - // { id: "bdstUsgCd", title: "건축물용도" }, { id: "frstArchPrmsnDt", title: "최초건축허가일" }, { id: "archArea", title: "건축면적" }, { id: "lawTrgtYn", title: "법적의무대상여부" }, { id: "bdstChgYn", title: "건축물변경여부" }, - // { id: "archChgPrmsnDt", title: "허가일", upName: "upChangeRe", upSequnce: 2 }, - // { id: "archChgArea", title: "면적", upName: "upChangeRe", upSequnce: 3 }, ]; const rainRes: customRainBdst[] = []; -export const selectClass = "w-full h-full text-2xl"; -const selectYN = [ - { text: "Y", val: "1" }, - { text: "N", val: "2" }, -]; +export const selectClass = "w-full h-full !text-2xl"; + export type rainFacState = { rain: { isInit: boolean; upHeadList: TableUpperProps[]; - selectYN: selectArray[]; rainRes: customRainBdst[]; // regRainForm:customRainBdst, }; }; type rainFacSActions = { - init: (txt:string|undefined) => void; - rainSearTxt: (txt:string) => void; - rainReg: (data: customRainBdst) => void; - rainUpdate: (data: customRainBdst) => void; + initRain: (code:string|number) => void; + getRainData:(pageNation:number, code:string|number) =>void; + rainSearch: (txt:string,pageNation:number,code:string|number) => void; + rainBdstReg: (data: customRainBdst, code:string|number) => void; + rainBdstUpdate: (data: customRainBdst, code:string|number) => void; }; export type rainFacType = rainFacState & rainFacSActions; @@ -158,37 +133,42 @@ export const rainFacStateExport: rainFacState = { isInit: false, rainRes: rainRes, upHeadList: upHeadList, - selectYN: selectYN, - //regRainForm:regRainForm, - }, }; - - - -const initFetch = async (txt:string|undefined) => { - - const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/1/20/41` +(txt? `/${txt}`:'')); - const chRainRes = rainRes.map((item: customRainBdst) => { - return { - ...item, - bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N", - } }) - return chRainRes; - - +const initFetch = async (code:string|number) => { + const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/1/20/${code}`); + return rainRes; }; export const rainFacActionsExport: (set: any) => rainFacSActions = ( set: any ) => { return { - init: async (txt:string|undefined) => { + getRainData: async(pageNation:number, code:string|number) =>{ + try{ + const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/${pageNation}/20/${code}`); + + + // 여기서 상태 업데이트 + return set((state: rainFacState) => ({ + ...state, + rain: { + ...state.rain, + rainRes: rainRes, + isInit: false, + }, + })); + + }catch(e){ + console.log(e) + + } + }, + + initRain: async (code:string|number) => { try { // 파라이터 수정 통합관리자 =0, 시관리자=시코드, 시군구 관리자= 시군구 코드 를 세번째 파라미터로 지정 / 건축물 서치가 있을경우 4번째 파라미터로 던지기 즉 1/20/42(서울시)/영현빌딩 이런식으로) - const rainRes = await initFetch(txt); - - + const rainRes = await initFetch(code); // 여기서 상태 업데이트 return set((state: rainFacState) => ({ ...state, @@ -200,14 +180,12 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( })); } catch (error) { console.log("error", error); - } finally { - console.log("finally"); - } + } }, - rainSearTxt: async(txt:string) =>{ + rainSearch: async(txt:string,pageNation:number) =>{ try{ - const rainRes = await getFetch('wr' , `/reuseFc/rainyInfoList/1/20/41` +(txt? `/${txt}`:'')) + const rainRes = await getFetch('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/41` +(txt? `/${txt}`:'')) set((state: rainFacState) => { return { rain: { @@ -221,7 +199,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( console.log("error", erTxt) } }, - rainReg: async (data: customRainBdst) => { + rainBdstReg: async (data: customRainBdst,code:string|number) => { try { const test =await makeRstr(data); @@ -248,7 +226,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( alert("등록이 완료되었습니다."); } } - const rainRes = await initFetch(undefined); + const rainRes = await initFetch(code); set((state: rainFacState) => ({ ...state, rain: { @@ -263,18 +241,15 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( } finally { } }, - rainUpdate: async (data: customRainBdst) => { + rainBdstUpdate: async (data: customRainBdst,code:string|number) => { try { - - const chData =await makeMdfr(data); const res = await putFectch("/reuseFc/rainyInfo", chData); console.log('rainUpdate', res); if(res.ok){ alert(" 수정이 완료되었습니다.") } - - const rainRes = await initFetch(undefined); + const rainRes = await initFetch(code); set((state: rainFacState) => ({ ...state, rain: { diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx index da219b226..ea7f38244 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx @@ -1,5 +1,5 @@ import { getFetch, postFectch, putFectch } from "@/components/lib/api"; -import { upHeadList, type chgBuilding, type TableUpperProps } from "../rainReg"; +import { upHeadList, type chgBuilding, type TableUpperProps } from "../rainReg"; import { z } from "zod"; import { makeMdfr, makeRstr } from "../bdstReg"; @@ -15,73 +15,77 @@ export const rswtZod = z.object({ archArea: z.number().default(0), archChgArea: z.number().default(0), - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), + rgtr: z.string().nullish().default(null), + mdfr: z.string().nullish().default(null), - reuseBuilding: z.array( - z.object({ - bdstRuseFcltPk: z.number().nullish(), - bdstInfoFk: z.number().nullish(), - instlCmptnDt: z.coerce.date().default(() => new Date()), - instlCst: z.number().default(0), - operMngCd: z.string().nullish().default(""), + reuseBuilding: z + .array( + z.object({ + bdstRuseFcltPk: z.number().nullish(), + bdstInfoFk: z.number().nullish(), + instlCmptnDt: z.coerce.date().default(() => new Date()), + instlCst: z.number().default(0), + operMngCd: z.string().nullish().default(""), - anlOperCst: z.number().default(0), - instlCstSprtYn: z.enum(["Y", "N"]), - instlCstSprtAmt: z.number().default(0), + anlOperCst: z.number().default(0), + instlCstSprtYn: z.enum(["Y", "N"]), + instlCstSprtAmt: z.number().default(0), - grntchBdstCertYn: z.enum(["Y", "N"]), - grntchBdstCertYr: z.string().default("") - .refine((year)=> year.length===0 ||/^\d{4}$/.test(year),{ - message:'4자리 연도만 입력하세요' - }), - grntchBdstCertNo: z.string().default(""), - grntchBdstCertGrd: z.string().default(""), - - crgRdctYn: z.enum(["Y", "N"]), // 안쓰는 값 - crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값 - crgRdctAmt: z.number().default(0), // 안쓰는 값 - ruseFcltFlg: z.string().default(""), - bdstUsgCd: z.number().default(0), - lawTrgtYn: z.string().default(""), - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), + grntchBdstCertYn: z.enum(["Y", "N"]), + grntchBdstCertYr: z + .string() + .default("") + .refine((year) => year.length === 0 || /^\d{4}$/.test(year), { + message: "4자리 연도만 입력하세요", + }), + grntchBdstCertNo: z.string().default(""), + grntchBdstCertGrd: z.string().default(""), - rswtrObj: z.object({ - bdstRuseFcltFk: z.number().nullish(), - wtrUsqty: z.number().default(0), - oblgTrgtWtrUsqty: z.number().nullish().default(0), - orgwtKndCd: z.string().default(""), - filtrTrtmfctProcs: z.string().default(""), - filtrTrtmfctUsgCd: z.string().default(""), - rswtrUsqty: z.number().default(0), - altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(),//안쓰는값 - altUswtrKndCd: z.string().default(""),//안쓰는값 - altUswtrUtztnQnt: z.number().default(0),//안쓰는값 - altUswtrIdntyMthdCd: z.string().default(""),//안쓰는값 - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), - }).default({}) - }) - ).default([]), + crgRdctYn: z.enum(["Y", "N"]), // 안쓰는 값 + crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값 + crgRdctAmt: z.number().default(0), // 안쓰는 값 + ruseFcltFlg: z.string().default(""), + bdstUsgCd: z.number().default(0), + lawTrgtYn: z.string().default(""), + rgtr: z.string().nullish().default(null), + mdfr: z.string().nullish().default(null), + + rswtrObj: z + .object({ + bdstRuseFcltFk: z.number().nullish(), + wtrUsqty: z.number().default(0), + oblgTrgtWtrUsqty: z.number().nullish().default(0), + orgwtKndCd: z.string().default(""), + filtrTrtmfctProcs: z.string().default(""), + filtrTrtmfctUsgCd: z.string().default(""), + rswtrUsqty: z.number().default(0), + altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(), //안쓰는값 + altUswtrKndCd: z.string().default(""), //안쓰는값 + altUswtrUtztnQnt: z.number().default(0), //안쓰는값 + altUswtrIdntyMthdCd: z.string().default(""), //안쓰는값 + rgtr: z.string().nullish().default(null), + mdfr: z.string().nullish().default(null), + }) + .default({}), + }) + ) + .default([]), chgBuilding: z - .array( - z.object({ - bdstInfoFk: z.number().nullish(), - archChgPrmsnDt: z.coerce.date() , - archChgArea: z.string().default("-"), - bdstChgNm: z.string().default(""), - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), - }) - ) - .default([]), - + .array( + z.object({ + bdstInfoFk: z.number().nullish(), + archChgPrmsnDt: z.coerce.date(), + archChgArea: z.string().default("-"), + bdstChgNm: z.string().default(""), + rgtr: z.string().nullish().default(null), + mdfr: z.string().nullish().default(null), + }) + ) + .default([]), }); - -export type customRswtBdst = z.infer<typeof rswtZod> +export type customRswtBdst = z.infer<typeof rswtZod>; const rswtRes: customRswtBdst[] = []; @@ -93,9 +97,11 @@ export type rswtFacState = { }; }; type rswtFacSActions = { - initRswt: (txt: string | undefined) => void; - rswtUpdate: (data: customRswtBdst) => void; - rswtReg: (data: customRswtBdst) => void; + initRswt: (code:string|number) => void; + rswtBdstUpdate: (data: customRswtBdst,code:string|number) => void; + getRswtBdstData:(pageNation:number, code:string|number) =>void; + rswtBdstSearch:(txt:string,pageNation:number, code:string|number) =>void; + rswtBdstReg: (data: customRswtBdst,code:string|number) => void; }; export type rswtFacType = rswtFacState & rswtFacSActions; @@ -108,25 +114,58 @@ export const rswtFacStateExport: rswtFacState = { }, }; -const initFetch = async (txt: string | undefined) => { - const rswtRes =await getFetch( +const initFetch = async (code:string|number) => { + const rswtRes = await getFetch( "wr", - `/reuseFc/waterreuseFc/1/20/41` + (txt ? `/${txt}` : "") - ); - const chRswtRes = rswtRes.map((item: customRswtBdst) => { - return { - ...item, - bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N", - } }) - return chRswtRes; + `/reuseFc/waterreuseFc/1/20/${code}`) + + return rswtRes; }; export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( set: any ) => { return { - initRswt: async (txt: string | undefined) => { + rswtBdstSearch: async(txt:string,pageNation:number,code:string|number) =>{ + try{ + + const rswtRes = await getFetch('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/${code}` +(txt? `/${txt}`:'')) + set((state: rswtFacState) => { + return { + ...state, + rswt: { + ...state.rswt, + rswtRes: rswtRes, + isInit: false, + }, + }; + })} + catch(erTxt){ + console.log("error", erTxt) + } + }, + getRswtBdstData: async (pageNation: number, code: string | number) => { try { - const rswtRes = await initFetch(txt); + const rswtRes = await getFetch( + "wr", + `/reuseFc/waterreuseFc/${pageNation}/20/${code}` + ); + console.log(pageNation) + // 여기서 상태 업데이트 + return set((state: rswtFacState) => ({ + ...state, + rswt: { + ...state.rswt, + rswtRes: rswtRes, + isInit: false, + }, + })); + } catch (e) { + console.log(e); + } + }, + initRswt: async (code: string | number) => { + try { + const rswtRes = await initFetch(code); return set((state: rswtFacState) => ({ ...state, rswt: { @@ -139,71 +178,72 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( console.log(error); } }, - rswtUpdate: async (data: customRswtBdst) => { - try { - const chData=await makeMdfr(data) - const res = await putFectch("/reuseFc/waterreuseFc", chData); - if (res.ok) { - alert("등록이 완료되었습니다."); - } - const rswtRes = await initFetch(undefined); - set((state: rswtFacState) => ({ - ...state, - rain: { - ...state.rswt, - rswtRes: rswtRes, - isInit: false, - }, - })); - } catch (errorUpdate) { - alert("업데이트 오류입니다. " + (errorUpdate instanceof Error ? errorUpdate.message : "")); - } finally { - } + rswtBdstUpdate: async (data: customRswtBdst, code:string|number) => { + try { + const chData = await makeMdfr(data); + const res = await putFectch("/reuseFc/waterreuseFc", chData); + if (res.ok) { + alert("등록이 완료되었습니다."); + } + const rswtRes = await initFetch(code); + set((state: rswtFacState) => ({ + ...state, + rain: { + ...state.rswt, + rswtRes: rswtRes, + isInit: false, + }, + })); + } catch (errorUpdate) { + alert( + "업데이트 오류입니다. " + + (errorUpdate instanceof Error ? errorUpdate.message : "") + ); + } finally { + } }, - rswtReg: async (data: customRswtBdst) => { - try { - const chData=await makeRstr(data) - const res = await postFectch("/reuseFc/waterreuseFc", chData); - if(res.ok){ - if(data.chgBuilding.length > 0){ - await res - .json() - .then((resData: any) => { - const chPK = resData?.data?.bdstInfoPk; - const makeCh = resData.data.chgBuilding.map( - (item: chgBuilding) => ({ - ...item, - bdstInfoFk: chPK, - }) - ); - const chch = postFectch("/reuseFc/chgBuilding", makeCh); - return chch; + rswtBdstReg: async (data: customRswtBdst,code:string|number) => { + try { + const chData = await makeRstr(data); + const res = await postFectch("/reuseFc/waterreuseFc", chData); + if (res.ok) { + if (data.chgBuilding.length > 0) { + await res + .json() + .then((resData: any) => { + const chPK = resData?.data?.bdstInfoPk; + const makeCh = resData.data.chgBuilding.map( + (item: chgBuilding) => ({ + ...item, + bdstInfoFk: chPK, }) - .then((chch: any) => { - if (chch.ok) { - alert("등록이 완료되었습니다."); - } - }); - }else{ - alert("등록이 완료되었습니다."); - - } - } - const rainRes = await initFetch(undefined); - set((state: rswtFacState) => ({ - ...state, - rain: { - ...state.rswt, - rswtRes: rswtRes, - isInit: false, - }, - })); - } catch (e) { - console.log("e", e); - alert("등록 오류입니다."); - } finally { + ); + const chch = postFectch("/reuseFc/chgBuilding", makeCh); + return chch; + }) + .then((chch: any) => { + if (chch.ok) { + alert("등록이 완료되었습니다."); + } + }); + } else { + alert("등록이 완료되었습니다."); } - }, - + } + const rainRes = await initFetch(code); + set((state: rswtFacState) => ({ + ...state, + rain: { + ...state.rswt, + rswtRes: rswtRes, + isInit: false, + }, + })); + } catch (e) { + console.log("e", e); + alert("등록 오류입니다."); + } finally { + } + }, }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx new file mode 100644 index 000000000..98fcc4210 --- /dev/null +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx @@ -0,0 +1,169 @@ +import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { TableUpperProps } from "../../fcltReg/rainReg"; + +export const pbnSttHeadNmExport: chHeadType[] = [ + { headNm: "catchment", text: "유역", length: 3 }, + { headNm: "adminDiv", text: "행정구역", length: 2 }, + { headNm: "rusSup", text: "재이용수공급가능량", length: 3 }, + { headNm: "yearResult", text: "연간실적정보(m³)", length: 3 }, + { headNm: "mngInfo", text: "운영정보", length: 4 }, +]; + +// id는 다확인해야함 +export const pbnSttHeadListExport: TableUpperProps[] = [ + { id: "a", title: "권역", upName: "catchment", upSequnce: 1, visible: true }, + { + id: "aaa", + title: "단위유역", + upName: "catchment", + upSequnce: 2, + visible: true, + }, + { + id: "aaaa", + title: "중권역", + upName: "catchment", + upSequnce: 3, + visible: false, + }, + { id: "operMngCd", title: "환경청", visible: true }, + { + id: "cityText", + title: "시도", + upName: "adminDiv", + upSequnce: 1, + visible: false, + }, + { + id: "sggText", + title: "시군구", + upName: "adminDiv", + upSequnce: 2, + visible: true, + }, + { id: "bdnstNm", title: "시설명", visible: true }, + { id: "locDiv", title: "지역구분", visible: true }, + { id: "phone", title: "전화번호", visible: true }, + + { id: "fcltQuantity", title: "시설용량(톤/일)", visible: true }, + { id: "rusNm", title: "재이용시설명", visible: true }, + + { + id: "fcltCpct", + title: "시설용량(m³/일)", + upName: "rusSup", + upSequnce: 1, + visible: true, + }, + { + id: "trbt", + title: "하수처리량(m³/일)", + upName: "rusSup", + upSequnce: 2, + visible: true, + }, + { + id: "ruseCpct", + title: "재이용량(m³/일)", + upName: "rusSup", + upSequnce: 3, + visible: true, + }, + + { + id: "total", + title: "합계", + upName: "yearResult", + upSequnce: 1, + visible: true, + }, + { + id: "ithlWtr", + title: "장내용수", + upName: "yearResult", + upSequnce: 2, + visible: true, + }, + { + id: "othlWtr", + title: "장외용수", + upName: "yearResult", + upSequnce: 3, + visible: true, + }, + + { + id: "mngMeth", + title: "운영방식", + upName: "mngInfo", + upSequnce: 1, + visible: true, + }, + { + id: "rprtvBzenty", + title: "대행업체", + upName: "mngInfo", + upSequnce: 2, + visible: true, + }, + { + id: "firstDay", + title: "시작일", + upName: "mngInfo", + upSequnce: 3, + visible: true, + }, + { + id: "LastDay", + title: "종료일", + upName: "mngInfo", + upSequnce: 4, + visible: true, + }, +]; + + + + +// 참고용 지워야함. +// rainChSttnHead: async (checkList: string[], type: string) => { +// const headList = +// type === "pbn" +// ? pbnSttHeadList +// : type === "rain" +// ? rainSttHeadList +// : null; + +// let chNm = type === "pbn" ? pbnSttHeadNm : rainSttNodeList; +// headList?.forEach((item) => { +// if (checkList.find((ch) => ch === item.id)) { +// item.visible = false; +// if (item.upName) { +// const upNames = Array.isArray(item.upName) +// ? item.upName +// : [item.upName]; +// upNames?.forEach((up) => { +// chNm.find((ch) => { +// if (ch.headNm === up) { +// ch.length = ch.length - 1; +// } +// }); +// }); +// } +// } +// }); +// set((state: rainSttnState) => ({ +// sttnCommon: { +// ...state.sttnCommon, +// pbnSttHeadList: +// type === "pbn" ? headList : state.sttnCommon.pbnSttHeadList, +// rainSttHeadList: +// type === "rain" ? headList : state.sttnCommon.rainSttHeadList, +// rainSttNodeList: +// type === "rain" ? chNm : state.sttnCommon.rainSttNodeList, +// pbnSttHeadNm: type === "rain" ? chNm : state.sttnCommon.pbnSttHeadNm, +// }, +// })); +// }, +// }; +// }; \ No newline at end of file diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/excel.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/excel.tsx new file mode 100644 index 000000000..264e3b6cc --- /dev/null +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/excel.tsx @@ -0,0 +1,33 @@ +import type { customRainBdst } from "../../fcltReg/rainReg"; + +export const excelSttnParsing = (data: customRainBdst[]): string[][] => { + const excelExportData: string[][] = []; + + data.forEach((item) => { + excelExportData.push([ + String(item.ctpvCd), + String(item.sggCd), + item.bdstNm ?? "", + item.daddr ?? "", + String(item.bdstInfoPk ?? ""), + String(item.frstArchPrmsnDt ?? ""), + String(item.archArea ?? ""), + String(item.reuseBuilding?.[0]?.lawTrgtYn ?? ""), + String(item.reuseBuilding?.[0]?.instlCmptnDt ?? ""), + String(item.reuseBuilding?.[0]?.instlCst ?? ""), + item.reuseBuilding?.[0]?.rainyObj?.pntfColKnd ?? "", + String(item.reuseBuilding?.[0]?.rainyObj?.pntfColArea ?? ""), + String(item.reuseBuilding?.[0]?.rainyObj?.filtrTrtmfctYn ?? ""), + String(item.reuseBuilding?.[0]?.rainyObj?.filtrTrtmfctCpct ?? ""), + String(item.reuseBuilding?.[0]?.rainyObj?.filtrTrtmfctPrs ?? ""), + String(item.reuseBuilding?.[0]?.rainyObj?.dtfcltCpct ?? ""), + String(item.reuseBuilding?.[0]?.instlCstSprtYn ?? ""), + String(item.reuseBuilding?.[0]?.instlCstSprtAmt ?? ""), + String(item.reuseBuilding?.[0]?.grntchBdstCertYn ?? ""), + String(item.reuseBuilding?.[0]?.grntchBdstCertYr ?? ""), + String(item.reuseBuilding?.[0]?.grntchBdstCertNo ?? ""), + String(item.reuseBuilding?.[0]?.grntchBdstCertGrd ?? "") + ]); + }); + return excelExportData; +}; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx new file mode 100644 index 000000000..c283194a1 --- /dev/null +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx @@ -0,0 +1,420 @@ +import { z } from "zod"; + + +export const rainSttnHeadListType = z.array( + z.object({ + id: z.string(), + title: z.string(), + visible: z.boolean(), + }) + ); + + +export const rainSttHeadListExport: z.infer<typeof rainSttnHeadListType> = [ + +{ + id: "cityText", + title: "시도", + visible: true, +}, +{ + id: "sggText", + title: "시군구", + visible: true, +}, +{ + id: "bdstNm", + title: "건축물명", + visible: true, +}, +{ + id: "daddr", + title: "주소", + visible: true, +}, +{ + id: "bdstUsgCd", + title: "건축물용도코드", + visible: true, +}, +{ + id: "frstArchPrmsnDt", + title: "최초건축허가일시", + visible: true, +}, +{ + id: "archArea", + title: "건축면적", + visible: true, +}, +{ + id: "lawTrgtYn", + title: "법적의무대상여부", + visible: true, +}, +{ + id: "instlCmptnDt", + title: "설치완료일시", + visible: true, +}, + +{ + id: "instlCst", + title: "설치비용", + visible: true, +}, + + +{ + id: "pntfColKnd", + title: "집수지점종류", + visible: true, +}, +{ + id: "pntfColArea", + title: "집수지점면적", + visible: true, +}, + +{ + id: "dtfcltCpct", + title: "저류조용량", + visible: true, +}, +{ + id: "filtrTrtmfctYn", + title: "여과처리시설유무", + visible: true, +}, +{ + id: "filtrTrtmfctCpct", + title: "여과처리시설용량", + visible: true, +}, +{ + id: "filtrTrtmfctPrs", + title: "여과처리시설처리공정", + visible: true, +}, + + +{ + id: "instlCstSprtYn", + title: "설치지원비용여부", + visible: true, +}, +{ + id: "instlCstSprtAmt", + title: "설치지원비용", + visible: true, +}, + +{ + id: "grntchBdstCertYn", + title: "녹색건축물인증여부", + visible: true, +}, +{ + id: "grntchBdstCertYr", + title: "녹색건축물인증년도", + visible: true, +}, +{ + id: "grntchBdstCertNo", + title: "녹색건축물인증번호", + visible: true, +}, +{ + id: "grntchBdstCertGrd", + title: "녹색건축물인증등급", + visible: true, +}, + +]; + + +// id는 다확인해야함 +export const rainSttNodeListExport: CommonTableProps[] = [ + { + id: "bdnstInfo", + title: "1.건축물정보", + visible: true, + row: 1, + rowSpan: 1, + colSpan: 9, + }, + { + id: "rainFcltInfo", + title: "2.빗물이용시설정보", + visible: true, + row: 1, + rowSpan: 1, + colSpan: 7, + }, + { + id: "insenInfo", + title: "3.인센티브 정보", + visible: true, + row: 1, + rowSpan: 1, + colSpan: 6, + }, + { + id: "adminDiv", + title: "행정구역", + visible: true, + row: 2, + upName:'bdnstInfo', + rowSpan: 1, + colSpan: 2, + }, + + + + // 3번째줄 시작 + { + id: "cityText", + title: "시도", + visible: true, + upName:'adminDiv', + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "sggText", + title: "시군구", + visible: true, + upName:'adminDiv', + row: 3, + rowSpan: 1, + colSpan: 1, + }, + + // 2번째 줄 + // 1번째 줄 건축물정보 아래의 행으로 만들 헤더 + { + id: "bdstNm", + title: "건축물명", + visible: true, + upName:'bdnstInfo', + row: 2, + rowSpan: 2, + colSpan: 1, + }, + { + id: "daddr", + title: "주소", + visible: true, + upName:'bdnstInfo', + row: 2, + rowSpan: 2, + colSpan: 1, + }, + { + id: "bdstUsgCd", + title: "건축물용도코드", + upName:'bdnstInfo', + visible: true, + row: 2, + rowSpan: 2, + colSpan: 1, + }, + { + id: "frstArchPrmsnDt", + title: "최초건축허가일시", + upName:'bdnstInfo', + visible: true, + row: 2, + rowSpan: 2, + colSpan: 1, + }, + { + id: "archArea", + title: "건축면적", + upName:'bdnstInfo', + visible: true, + row: 2, + rowSpan: 2, + colSpan: 1, + }, + { + id: "lawTrgtYn", + title: "법적의무대상여부", + upName:'bdnstInfo', + visible: true, + row: 2, + rowSpan: 2, + colSpan: 1, + }, + { + id: "instlCmptnDt", + title: "설치완료일시", + upName:'bdnstInfo', + visible: true, + row: 2, + rowSpan: 2, + colSpan: 1, + }, + + { + id: "instlCst", + title: "설치비용", + upName:'rainFcltInfo', + visible: true, + row: 2, + rowSpan: 2, + colSpan: 1, + }, + + { + id: "pntfCol", + title: "집수면", + upName:'rainFcltInfo', + visible: true, + row: 2, + rowSpan: 1, + colSpan: 2, + }, + + { + id: "pntfColKnd", + title: "집수지점종류", + upName:'pntfCol', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "pntfColArea", + title: "집수지점면적", + upName:'pntfCol', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + + { + id: "dtfcltCpct", + title: "저류조용량", + upName:'rainFcltInfo', + visible: true, + row: 2, + rowSpan: 2, + colSpan: 1, + }, + { + id: "filtrTrtmfctYn", + title: "여과처리시설유무", + upName:'filtrTrtmfct', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "filtrTrtmfctCpct", + title: "여과처리시설용량", + upName:'filtrTrtmfct', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "filtrTrtmfctPrs", + title: "여과처리시설처리공정", + upName:'filtrTrtmfct', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + + { + id: "filtrTrtmfct", + title: "여과등 처리시설", + visible: true, + upName:'insenInfo', + row: 2, + rowSpan: 1, + colSpan: 3, + }, + { + id: "instlCstSprtYn", + title: "설치지원비용여부", + upName:'instlCstSprt', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "instlCstSprtAmt", + title: "설치지원비용", + upName:'instlCstSprt', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + + { + id: "instlCstSprt", + title: "설치비지원", + upName:'insenInfo', + visible: true, + row: 2, + rowSpan: 1, + colSpan: 2, + }, + + { + id: "grntchBdstCertYn", + title: "녹색건축물인증여부", + upName:'grntchBdstCert', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "grntchBdstCertYr", + title: "녹색건축물인증년도", + upName:'grntchBdstCert', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "grntchBdstCertNo", + title: "녹색건축물인증번호", + upName:'grntchBdstCert', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "grntchBdstCertGrd", + title: "녹색건축물인증등급", + upName:'grntchBdstCert', + visible: true, + row: 3, + rowSpan: 1, + colSpan: 1, + }, + { + id: "grntchBdstCert", + title: "녹색건축물인증", + upName:'insenInfo', + visible: true, + row: 2, + rowSpan: 1, + colSpan: 4, + }, +]; + diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx new file mode 100644 index 000000000..3c9a507ac --- /dev/null +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx @@ -0,0 +1,163 @@ +import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { fetchType, getFetch } from "@/components/lib/api"; +import { + type customRainBdst, +} from "../../fcltReg/rainReg"; +import { excelSttnParsing } from "./excel"; +import { + rainSttHeadListExport, + rainSttnHeadListType, + rainSttNodeListExport, +} from "./headList"; +import type { z } from "zod"; +import type { CommonTableProps } from "@/app/store/common/type/headder"; + +// 테이블 헤드 리스트 +const rainSttNodeList = rainSttNodeListExport; +const rainSttHeadList = rainSttHeadListExport; +const rainSttnRes: customRainBdst[] = []; + + + +const visibleHeadList = (falseHeads:CommonTableProps[], orgNodeList:CommonTableProps[])=>{ + const visibleHeads = orgNodeList.map((node) => { + const copyNode = {...node} + falseHeads.forEach((head)=>{ + if(copyNode.id ===head.id) + copyNode.visible = head.visible + }) + return copyNode; + }) + return visibleHeads +} + +const getColspanReductionMap = (falseHeads:CommonTableProps[], orgList:CommonTableProps[]):Record<string, number> => { + const reduceMap:Record<string, number> = {}; + falseHeads.forEach(head => { + const node = orgList.find(n => n.id === head.id); + if (node?.upName) { + reduceMap[node.upName] = (reduceMap[node.upName] || 0) + 1; + if (node.row&& node.row >= 3) { + const upperUpName = orgList.find(n => n.id === node.upName)?.upName; + if (upperUpName) { + reduceMap[upperUpName] = (reduceMap[upperUpName] || 0) + 1; + } + } + } + }); + return reduceMap; +}; + +// colSpan 반영 및 visible 처리 +const applyColspanReduction = ( + orgList: CommonTableProps[], + reduceMap: Record<string, number> +): CommonTableProps[] => { + return orgList.map(node => { + const newNode: CommonTableProps = { ...node }; + const reduceCount = reduceMap[node.id]; + + if ( + newNode.colSpan !== undefined && + reduceCount !== undefined && + typeof newNode.colSpan === "number" + ) { + newNode.colSpan -= reduceCount; + if (newNode.colSpan <= 0) { + newNode.visible = false; + } + } + + return newNode; + }); +}; +// 일단 헤더가 3개 이상인경우 visible 처리를 위해서 공통함수로 작업 +export const controlHeadView = (headList:CommonTableProps[], orgNodeList:CommonTableProps[] ) =>{ + const falseHeads = headList.filter((item) => item.visible == false); + + const viewHeadList = visibleHeadList(falseHeads, orgNodeList) + const reduceMap= getColspanReductionMap( falseHeads,viewHeadList) + return applyColspanReduction(viewHeadList,reduceMap); +} + + + +export type rainSttnState = { + rainSttn: { + rainSttnRes: customRainBdst[]; + rainSttHeadList: CommonTableProps[]; + rainSttNodeList: CommonTableProps[]; + excelList: []; + isInit: boolean; + }; +}; +type rainSttnActions = { + rainSttnSearch: (page: string, total: string, con: string) => void; + rainChSttnHead: ( + headList: z.infer<typeof rainSttnHeadListType>, + ) => void; +}; + +export type rainSttnType = rainSttnState & rainSttnActions; + +export const rainSttnStateExport: rainSttnState = { + rainSttn: { + rainSttHeadList: rainSttHeadList, + rainSttNodeList: rainSttNodeList, + rainSttnRes: rainSttnRes, + excelList: [], + isInit: false, + }, +}; + +export const rainSttnActionsExport: (set: any) => rainSttnActions = ( + set: any +) => { + return { + rainSttnSearch: async (page: string, total: string, con: string) => { + try { + const rainSttnRes = await getFetch( + fetchType.WR, + `/reuseFc/rainyInfoList/${page}/${total}/${con}` + ); + if (Number(total) > 9000) { + const rainExcel = excelSttnParsing(rainSttnRes); + set((state: rainSttnState) => { + return { + ...state, + rainSttn: { + ...state.rainSttn, + excelList: rainExcel, + }, + }; + }); + } else + set((state: rainSttnState) => { + return { + ...state, + rainSttn: { + ...state.rainSttn, + rainSttnRes: rainSttnRes, + isInit: false, + }, + }; + }); + } catch (erTxt) { + console.log("error", erTxt); + } + }, + rainChSttnHead: async ( + headList: z.infer<typeof rainSttnHeadListType> + ) => { + const changeNodeList= controlHeadView(headList,rainSttNodeList) + + return set((state: rainSttnState) => ({ + rainSttn: { + ...state.rainSttn, + rainSttHeadList: headList, + rainSttNodeList: changeNodeList, + }, + })); + }, + }; +}; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/sttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/sttn/index.tsx deleted file mode 100644 index 727d8df1b..000000000 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/sttn/index.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import { - upHeadList, - type TableTripleProps, - type TableUpperProps, -} from "../../fcltReg/rainReg"; - -export const pbnSttHeadNm: chHeadType[] = [ - { headNm: "catchment", text: "유역", length: 3 }, - { headNm: "adminDiv", text: "행정구역", length: 2 }, - { headNm: "rusSup", text: "재이용수공급가능량", length: 3 }, - { headNm: "yearResult", text: "연간실적정보(m³)", length: 3 }, - { headNm: "mngInfo", text: "운영정보", length: 4 }, -]; - -// id는 다확인해야함 -export const pbnSttHeadList: TableUpperProps[] = [ - { id: "a", title: "권역", upName: "catchment", upSequnce: 1, visible: true }, - { - id: "aaa", - title: "단위유역", - upName: "catchment", - upSequnce: 2, - visible: true, - }, - { - id: "aaaa", - title: "중권역", - upName: "catchment", - upSequnce: 3, - visible: false, - }, - { id: "operMngCd", title: "환경청", visible: true }, - { - id: "cityText", - title: "시도", - upName: "adminDiv", - upSequnce: 1, - visible: false, - }, - { - id: "sggText", - title: "시군구", - upName: "adminDiv", - upSequnce: 2, - visible: true, - }, - { id: "bdnstNm", title: "시설명", visible: true }, - { id: "locDiv", title: "지역구분", visible: true }, - { id: "phone", title: "전화번호", visible: true }, - - { id: "fcltQuantity", title: "시설용량(톤/일)", visible: true }, - { id: "rusNm", title: "재이용시설명", visible: true }, - - { - id: "fcltCpct", - title: "시설용량(m³/일)", - upName: "rusSup", - upSequnce: 1, - visible: true, - }, - { - id: "trbt", - title: "하수처리량(m³/일)", - upName: "rusSup", - upSequnce: 2, - visible: true, - }, - { - id: "ruseCpct", - title: "재이용량(m³/일)", - upName: "rusSup", - upSequnce: 3, - visible: true, - }, - - { - id: "total", - title: "합계", - upName: "yearResult", - upSequnce: 1, - visible: true, - }, - { - id: "ithlWtr", - title: "장내용수", - upName: "yearResult", - upSequnce: 2, - visible: true, - }, - { - id: "othlWtr", - title: "장외용수", - upName: "yearResult", - upSequnce: 3, - visible: true, - }, - - { - id: "mngMeth", - title: "운영방식", - upName: "mngInfo", - upSequnce: 1, - visible: true, - }, - { - id: "rprtvBzenty", - title: "대행업체", - upName: "mngInfo", - upSequnce: 2, - visible: true, - }, - { - id: "firstDay", - title: "시작일", - upName: "mngInfo", - upSequnce: 3, - visible: true, - }, - { - id: "LastDay", - title: "종료일", - upName: "mngInfo", - upSequnce: 4, - visible: true, - }, -]; -export const rainSttHeadNm: chHeadType[] = [ - { headNm: "bdnstInfo", text: "1.건축물정보", length: 9 }, - { headNm: "rainFcltInfo", text: "2.빗물이용시설정보", length: 7 }, - { headNm: "fcltMngInfo", text: "3.시설운영및 이용정보", length: 2 }, - { headNm: "insenInfo", text: "4.인센티브 정보", length: 9 }, - - { headNm: "adminDiv", text: "행정구역", length: 2 }, - { headNm: "pntfCol", text: "집수면", length: 2 }, - { headNm: "filtrTrtmfct", text: "여과등 처리시설", length: 3 }, - { headNm: "instlCstSprt", text: "설치비지원", length: 2 }, - - { headNm: "crgRdct", text: "요금감면", length: 3 }, - { headNm: "grntchBdstCert", text: "녹색건축물인증여부", length: 4 }, -]; - -// id는 다확인해야함 -export const rainSttHeadList: TableTripleProps[] = [ - { - id: "ctpvCd", - title: "시도", - visible: true, - upName: ["bdnstInfo", "adminDiv"], - upSequnce: [1, 1], - }, - { - id: "sggCd", - title: "시군구", - visible: true, - upName: ["bdnstInfo", "adminDiv"], - upSequnce: [2, 2], - }, - { - id: "bdstNm", - title: "건축물명", - visible: true, - upName: ["bdnstInfo"], - upSequnce: [3], - }, - { - id: "daddr", - title: "주소", - visible: true, - upName: ["bdnstInfo"], - upSequnce: [4], - }, - { - id: "bdstUsgCd", - title: "건축물용도코드", - visible: true, - upName: ["bdnstInfo"], - upSequnce: [5], - }, - { - id: "frstArchPrmsnDt", - title: "최초건축허가일시", - visible: true, - upName: ["bdnstInfo"], - upSequnce: [6], - }, - { - id: "archArea", - title: "건축면적", - visible: true, - upName: ["bdnstInfo"], - upSequnce: [7], - }, - { - id: "lawTrgtYn", - title: "법적의무대상여부", - visible: true, - upName: ["bdnstInfo"], - upSequnce: [8], - }, - { - id: "instlCmptnDt", - title: "설치완료일시", - visible: true, - upName: ["bdnstInfo"], - upSequnce: [9], - }, - - { - id: "instlCst", - title: "설치비용", - visible: true, - upName: ["rainFcltInfo"], - upSequnce: [1], - }, - { - id: "pntfColKnd", - title: "접수지점종류", - visible: true, - upName: ["rainFcltInfo", "pntfCol"], - upSequnce: [2, 1], - }, - { - id: "pntfColArea", - title: "접수지점면적", - visible: true, - upName: ["rainFcltInfo", "pntfCol"], - upSequnce: [3, 2], - }, - { - id: "filtrTrtmfctYn", - title: "여과처리시설유무", - visible: true, - upName: ["rainFcltInfo", "filtrTrtmfct"], - upSequnce: [4, 1], - }, - { - id: "filtrTrtmfctCpct", - title: "여과처리시설용량", - visible: true, - upName: ["rainFcltInfo", "filtrTrtmfct"], - upSequnce: [5, 2], - }, - { - id: "filtrTrtmfctPrs", - title: "여과처리시설처리공정", - visible: true, - upName: ["rainFcltInfo", "filtrTrtmfct"], - upSequnce: [6, 3], - }, - { - id: "dtfcltCpct", - title: "저류조용량", - visible: true, - upName: ["rainFcltInfo"], - upSequnce: [7], - }, - - { - id: "operMngCd", - title: "운영관리코드", - visible: true, - upName: ["fcltMngInfo"], - upSequnce: [1], - }, - { - id: "annRnwtQty", - title: "연간빗물운영량", - visible: true, - upName: ["fcltMngInfo"], - upSequnce: [2], - }, - - { - id: "instlCstSprtYn", - title: "설치지원비용여부", - visible: true, - upName: ["insenInfo", "instlCstSprt"], - upSequnce: [1, 1], - }, - { - id: "instlCstSprtAmt", - title: "설치지원비용", - visible: true, - upName: ["insenInfo", "instlCstSprt"], - upSequnce: [2, 2], - }, - { - id: "crgRdctYn", - title: "감면여부", - visible: true, - upName: ["insenInfo", "crgRdct"], - upSequnce: [3, 1], - }, // 확인필요 - { - id: "crgRdctBss", - title: "감면근거", - visible: true, - upName: ["insenInfo", "crgRdct"], - upSequnce: [4, 2], - }, // 확인필요 - { - id: "crgRdctAmt", - title: "감면금액", - visible: true, - upName: ["insenInfo", "crgRdct"], - upSequnce: [5, 3], - }, // 확인필요 - { - id: "grntchBdstCertYn", - title: "녹색건축물인증여부", - visible: true, - upName: ["insenInfo", "grntchBdstCert"], - upSequnce: [6, 1], - }, - { - id: "grntchBdstCertYr", - title: "녹색건축물인증년도", - visible: true, - upName: ["insenInfo", "grntchBdstCert"], - upSequnce: [7, 2], - }, - { - id: "grntchBdstCertNo", - title: "녹색건축물인증번호", - visible: true, - upName: ["insenInfo", "grntchBdstCert"], - upSequnce: [8, 3], - }, - { - id: "grntchBdstCertGrd", - title: "녹색건축물인증등급", - visible: true, - upName: ["insenInfo", "grntchBdstCert"], - upSequnce: [9, 4], - }, -]; - -export type sttnState = { - sttnCommon: { - pbnSttHeadList: TableUpperProps[]; - pbnSttHeadNm: chHeadType[]; - rainSttHeadList: TableTripleProps[]; - rainSttHeadNm: chHeadType[]; - }; -}; -type sttnActions = { - chSttnHead: (checkList: string[], type: string) => void; - pbnSttnInit: (sggCd: string, searchTxt: string, flg: string) => void; - -}; - -export type sttnType = sttnState & sttnActions; - -export const sttnStateExport: sttnState = { - sttnCommon: { - pbnSttHeadList: pbnSttHeadList, - pbnSttHeadNm: pbnSttHeadNm, - rainSttHeadList: rainSttHeadList, - rainSttHeadNm: rainSttHeadNm, - }, -}; - -export const sttnActionsExport: (set: any) => sttnActions = (set: any) => { - return { - pbnSttnInit: async (sggCd: string, searchTxt: string, flg: string) => {}, - - chSttnHead: async (checkList: string[], type: string) => { - const headList = - type === "pbn" - ? pbnSttHeadList - : type === "rain" - ? rainSttHeadList - : null; - - let chNm = type === "pbn" ? pbnSttHeadNm : rainSttHeadNm; - headList?.forEach((item) => { - if (checkList.find((ch) => ch === item.id)) { - item.visible = false; - if (item.upName) { - const upNames = Array.isArray(item.upName) ? item.upName : [item.upName]; - upNames?.forEach((up) => { - chNm.find((ch) => { - if (ch.headNm === up) { - ch.length = ch.length - 1; - } - } - ); - - }) - } - - } - }); - set((state: sttnState) => ({ - sttnCommon: { - ...state.sttnCommon, - pbnSttHeadList: type === "pbn" ? headList : state.sttnCommon.pbnSttHeadList, - rainSttHeadList: type === "rain" ? headList : state.sttnCommon.rainSttHeadList, - rainSttHeadNm: type === "rain" ? chNm : state.sttnCommon.rainSttHeadNm, - pbnSttHeadNm: type === "rain" ? chNm : state.sttnCommon.pbnSttHeadNm, - }, - })); - }, - }; -}; diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx index f3e720add..848ba0b03 100644 --- a/apps/wr/app/store/store.tsx +++ b/apps/wr/app/store/store.tsx @@ -1,4 +1,20 @@ import { createStore } from "zustand/vanilla"; +import { codeActionExport, comCodeStateExport, getCityCd, getEnvPartCd, getMiddleRegionCd, getRegionCd, getSggCd, getUnitWaterShedCd, type comCodeState, type comCodeType } from "./common/code"; +import { + matDmdActionsExport, + matDmdStateExport, + type matDmdState, + type matDmdType, +} from "./matDmd"; +import { rainChkgdnActionsExport, rainChkgdnStateExport, type rainChkgdnState, type rainChkgdnType } from "./prfmncReg/chkgdnReg/rainChkgdn"; +import { rswtChkgdnActionsExport, rswtChkgdnStateExport, type rswtChkgdnState, type rswtChkgdnType } from "./prfmncReg/chkgdnReg/rswrtChkgdn"; +import { bdstActionsExport, bdstStateExport, type bdstFulType, type bdstState } from "./ruseFcltMng/fcltReg/bdstReg"; +import { + htdflFacActionsExport, + htdflFacStateExport, + type htdflFacState, + type htdflFacType, +} from "./ruseFcltMng/fcltReg/htdflReg"; import { pubFacActionsExport, pubFacStateExport, @@ -17,23 +33,7 @@ import { type rswtFacState, type rswtFacType, } from "./ruseFcltMng/fcltReg/rswtReg"; -import { - matDmdActionsExport, - matDmdStateExport, - type matDmdState, - type matDmdType, -} from "./matDmd"; -import { - htdflFacActionsExport, - htdflFacStateExport, - type htdflFacState, - type htdflFacType, -} from "./ruseFcltMng/fcltReg/htdflReg"; -import { codeActionExport, comCodeStateExport, getCityCd, getEnvPartCd, getMiddleRegionCd, getRegionCd, getSggCd, getUnitWaterShedCd, type comCodeState, type comCodeType } from "./common/code"; -import { bdstActionsExport, bdstStateExport, type bdstFulType, type bdstState } from "./ruseFcltMng/fcltReg/bdstReg"; -import { rainChkgdnActionsExport, rainChkgdnStateExport, type rainChkgdnState, type rainChkgdnType } from "./prfmncReg/chkgdnReg/rainChkgdn"; -import { rswtChkgdnActionsExport, rswtChkgdnStateExport, type rswtChkgdnState, type rswtChkgdnType } from "./prfmncReg/chkgdnReg/rswrtChkgdn"; -import { sttnActionsExport, sttnStateExport, type sttnState, type sttnType } from "./ruseFcltMng/fcltSttn/sttn"; +import { rainSttnActionsExport, rainSttnStateExport, type rainSttnState, type rainSttnType } from "./ruseFcltMng/fcltSttn/rainSttn"; export type WrStore = comCodeType& pubFacType & @@ -44,7 +44,7 @@ export type WrStore = comCodeType& bdstFulType& rainChkgdnType& rswtChkgdnType& - sttnType + rainSttnType ; export const StoreZus = ( @@ -57,7 +57,7 @@ export const StoreZus = ( bdstState & rainChkgdnState& rswtChkgdnState& - sttnState + rainSttnState = { ...comCodeStateExport, ...pubFacStateExport, @@ -68,15 +68,15 @@ export const StoreZus = ( ...bdstStateExport, ...rainChkgdnStateExport, ...rswtChkgdnStateExport, - ...sttnStateExport + ...rainSttnStateExport } ) => { return createStore<WrStore>()((set) => { - getSggCd(set), - getCityCd(set), - getRegionCd(set), - getMiddleRegionCd(set), - getUnitWaterShedCd(set), + getSggCd(set); + getCityCd(set); + getRegionCd(set); + getMiddleRegionCd(set); + getUnitWaterShedCd(set) getEnvPartCd(set) return { ...initState, @@ -85,11 +85,11 @@ export const StoreZus = ( ...rswtFacActionsExport(set), ...matDmdActionsExport(set), ...htdflFacActionsExport(set), - ...codeActionExport(set), - ...bdstActionsExport(set), - ...rainChkgdnActionsExport(set), - ...rswtChkgdnActionsExport(set), - ...sttnActionsExport(set) + ...codeActionExport(set), + ...bdstActionsExport(set), + ...rainChkgdnActionsExport(set), + ...rswtChkgdnActionsExport(set), + ...rainSttnActionsExport(set) }; }); }; diff --git a/apps/wr/components/lib/api/index.ts b/apps/wr/components/lib/api/index.ts index 15b6d9aff..0ffa0d53c 100644 --- a/apps/wr/components/lib/api/index.ts +++ b/apps/wr/components/lib/api/index.ts @@ -1,11 +1,11 @@ //8880 -import { DEV_URL_FO, DEV_URL_WR } from "../config/"; - +import { DEV_URL_FO, DEV_URL_WR } from "../config/"; +export const fetchType={COMMON: "common", WR: "wr"} export const getFetch = async( type:string , url: string) => { - const div = type === 'common' ? DEV_URL_FO : DEV_URL_WR + const div = type === fetchType.COMMON ? DEV_URL_FO : DEV_URL_WR const response = await fetch( div+url , { method: "GET", headers: { diff --git a/apps/wr/components/lib/config/index.ts b/apps/wr/components/lib/config/index.ts index 66ab1c169..4028f6cc3 100644 --- a/apps/wr/components/lib/config/index.ts +++ b/apps/wr/components/lib/config/index.ts @@ -1,14 +1,14 @@ const LOCAL_PORT = "3000"; const DEV_PORT = "11080"; -const DEV_PORT_NEW="8882" +const DEV_PORT_NEW="11082" export const LOCAL_URL_WR = `http://localhost:${LOCAL_PORT}/api/v1`; export const DEV_URL_WR = `http://con.mind-one.co.kr:${DEV_PORT}/api/v1`; //export const DEV_URL_FO = `http://con.mind-one.co.kr:${DEV_PORT_FO}/api/v1`; -export const DEV_URL_FO = `http://192.168.1.193:${DEV_PORT_NEW}/api/v1`; +export const DEV_URL_FO = `http://con.mind-one.co.kr:${DEV_PORT_NEW}/api/v1`; diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx new file mode 100644 index 000000000..08126336e --- /dev/null +++ b/apps/wr/components/lib/func/TableData.tsx @@ -0,0 +1,142 @@ +import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui"; + + + + + + +export const rightTableData = (rainChk: rainChkZodType[]) => { + // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 + const maketotal = rainChk.map((item: rainChkZodType) => { + const selectTotal = item.guideDetails.reduce((acc: any, cur: any) => { + const code = cur.utztnUsgCd; + const fk = cur.chkgdnFk; + + const key = `${fk}_${code}`; + acc[key] = acc[key] || { + totalSplyUswtrUtztnQnt: 0, + totalRuseFcltUtztnQnt: 0, + }; + + acc[key].totalSplyUswtrUtztnQnt += cur.splyUswtrUtztnQnt; + acc[key].totalRuseFcltUtztnQnt += cur.ruseFcltUtztnQnt; + + return acc; + }, {}); + + return selectTotal; // 모든 키: `${chkgdnFk}_${utztnUsgCd}` 형태 + }); + + + // 2. 누계 정보들을 하나의 객체로 합치기 (평탄화) + const flatTotalMap = Object.assign({}, ...maketotal); + + // 3. rainyDetails에 누계 정보 주입 + + const updatedRainyDetails: any[] = []; + rainChk.forEach((rd: rainChkZodType) => { + rd.rainyDetails.forEach((rainyItem: any) => { + const key = `${rainyItem.chkgdnFk}_${rainyItem.utztnUsgCd}`; + const totals = flatTotalMap[key] || { + totalSplyUswtrUtztnQnt: 0, + totalRuseFcltUtztnQnt: 0, + }; + + updatedRainyDetails.push({ + ...rd, + ...rd.building, + ...rainyItem, + ...totals, + rowspan: rd.rainyDetails?.length, + }); + }); + }); + + return updatedRainyDetails; +}; + +export const chRowspanTable = ( + makeTableData: any[], + headList: TableUpperProps[], + handleChange: ( + rowIndex: number, + field: keyof (typeof makeTableData)[0], + value: string | number + ) => void, + toggleSelection: (pk: number, checked: boolean) => void, + selectedIds: number[], + handleCellClick: (index: number, headId: string) => void + ) => { + // rowspan된 셀 렌더링 여부 추적용 + const renderedMap = new Map<string, Set<number>>(); + return ( + <> + {makeTableData.map((row, rowIndex) => ( + <TableRow key={rowIndex}> + {headList.map((head) => { + const key = head.id; + const isMerged = head.rowSpan; + const value = row[key]; + + // 병합 대상이면 중복 렌더링 여부 판단 + if (isMerged) { + const renderedSet = renderedMap.get(key) ?? new Set<number>(); + if (renderedSet.has(rowIndex)) return null; // 이미 렌더링된 셀은 skip + + const rowspan = row.rowspan ?? 1; + for (let i = 0; i < rowspan; i++) { + renderedSet.add(rowIndex + i); + } + renderedMap.set(key, renderedSet); + + return ( + <TableCell + key={key} + rowSpan={rowspan} + className="align-middle text-center whitespace-nowrap" + > + {key === "order" ? ( + <Checkbox + checked={selectedIds.includes(row.chkgdnPk)} + onCheckedChange={(checked) => + toggleSelection(row.chkgdnPk, checked === true) + } + ></Checkbox> + ) : ( + value + )} + </TableCell> + ); + } + + // 기본 셀 + return ( + <TableCell + key={key} + className="text-center whitespace-nowrap" + onClick={() => handleCellClick(rowIndex, head.id)} + > + {key === "totalSplyUswtrUtztnQnt" || + key === "totalRuseFcltUtztnQnt" || + key === "utztnUsgCd" ? ( + `${value}` + ) : ( + <Input + className={`${head.type === "number" ? "text-right" : "text-center"} !text-xl`} + type={head.type} + onChange={(e) => { + handleChange(rowIndex, head.id, e.target.value); + }} + value={value} + /> + )} + </TableCell> + ); + })} + </TableRow> + ))} + </> + ); + }; \ No newline at end of file diff --git a/apps/wr/components/lib/func/commom.ts b/apps/wr/components/lib/func/commom.ts deleted file mode 100644 index 3e5be1593..000000000 --- a/apps/wr/components/lib/func/commom.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { comCodeState, selectArray } from "@/app/store/common/code"; - - - - - -export const getCity = (val: string, sggCd: selectArray[]) => { - const data = sggCd - .filter((item) => String(item.val).substring(0, 2) === val) - .map((item) => ({ - val: item.val, - text: item.text // 한국어 텍스트 - })); - return data - - }; - - -// cd text 넣기 - export const tableData = ( data: any,code:comCodeState)=>{ - const chCode = code.code; - - return data?.map((item: { sggCd: string; ctpvCd: string; reuseBuilding: { lawTrgtYn: any , bdstUsgCd:any}[]; }) => { - let returnData = {}; - const sggText = chCode.sggCd.find( - (cd) => cd.val === item.sggCd - )?.text; - const cityText = chCode.cityCd.find( - (cd) => cd.val === item.ctpvCd - )?.text; - - if (item?.reuseBuilding?.length >0) { - const bdsgUsgText = chCode.bdstUsgCd.find( - (cd) =>cd.val === item?.reuseBuilding[0]?.bdstUsgCd - )?.text - const lawTrgtYn = item?.reuseBuilding[0]?.lawTrgtYn - - returnData= { ...item, sggText: sggText, cityText: cityText ,bdsgUsgText:bdsgUsgText ,lawTrgtYn:lawTrgtYn}; - }else{ - returnData= { ...item, sggText: sggText, cityText: cityText}; - } - - // console.log(" returnData ", returnData) - return returnData; - - }); - } - - \ No newline at end of file diff --git a/apps/wr/components/lib/func/commom.tsx b/apps/wr/components/lib/func/commom.tsx new file mode 100644 index 000000000..b7f9d9eed --- /dev/null +++ b/apps/wr/components/lib/func/commom.tsx @@ -0,0 +1,85 @@ +import type { comCodeState, } from "@/app/store/common/code"; +import { filePickedBlob, type SelectDataType } from "@common/business_components/ui"; + + + + + +export const getCity = (val: string, sggCd: SelectDataType[]) => { + const data = sggCd + .filter((item) => String(item.val).substring(0, 2) === val) + .map((item) => ({ + val: item.val, + text: item.text // 한국어 텍스트 + })); + return data + + }; + + +// cd text 넣기 + export const tableData = ( data: any,code:comCodeState)=>{ + const chCode = code.code; + return data?.map((item: { sggCd: string; ctpvCd: string; reuseBuilding: { lawTrgtYn: any , bdstUsgCd:any}[]; }) => { + let returnData = {}; + const sggText = chCode.sggCd.find( + (cd) => cd.val === String(item.sggCd) + )?.text; + const cityText = chCode.cityCd.find( + (cd) => cd.val === String(item.ctpvCd) + )?.text; + console + .log(item?.reuseBuilding) + if (item?.reuseBuilding?.length >0) { + + const bdsgUsgText = chCode.bdstUsgCd.find( + (cd) =>Number(cd.val) === item?.reuseBuilding[0]?.bdstUsgCd + )?.text + const lawTrgtYn = item?.reuseBuilding[0]?.lawTrgtYn + console + .log(bdsgUsgText) + + returnData= { ...item, sggText: sggText??'없음', cityText: cityText??'없음' ,bdsgUsgText:bdsgUsgText ,lawTrgtYn:lawTrgtYn}; + }else{ + returnData= { ...item, sggText: sggText??'없음', cityText: cityText??'없음'}; + } + + return returnData; + + }); + } + + + + export const excelDownload =(excelList: [][], fileNm:string ,sampleFile:string, headerRange='A1:V3') =>{ + if (excelList.length === 0) return; + fetch(`/${sampleFile}`, {}) + .then(async (response) => { + if (!response.ok) { + throw Error(response.statusText) + } + // 받은 파일 바인너리 처리 + const blobRet = await response.arrayBuffer() + // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 + await filePickedBlob(blobRet, excelList,fileNm, 4,headerRange) + }) +} + + +// onchange 텍스트를 숫자로 and ,제거 +export const handleCommaNumberChange = ( + e: React.ChangeEvent<HTMLInputElement>, + onChange: (value: number | "") => void +) => { + const raw = e.target.value.replace(/,/g, ""); + if (!/^\d*$/.test(raw)) return; + onChange(raw === "" ? "" : Number(raw)); +}; +// 숫자입력시 , 삽입 + +export const formatCommaNumber = ( + value: number | string | undefined | null +): string => { + if (value === undefined || value === null || value === "") return ""; + return Number(value).toLocaleString(); +}; \ No newline at end of file diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx index a4107268f..02610279f 100644 --- a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx @@ -1,9 +1,18 @@ import { useWrStore } from "@/app/store"; import type { selectArray } from "@/app/store/common/code"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { getCity } from "@/components/lib/func/commom"; +import { + formatCommaNumber, + getCity, + handleCommaNumberChange, +} from "@/components/lib/func/commom"; import type { objSearchType } from "@/components/ui/modal/bdstRegModal/bdstRegModal"; -import { FormField, FormUi, DatePicker, SelectBox } from "@common/business_components"; +import { + FormField, + FormUi, + DatePicker, + SelectBox, +} from "@common/business_components"; import { Button, Input } from "@common/components"; import { useEffect, useRef, useState } from "react"; import { useFieldArray } from "react-hook-form"; @@ -30,49 +39,46 @@ export default function BdstReg({ form }: { form: any }) { if (fields.length > 0) { remove(fields.length - 1); } - }; + }; - const [selectSgg, setSelectSgg] = useState<selectArray[] | undefined>() - const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""}); - - const getSelCity = (val: string) => { - const data= getCity(val,code.sggCd) - setSelectSgg(data); - const sgg =form.getValues('sggCd') + const [selectSgg, setSelectSgg] = useState<selectArray[] | undefined>(); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); - setObjSearch({ city:val , sgg:''}) - - }; - - const getSgg = (val: string | number) => { + const getSelCity = (val: string) => { + const data = getCity(val, code.sggCd); + setSelectSgg(data); + const sgg = form.getValues("sggCd"); - const sgg =form.getValues('sggCd') - setObjSearch({...objSearch,sgg: val!=''?String(val):sgg }) - }; + setObjSearch({ city: val, sgg: "" }); + }; - - useEffect(()=>{ - const city =form.getValues('ctpvCd') - const sgg =form.getValues('sggCd') - setObjSearch({city:city , sgg:sgg }) - - }, [selectSgg]) + const getSgg = (val: string | number) => { + const sgg = form.getValues("sggCd"); + setObjSearch({ ...objSearch, sgg: val != "" ? String(val) : sgg }); + }; + + useEffect(() => { + const city = form.getValues("ctpvCd"); + const sgg = form.getValues("sggCd"); + setObjSearch({ city: city, sgg: sgg }); + }, [selectSgg]); useEffect(() => { const subscription = form.form?.watch((value: any) => { - console.log('vale', value) + console.log("vale", value); }); - + return () => subscription?.unsubscribe(); }, [form.form]); - const safeDate = (value: any): Date | undefined => { const date = new Date(value); return isNaN(date.getTime()) ? undefined : date; }; - - + return ( <> <h1 className="bg-gray-400 text-xl text-center border-2 p-2 mt-4 pl-6"> @@ -86,19 +92,15 @@ export default function BdstReg({ form }: { form: any }) { render={({ field }) => ( <FormUi label="시도"> <SelectBox - className="col-span-3 " - label={""} - selectClass={selectClass} - selectArray={code.cityCd} - - onSelectValue={(val)=>{ - getSelCity(String(val)) - field.onChange(Number(val) ); - } - - } - value={field.value} - + className="col-span-3 " + label={""} + selectClass={selectClass} + selectArray={code.cityCd} + onSelectValue={(val) => { + getSelCity(String(val)); + field.onChange(Number(val)); + }} + value={field.value} /> </FormUi> )} @@ -111,16 +113,15 @@ export default function BdstReg({ form }: { form: any }) { render={({ field }) => ( <FormUi label="시군구"> <SelectBox - className="col-span-3" - label={""} - selectClass={selectClass} - selectArray={selectSgg? selectSgg:code.sggCd || []} - onSelectValue={(val) =>{ - getSgg(val) - field.onChange(Number(val)) - }} - value={field.value} - + className="col-span-3" + label={""} + selectClass={selectClass} + selectArray={selectSgg ? selectSgg : code.sggCd || []} + onSelectValue={(val) => { + getSgg(val); + field.onChange(Number(val)); + }} + value={field.value} /> </FormUi> )} @@ -135,7 +136,7 @@ export default function BdstReg({ form }: { form: any }) { render={({ field }) => ( <FormUi label="건축물명"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="text" {...field} @@ -151,7 +152,7 @@ export default function BdstReg({ form }: { form: any }) { render={({ field }) => ( <FormUi label="위치"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="search" {...field} @@ -186,16 +187,14 @@ export default function BdstReg({ form }: { form: any }) { name="frstArchPrmsnDt" render={({ field }) => ( <FormUi label="최초건축허가일"> - <DatePicker - mode={"single"} - field={{ - value: field.value|| new Date(), - onChange: (date: Date | undefined) => - field.onChange(date), - }} - selectClass={selectClass} - ></DatePicker> - + <DatePicker + mode={"single"} + field={{ + value: field.value || new Date(), + onChange: (date: Date | undefined) => field.onChange(date), + }} + selectClass={'w-full'} + ></DatePicker> </FormUi> )} /> @@ -207,14 +206,13 @@ export default function BdstReg({ form }: { form: any }) { render={({ field }) => ( <FormUi label="건축면적(m³)"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="number" - {...field} onChange={(e) => { - const value = e.target.value; - field.onChange(value === "" ? "" : Number(value)); + handleCommaNumberChange(e, field.onChange); }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -249,7 +247,7 @@ export default function BdstReg({ form }: { form: any }) { 이력추가 </Button> <Button - type="button" + type="button" className="rounded-lg bg-red-500 text-white" onClick={removeLastItem} > @@ -270,7 +268,6 @@ export default function BdstReg({ form }: { form: any }) { selectClass={selectClass} label={""} selectArray={code.chBuCd} - onSelectValue={(val) => { field.onChange(val); }} @@ -286,15 +283,15 @@ export default function BdstReg({ form }: { form: any }) { name={`chgBuilding.${index}.archChgPrmsnDt`} render={({ field }) => ( <FormUi label="허가일"> - <DatePicker - mode={"single"} - field={{ - value: safeDate(field.value) || new Date(), - onChange: (date: Date | undefined) => - field.onChange(date), - }} - selectClass={selectClass} - ></DatePicker> + <DatePicker + mode={"single"} + field={{ + value: safeDate(field.value) || new Date(), + onChange: (date: Date | undefined) => + field.onChange(date), + }} + selectClass={'w-full'} + ></DatePicker> </FormUi> )} /> @@ -306,12 +303,13 @@ export default function BdstReg({ form }: { form: any }) { render={({ field }) => ( <FormUi label="면적"> <Input - className="" + className={selectClass} placeholder="-" type="text" - value={ field.value??"-"} - onChange={(e) => field.onChange((e.target.value))} - + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} diff --git a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx index 5e58b9f8a..62af8cd19 100644 --- a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx @@ -18,6 +18,10 @@ import { } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; import { useEffect } from "react"; import BdstReg from "../bdstReg/bdstReg"; +import { + formatCommaNumber, + handleCommaNumberChange, +} from "@/components/lib/func/commom"; export default function HtdflRegForm({ htdflForm, @@ -35,19 +39,19 @@ export default function HtdflRegForm({ defaultValues: defaultValues, }); - const onSubmit=(values: z.infer<typeof hdtflZod>)=> { + const onSubmit = (values: z.infer<typeof hdtflZod>) => { if (isModal) { htdflReg(values); } else { htdflUpdate(values); } - } + }; const onSelectValue = (val: string | number) => { console.log(val); }; - const cleanHtdflData=(raw: any): z.infer<typeof hdtflZod> =>{ + const cleanHtdflData = (raw: any): z.infer<typeof hdtflZod> => { return { ...raw, frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null), @@ -70,16 +74,12 @@ export default function HtdflRegForm({ }, })), }; - } - - - + }; useEffect(() => { console.log("form errors:", form.formState.errors); }, [form.formState.errors]); - useEffect(() => { if (hdtflZod) form.reset(cleanHtdflData(htdflForm)); }, [htdflForm]); @@ -91,26 +91,24 @@ export default function HtdflRegForm({ <div> <div className="grid grid-cols-12"> <h1 className="pl-3 text-xl col-span-10">○온배수 시설 정보</h1> - <Button size={"sm"} type="submit" className="col-start-12 col-span-1"> + <Button + size={"sm"} + type="submit" + className="col-start-12 col-span-1" + > 저장 </Button> </div> </div> - { isModal && htdflForm != undefined ? ( - <BdstReg form={form} /> - ) : ( - <></> - )} - {isModal ? ( - <h1 className="pl-3 text-xl col-span-10 mt-4 "> - ○ 중수도 시설 정보{" "} - </h1> - ) : ( - <></> - )} - - + {isModal && htdflForm != undefined ? <BdstReg form={form} /> : <></>} + {isModal ? ( + <h1 className="pl-3 text-xl col-span-10 mt-4 "> + ○ 중수도 시설 정보{" "} + </h1> + ) : ( + <></> + )} <div className="grid grid-cols-6 gap-2 mt-4 pl-6"> <div className="col-span-2"> @@ -120,7 +118,7 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="발전유형(코드정비후 수정)"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="text" value={field.value ?? ""} @@ -138,13 +136,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="설비용량"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="text" - value={field.value ?? 0} onChange={(e) => { - field.onChange(Number(e.target.value)); + handleCommaNumberChange(e, field.onChange); }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -183,7 +181,7 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="원수취수 지점(코드정비후 수정)"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="text" value={field.value ?? 0} @@ -202,7 +200,7 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="원수발생 공정"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="" value={field.value ?? ""} @@ -219,13 +217,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="취수구 온도"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="" - value={field.value ?? 0} + type="text" onChange={(e) => { - field.onChange(Number(e.target.value)); + handleCommaNumberChange(e, field.onChange); }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -238,11 +236,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="발생량(m³/년)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -273,11 +273,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="처리시설 용량(m³/년)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -308,11 +310,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="이용량(m³/년)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -325,7 +329,7 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="이용용도"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="text" value={field.value ?? ""} @@ -351,10 +355,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="총대장균군"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -368,10 +375,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="총질소"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -387,10 +397,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="결합잔류염소"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -404,10 +417,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="총인"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -423,10 +439,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="탁도"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -440,10 +459,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="수소이온농도"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -459,10 +481,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="생물학적 산소요구량"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -476,10 +501,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="염화물"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -495,10 +523,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="냄새"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -512,10 +543,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="전기전도도"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -531,10 +565,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="색도"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -548,10 +585,13 @@ export default function HtdflRegForm({ render={({ field }) => ( <FormUi label="배출구온도"> <Input + className={selectClass} placeholder="10" type="text" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} diff --git a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx index 88d7638cf..30249fa68 100644 --- a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx @@ -15,6 +15,7 @@ import { useEffect, useState } from "react"; import { useForm, useWatch, type UseFormReturn } from "react-hook-form"; import { z } from "zod"; import BdstReg from "../bdstReg/bdstReg"; +import { formatCommaNumber, handleCommaNumberChange } from "@/components/lib/func/commom"; export default function RainRegForm({ rainForm, @@ -23,7 +24,7 @@ export default function RainRegForm({ rainForm: customRainBdst; isModal: boolean; }) { - const { code, rainReg, rainUpdate, rain } = useWrStore((state) => state); + const { code, rainBdstReg, rainBdstUpdate, rain } = useWrStore((state) => state); const { rainFcltCd } = code; const defaultValues: z.infer<typeof rainZod> = rainZod.parse({}); @@ -87,9 +88,9 @@ useEffect(() =>{ const onSubmit =(values: z.infer<typeof rainZod>)=> { if (isModal) { - rainReg(values); + rainBdstReg(values ,'41'); } else { - rainUpdate(values); + rainBdstUpdate(values, '41'); } } @@ -101,7 +102,7 @@ useEffect(() =>{ - + const inputClass = '!text-lg' return ( <div className=""> @@ -109,7 +110,7 @@ useEffect(() =>{ <form onSubmit={form.handleSubmit(onSubmit)}> <div> <div className="grid grid-cols-12"> - <h1 className="pl-3 text-xl col-span-10"> + <h1 className="pl-3 !text-lg col-span-10"> {isModal ? "○건축물 운영정보" : "○ 빗물이용시설 정보"} </h1> <Button type="submit" className="mr-4 rounded-lg col-span-2"> @@ -145,7 +146,7 @@ useEffect(() =>{ : new Date(), // Provide a default Date value onChange: (date) => field.onChange(date), }} - selectClass={""} + selectClass={'w-full'} /> </FormUi> )} @@ -159,13 +160,11 @@ useEffect(() =>{ render={({ field }) => ( <FormUi label="설치비"> <Input - className="" - placeholder="1,000,000" - type="number" - value={field.value ?? 0} - onChange={(e) => { - field.onChange(e.target.value === "" ? "" : Number(e.target.value)); - }} + className={selectClass} + placeholder="1,000,000" + type="text" + onChange={(e) => {handleCommaNumberChange(e, field.onChange) }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -207,11 +206,11 @@ useEffect(() =>{ render={({ field }) => ( <FormUi label="면적(m³)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="number" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => {handleCommaNumberChange(e, field.onChange) }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -248,11 +247,11 @@ useEffect(() =>{ render={({ field }) => ( <FormUi label="용량(m³/일)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="number" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => {handleCommaNumberChange(e, field.onChange) }} + value={formatCommaNumber(field.value)} readOnly={filtrTrtmfctYn!=='Y'} /> @@ -267,7 +266,7 @@ useEffect(() =>{ render={({ field }) => ( <FormUi label="처리공정"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="" value={field.value ?? ""} @@ -314,15 +313,12 @@ useEffect(() =>{ render={({ field }) => ( <FormUi label="지원금액(원)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="number" - onChange={(e) => { - const value = e.target.value; - field.onChange(value === "" ? "" : Number(value)); - }} - value={field.value ?? 0} - readOnly={instlCstSprtYn!=='Y'} + type="text" + onChange={(e) => {handleCommaNumberChange(e, field.onChange) }} + value={formatCommaNumber(field.value)} + readOnly={instlCstSprtYn !== 'Y'} /> </FormUi> )} @@ -358,7 +354,7 @@ useEffect(() =>{ name="reuseBuilding.0.grntchBdstCertYr" render={({ field }) => ( <FormUi label="인증년도"> - <Input className="" placeholder="2024" type="" value={field.value ?? ""} + <Input className={selectClass} placeholder="2024" type="" value={field.value ?? ""} onChange={field.onChange} readOnly={grntchBdstCertYn!=='Y'}/> @@ -373,7 +369,7 @@ useEffect(() =>{ render={({ field }) => ( <FormUi label="인증번호"> <Input - className="" + className={selectClass} placeholder="ab1234678" type="" value={field.value ?? ""} @@ -390,7 +386,7 @@ useEffect(() =>{ name="reuseBuilding.0.grntchBdstCertGrd" render={({ field }) => ( <FormUi label="인증등급"> - <Input className="" placeholder="A" type="" value={field.value ?? ""} + <Input className={selectClass} placeholder="A" type="" value={field.value ?? ""} onChange={field.onChange} readOnly={grntchBdstCertYn!=='Y'} /> diff --git a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx index 11dccc189..7696e88d7 100644 --- a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx @@ -9,8 +9,8 @@ import { } from "@common/business_components/ui"; import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; import { useWrStore } from "@/app/store"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { @@ -19,6 +19,10 @@ import { } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import { useEffect } from "react"; import BdstReg from "../bdstReg/bdstReg"; +import { + formatCommaNumber, + handleCommaNumberChange, +} from "@/components/lib/func/commom"; export default function RswtrRegForm({ rswtForm, @@ -27,78 +31,69 @@ export default function RswtrRegForm({ rswtForm: customRswtBdst; isModal: boolean; }) { - const { rswt, code ,rswtUpdate,rswtReg} = useWrStore((state) => state); - + const { rswt, code, rswtBdstUpdate, rswtBdstReg } = useWrStore((state) => state); const defaultValues: z.infer<typeof rswtZod> = rswtZod.parse({}); - const form = useForm<z.infer<typeof rswtZod>>({ resolver: zodResolver(rswtZod), defaultValues: defaultValues, - - }) + }); - const [grntchBdstCertYn, instlCstSprtYn,filtrTrtmfctProcs] = form.watch([ + const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs] = form.watch([ "reuseBuilding.0.grntchBdstCertYn", "reuseBuilding.0.instlCstSprtYn", "reuseBuilding.0.rswtrObj.filtrTrtmfctProcs", ]); - const onSubmit =(values: z.infer<typeof rswtZod>) => { + const onSubmit = (values: z.infer<typeof rswtZod>) => { if (isModal) { - rswtReg(values); - } else { - rswtUpdate(values); - } - } - const cleanRswtData = (raw: any): z.infer<typeof rswtZod> =>{ + rswtBdstReg(values,'41'); + } else { + rswtBdstUpdate(values,'41'); + } + }; + const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => { return { ...raw, - frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt||null), - archChgPrmsnDt: raw?.archChgPrmsnDt ? new Date(raw?.archChgPrmsnDt) : null, + frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null), + archChgPrmsnDt: raw?.archChgPrmsnDt + ? new Date(raw?.archChgPrmsnDt) + : null, reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({ ...item, instlCmptnDt: new Date(item?.instlCmptnDt), operMngCd: item?.operMngCd ?? "", // null → "" - grntchBdstCertYr: typeof item?.grntchBdstCertYr === "string" - ? item?.grntchBdstCertYr - : "", // null → "" + grntchBdstCertYr: + typeof item?.grntchBdstCertYr === "string" + ? item?.grntchBdstCertYr + : "", // null → "" rswtrObj: { - ...item?.rswtrObj - } - })) + ...item?.rswtrObj, + }, + })), }; - } + }; + useEffect(() => { + console.log("form errors:", form.formState.errors); + }, [form.formState.errors]); -useEffect(() => { - console.log("form errors:", form.formState.errors); -}, [form.formState.errors]); + useEffect(() => { + console.log("filtrTrtmfctProcs ", filtrTrtmfctProcs); + if (grntchBdstCertYn === "N") { + form.setValue("reuseBuilding.0.grntchBdstCertYr", ""); + form.setValue("reuseBuilding.0.grntchBdstCertNo", ""); + form.setValue("reuseBuilding.0.grntchBdstCertGrd", ""); + } else if (instlCstSprtYn === "N") { + form.setValue("reuseBuilding.0.instlCstSprtAmt", 0); + } + }, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs]); - - -useEffect(() =>{ - - console.log("filtrTrtmfctProcs ", filtrTrtmfctProcs) - if(grntchBdstCertYn ==='N'){ - form.setValue('reuseBuilding.0.grntchBdstCertYr' ,"" ) - form.setValue('reuseBuilding.0.grntchBdstCertNo' ,"" ) - form.setValue('reuseBuilding.0.grntchBdstCertGrd' ,"" ) - }else if(instlCstSprtYn ==='N'){ - form.setValue('reuseBuilding.0.instlCstSprtAmt' ,0 ) - } -},[grntchBdstCertYn,instlCstSprtYn,filtrTrtmfctProcs ]) - - - - -useEffect(() => { - if(rswtZod) - form.reset( cleanRswtData(rswtForm)) + useEffect(() => { + if (rswtZod) form.reset(cleanRswtData(rswtForm)); }, [rswtForm]); - return ( <div className=""> <Form {...form}> @@ -106,20 +101,18 @@ useEffect(() => { {/* <div className="flex justify-between items-center mx-3"> */} <div> <div className="grid grid-cols-12"> - <h1 className="pl-3 text-xl col-span-10"> - ○ 중수도 시설 정보 - </h1> - <Button size={"sm"} type="submit" className="col-start-12 col-span-1"> + <h1 className="pl-3 text-xl col-span-10">○ 중수도 시설 정보</h1> + <Button + size={"sm"} + type="submit" + className="col-start-12 col-span-1" + > 저장 </Button> </div> </div> - {isModal && rswtForm != undefined ? ( - <BdstReg form={form} /> - ) : ( - <></> - )} + {isModal && rswtForm != undefined ? <BdstReg form={form} /> : <></>} {isModal ? ( <h1 className="pl-3 text-xl col-span-10 mt-4 "> ○ 중수도 시설 정보{" "} @@ -160,11 +153,13 @@ useEffect(() => { render={({ field }) => ( <FormUi label="설치비"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="number" - value={field.value ?? ""} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -179,11 +174,13 @@ useEffect(() => { render={({ field }) => ( <FormUi label="물사용량(m³)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="number" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -197,11 +194,13 @@ useEffect(() => { render={({ field }) => ( <FormUi label="의무대상 물사용량(m³)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="number" - value={field.value ?? 0} - onChange={(e) => field.onChange(Number(e.target.value))} + type="text" + onChange={(e) => { + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} /> </FormUi> )} @@ -240,7 +239,7 @@ useEffect(() => { render={({ field }) => ( <FormUi label="주요처리공정"> <Input - className="" + className={selectClass} placeholder="1,000,000" type="" value={field.value ?? ""} @@ -286,14 +285,14 @@ useEffect(() => { render={({ field }) => ( <FormUi label="지원금액(원)"> <Input - className="" + className={selectClass} placeholder="1,000,000" - type="number" - value={field.value ?? 0} + type="text" onChange={(e) => { - field.onChange(Number(e.target.value)); + handleCommaNumberChange(e, field.onChange); }} - readOnly={instlCstSprtYn!=='Y'} + value={formatCommaNumber(field.value)} + readOnly={instlCstSprtYn !== "Y"} /> </FormUi> )} @@ -330,13 +329,13 @@ useEffect(() => { render={({ field }) => ( <FormUi label="인증년도"> <Input - className="" + className={selectClass} placeholder="2024" type="text" {...field} value={field.value ?? ""} onChange={field.onChange} - readOnly={grntchBdstCertYn!=='Y'} + readOnly={grntchBdstCertYn !== "Y"} /> </FormUi> )} @@ -349,13 +348,12 @@ useEffect(() => { render={({ field }) => ( <FormUi label="인증번호"> <Input - className="" + className={selectClass} placeholder="ab1234678" type="" value={field.value ?? ""} onChange={field.onChange} - readOnly={grntchBdstCertYn!=='Y'} - + readOnly={grntchBdstCertYn !== "Y"} /> </FormUi> )} @@ -368,13 +366,12 @@ useEffect(() => { render={({ field }) => ( <FormUi label="인증등급"> <Input - className="" + className={selectClass} placeholder="A" type="" value={field.value ?? ""} onChange={field.onChange} - readOnly={grntchBdstCertYn!=='Y'} - + readOnly={grntchBdstCertYn !== "Y"} /> </FormUi> )} diff --git a/apps/wr/components/ui/modal/bdstRegModal/bdstRegModal.tsx b/apps/wr/components/ui/modal/bdstRegModal/bdstRegModal.tsx index 308c01241..c00f54bd1 100644 --- a/apps/wr/components/ui/modal/bdstRegModal/bdstRegModal.tsx +++ b/apps/wr/components/ui/modal/bdstRegModal/bdstRegModal.tsx @@ -1,20 +1,19 @@ "use client"; -import { headMakeColSpan } from "@/app/ruseFcltMng/fcltReg/rainReg/page"; import { useWrStore } from "@/app/store"; import { selectClass, type customRainBdst, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { ScrollArea, SelectBox, UiTable } from "@common/business_components"; +import { ScrollArea, SelectBox, UiTable, type SelectDataType } from "@common/business_components"; import { Button, Input, Label } from "@common/components"; import { useEffect, useState } from "react"; import RainRegForm from "../../form/fcltReg/rainReg/rainRegForm"; -import { type selectArray } from "@/app/store/common/code"; import { getCity, tableData } from "@/components/lib/func/commom"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import HtdflRegForm from "../../form/fcltReg/htdflReg/htdflRegForm"; import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; import RswtrRegForm from "../../form/fcltReg/rswtrReg/rswtrRegForm"; +import { headMakeColSpan } from "@/app/ruseFcltMng/fcltReg/rainReg/TableHead"; export type objSearchType = { sgg: string|number; @@ -40,7 +39,7 @@ export function BdstReg<T extends MoType>({ moType }: BdstRegProps<T>) { const [bdstTable, setbdstTable] = useState<BdstTypeMap[T][]>(); const [rainBdstForm, setRainBdstForm] = useState<BdstTypeMap[T]>({} as BdstTypeMap[T]); const [searchTxt, setSearchTxt] = useState<string>() - const [selectSgg, setSelectSgg] = useState<selectArray[] | []>() + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""}); const getSelCity = (val: string | number) => { diff --git a/apps/wr/components/ui/modal/chkgdExcel/chkgdExcel.tsx b/apps/wr/components/ui/modal/chkgdExcel/chkgdExcel.tsx index 28aebe0f4..895af4388 100644 --- a/apps/wr/components/ui/modal/chkgdExcel/chkgdExcel.tsx +++ b/apps/wr/components/ui/modal/chkgdExcel/chkgdExcel.tsx @@ -1,4 +1,6 @@ -import { rainRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { useWrStore } from "@/app/store"; +import { rainChkZod, rainRegExcel, type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { excelToRainChkData } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { DatePicker, @@ -9,17 +11,20 @@ import { FormUi, Title, } from "@common/business_components/ui"; -import { Button } from "@common/components/ui"; +import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; +import toast, { Toaster } from "react-hot-toast"; import type { z } from "zod"; +import { ToastFormUi } from "../../toast/toastFromUi"; export default function ChkgdExcel({ type }: { type: string }) { - const [files, setFiles] = useState(null); - - const [dmdDate, setDmdDate] = useState(new Date()); - + const { rainChkExcelDataUPload } = 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 form = useForm<z.infer<typeof rainRegExcel>>({ @@ -27,22 +32,40 @@ export default function ChkgdExcel({ type }: { type: string }) { defaultValues: defaultValues, }); - const onChangeDate = (val: Date | undefined) => { - if (val) setDmdDate(val); - }; - useEffect(() => { - if (files) { - const file = files[0]; - if(file) filePicked(file,1).then((res) => console.log(res)); - }else{ - + if (files) { + const file = files[0]; + if(form.getValues("chckYr").length<1 ){ + ToastFormUi({body:"파일업로드 이전에 등록년도를 작성해주세요 " ,title:'지도점검 등록'}) + setFiles(null) + return + } + if (file) + filePicked(file, 0).then((res) => { + if (res !== undefined) + setExcelData(excelToRainChkData(res, form.getValues("chckYr"))) + }); + } + }, [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 } - }, [files]) + if (excelData) { + rainChkExcelDataUPload(excelData); + } + } + return ( <> <div> <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)}> <div> <Title title={ @@ -57,25 +80,22 @@ export default function ChkgdExcel({ type }: { type: string }) { {"○점검정보 입력"} </h3> - <Button className="">저장</Button> + <Button className="" type="submit"> + 저장 + </Button> </div> <div> <FormField control={form.control} - name="chckYmd" + name="chckYr" render={({ field }) => ( - <FormUi label="점검일자"> - <DatePicker - mode="single" - field={{ - value: - field.value && !isNaN(new Date(field.value).getTime()) - ? new Date(field.value) - : new Date(), // Provide a default Date value - onChange: (date) => field.onChange(date), - }} - selectClass={selectClass} + <FormUi label="등록년도"> + <Input + className={`text-3xl`} + type="text" + value={field.value} + onChange={field.onChange} /> </FormUi> )} @@ -87,16 +107,20 @@ export default function ChkgdExcel({ type }: { type: string }) { render={({ field }) => ( <FormUi label="점검결과 파일"> <FileUpload - files={field.value} - setFiles={setFiles} + files={files || []} + setFiles={(files: File[] | null ) => { + if(files) setFiles(files) + } } fileTypes="xlsx" ></FileUpload> </FormUi> )} /> </div> + </form> </Form> </div> + </> ); } diff --git a/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx index 96b324b3c..c07a84341 100644 --- a/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx @@ -1,10 +1,10 @@ -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; 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 { GuideDetailsTable } from "../../table/chkgdTable/guideDetailTable/guideDetailTable"; import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { const { rainChkgdn, rainChkDetilUpdate, rainChkGuidUpdate } = useWrStore( diff --git a/apps/wr/components/ui/modal/headChModal/headChModal.tsx b/apps/wr/components/ui/modal/headChModal/headChModal.tsx index 979834dbb..2f1236f27 100644 --- a/apps/wr/components/ui/modal/headChModal/headChModal.tsx +++ b/apps/wr/components/ui/modal/headChModal/headChModal.tsx @@ -1,43 +1,44 @@ import { useWrStore } from "@/app/store"; -import type { TableProps } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg"; -import type { TableTripleProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { rainSttnHeadListType } from "@/app/store/ruseFcltMng/fcltSttn/rainSttn/headList"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@common/business_components/ui"; import { Button, Checkbox } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; export default function HeadChModal({type }:{type: string }) { - const { sttnCommon ,chSttnHead} = useWrStore((state) => state); + const { rainSttn ,rainChSttnHead} = useWrStore((state) => state); - const { rainSttHeadList,pbnSttHeadList } =sttnCommon; - let items = rainSttHeadList.map(item => ({id:item.id, label:item.title})); + const { rainSttHeadList, rainSttNodeList } =rainSttn; + let items = rainSttHeadList.map(item => ({id:item.id, title:item.title, val:item.visible })); + - const FormSchema = z.object({ - data: z.array(z.string()).refine((value) => value.some((item) => item), { - message: "최소한 하나를 선택해주시길 바랍니다.", - - }), - }) - - const form = useForm<z.infer<typeof FormSchema>>({ - resolver: zodResolver(FormSchema), - defaultValues: { - data: [], - }, - }) - - - - - const onSubmit = (val : z.infer<typeof FormSchema>) =>{ - - if(val?.data.length > 0) - chSttnHead(val?.data, 'rain') + // const FormSchema = + // z.object({ + // id: z.string().refine((value) => value.some((item) => item), { + // message: "최소한 하나를 선택해주시길 바랍니다.", + // }), + // visible: z.boolean() + // }) + + const form = useForm<z.infer<typeof rainSttnHeadListType>>({ + resolver: zodResolver(rainSttnHeadListType), + defaultValues: [], + }) + + + useEffect(() =>{ + form.reset(rainSttHeadList) + + + },[rainSttHeadList]) + + const onSubmit = (headList : z.infer<typeof rainSttnHeadListType> ) =>{ + rainChSttnHead(headList) } return ( @@ -45,57 +46,41 @@ export default function HeadChModal({type }:{type: string }) { <div> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8"> - <FormField - control={form.control} - name="data" - render={() => ( - <FormItem> + <div className="mb-4"> - <FormLabel className="text-2xl"> 조회항목 설정</FormLabel> - + <h3>조회항목 설정</h3> </div> - {items.map((item) => ( + {items.map((item,index) => ( <FormField - key={item.id} + key={`${index}.id`} control={form.control} - name="data" + name={`${index}.visible`} render={({ field }) => { return ( <FormItem - key={item.id} + key={`${index}.id`+'item'} className="flex flex-row items-start space-x-3 space-y-0" > <FormControl> <Checkbox - checked={field.value?.includes(item.id)} + checked={field.value} onCheckedChange={(checked) => - { - return checked - ? field.onChange([...field.value, item.id]) - : field.onChange( - field.value?.filter( - (value) => value !== item.id - ) - ); - } - + field.onChange(checked); + return; + } } /> </FormControl> <FormLabel className="text-xl"> - {item.label} + {item.title} </FormLabel> </FormItem> ); }} /> ))} - <FormMessage /> - </FormItem> - )} - /> <Button type="submit">항목 표출 변경</Button> </form> </Form> diff --git a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx index c38fc93d3..d87f4ca28 100644 --- a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx @@ -1,8 +1,7 @@ "use client"; -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; +import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; import type { - rainChkZodType, splRuseWaterType, } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; @@ -30,7 +29,6 @@ export function GuideDetailsTable({ const { code, rainChkgdn } = useWrStore((state) => state); const [guidData, setGuidData] = useState<splRuseWaterType[]>(); - const nodeList = headMakeprfmnc(headList, rainChkgdn?.rainHeadNm); const handleChange = ( rowIndex: number, @@ -89,7 +87,7 @@ export function GuideDetailsTable({ <> <div className={`card !m-[1.2rem] !p-0r `}> <Table variant="secondary"> - <TableHeader className="font-bold">{nodeList}</TableHeader> + <TableHeader className="font-bold">{headMakeprfmnc(headList, rainChkgdn?.rainHeadNm)}</TableHeader> <TableBody > {tableBody(guidData ?? [])} </TableBody> diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx index f34efa467..4aa57fe5e 100644 --- a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -1,188 +1,31 @@ "use client"; -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; +import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { tableData } from "@/components/lib/func/commom"; -import { UiModal } from "@common/business_components/ui"; import { - Checkbox, - Input, + chRowspanTable, + rightTableData +} from "@/components/lib/func/TableData"; +import { Table, TableBody, - TableCell, TableHeader, - TableRow, } from "@common/components/ui"; -import { useEffect, useState } from "react"; -import ChkgdModal from "../../../modal/chkgdModal/chkgdModal"; - -export const totalData = ( - makeTableData: any[], - headList: TableUpperProps[], - handleChange: ( - rowIndex: number, - field: keyof (typeof makeTableData)[0], - value: string | number - ) => void, - toggleSelection: (pk: number, checked: boolean) => void, - selectedIds: number[], - handleCellClick: (index: number, headId: string) => void -) => { - const mergeKeys = [ - "order", - "cityText", - "sggText", - "bdstNm", - "operMngCd", - "flowCheck", - "yearFee", - "rainDtnbaOpct", - "chckYmd", - ]; - - // rowspan된 셀 렌더링 여부 추적용 - const renderedMap = new Map<string, Set<number>>(); - return ( - <> - {makeTableData.map((row, rowIndex) => ( - <TableRow key={rowIndex}> - {headList.map((head) => { - const key = head.id; - const isMerged = head.rowSpan; - const value = row[key]; - - // 병합 대상이면 중복 렌더링 여부 판단 - if (isMerged) { - const renderedSet = renderedMap.get(key) ?? new Set<number>(); - if (renderedSet.has(rowIndex)) return null; // 이미 렌더링된 셀은 skip - - const rowspan = row.rowspan ?? 1; - for (let i = 0; i < rowspan; i++) { - renderedSet.add(rowIndex + i); - } - renderedMap.set(key, renderedSet); - - return ( - <TableCell - key={key} - rowSpan={rowspan} - className="align-middle text-center whitespace-nowrap" - > - {key === "order" ? ( - <Checkbox - checked={selectedIds.includes(row.chkgdnPk)} - onCheckedChange={(checked) => - toggleSelection(row.chkgdnPk, checked === true) - } - ></Checkbox> - ) : ( - value - )} - </TableCell> - ); - } - - // 기본 셀 - return ( - <TableCell - key={key} - className="text-center whitespace-nowrap" - onClick={() => handleCellClick(rowIndex, head.id)} - > - {key === "totalSplyUswtrUtztnQnt" || - key === "totalRuseFcltUtztnQnt" || - key === "utztnUsgCd" ? ( - `${value}` - ) : ( - <Input - className={`${head.type === "number" ? "text-right" : "text-center"} text-3xl`} - type={head.type} - onChange={(e) => { - handleChange(rowIndex, head.id, e.target.value); - }} - value={value} - /> - )} - </TableCell> - ); - })} - </TableRow> - ))} - </> - ); -}; - -export const rightTableData = (rainChk: rainChkZodType[]) => { - // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 - const maketotal = rainChk.map((item: any) => { - const selectTotal = item.guideDetails.reduce((acc: any, cur: any) => { - const code = cur.utztnUsgCd; - const fk = cur.chkgdnFk; - - const key = `${fk}_${code}`; - acc[key] = acc[key] || { - totalSplyUswtrUtztnQnt: 0, - totalRuseFcltUtztnQnt: 0, - }; - - acc[key].totalSplyUswtrUtztnQnt += cur.splyUswtrUtztnQnt; - acc[key].totalRuseFcltUtztnQnt += cur.ruseFcltUtztnQnt; - - return acc; - }, {}); - - return selectTotal; // 모든 키: `${chkgdnFk}_${utztnUsgCd}` 형태 - }); - - // 2. 누계 정보들을 하나의 객체로 합치기 (평탄화) - const flatTotalMap = Object.assign({}, ...maketotal); - - // 3. rainyDetails에 누계 정보 주입 - - const updatedRainyDetails: any[] = []; - rainChk.forEach((rd: any) => { - const details = rd.rainyDetails.forEach((rainyItem: any) => { - const key = `${rainyItem.chkgdnFk}_${rainyItem.utztnUsgCd}`; - const totals = flatTotalMap[key] || { - totalSplyUswtrUtztnQnt: 0, - totalRuseFcltUtztnQnt: 0, - }; - - updatedRainyDetails.push({ - ...rd, - ...rd.building, - ...rainyItem, - ...totals, - rowspan: rd.rainyDetails?.length, - }); - }); - }); - - return updatedRainyDetails; -}; - +import { useCallback, useEffect, useState } from "react"; export default function RainChkgdTable({ - detailUp, + detailUp, + handleClick=() => {}, + deleteData }: { detailUp: (data: rainChkZodType[]) => void; + handleClick?: (data:any) => void; + deleteData:(selectedIds:number[])=>void }) { const { code, rainChkgdn } = useWrStore((state) => state); const [makeTableData, setMakeTableData] = useState<any[]>([]); - const { rainChk } = rainChkgdn; const [selectedIds, setSelectedIds] = useState<number[]>([]); const [upRaintDetail, setUpRaintDetail] = useState<rainChkZodType[]>([]); - const [isModal, setIsModal] = useState({open:false, data:{}}); - - const handleCellClick = (index: number, headId: string) => { - if ( - headId === "totalSplyUswtrUtztnQnt" || - headId === "totalRuseFcltUtztnQnt" - ) { - setIsModal({open:true, data: makeTableData[index]}); - } - }; - const toggleSelection = (pk: number, checked: boolean) => { setSelectedIds((prev) => checked ? [...prev, pk] : prev.filter((item) => item !== pk) @@ -193,48 +36,60 @@ export default function RainChkgdTable({ field: keyof (typeof makeTableData)[0], value: string | number ) => { + setMakeTableData((prev) => - prev.map((row, idx) => - idx === rowIndex ? { ...row, [field]: value } : row + prev.map((row, idx) => { + return idx === rowIndex ? { ...row, [field]: value } : row + } ) ); }; - const nodeList = headMakeprfmnc( - rainChkgdn?.rainChkgdnHeadList, - rainChkgdn?.rainHeadNm - ); + const handleCellClick= useCallback((index: number, headId: string) => { + if ( + headId === "totalSplyUswtrUtztnQnt" || + headId === "totalRuseFcltUtztnQnt" + ) { + handleClick(makeTableData[index]) + } + },[makeTableData, handleClick]); + + useEffect(() => { - const rainChg = rainChk.map((item: any) => { + setSelectedIds([])// 셀렉트 초기화를 위한 작업 + const rainChg = rainChkgdn.rainChk.map((item: any) => { const bud = tableData([item.building], { code }); - return { ...item, ...bud[0], rowspan: item.rainyDetails?.length, }; }); - - setMakeTableData(rightTableData(rainChg)); - }, [rainChk, code]); - - + const tableTotalData = rightTableData(rainChg) + setMakeTableData(tableTotalData); + }, [rainChkgdn.rainChk, code]); useEffect(() => { - const selectedData = makeTableData.filter((item) => - selectedIds.includes(item.chkgdnPk) - ); - if (selectedData.length > 1) { - const updateTableData = rainChk + + + //데이터를 평탄화 한것중에 체크박스 선택한 테이블만 선택 + const selectedData = makeTableData.filter((item) =>selectedIds.includes(item.chkgdnPk)); + + if (selectedData.length > 0) { + const updateTableData = rainChkgdn.rainChk .map((rc) => { const newRainyDetail = rc.rainyDetails .map((rd) => { + + // 변경 데이터는 평탄화한 데이터 즉 루트에 변경되어 있음 이용용도까지 잇음 그걸로 찾기 const findRain = selectedData.find( (sd) => rd.chkgdnFk === sd.chkgdnPk && rd.utztnUsgCd === sd.utztnUsgCd ); + if (findRain != undefined) { + console.log(findRain) return { ...rd, ph: Number(findRain.ph), @@ -260,39 +115,47 @@ export default function RainChkgdTable({ } }) .filter(Boolean); + setUpRaintDetail(updateTableData as rainChkZodType[]); } - }, [makeTableData]); + }, [makeTableData,selectedIds]); useEffect(() => { detailUp(upRaintDetail); }, [upRaintDetail]); + + useEffect(() =>{ + if(selectedIds.length >0){ + // 삭제를 위한 데이터 삽입 + deleteData(selectedIds ) + } + },[selectedIds]) + + useEffect(() => { + + },[]) + + return ( - <> - <Table variant="secondary"> - <TableHeader className="font-bold">{nodeList}</TableHeader> + <Table variant="secondary"> + <TableHeader className="font-bold"> + {headMakeprfmnc( + rainChkgdn?.rainChkgdnHeadList, + rainChkgdn?.rainHeadNm + )} + </TableHeader> - <TableBody> - {totalData( - makeTableData, - rainChkgdn.rainChkgdnHeadList, - handleChange, - toggleSelection, - selectedIds, - handleCellClick - )} - </TableBody> - </Table> - - <UiModal - open={isModal.open} - onOpenChange={() => { - setIsModal({ open:!open , data:{} }); - }} - bodyClass={"w-[80vw] max-w-none"} - body={<ChkgdModal type={"RNB"} obj={isModal.data} />} - ></UiModal> - </> + <TableBody> + {chRowspanTable( + makeTableData, + rainChkgdn.rainChkgdnHeadList, + handleChange, + toggleSelection, + selectedIds, + handleCellClick + )} + </TableBody> + </Table> ); } diff --git a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx index 376ab7a95..b378167cc 100644 --- a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx @@ -1,6 +1,6 @@ 'use client' -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; +import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; import { UiTable } from "@common/business_components/ui"; diff --git a/apps/wr/components/ui/toast/toastFromUi.tsx b/apps/wr/components/ui/toast/toastFromUi.tsx index 465870c8b..5886c2e0b 100644 --- a/apps/wr/components/ui/toast/toastFromUi.tsx +++ b/apps/wr/components/ui/toast/toastFromUi.tsx @@ -1,55 +1,46 @@ - import { Button } from "@common/components/ui"; import Link from "next/link"; import toast from "react-hot-toast"; +interface toastFormType { + body: string; + title: string; + url?: string; + buttonName?: string; +} - -export function ToastFormUi(body:string,title:string,url:string,buttonName:string){ - +export function ToastFormUi({ body, title, url, buttonName }: toastFormType) { //const router = useRouter(); - return( - - toast.custom((t) => ( - - <div - className={`${ - t.visible ? 'animate-enter' : 'animate-leave' - } w-4/12 h-40 bg-white shadow-lg rounded-lg pointer-events-auto flex ring-1 ring-black ring-opacity-5`} - > - <div className="w-full flex-1 py-10"> - <div className="flex items-start"> - <div className="flex-shrink-0 pt-0.5"> - - </div> - <div className="ml-3 flex-1"> - <p className="text-xl font-medium underline"> - {title} - </p> - <p className="mt-1 text-2xl"> - {body} - </p> - </div> - </div> - </div> - <div className="flex py-20"> - <Button - size='sm' - onClick={() => toast.dismiss(t.id)} - > - <Link href={url}> {buttonName}</Link> - </Button> - </div> - <div className="flex pl-4 pr-4 py-20"> - <Button - onClick={() => toast.dismiss(t.id)} - size='sm' - > - 닫기 - </Button> + return toast.custom((t) => ( + <div + className={`${ + t.visible ? "animate-enter" : "animate-leave" + } w-4/12 h-40 bg-white shadow-lg rounded-lg pointer-events-auto flex ring-1 ring-black ring-opacity-5`} + > + <div className="w-full flex-1 py-10"> + <div className="flex items-start"> + <div className="flex-shrink-0 pt-0.5"></div> + <div className="ml-3 flex-1"> + <p className="text-xl font-medium underline">{title}</p> + <p className="mt-1 text-2xl">{body}</p> </div> </div> - )) - ) -} \ No newline at end of file + </div> + <div className="flex py-20"> + {url && buttonName ? ( + <Button size="sm" onClick={() => toast.dismiss(t.id)}> + <Link href={url}> {buttonName}</Link> + </Button> + ) : ( + <></> + )} + </div> + <div className="flex pl-4 pr-4 py-20"> + <Button onClick={() => toast.dismiss(t.id)} size="sm"> + 닫기 + </Button> + </div> + </div> + )); +} diff --git a/apps/wr/public/sample.xlsx b/apps/wr/public/sample.xlsx new file mode 100644 index 000000000..ee4b23edb Binary files /dev/null and b/apps/wr/public/sample.xlsx differ diff --git a/apps/wr/public/sample_rainSttn.xlsx b/apps/wr/public/sample_rainSttn.xlsx new file mode 100644 index 000000000..006e06aba Binary files /dev/null and b/apps/wr/public/sample_rainSttn.xlsx differ diff --git a/apps/wr/public/sample_rainSttn_test.xlsx b/apps/wr/public/sample_rainSttn_test.xlsx new file mode 100644 index 000000000..57ea2f222 Binary files /dev/null and b/apps/wr/public/sample_rainSttn_test.xlsx differ diff --git a/apps/wr/public/sample_rainy.xlsx b/apps/wr/public/sample_rainy.xlsx new file mode 100644 index 000000000..ee4b23edb Binary files /dev/null and b/apps/wr/public/sample_rainy.xlsx differ diff --git a/apps/wr/tailwind.config.ts b/apps/wr/tailwind.config.ts index dc688050e..00237ea18 100644 --- a/apps/wr/tailwind.config.ts +++ b/apps/wr/tailwind.config.ts @@ -5,7 +5,7 @@ import presetConfig from "../../tailwind.config.preset"; export default { presets: [presetConfig], content: [ - "./src/**/*.{js,ts,jsx,tsx,mdx}", + "./app/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", "../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx,mdx}", "../../packages/common/business_components/src/ui/**/*.{js,ts,jsx,tsx,mdx}", diff --git a/packages/common/business_components/package.json b/packages/common/business_components/package.json index 1f02a708e..a23f31058 100644 --- a/packages/common/business_components/package.json +++ b/packages/common/business_components/package.json @@ -43,6 +43,7 @@ "sonner": "^2.0.1", "tailwind-merge": "^3.0.1", "xlsx": "^0.18.5", + "xlsx-populate": "^1.21.0", "zod": "^3.24.2" }, "devDependencies": { @@ -58,6 +59,7 @@ "@storybook/test": "^8.5.3", "@storybook/theming": "^8.5.5", "@vitejs/plugin-react": "^4.3.4", + "@xlsx/xlsx-populate": "^0.0.8", "autoprefixer": "^10.4.20", "eslint": "^9.17.0", "eslint-plugin-react-hooks": "^5.0.0", diff --git a/packages/common/business_components/src/ui/excel/excelStyle.tsx b/packages/common/business_components/src/ui/excel/excelStyle.tsx new file mode 100644 index 000000000..2475d1453 --- /dev/null +++ b/packages/common/business_components/src/ui/excel/excelStyle.tsx @@ -0,0 +1,24 @@ +import * as XlsxPopulate from '@xlsx/xlsx-populate'; +export const excelStyle = async (data: ArrayBuffer, range: string = "A1:V3", fileNm:string) => { + console.log("excelStyle", data, range, fileNm); + const workbook = await XlsxPopulate.Workbook.fromData(data); + const rangeCells = workbook.activeSheet(0)?.sheet(0)?.range(range); + console.log(rangeCells); + rangeCells?.style((styleQ)=>{ + console.log(styleQ); + styleQ.fill({ type: "solid", color: {rgb:"9bc1e7"} }); + styleQ.borderEach( { style: "thin", color: { rgb: "FFFFFF" } } ); + styleQ.wrapText(true); + // styleQ.fontColor({rgb:"FFFFFF"}); + styleQ.fontSize(15); + styleQ.horizontalAlignment("center"); + styleQ.verticalAlignment("center"); + styleQ.bold(true); + }); + const outputData = await workbook.output("array-buffer"); + const blob = new Blob([outputData], { type: "application/octet-stream" }); + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = fileNm+".xlsx"; + link.click(); +} \ No newline at end of file diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx new file mode 100644 index 000000000..c17aa0660 --- /dev/null +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -0,0 +1,86 @@ +import * as XLSX from 'xlsx'; +import { excelStyle } from './excelStyle'; + +type ExcelDownloadProps = { + data: JSON | JSON[]; + fileName: string; + sheetNameArray: string[]; + headerRange: string; +} + +export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3'}: ExcelDownloadProps) => { + const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); + excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); +}; + + + +export const filePicked=(oFile: File, headerNum:number=0):Promise<JSON | undefined> =>{ + // Create A File Reader HTML5 + const reader = new FileReader(); + return new Promise<JSON | undefined>((resolve, reject) => { + // Ready The Event For When A File Gets Selected + reader.onload = function (e) { + const data = e.target?.result; + if (!data) { + console.error("Failed to read file: e.target.result is null"); + resolve(undefined); + return; + } + //셀데이터에서 데이트 형식으로 입력하면 yyyymmdd 형식으로 변환 + const wb = XLSX.read(data, { type: 'binary', cellDates: true, dateNF: "yyyymmdd" }); + let jsonXls: JSON | undefined; + + // Loop Over Each Sheet + wb.SheetNames.forEach(function (sheetName,index ) { + // Obtain The Current Row As CSV + // 일단 첫번째 시트만 읽을 수 있도록 수정 + if(index ===0){ + const sheet = wb.Sheets[sheetName]; + + if (sheet) { + jsonXls = XLSX.utils.sheet_to_json(sheet, { range: headerNum, raw:false }) as unknown as JSON; + } else { + console.error(`Sheet "${sheetName}" is undefined.`); + } + } + }); + resolve(jsonXls); + }; + + reader.onerror = function () { + console.error("Error reading file"); + reject(undefined); + }; + + // Tell JS To Start Reading The File.. You could delay this if desired + reader.readAsBinaryString(oFile); + }); +} + + + +export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, headerNum:number=0, headerRange='A1:V3'):Promise<JSON | undefined> =>{ // Create A File Reader HTML5 + return new Promise<JSON | undefined>(() => { + // Ready The Event For When A File Gets Selected + const wb = XLSX.read(oFile, { type: 'binary' }); + // Loop Over Each Sheet + wb.SheetNames.forEach(async function (sheetName, index) { + // Obtain The Current Row As CSV + if(index==0){ + const sheet = wb.Sheets[sheetName]; + if (sheet) { + //오리진 확인 test 필요 + // const sheet = XLSX.utils.json_to_sheet(data); + XLSX.utils.sheet_add_aoa(sheet, data, { origin: 'A'+headerNum }); + // XLSX.utils.book_append_sheet(wb, sheet, 'test'); + await excelStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), headerRange, fileNm) + } else { + console.error(`Sheet "${sheetName}" is undefined.`); + } + } + }); + }); + } \ No newline at end of file diff --git a/packages/common/business_components/src/ui/excel_download/index.tsx b/packages/common/business_components/src/ui/excel_download/index.tsx deleted file mode 100644 index 21d009dbc..000000000 --- a/packages/common/business_components/src/ui/excel_download/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as XLSX from 'xlsx'; - -type ExcelDownloadProps = { - data: JSON | JSON[]; - fileName: string; - sheetNameArray: string[]; -} - -export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"] }: ExcelDownloadProps) => { - const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]); - const workbook = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); - //let buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }); - //XLSX.write(workbook, { bookType: "xlsx", type: "binary" }); - XLSX.writeFile(workbook, fileName + '.xlsx'); -}; -export const filePicked=(oFile: File, headerNum:number=0):Promise<JSON | undefined> =>{ - // Create A File Reader HTML5 - const reader = new FileReader(); - return new Promise<JSON | undefined>((resolve, reject) => { - // Ready The Event For When A File Gets Selected - reader.onload = function (e) { - const data = e.target?.result; - if (!data) { - console.error("Failed to read file: e.target.result is null"); - resolve(undefined); - return; - } - const wb = XLSX.read(data, { type: 'binary' }); - let jsonXls: JSON | undefined; - // Loop Over Each Sheet - wb.SheetNames.forEach(function (sheetName) { - // Obtain The Current Row As CSV - const sheet = wb.Sheets[sheetName]; - if (sheet) { - jsonXls = XLSX.utils.sheet_to_json(sheet, { range: headerNum }) as unknown as JSON; - } else { - console.error(`Sheet "${sheetName}" is undefined.`); - } - }); - resolve(jsonXls); - }; - - reader.onerror = function () { - console.error("Error reading file"); - reject(undefined); - }; - - // Tell JS To Start Reading The File.. You could delay this if desired - reader.readAsBinaryString(oFile); - }); -} \ No newline at end of file diff --git a/packages/common/business_components/src/ui/file-upload/index.tsx b/packages/common/business_components/src/ui/file-upload/index.tsx index 3d581ed05..4c6dcec00 100644 --- a/packages/common/business_components/src/ui/file-upload/index.tsx +++ b/packages/common/business_components/src/ui/file-upload/index.tsx @@ -6,14 +6,22 @@ const dropZoneConfig = { maxSize: 1024 * 1024 * 4, multiple: true, }; + + + interface FileUploadProps { + files: File[]; // 파일 배열 + setFiles: (files: File[] | null) => void; // 파일 배열 세터 + fileTypes?: string; // 옵션 (파일 확장자 문자열) + } + export const FileUpload = -(({ ...props }) => { +({ files, setFiles, fileTypes }: FileUploadProps) => { return ( <FileUploader - value={props.files} - onValueChange={props.setFiles} + value={files} + onValueChange={setFiles} dropzoneOptions={dropZoneConfig} - acceptName={props?.fileTypes} + acceptName={fileTypes} className="relative bg-background rounded-lg p-2" > <FileInput @@ -23,18 +31,18 @@ export const FileUpload = <div className="flex items-center justify-center flex-col p-8 w-full "> <CloudUpload className='text-gray-500 w-10 h-10' /> <p className="mb-1 text-sm text-gray-500 dark:text-gray-400"> - <span className="font-semibold">Click to upload</span> -   or drag and drop + <span className="font-semibold">클릭 후 업로드 </span> +   혹은 파일을 드래그 해주세요 </p> <p className="text-xs text-gray-500 dark:text-gray-400"> - {!props?.fileTypes?"SVG, PNG, JPG, GIF":props?.fileTypes} + {!fileTypes?"SVG, PNG, JPG, GIF":fileTypes} </p> </div> </FileInput> <FileUploaderContent> - {props.files && - props.files.length > 0 && - props.files.map((file:File, i:number) => ( + {files&& + files.length > 0 && + files.map((file:File, i:number) => ( <FileUploaderItem key={i} index={i}> <Paperclip className="h-4 w-4 stroke-current" /> <span>{file.name}</span> @@ -43,4 +51,4 @@ export const FileUpload = </FileUploaderContent> </FileUploader> ) -}) \ No newline at end of file +} \ No newline at end of file diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index e591be5b5..90bf029c0 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -1,7 +1,7 @@ export * from "./chart"; export * from "./date_picker"; export * from "./dialog_ui"; -export * from "./excel_download"; +export * from "./excel"; export * from "./file-upload"; export * from "./form"; export * from "./form_ui"; @@ -19,3 +19,4 @@ export * from "./tab"; export * from "./table"; export * from "./table_div"; export * from "./title"; + diff --git a/packages/common/business_components/src/ui/search_base_form/index.tsx b/packages/common/business_components/src/ui/search_base_form/index.tsx index 90ad0b05e..9dc1bf735 100644 --- a/packages/common/business_components/src/ui/search_base_form/index.tsx +++ b/packages/common/business_components/src/ui/search_base_form/index.tsx @@ -13,6 +13,7 @@ type SearchBaseType = { selectMiddleRegionData?: SelectDataType[] | []; selectEnvPartData?: EnvPartSelectDataType[] | []; queryClick:(returnType:ReturnType) => void; + excelName?:string; excelClick:(returnType:ReturnType) => void; initClick:() => void; btnClass:string; @@ -39,6 +40,7 @@ function SearchBaseForm ({ selectMiddleRegionData, selectEnvPartData, btnClass, + excelName, queryClick, excelClick, initClick, @@ -120,7 +122,7 @@ function SearchBaseForm ({ </SearchFormLeft> <SearchFormRight> <Button className={btnClass} color="green" onClick={excelDownload}> - 엑셀다운로드 + {excelName?excelName:"엑셀다운로드"} </Button> <div> <Button className={btnClass} onClick={initVal}> diff --git a/packages/common/business_components/src/ui/table/HeadMakeColSpan.tsx b/packages/common/business_components/src/ui/table/HeadMakeColSpan.tsx index dc859a55d..ebd611c1d 100644 --- a/packages/common/business_components/src/ui/table/HeadMakeColSpan.tsx +++ b/packages/common/business_components/src/ui/table/HeadMakeColSpan.tsx @@ -8,16 +8,20 @@ interface TableUpperProps { row? : number; rowSpan?: number; colSpan?: number; + visible?:boolean; } const HeadMakeColSpan = ({ upHeadList }: { upHeadList: TableUpperProps[] }) => { - const maxRow = upHeadList.reduce((max, head) => Math.max(max, head.row || 0), 0); + const maxRow = upHeadList?.reduce((max, head) => Math.max(max, head.row || 0), 0); + //upHeadList.forEach((item) => item.visible ?item.visible:true) if(maxRow == 0){ return ( <> <TableRow className="bg-gray-50"> - {upHeadList.map((head: TableUpperProps) => { + {upHeadList + .filter((item) => item.visible != false) + .map((head: TableUpperProps) => { return ( <TableHead key={head.id} @@ -38,7 +42,9 @@ const HeadMakeColSpan = ({ upHeadList }: { upHeadList: TableUpperProps[] }) => { <> {Array.from({ length: maxRow + 1 }, (_, rowIndex) => ( <TableRow key={rowIndex+ " headerRow"} className="bg-gray-50"> - {upHeadList.map((head: TableUpperProps) => { + {upHeadList + .filter((item) => item.visible != false) + .map((head: TableUpperProps) => { if (head.row === rowIndex) { return ( <TableHead diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index 45748fb37..00fc376e6 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -20,6 +20,7 @@ type UiHeadProps = { id: string; title: string; align?: string; + visible?:boolean; } export function UiTable({ tableData, headlist, pageSize, total, headName, children, cellClick, onPageChange, className = '', resetPageNo = false }: UiTableProps) { @@ -58,7 +59,9 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr <TableBody className='text-center'> {tableData.length > 0 ? tableData?.map((el: { [key: string]: any}, index) => ( <TableRow key={`row-${index}`}> - {headlist?.map((head) => ( + {headlist + .filter((item) => item.visible != false) + .map((head) => ( head.id && head.id.length > 1 && ( <TableCell className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${