diff --git a/.gitignore b/.gitignore index d0bb49da9..6b685ea40 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,5 @@ apps/wr/.next/**/* apps/fo/.next/**/* # env -.env* +#.env* .qodo diff --git a/apps/wr/.env.development b/apps/wr/.env.development new file mode 100644 index 000000000..dccfb1453 --- /dev/null +++ b/apps/wr/.env.development @@ -0,0 +1,12 @@ +NEXT_PUBLIC_SITE_ID = WR +NEXT_PUBLIC_PORT = 11301 +NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11301 +NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 +NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver +NEXT_PUBLIC_TEMP_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver #TODO 운영에서 바꿔야 함 +NEXT_PUBLIC_CLAIM_NAME = Authorization +NEXT_PUBLIC_AUTH_USER_ID = token-id +NEXT_PUBLIC_ACCESS_TOKEN = access-token +NEXT_PUBLIC_REFRESH_TOKEN = refresh-token + +NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API diff --git a/apps/wr/.env.local b/apps/wr/.env.local new file mode 100644 index 000000000..858181f32 --- /dev/null +++ b/apps/wr/.env.local @@ -0,0 +1,14 @@ +NEXT_PUBLIC_SITE_ID = WR +NEXT_PUBLIC_PORT = 3001 +NEXT_PUBLIC_PROXY_HOST = http://localhost:3001 +NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 +NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver +NEXT_PUBLIC_TEMP_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver #TODO 운영에서 바꿔야 함 +NEXT_PUBLIC_CLAIM_NAME = Authorization +NEXT_PUBLIC_AUTH_USER_ID = token-id +NEXT_PUBLIC_ACCESS_TOKEN = access-token +NEXT_PUBLIC_REFRESH_TOKEN = refresh-token + +NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API +#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성 +#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정 diff --git a/apps/wr/.gitignore b/apps/wr/.gitignore index 5ef6a5207..8c5b2ee3a 100644 --- a/apps/wr/.gitignore +++ b/apps/wr/.gitignore @@ -31,7 +31,7 @@ yarn-error.log* .pnpm-debug.log* # env files (can opt-in for committing if needed) -.env* +#.env* # vercel .vercel diff --git a/apps/wr/app/map/htdflSttn/page.tsx b/apps/wr/app/map/htdflSttn/page.tsx index 535c08d69..b3a030421 100644 --- a/apps/wr/app/map/htdflSttn/page.tsx +++ b/apps/wr/app/map/htdflSttn/page.tsx @@ -124,7 +124,7 @@ const Map = () => { treeData={treeData} isSearch={false} gisMaps={gisMaps} - isMiniMap={true} + isMiniMap={false} searchView={undefined} // searchView={(props: any) => ( // void; } +// 탭 +const TABS = [ + { val: "0", text: "재이용시설1" }, + { val: "1", text: "재이용시설2" }, + { val: "2", text: "재이용시설n" }, +]; + // 데이터의 속성(key)을 사용자에게 보여줄 한글 이름으로 변환하기 위한 맵 // 실제 데이터에 맞게 이 부분을 확장해야 합니다. const propertyNameMap: { [key: string]: string } = { @@ -202,6 +210,7 @@ const NewWindowPopup: React.FC = ({ }, [featureData]); + // 빗물재이용시설 cellClick 이벤트 (상세정보) const rainCellClick = (index: number | undefined, headId: string) => { if ( diff --git a/apps/wr/app/map/service/map.ts b/apps/wr/app/map/service/map.ts index bf0c8a694..5002afef7 100644 --- a/apps/wr/app/map/service/map.ts +++ b/apps/wr/app/map/service/map.ts @@ -2,8 +2,8 @@ /** * 관망도 API */ -// const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map` -const API_URL = "http://con.mind-one.co.kr:11083/sewerage-service/api/v1/map"; + const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map` +//const API_URL = "http://con.mind-one.co.kr:11083/sewerage-service/api/v1/map"; export type LyrStngProps = { lyr_sn: string diff --git a/apps/wr/app/matMng/coMat/coMatRvw/page.tsx b/apps/wr/app/matMng/coMat/coMatRvw/page.tsx index c1e601320..15bff0b32 100644 --- a/apps/wr/app/matMng/coMat/coMatRvw/page.tsx +++ b/apps/wr/app/matMng/coMat/coMatRvw/page.tsx @@ -9,6 +9,7 @@ import { } from "@/app/store/matDmd/coMatRvw/type"; import { formH1Class, formTableName } from "@/components/lib/class/comClass"; import { + formatPhoneNumber, getCity, getdmdMatFlag, tableData, @@ -33,7 +34,7 @@ import { import ListDiv from "@common/business_components/ui/list_div"; import { Button, Input, Label } from "@common/components/ui"; import { useEffect, useRef, useState } from "react"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import toast, { Toaster } from "react-hot-toast"; import { z } from "zod"; import moment from "moment"; @@ -45,7 +46,7 @@ import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/b export default function CoMatRvw() { const { code, coRvw, coMatRvwInit, coMatRvwSearch, coMatRvwInqua } = useWrStore((state) => state); - const { coMatRvwRes } = coRvw; + const { coMatRvwRes,coMatRvwCount } = coRvw; //init, sub, match const initRef = useRef(false); const { coRvwHeadList } = coRvw; @@ -68,6 +69,7 @@ export default function CoMatRvw() { const [selectData, setSelectData] = useState( {} as DmdCoReqType ); + const [selectionVersion, setSelectionVersion] = useState(0); const getSearch = ( startYear: number, @@ -91,39 +93,45 @@ export default function CoMatRvw() { const form = useForm>({ resolver: zodResolver(DmdCoReqSchema), + shouldUnregister: false, + // defaultValues: DmdCoReqSchema.parse({}) }); + const TableCellClick = (index: number) => { - console.log(coMatRvwRes); if (coMatRvwRes && coMatRvwRes[index]) { - setSelectData(coMatRvwRes[index]); + setSelectionVersion((v) => v + 1); // 행을 클릭할 때마다 버전을 1씩 증가 } }; + const useUsgCdWatch = useWatch({ control: form.control, name: "useUsgCd" }); useEffect(() => { - if (form?.getValues("useUsgCd")) { + + if (useUsgCdWatch) { form.setValue( "demandCst.usgPrcsProcs", usageProcData?.find( - (item) => item.usage === (form?.getValues("useUsgCd") as string) + (item) => item.usage === useUsgCdWatch )?.process ?? "" ); } - }, [form.watch("useUsgCd")]); + }, [useUsgCdWatch, form,selectionVersion]); useEffect(() => { - if (coMatRvwRes.length > 0) { + if (coMatRvwRes&&coMatRvwRes.length > 0) { const data = coMatRvwRes?.map((item, index) => { let flag = ""; - flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ??""); + + flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ||undefined); + return { ...item, ctpvCd: item.demandCo?.ctpvCd, sggCd: item.demandCo?.sggCd, dmdCoNm: item.demandCo?.dmdCoNm, daddr: item.demandCo?.daddr, - telno: item.demandCo?.telno, - regDt: moment(item?.demandCo?.regDt).format("YYYY-MM-DD"), + telno: formatPhoneNumber(item?.demandCo?.telno||''), + dmndTmng: item?.dmndTmng, splyFcltFlg: flag, }; }); @@ -151,14 +159,23 @@ export default function CoMatRvw() { useEffect(() => { if (selectData) { - console.log(selectData); - form.reset(selectData); + + try { + DmdCoReqSchema.parse(selectData); + } catch (e) { + if (e instanceof z.ZodError) { + console.log(e.flatten()); + } + } + form.reset( selectData); + setSelectionVersion((v) => v + 1); // 강제로 바뀌었다고 알리기 } }, [selectData, form]); return ( <>
+
<SearchDiv> @@ -181,7 +198,7 @@ export default function CoMatRvw() { <div className="col-span-7 w-full"> <div className="flex flex-row items-center"> <Label className="text-xl text-gray-600 mx-6"> - 하수 재이용년도 + 수요신청년도 </Label> <SelectBox className="h-full w-32 text-2xl" @@ -259,7 +276,7 @@ export default function CoMatRvw() { tableData={dmdMatData || []} headlist={coRvwHeadList} pageSize={20} - total={100000} + total={coMatRvwCount} cellClick={(index: number | undefined, headId: string) => { if (index !== undefined && index >= 0) { TableCellClick(index); @@ -269,7 +286,7 @@ export default function CoMatRvw() { ></UiTable> </ListDiv> <hr /> - <ScrollArea className="h-[49vh]"> + {/* <ScrollArea className="h-[49vh]"> */} <ListDiv> <h3 className="mt-4 ml-2 text-2xl font-medium text-label"> 수요신청 상세현황 @@ -279,7 +296,7 @@ export default function CoMatRvw() { <div className="col-span-3 mt-4"> <FormField control={form.control} - name="demandCo.regDt" + name="dmndTmng" render={({ field }) => ( <FormUi label="요구시기"> <Input @@ -660,9 +677,9 @@ export default function CoMatRvw() { </div> </div> </Form> - <ConCostForm form={form} type={"mat"} /> + <ConCostForm form={form} type={"mat"} selectionVersion={selectionVersion} /> </ListDiv> - </ScrollArea> + {/* </ScrollArea> */} </div> </div> </ContentsDiv> diff --git a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx index 436b77736..a81a85e19 100644 --- a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx +++ b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx @@ -5,6 +5,7 @@ import { ruseUtzType } from "@/app/store/matDmd/ruseCaseMng/headList"; import { excelDownload, getCity } from "@/components/lib/func/commom"; import RuseCaseMngExcel from "@/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { ContentsDiv, filePickedBlobArray, @@ -20,11 +21,12 @@ import { } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; -import { useState } from "react"; +import { useEffect, useState } from "react"; +import { toast, Toaster } from "react-hot-toast"; export default function RuseCaseMng() { const { code, ruseCaseMng, selectRuseCaseMng } = useWrStore((state) => state); - const { ruseCaseMngList } = ruseCaseMng; + const { ruseCaseMngList, status, count } = ruseCaseMng; const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>([]); const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); @@ -34,8 +36,10 @@ export default function RuseCaseMng() { const [name, setName] = useState<string>(""); // 물재이용사례 조회 - const searchRuseCaseMng = async () => { + const searchRuseCaseMng = async (pageNo: number, pageSize: number) => { const res = await selectRuseCaseMng( + pageNo, + pageSize, sidoCd ?? "", sigunguCd ?? "", selectUtz[0] ?? "", @@ -68,7 +72,7 @@ export default function RuseCaseMng() { // 다운로드 const download = () => { - searchRuseCaseMng(); + searchRuseCaseMng(1, 10000);; fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => { if (!response.ok) { @@ -142,7 +146,7 @@ export default function RuseCaseMng() { } ]; // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 - await filePickedBlobArray(blobRet, '시설정보및운영현황황', sheetParameter); + await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter); }); } @@ -157,6 +161,12 @@ export default function RuseCaseMng() { ); } + useEffect(() => { + if(status === 200){ + setIsExcelOpen({ isModal: false }); + } + }, [status]); + return ( <> <ContentsDiv> @@ -202,7 +212,7 @@ export default function RuseCaseMng() { <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2"> <div className="space-y"> <div className="flex flex-row space-x-2"> - <Button size={"sm"} onClick={() => { searchRuseCaseMng() }}> + <Button size={"sm"} onClick={() => { searchRuseCaseMng(1, 20) }}> 조회 </Button> <Button size={"sm"} onClick={() => { setIsExcelOpen({ isModal: true }); }}> @@ -230,16 +240,18 @@ export default function RuseCaseMng() { children={undefined} headlist={ruseCaseMng.ruseHeadList} pageSize={20} - total={100000} + total={count} cellClick={(index: number | undefined, headId: string) => {}} - onPageChange={() => {}} + onPageChange={(pageNo: number) => { + searchRuseCaseMng(pageNo, 10); + }} /> </div> </ListDiv> </div> </div> </ContentsDiv> - + <Toaster position="top-center" /> {/* 엑셀 등록 모달 */} <UiModal open={isExcelOpen.isModal} diff --git a/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx b/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx index 2d339b869..d0a6bcb93 100644 --- a/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx +++ b/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx @@ -7,6 +7,7 @@ import { type RvwHistTableType, } from "@/app/store/matDmd/coMatRvw/type"; import { + formatPhoneNumber, getCity, getdmdMatFlag, yearOptions, @@ -43,7 +44,7 @@ export default function RuseRvwHstry() { ruseRvwInqua, ruseRvwComplete, } = useWrStore((state) => state); - const { rvwHistRes, ruseHistHeadList } = ruseHist; + const { rvwHistRes, ruseHistHeadList,rvwHistCount } = ruseHist; const [pageNation, setPageNatiion] = useState<number>(1); const [dmdCoNm, setDmdCoNm] = useState<string>(""); @@ -69,6 +70,36 @@ export default function RuseRvwHstry() { setObjSearch({ city: cityValue, sgg: "0" }); }; + useEffect(() =>{ + getButtonSearch() + },[pageNation]) + + const getButtonSearch=()=>{ + if (fromDate && toDate) { + const fromNum = Number(fromDate); + const toNum = Number(toDate); + if (fromNum > toNum) { + toast.error( + "시작년도가 종료년도 이후로 설정할 수 없습니다." + ); + } else { + let con: string | number = ""; + if (String(objSearch.city).length > 0) { + con = String(objSearch.city); + } + if (String(objSearch.sgg).length > 0 && objSearch.sgg !== "0") { + con = String(objSearch.sgg); + } + getSearch( + fromNum, + toNum, + con, + dmdCoNm, + ruseUtztnFcltNm + ); + } + } + } const getSgg = (val: string | number) => { console.log(val); setObjSearch({ ...objSearch, sgg: String(val) }); @@ -163,23 +194,29 @@ export default function RuseRvwHstry() { const data = rvwHistRes?.map((item, index) => { let flag = ""; flag = getdmdMatFlag(item.demandMatching?.splyFcltFlg ?? ""); - + const formatDate = (dateStr: string | null | undefined) => { + // null, undefined, 빈 문자열인 경우 '없음'을 반환합니다. + if (!dateStr) return "없음"; + // "YYYYMMDD" 형식으로 날짜를 파싱합니다. + const d = moment(dateStr, "YYYYMMDD"); + // 파싱된 날짜가 유효한 경우에만 포맷하고, 그렇지 않으면 '없음'을 반환합니다. + return d.isValid() ? d.format("YYYY-MM-DD") : "없음"; + }; + return { ...item, ctpvCd: item.demandCo?.ctpvCd, sggCd: item.demandCo?.sggCd, dmdCoNm: item.demandCo?.dmdCoNm, daddr: item.demandCo?.daddr, - telno: item.demandCo?.telno, - regDt: item?.demandCo?.regDt - ? moment(item?.demandCo?.regDt).format("YYYY-MM-DD") - : "없음", - rvwCmptnYmd: item?.rvwCmptnYmd - ? moment(item?.rvwCmptnYmd).format("YYYY-MM-DD") - : "없음", - mtchnCmptnYmd: item?.mtchnCmptnYmd - ? moment(item?.mtchnCmptnYmd).format("YYYY-MM-DD") + telno: formatPhoneNumber(item.demandCo?.telno ||''), + dmndTmng: item?.dmndTmng + ? moment(item?.dmndTmng).format("YYYY-MM-DD") : "없음", + + rvwCmptnYmd: formatDate(item.demandMatching?.rvwCmptnYmd), + mtchnCmptnYmd: formatDate(item.demandMatching?.mtchnCmptnYmd), + ruseUtztnFcltNm: item.ruseUtztnFcltNm, dmndQty: item.dmndQty, splyFcltFlg: flag, @@ -272,30 +309,7 @@ export default function RuseRvwHstry() { <Button size={"sm"} onClick={(e) => { - if (fromDate && toDate) { - const fromNum = Number(fromDate); - const toNum = Number(toDate); - if (fromNum > toNum) { - toast.error( - "시작년도가 종료년도 이후로 설정할 수 없습니다." - ); - } else { - let con: string | number = ""; - if (String(objSearch.city).length > 0) { - con = String(objSearch.city); - } - if (String(objSearch.sgg).length > 0 && objSearch.sgg !== "0") { - con = String(objSearch.sgg); - } - getSearch( - fromNum, - toNum, - con, - dmdCoNm, - ruseUtztnFcltNm - ); - } - } + getButtonSearch() }} > 조회 @@ -318,17 +332,23 @@ export default function RuseRvwHstry() { tableData={rvwHistData || []} headlist={ruseHistHeadList} pageSize={20} - total={100000} + total={rvwHistCount} cellClick={(index: number | undefined, headId: string) => { TableCellClick(index); }} - onPageChange={setPageNatiion} + onPageChange={ + (page)=>{ + setPageNatiion(page) + + } + + } ></UiTable> - <hr /> + {/* <hr /> <h3 className="mt-4 ml-2 text-2xl font-medium text-label"> 수요신청 상세현황 </h3> - <ConCostForm form={form} type={"hist"} /> + <ConCostForm form={form} type={"hist"} selectionVersion={0} /> */} </ListDiv> </div> </div> diff --git a/apps/wr/app/matMng/coMng/coSttn/page.tsx b/apps/wr/app/matMng/coMng/coSttn/page.tsx index 163195756..e828f4226 100644 --- a/apps/wr/app/matMng/coMng/coSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/coSttn/page.tsx @@ -5,6 +5,7 @@ import { btnClass } from "@/app/store/common/code"; import { fetchType, getFetch } from "@/components/lib/api"; import { excelDownload, + formatPhoneNumber, getCity, tableData } from "@/components/lib/func/commom"; @@ -26,6 +27,7 @@ import ListDiv from "@common/business_components/ui/list_div"; import SdmInsertForm from "@common/business_components/ui/sdmInsertForm"; import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; import { Button } from "@common/components/ui"; +import moment from "moment"; import { useCallback, useEffect, useState } from "react"; import toast, { Toaster } from "react-hot-toast"; @@ -59,17 +61,29 @@ export default function CoSttn() { const [seartchTxt, setSearchTxt] = useState<string>(); const [upadateData, setUpdateData] = useState<DemandCompType>(); - const getSelCity = (val: string | number) => { - const cityValue = String(val); // Ensure val is treated as a string - const data = getCity(cityValue, code.sggCd); - setSelectSgg(data); - setObjSearch({ city: cityValue, sgg: "" }); - }; + const getSelCity = useCallback((val: string | number) => { + const cityValue = String(val); + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + // 시/도를 변경하면 시/군/구는 '전체'("0")로 초기화합니다. + setObjSearch({ city: cityValue, sgg: "0" }); + }, [code.sggCd]); - const getSgg = (val: string | number) => { - setObjSearch({ ...objSearch, sgg: String(val) }); - }; + const getSgg = useCallback((val: string | number) => { + setObjSearch((prev) => ({ ...prev, sgg: String(val) })); + }, []); + useEffect(() => { + // code.cityCd 데이터가 로드되었고, 아직 시/도 선택이 안된 초기 상태일 때 실행 + if (code.cityCd && code.cityCd.length > 0 && !objSearch.city) { + const firstCityVal = code.cityCd[0]?.val; + if (firstCityVal) { + // 첫 번째 시/도 값으로 상태를 초기화합니다. + getSelCity(firstCityVal); + } + } + }, [code.cityCd, objSearch.city, getSelCity]); + useEffect(() => { if (!coSttn.isInit) { coSttnInit("1", "13", "0"); @@ -77,15 +91,21 @@ export default function CoSttn() { }, [coSttn.isInit, coSttnInit]); useEffect(() => { - if (coSttnRes?.length > 0 && code.cityCd.length > 0) { - const data = tableData(coSttnRes, { code }); - const chData = data.map((item: any) => ({ - ...item, - })); - // .filter((item: any) => item !== undefined); - setBdstTable(chData); - } else if (coSttnRes.length == 0) { - setBdstTable([]); + if(coSttnRes){ + + if (coSttnRes?.length > 0 && code.cityCd.length > 0) { + const data = tableData(coSttnRes, { code }); + const chData = data.map((item: any) => ({ + ...item, + telno:formatPhoneNumber(item.telno||undefined), + regDt: moment(item.regDt).format("YYYY-MM-DD") + + })); + // .filter((item: any) => item !== undefined); + setBdstTable(chData); + } else if (coSttnRes?.length == 0) { + setBdstTable([]); + } } }, [coSttnRes, code]); @@ -116,8 +136,11 @@ export default function CoSttn() { const searchClick = () => { const con = (objSearch.sgg && objSearch.sgg !== "0") ? objSearch.sgg : objSearch.city; + if (con) { if (seartchTxt && seartchTxt?.length > 0) { + + console.log(' seartchTxt ', seartchTxt) coSttnTxtSearch("1", "13", String(con), seartchTxt ?? ""); } else { coSttnSearch("1", "13", String(con)); @@ -139,13 +162,15 @@ export default function CoSttn() { selectClass={""} selectArray={code.cityCd || []} onSelectValue={getSelCity} + value={objSearch.city} /> <SelectBox className="col-span-2 w-1/6 h-full text-2xl" label="시군구" selectClass={""} - selectArray={selectSgg?selectSgg : [{text:"전체",val:"0"}]} + selectArray={selectSgg || []} onSelectValue={getSgg} + value={objSearch.sgg} /> <SearchInput className={"!text-3xl"} @@ -159,7 +184,7 @@ export default function CoSttn() { </SearchFormLeft> <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> <div className="flex flex-row space-x-2"> - <Button size={"sm"} onClick={searchClick}> + <Button className="mt-2" size={"sm"} onClick={searchClick}> 조회 </Button> <Button @@ -179,7 +204,7 @@ export default function CoSttn() { onClick={() => { /* 저장 로직 */ if (!upadateData) { - <ToastFormUi body={"수요처 변경을 원하는 행을 선택해주세요"} title={"수요처관리"}></ToastFormUi>; + toast.error("수요처 변경을 원하는 행을 선택해주세요") }else{ setIsDmdModal({ ...isDmdModal, @@ -187,7 +212,7 @@ export default function CoSttn() { } }} > - 저장 + 수정 </Button> <Button size={"sm"} diff --git a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx index d7c5170b2..55dbeb454 100644 --- a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx @@ -3,18 +3,17 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import type { customDrgt } from "@/app/store/matDmd/drgtSttn"; import { drgtHeadListExport } from "@/app/store/matDmd/drgtSttn/headList"; -import { excelDownload, getCity } from "@/components/lib/func/commom"; +import { getCity } from "@/components/lib/func/commom"; import DrgtDetailModal from "@/components/ui/modal/coMat/drgtDetailModal"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; -import { ContentsDiv, DateMonthPicker, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiModal, UiTable, type SelectDataType } from "@common/business_components/ui"; -import { MonthPicker } from "@common/business_components/ui/date_month_picker/mothPicker"; +import { ContentsDiv, DateMonthPicker, downloadExcel, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiModal, UiTable, type SelectDataType } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { Button, DatePicker, Label } from "@common/components/ui"; -import { useCallback, useEffect, useState } from "react"; +import { Button, Label, ScrollArea } from "@common/components/ui"; +import { useEffect, useState } from "react"; import { toast, Toaster } from "react-hot-toast"; export default function DrgtSttn() { - const { code, drgt, drgtSearch, drgtModalSearch } = useWrStore((state) => state); + const { code, drgt, drgtSearch, drgtModalSearch, drgtInit } = useWrStore((state) => state); const { drgtRes, drgtMoRes } = drgt; const [fromDate, setFromDate] = useState<string>(); const [toDate, setToDate] = useState<string>(); @@ -22,6 +21,7 @@ export default function DrgtSttn() { const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); const [tableData, setTableData] = useState<customDrgt[]>(); const [selectedSgg, setSelectedSgg] = useState<string>(''); + const [excelData, setExcelData] = useState<any[]>(); const [drgtModal, setDrgtModal] = useState<{ isOpen: boolean; data: customDrgt | undefined; @@ -35,45 +35,82 @@ export default function DrgtSttn() { } } + const excelClick = () => { + downloadExcel({ + data: excelData ?? [], + fileName: "우리동네가뭄 현황", + sheetNameArray: ["Sheet1"], + headerRange: "A1:G1" + }) + } + + useEffect(() => { + if (!drgt.isInit) { + drgtInit(); + } + }, [drgt.isInit, drgtInit]); + + useEffect(() => { + let resData = Array.isArray(drgtRes) ? drgtRes : [drgtRes]; + resData = resData.map((item) => { + if (item.sggNm === '세종시') { + return { + ...item, + ctpvCd: '세종특별자치시', + sggNm: '' + } + } + + return { + ...item, + ctpvCd: code.cityCd.find(ct => (ct.text == item.sggNm || (code.sggCd.find(sgg => sgg.text == item.sggNm)?.val.substring(0, 2) == ct.val)))?.text, + sggNm: code.sggCd.find(sgg => sgg.text == item.sggNm)?.text + } + }) + const data = Array.isArray(resData) + ? resData.map((item: customDrgt) => { + return { + "시도": item.ctpvCd, + "시군구": item.sggNm, + "정상(횟수)": item.normal, + "관심(횟수)": item.attention, + "주의(횟수)": item.caution, + "관심+주의(횟수)": item.warning, + "가뭄순위": item.ranking, + } + }) : []; + setExcelData(data) + setTableData(resData) + }, [drgtRes]) + useEffect(() => { if (drgtMoRes && drgtMoRes.length > 0) { setDrgtModal({ isOpen: true, data: drgtMoRes }); } }, [drgtMoRes]); - const getCityVal = (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; - }; - const getSelCity = (val: string | number) => { const cityValue = String(val); - const data = getCityVal(cityValue, code.sggCd); - setSelectSgg(data); - const sggVal = data.length > 0 ? data[0].val : ''; - setSelectedSgg(sggVal); // 시군구 value 세팅 - setObjSearch({ city: cityValue, sgg: sggVal }); + if (cityValue === "0") { + setSelectSgg([]); + setSelectedSgg(''); + setObjSearch({ city: cityValue, sgg: '' }); + } else { + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + + const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? ""); + setSelectedSgg(firstSggVal); + setObjSearch({ city: cityValue, sgg: firstSggVal }); + } }; + const getSgg = (val: string | number) => { setSelectedSgg(String(val)); setObjSearch({ ...objSearch, sgg: String(val) }); }; - const excelClick = useCallback(() => { - excelDownload( - [[]], - "우리동네가뭄", - "sample_drgtSttn.xlsx", - "A1:H1" - ); - }, []); - useEffect(() => { if (fromDate === undefined && toDate === undefined) { const today = new Date(); @@ -101,7 +138,7 @@ export default function DrgtSttn() { onSelectValue={getSelCity} /> <SelectBox - className="col-span-2 w-1/6 h-full text-2xl" + className="col-span-2 w-1/6 h-full text-2xl ml-8" label="시군구" selectClass={""} selectArray={selectSgg || []} @@ -110,7 +147,7 @@ export default function DrgtSttn() { /> <div className="col-span-5 w-auto"> <div className="flex flex-row items-center"> - <Label className="text-xl text-gray-600">조회기간</Label> + <Label className="text-xl text-gray-600 ml-8">조회기간</Label> <div className="flex flex-row w-1/4"> <DateMonthPicker field={{ @@ -125,8 +162,9 @@ export default function DrgtSttn() { setFromDate(formatted); } }} + selectClass="ml-4 text-2xl" /> - <span>~</span> + <span className="ml-2 text-center">~</span> <DateMonthPicker field={{ value: toDate, @@ -140,6 +178,7 @@ export default function DrgtSttn() { setToDate(formatted); } }} + selectClass="ml-4" /> </div> </div> @@ -148,35 +187,42 @@ export default function DrgtSttn() { </SearchFormLeft> <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> - <div className="flex flex-row space-x-2"> + <div className="flex flex-row space-x-2 items-center"> <Button size={"sm"} onClick={(e) => { let sidoText = ''; - let sggText = ''; + let sggText = []; if (objSearch?.city.toString().length > 0) { sidoText = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? ''; } if (objSearch?.sgg.toString().length > 1) { sggText = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? ''; + } else { + sggText = code.sggCd.filter((item) => item.val.substring(0, 2) === objSearch?.city).map((item) => item.text); + } + if (sidoText === '전체') { sidoText = '' } + if (sidoText === '세종특별자치시') { sidoText = '세종시'; sggText = sidoText; } - drgtSearch(fromDate ?? "", toDate ?? "", sidoText, sggText) + + const searchArr = []; + if (sidoText) searchArr.push(sidoText); + if (Array.isArray(sggText)) { + searchArr.push(...sggText); + } else if (sggText) { + searchArr.push(sggText); + } + + drgtSearch(fromDate ?? "", toDate ?? "", searchArr) }} > 조회 </Button> - <Button - size={"sm"} - className={btnClass} - onClick={() => { }} - > - 상세보기 - </Button> <Button size={"sm"} className={`${btnClass} green`} @@ -199,17 +245,19 @@ export default function DrgtSttn() { <div className="grid grid-cols-6 gap-4 "> <div className="col-span-6"> <ListDiv> - <UiTable - headName={[]} - tableData={drgtRes || []} - headlist={drgtHeadListExport} - pageSize={20} - total={10000} - cellClick={(index: number | undefined, headId: string) => { - cellClick(index ?? undefined, headId); - }} - onPageChange={() => { }} - ></UiTable> + <ScrollArea className="h-[66vh]"> + <UiTable + headName={undefined} + tableData={tableData || []} + headlist={drgtHeadListExport} + pageSize={14} + total={0} + cellClick={(index: number | undefined, headId: string) => { + cellClick(index ?? undefined, headId); + }} + onPageChange={() => { }} + ></UiTable> + </ScrollArea> </ListDiv> </div> </div> @@ -219,7 +267,7 @@ export default function DrgtSttn() { setDrgtModal({ ...drgtModal, isOpen: !drgtModal.isOpen }); }} bodyClass={"w-[50vw] max-w-none h-[80vh]"} - body={<DrgtDetailModal data={drgtModal.data} /*formObj={drgtModal.data}*/ />} + body={<DrgtDetailModal data={drgtModal.data} />} /> <Toaster position="top-center" /> </ContentsDiv> diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx index c5daee29c..eb43b29bf 100644 --- a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx @@ -44,7 +44,7 @@ export default function LdrmntCoSttn() { const [searchTxt, setSearchTxt] = useState<string>(); const ref = useRef<ReturnType>({} as ReturnType); const [excelData, setExcelData] = useState<any[]>(); - + const [isExcelDownload, setIsExcelDownload] = useState(false); const excelClick = useCallback(() => { excelDownload( @@ -57,14 +57,22 @@ export default function LdrmntCoSttn() { }, []); const excelDownloadClick = () => { - downloadExcel({ - data: excelData ?? [], - fileName: "잠재수요처 관리", - sheetNameArray: ["Sheet1"], - headerRange: "A1:F1" - }) + ldrmntSearch(1, "10000", "0", ""); + setIsExcelDownload(true); } + useEffect(() => { + if (isExcelDownload && excelData && excelData.length > 0) { + downloadExcel({ + data: excelData, + fileName: "잠재수요처 관리", + sheetNameArray: ["Sheet1"], + headerRange: "A1:F1" + }); + setIsExcelDownload(false); + } + }, [excelData, isExcelDownload]); + const [isExcelOpen, setIsExcelOpen] = useState<{ isModal: boolean; }>({ isModal: false }); @@ -73,14 +81,21 @@ export default function LdrmntCoSttn() { if (index !== undefined) { setDetailModal({ isOpen: true, data: ldrmntRes[index] }); } - } const getSelCity = (val: string | number) => { - const cityValue = String(val); // Ensure val is treated as a string - const data = getCity(cityValue, code.sggCd); - setSelectSgg(data); - setObjSearch({ city: cityValue, sgg: '' }); + const cityValue = String(val); + + if (cityValue === "0") { + setSelectSgg([]); + setObjSearch({ city: cityValue, sgg: "" }); + } else { + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + + const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? ""); + setObjSearch({ city: cityValue, sgg: firstSggVal }); + } }; const getSgg = (val: string | number) => { @@ -125,10 +140,9 @@ export default function LdrmntCoSttn() { setExcelData(data) }, [excelList]) - useEffect(() => { - let cityTxt = ''; - let sggTxt = ''; + let cityTxt = '' + let sggTxt = '' if (objSearch?.city.toString().length > 0) { cityTxt = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? ''; @@ -138,21 +152,23 @@ export default function LdrmntCoSttn() { sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? ''; } - let cityNm = ""; + if (cityTxt === '전체' || cityTxt === '') { + cityTxt = '0' + } + + let cityNm = "" if (sggTxt !== "0") { - cityNm = cityTxt + " " + sggTxt; + cityNm = cityTxt + " " + sggTxt } else { - cityNm = cityTxt; + cityNm = cityTxt } - if (cityNm) { - if (cityTxt === '') cityNm = "0"; - ldrmntSearch(pageNation, cityNm, searchTxt || ""); + ldrmntSearch(pageNation, '20', cityNm, searchTxt || ""); } else { - ldrmntSearch(pageNation, "", searchTxt || ""); + ldrmntSearch(pageNation, '20', '0', searchTxt || ""); } - }, [pageNation, objSearch, code, searchTxt, ldrmntSearch]) + }, [pageNation]); return ( <> @@ -175,6 +191,7 @@ export default function LdrmntCoSttn() { label="시군구" selectClass={""} selectArray={selectSgg || []} + value={objSearch.sgg} // value props 추가 onSelectValue={getSgg} /> <SearchInput @@ -189,7 +206,7 @@ export default function LdrmntCoSttn() { </SearchFormLeft> <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> - <div className="flex flex-row space-x-2"> + <div className="flex flex-row space-x-2 items-center"> <Button size={"sm"} onClick={(e) => { @@ -205,6 +222,10 @@ export default function LdrmntCoSttn() { sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? ''; } + if (cityTxt === '전체' || cityTxt === '') { + cityTxt = '0' + } + let cityNm = "" if (sggTxt !== "0") { @@ -212,10 +233,8 @@ export default function LdrmntCoSttn() { } else { cityNm = cityTxt } - if (cityNm) { - if (cityTxt === '') cityNm = "0"; - ldrmntSearch(pageNation, cityNm, searchTxt || ""); + ldrmntSearch(pageNation, '20', cityNm, searchTxt || ""); } }} > diff --git a/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx index 8227e0347..9b3688e61 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx @@ -16,73 +16,80 @@ import { Button } from "@common/components"; import ListDiv from "@common/business_components/ui/list_div"; import { useEffect, useState } from "react"; import { tableData } from "@/components/lib/func/commom"; -import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm"; +import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm"; import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import { Toaster } from "react-hot-toast"; export default function Home() { - const { code, htdfl, initHtdfl,getHtdflBdstData } = useWrStore((state) => state); + const { code, htdfl, initHtdflReg, getHtdflBdstData ,htdflNmSearch} = useWrStore( + (state) => state + ); const [searchTxt, setSearchTxt] = useState(""); const [pageNation, setPageNation] = useState(1); const [htdflForm, setHtdflForm] = useState<customHtdflBdst>(); const [bdstTable, setbdstTable] = useState<customHtdflBdst[]>(); - const [issNewReg,setIsNewReg] = useState<boolean>( false); + const [issNewReg, setIsNewReg] = useState<boolean>(false); + + const [bdstChgProps, setBdstChgProps] = useState<{ + isOpen: boolean; + chgBuilding: chgBuilding[]; + }>({ isOpen: false, chgBuilding: [] }); - const [bdstChgProps, setBdstChgProps] = useState<{ - isOpen: boolean; - chgBuilding: chgBuilding[]; - }>({ isOpen: false, chgBuilding: [] }); - const { htdflRes } = htdfl; useEffect(() => { if (!htdfl.isInit) { - initHtdfl('0'); + initHtdflReg('41') } - }, [htdfl.isInit, initHtdfl]); - + }, [htdfl.isInit, initHtdflReg]); useEffect(() => { - if (code.sggCd.length > 0) { + if (htdflRes&&htdflRes.length>0) { - const htdflData = tableData(htdflRes, { code }).map( - (item: customHtdflBdst) => { - return { - ...item, - bdstChgYn: item?.chgBuilding && item.chgBuilding.length > 0 && item.chgBuilding[0]?.bdstChgNm !== null ? 'Y' : 'N', - bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd - }; - } - ); - setbdstTable(htdflData); + console.log('htdflRes ', htdflRes) + const htdflData = tableData(htdflRes, { code }).map( + (item: customHtdflBdst) => { + let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가' + + return { + ...item, + archArea:archArea + + }; + } + ); + setbdstTable(htdflData); + }else{ + setbdstTable([]); } }, [code, htdflRes]); - const cellClick: (val: number|undefined ,headId: string) => void = ( - val - ,headId) => { + const cellClick: (val: number | undefined, headId: string) => void = ( + val, + headId + ) => { if ((bdstTable ?? []).length > 0 && val !== undefined) { { setHtdflForm(htdflRes[val]); } } - - if (headId === "bdstChgYn" && val !== undefined) { - if ( - htdflRes[val]?.bdstInfoPk != null && - htdflRes[val]?.chgBuilding?.length > 0 - ) { - bdstChgModal(htdflRes[val]?.chgBuilding as chgBuilding[]); - } - } - }; - const bdstChgModal = (chgBuilding: chgBuilding[]) => { - setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding }); + // if (headId === "bdstChgYn" && val !== undefined) { + // if ( + // htdflRes[val]?.bdstInfoPk != null && + // htdflRes[val]?.chgBuilding?.length > 0 + // ) { + // bdstChgModal(htdflRes[val]?.chgBuilding as chgBuilding[]); + // } + // } }; + // const bdstChgModal = (chgBuilding: chgBuilding[]) => { + // setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding }); + // }; useEffect(() => { - getHtdflBdstData(pageNation, "0"); + getHtdflBdstData(pageNation, "41"); }, [pageNation]); return ( @@ -103,14 +110,23 @@ export default function Home() { /> </SearchFormLeft> <SearchFormRight> - <div className="flex flex-row space-x-2 items-center"> - <Button size={"sm"} onClick={()=>{initHtdfl(searchTxt||"")}}>조회</Button> - <Button + <div className="flex flex-row space-x-2 items-center"> + <Button size={"sm"} - onClick={() => setIsNewReg(!issNewReg)} - > - 신규등록 - </Button> + onClick={() => { + if(searchTxt&&searchTxt.length>0){ + htdflNmSearch(String(41),searchTxt) + }else{ + initHtdflReg(String(41) ); + + } + }} + > + 조회 + </Button> + <Button size={"sm"} onClick={() => setIsNewReg(!issNewReg)}> + 신규등록 + </Button> </div> </SearchFormRight> </SearchDiv> @@ -126,41 +142,50 @@ export default function Home() { pageSize={100} total={10} headName={"건축물 목록"} - cellClick={(val, headId) => { cellClick(val || undefined, headId); } } + cellClick={(val, headId) => { + cellClick(val || undefined, headId); + }} onPageChange={setPageNation} - > - </UiTable> + ></UiTable> </ListDiv> </div> <div className="col-span-2 max-h-full"> - <ListDiv> - <ScrollArea className="h-[60vh]"> - <HtdflRegForm - htdflForm={htdflForm ?? ({} as customHtdflBdst)} - isModal={false} - /> - </ScrollArea> + <ListDiv> + <ScrollArea className="h-[60vh]"> + <HtdflRegForm + htdflForm={htdflForm ?? ({} as customHtdflBdst)} + isModal={false} + /> + </ScrollArea> </ListDiv> </div> </div> - <UiModal - body={<BdstReg moType="HTB"></BdstReg>} - bodyClass="w-[68vw] max-w-none h-[90vh]" - open={issNewReg} - onOpenChange={(open) => { - setIsNewReg(open); - }} - /> - - <UiModal + <UiModal + body={ + <BdstReg + moType="HTB" + isModal={false} + setIsModal={setIsNewReg} + ></BdstReg> + } + bodyClass="w-[68vw] max-w-none h-[90vh]" + open={issNewReg} + onOpenChange={(open) => { + setIsNewReg(open); + }} + /> + +<Toaster position="top-center" /> +{/* <UiModal bodyClass={""} open={bdstChgProps.isOpen} - body={<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>} + body={ + <BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal> + } onOpenChange={(open) => { setBdstChgProps({ ...bdstChgProps, isOpen: open }); - } - } - /> + }} + /> */} </ContentsDiv> </> ); diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx index 174f268d0..9f243627c 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -35,6 +35,10 @@ import { useFieldArray, useForm, type FieldErrors } from "react-hook-form"; // F import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; +import { createDefaultPbnstItem } from "./utilsZod"; + + + export default function PublicReuseFaciltyInsert() { const { code, @@ -66,6 +70,8 @@ export default function PublicReuseFaciltyInsert() { // defaultValues: { items: pbnstRegArrayZod.parse([]) }, mode: "onChange", }); + const { isDirty } = form.formState; + const { fields: items, append, @@ -83,7 +89,11 @@ export default function PublicReuseFaciltyInsert() { }, [pbnst.isInit, pubHasuInit]); const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { - const data = writeRgtrAndMdfr(valuse.items); + + if (!isDirty) { + toast.error("변경사항이 없습니다."); // 변경사항이 없으면 메시지 표시 + return; + } const data = writeRgtrAndMdfr(valuse.items); let bizs = [] as fcBizType[]; data.forEach((fclt) => { bizs = [...bizs, ...fclt.fcBizs]; @@ -100,66 +110,71 @@ export default function PublicReuseFaciltyInsert() { fcOpers: fclt.fcOpers, }; }); - await pbnstRuseFcltUpdate(pbnst as customPbnst[]); + await pbnstRuseFcltUpdate(pbnst as customPbnst[]) await pbnstRuseBizUpdate(bizs); }; // 폼 유효성 검사 실패 시 호출될 함수 - const onInvalid = ( - errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }> - ) => { - // 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다. + const onInvalid = (errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>) => { + console.log("errors:", errors); + const findAllErrors = ( errorObject: any, path: (string | number)[] = [] ): { message: string; path: (string | number)[] }[] => { if (!errorObject) return []; - + return Object.keys(errorObject).flatMap((key) => { const value = errorObject[key]; const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key; const newPath = [...path, currentKey]; + if (value && typeof value === "object") { - if (typeof value.message === "string") { - return [{ message: value.message, path: newPath }]; // 에러 메시지와 경로 반환 + if (value.message) { + return [{ message: value.message, path: newPath }]; } + return findAllErrors(value, newPath); } return []; }); }; + const errorList = findAllErrors(errors); + if (errorList.length > 0) { errorList.forEach((errorInfo) => { const { message, path } = errorInfo; let prefix = ""; + const itemsIndex = path.indexOf("items"); - + if (itemsIndex > -1 && path.length > itemsIndex + 1) { const itemIdx = path[itemsIndex + 1] as number; - const facilityName = form.getValues( - `items.${itemIdx}.ruseUtztnFcltNm` - ); + const facilityName = form.getValues(`items.${itemIdx}.ruseUtztnFcltNm`); if (facilityName) { prefix += `[${facilityName}] `; } - + const fcBizsIndex = path.indexOf("fcBizs"); if (fcBizsIndex > -1 && path.length > fcBizsIndex + 1) { const bizIdx = path[fcBizsIndex + 1] as number; - const cycle = form.getValues( - `items.${itemIdx}.fcBizs.${bizIdx}.cycl` - ); + const cycle = form.getValues(`items.${itemIdx}.fcBizs.${bizIdx}.cycl`); if (cycle) { prefix += `[${cycle}차수] `; } } } + + // 최종 오류 메시지 출력 toast.error(`${prefix}${message}`); }); } }; + useEffect(() => { + console.log("form errors:", form.formState.errors); + }, [form.formState.errors]); useEffect(() => { if (code.sggCd.length && pbnstHasuRes.length > 0) { @@ -184,7 +199,11 @@ export default function PublicReuseFaciltyInsert() { useEffect(() => { if (pbnst.pbnstRes && pbnst.pbnstRes?.length > 0) { - form.reset({ items: pbnstRegArrayZod.parse(pbnst.pbnstRes) }); + + + + form.reset({ items: pbnst.pbnstRes }); + } else { form.reset({ items: [] }); } @@ -204,21 +223,23 @@ export default function PublicReuseFaciltyInsert() { if (pbnstRes && pbnstRes.length > 0) { const lastPbnst = pbnstRes[pbnstRes.length - 1]; if (lastPbnst && selecTableRow) { - append( - pbnstRegZod.parse({ - pbnstRuseFcltPk: - String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1), - ruseUtztnFcltNm: "", - fcBizs: [ - fcBizSchema.parse({ - pbnstRuseFcltFk: - String(lastPbnst.pbnstRuseFcltPk) + - String(pbnstRes.length + 1), - cycl: 1, - }), - ] as fcBizType[], - }) - ); + // append( + // pbnstRegZod.parse({ + // pbnstRuseFcltPk: + // String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1), + // ruseUtztnFcltNm: null, + // fcBizs: [ + // fcBizSchema.parse({ + // pbnstRuseFcltFk: + // String(lastPbnst.pbnstRuseFcltPk) + + // String(pbnstRes.length + 1), + // cycl: 1, + // }), + // ] as fcBizType[], + // }) + // ); + append(createDefaultPbnstItem(selecTableRow, pbnstRes.length)); + setIsRuseReg({ isModal: true }); } } else { @@ -400,6 +421,8 @@ export default function PublicReuseFaciltyInsert() { setIsRuseReg({ isModal: false }); } }} + + onInvalid ={onInvalid} ></PbnstRegModal> } bodyClass="w-[68vw] max-w-none h-[90vh]" diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx new file mode 100644 index 000000000..3433a62c5 --- /dev/null +++ b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx @@ -0,0 +1,38 @@ +import type { fcBizType, pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; + +export function createDefaultPbnstItem( + selecTableRow: pubHasuType, + index: number + ) { + const pk = String(selecTableRow.bscFctCd) + String(index + 1); + + return { + pbnstRuseFcltPk: pk, + swtrmtFcltFk: "", + ruseUtztnFcltNm: "", // 필수 입력이므로 빈 문자열로 + fcltCpct: 0, + ruseCpct: 0, + splyExtraCpct: 0, + regDt: null, + rgtr: "test", + mdfcnDt: null, + mdfr: "test", + fcFiles: [], + fcBizs: [ + createDefaultBiz(pk, 1), // 첫 차수 + ], + fcOpers: [], + }; + } + + + export function createDefaultBiz( + pbnstRuseFcltFk: string, + cycl: number + ): fcBizType { + return { + pbnstRuseFcltFk, + cycl, + // 필요한 값 있으면 여기에 추가 + } as fcBizType; + } \ 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 2fa8b12b8..8ecc1221f 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx @@ -21,11 +21,14 @@ import { import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components"; import { useEffect, useState } from "react"; +import { Toaster } from "react-hot-toast"; export default function Home() { - const { rain, code, initRain, rainSearch, getRainData } = useWrStore((state) => { - return state; - }); + const { rain, code, initRain, rainSearch, getRainData } = useWrStore( + (state) => { + return state; + } + ); const { rainRes } = rain; const [rainForm, setRainForm] = useState<customRainBdst>(); const [issNewReg, setIsNewReg] = useState<boolean>(false); @@ -38,10 +41,9 @@ export default function Home() { }>({ isOpen: false, chgBuilding: [] }); useEffect(() => { - setIsNewReg( false) + setIsNewReg(false); if (!rain.isInit) { - initRain('41'); - + initRain("41"); } }, [rain.isInit, initRain]); @@ -49,8 +51,11 @@ export default function Home() { if (code.sggCd.length > 0) { const rainData = tableData(rainRes, { code }).map( (item: customRainBdst) => { + let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가' return { ...item, + archArea:archArea, + bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N", }; } @@ -130,35 +135,39 @@ export default function Home() { <div className="col-span-4 h-full min-h-0"> <ListDiv className="min-h-0"> {/* <ScrollArea className="h-[60vh]"> */} - <UiTable - tableData={bdstTable || []} - headlist={rain.upHeadList} - pageSize={20} - total={10000} - headName={"건축물 목록"} - cellClick={(val, headId) => { - cellClick(val, headId); - }} - onPageChange={setPageNation} - > - </UiTable> + <UiTable + tableData={bdstTable || []} + headlist={rain.upHeadList} + pageSize={20} + total={10000} + headName={"건축물 목록"} + cellClick={(val, headId) => { + cellClick(val, headId); + }} + onPageChange={setPageNation} + ></UiTable> {/* </ScrollArea> */} </ListDiv> </div> <div className="col-span-2 max-h-full"> - <ListDiv className=""> <ScrollArea className="h-[60vh]"> - <RainRegForm - rainForm={rainForm ?? ({} as customRainBdst)} - isModal={false} - ></RainRegForm> + <RainRegForm + rainForm={rainForm ?? ({} as customRainBdst)} + isModal={false} + ></RainRegForm> </ScrollArea> </ListDiv> </div> </div> <UiModal - body={<BdstReg moType="RNB"></BdstReg>} + body={ + <BdstReg + moType="RNB" + isModal={issNewReg} + setIsModal={setIsNewReg} + ></BdstReg> + } bodyClass="w-[68vw] max-w-none h-[90vh]" open={issNewReg} onOpenChange={(open) => { @@ -176,6 +185,8 @@ export default function Home() { setBdstChgProps({ ...bdstChgProps, isOpen: open }); }} /> + + <Toaster position="top-center" /> </ContentsDiv> </> ); diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx index d57c730ce..94224d40d 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx @@ -20,6 +20,7 @@ import { import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components"; import { useEffect, useState } from "react"; +import { Toaster } from "react-hot-toast"; export default function Home() { const { code, rswt, initRswt, rswtBdstSearch, getRswtBdstData } = useWrStore( @@ -45,8 +46,13 @@ export default function Home() { if (code.sggCd.length > 0 && rswtRes?.length > 0) { const rswtData = tableData(rswtRes, { code })?.map( (item: customRswtBdst) => { + let archArea = + item?.archArea.split(".")[0] !== "-1" + ? item?.archArea.split(".")[0] + : "확인불가"; return { ...item, + archArea: archArea, bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N", bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd, }; @@ -151,7 +157,13 @@ export default function Home() { </div> <UiModal - body={<BdstReg moType="RST" setIsModal={setIsNewReg}></BdstReg>} + body={ + <BdstReg + moType="RST" + setIsModal={setIsNewReg} + isModal={issNewReg} + ></BdstReg> + } bodyClass="w-[68vw] max-w-none h-[90vh]" open={issNewReg} onOpenChange={(open) => { @@ -162,12 +174,14 @@ export default function Home() { bodyClass={""} open={bdstChgProps.isOpen} body={ - <BdstChgModal chgBuilding={bdstChgProps.chgBuilding} ></BdstChgModal> + <BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal> } onOpenChange={(open) => { setBdstChgProps({ ...bdstChgProps, isOpen: open }); }} /> + + <Toaster position="top-center" /> </ContentsDiv> </> ); diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx index e43d5b04f..959367202 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx @@ -8,6 +8,7 @@ import type { } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { excelDownload, + getCity, getCityOrSgg, tableData, } from "@/components/lib/func/commom"; @@ -16,16 +17,23 @@ import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDeta import { ContentsDiv, SearchBaseForm, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, Title, UiModal, UiTable, type ReturnType, + type SelectDataType, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { Button } from "@common/components/ui"; +import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; import { excelHtdflSttnParsing } from "@/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; export default function HtdflSttn() { const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore( @@ -38,6 +46,8 @@ export default function HtdflSttn() { const [pageNation, setPageNation] = useState(1); const [isChHead, setIsChHead] = useState(false); const [bdstTable, setBdstTable] = useState<customRainBdst[]>(); + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() + const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); const [detailModal, setDetailModal] = useState<{ isOpen: boolean; data: customRainBdst | undefined; @@ -46,17 +56,47 @@ export default function HtdflSttn() { isOpen: boolean; chBuilding: chgBuilding[]; }>({ isOpen: false, chBuilding: [] }); - - const codeData = getCityOrSgg(ref); + const [fcltNm, setFcltNm] = useState<string>(""); const excelClick = useCallback(() => { - if (codeData) htdflSttnSearch(1, "10000", codeData); - }, [htdflSttnSearch, codeData]); + // 최신 검색 조건 반영 + const con = getConValue(); + htdflSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd); + }, [htdflSttnSearch, objSearch, code.cityCd, code.sggCd]); useEffect(() => { - if (codeData != null) htdflSttnSearch(pageNation, "20", codeData); + htdflSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); }, [pageNation]); + const getSelCity = (val: string | number) => { + const cityValue = String(val); + + if (cityValue === "0") { + setSelectSgg([]); + setObjSearch({ city: cityValue, sgg: "" }); + } else { + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + + const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? ""); + setObjSearch({ city: cityValue, sgg: firstSggVal }); + } + }; + + const getSgg = (val: string | number) => { + setObjSearch({ ...objSearch, sgg: String(val) }) + }; + + const getConValue = () => { + if (!objSearch.city || objSearch.city === "0") { + return "0"; + } + if (objSearch.sgg && objSearch.sgg !== "0") { + return objSearch.sgg; + } + return objSearch.city; + }; + const cellClick = (index: number | undefined, headId: string) => { if ( headId !== "chBuildingYn" && @@ -67,42 +107,34 @@ export default function HtdflSttn() { } }; useEffect(() => { - const excelDown = async () => { - if (htdflSttn.excelList.length > 0) { - if (htdflSttn.excelList.length === 0) return; - const excelData = await tableData(htdflSttn.excelList, { code }); - const htdflExcel = excelHtdflSttnParsing(excelData, code.cityCd, code.sggCd); - excelDownload( - htdflExcel as [[]], - "온배수시설 현황", - "sample_htdflSttn.xlsx", - "A1:S3" - ); - } - }; - excelDown(); + if (htdflSttn.excelList.length > 0) { + if (htdflSttn.excelList.length === 0) return; + excelDownload( + htdflSttn.excelList, + "온배수시설 현황", + "sample_htdflSttn.xlsx", + "A1:S3" + ); + } }, [htdflSttn.excelList, code]); useEffect(() => { if (!htdflSttn.isInit) { - initHtdfl(codeData ?? "0"); + initHtdfl(1, "20", "0", fcltNm, code.cityCd, code.sggCd); } }, [htdflSttn.isInit, initHtdfl]); useEffect(() => { - if (htdflSttnRes.length > 0 && code.cityCd.length > 0) { - const data = tableData(htdflSttnRes, { code }); - const chData = data - .map((item: any) => ({ - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0].htdflObj, - chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", - })) - .filter((item: any) => item.htdflObj !== undefined); - - setBdstTable(chData); - } + const data = tableData(htdflSttnRes, { code }); + const chData = data + .map((item: any) => ({ + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].htdflObj, + chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + })) + .filter((item: any) => item.htdflObj !== undefined); + setBdstTable(chData); }, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]); return ( @@ -111,43 +143,76 @@ export default function HtdflSttn() { <div className="grid grid-cols-4 gap-4 "> <div className="col-span-4"> <Title title={"온배수 시설 현황"} /> - <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; - } - htdflSttnSearch(pageNation, "20", con); - } } - excelClick={excelClick} - initClick={function (): void { } } - btnClass={btnClass} - ref={ref} isAdmin={false} /> + + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd} + onSelectValue={getSelCity} + /> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + value={objSearch.sgg} // value props 추가 + onSelectValue={getSgg} + /> + <div className="col-span-2 flex flex-row space-x-2"> + <Label className="w-28 mt-2 text-xl text-gray-600"> + {"시설명"} + </Label> + <SearchInput + className={"w-full h-full text-2xl"} + label={""} + textValue={fcltNm || ""} + setText={setFcltNm} + /> + </div> + </div> + </SearchFormLeft> + <SearchFormRight + className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2 items-center"> + <Button + size={"sm"} + onClick={() => { + const con = getConValue(); + htdflSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd); + }} + > + 조회 + </Button> + <Button + size={"sm"} + className={`${btnClass} green`} + onClick={excelClick} + > + 다운로드 + </Button> + <Button + size={"sm"} + className={btnClass} + onClick={() => { + setIsChHead(true); + }} + > + 조회항목설정 + </Button> + </div> + </SearchFormRight> + </SearchDiv> </div> </div> <div className="grid grid-cols-6 gap-4 "> <div className="col-span-6"> <ListDiv> <UiTable - headName={[]} + headName={undefined} tableData={bdstTable || []} children={ <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx index f101be91b..0b6dffe07 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx @@ -4,6 +4,7 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import { excelDownload, + getCity, getCityOrSgg, tableData, } from "@/components/lib/func/commom"; @@ -11,13 +12,19 @@ import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal"; import { ContentsDiv, SearchBaseForm, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, Title, UiModal, UiTable, type ReturnType, + type SelectDataType, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { Button } from "@common/components/ui"; +import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; import type { chgBuilding, @@ -26,6 +33,7 @@ import type { import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; export default function RainSttn() { const { code, rainSttn, rainSttnSearch, rainSttnInit } = useWrStore( @@ -37,13 +45,14 @@ export default function RainSttn() { const [pageNation, setPageNation] = useState(1); const [isChHead, setIsChHead] = useState(false); const [bdstTable, setBdstTable] = useState<customRainBdst[]>(); + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() + const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRainBdst | undefined }>({ data: undefined, isOpen: false }) const [bdstChgProps, setBdstChgProps] = useState<{ isOpen: boolean; chBuilding: chgBuilding[]; }>({ isOpen: false, chBuilding: [] }); - - const codeData = getCityOrSgg(ref); + const [fcltNm, setFcltNm] = useState<string>(""); const cellClick = (index: number | undefined, headId: string) => { @@ -56,30 +65,74 @@ export default function RainSttn() { } }; + const getSelCity = (val: string | number) => { + const cityValue = String(val); + + if (cityValue === "0") { + setSelectSgg([]); + setObjSearch({ city: cityValue, sgg: "" }); + } else { + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + + const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? ""); + setObjSearch({ city: cityValue, sgg: firstSggVal }); + } + }; + + const getSgg = (val: string | number) => { + setObjSearch({ ...objSearch, sgg: String(val) }) + }; + + const getConValue = () => { + if (!objSearch.city || objSearch.city === "0") { + return "0"; + } + if (objSearch.sgg && objSearch.sgg !== "0") { + return objSearch.sgg; + } + return objSearch.city; + }; + useEffect(() => { if (!rainSttn.isInit) { - rainSttnInit(codeData ?? "0"); + rainSttnInit(1, "20", "0", fcltNm, code.cityCd, code.sggCd); } }, [rainSttn.isInit, rainSttnInit]); useEffect(() => { - if (rainSttnRes.length > 0 && code.cityCd.length > 0) { - const data = tableData(rainSttnRes, { code }); - const chData = data - .map((item: any) => ({ + const data = tableData(rainSttnRes, { code }); + const chData = data + .map((item: any) => { + return { ...item, ...item.reuseBuilding[0], ...item.reuseBuilding[0].rainyObj, + dtfcltCpct: item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.dtfcltCpct, + instlCst: item.reuseBuilding[0].instlCst === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCst, + instlCstSprtAmt: item.reuseBuilding[0].instlCstSprtAmt === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCstSprtAmt, chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", - })) - .filter((item: any) => item.rainyObj !== undefined); - - setBdstTable(chData); - } + pntfColArea: item.reuseBuilding[0].rainyObj.pntfColArea === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.pntfColArea, + filtrTrtmfctCpct: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, + archArea: Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, + }; + }) + .filter((item: any) => item.rainyObj !== undefined); + setBdstTable(chData); }, [code, rainSttnRes, rainSttn.rainSttHeadList]); useEffect(() => { - if (codeData != null) rainSttnSearch(pageNation, "20", codeData, code.cityCd, code.sggCd); + rainSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); }, [pageNation]); useEffect(() => { @@ -95,8 +148,10 @@ export default function RainSttn() { }, [rainSttn.excelList]); const excelClick = useCallback(() => { - if (codeData) rainSttnSearch(1, "10000", codeData, code.cityCd, code.sggCd); - }, [rainSttnSearch, codeData, code.cityCd, code.sggCd]); + // 최신 검색 조건 반영 + const con = getConValue(); + rainSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd); + }, [rainSttnSearch, objSearch, code.cityCd, code.sggCd]); return ( <> @@ -104,47 +159,75 @@ export default function RainSttn() { <div className="grid grid-cols-4 gap-4 "> <div className="col-span-4"> <Title title={"빗물재이용 시설 현황"} /> - <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, code.cityCd, code.sggCd); - }} - excelClick={excelClick} - initClick={function (): void { }} - btnClass={btnClass} - ref={ref} - isAdmin={false} - /> + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd} + onSelectValue={getSelCity} + /> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + value={objSearch.sgg} // value props 추가 + onSelectValue={getSgg} + /> + <div className="col-span-2 flex flex-row space-x-2"> + <Label className="w-28 mt-2 text-xl text-gray-600"> + {"시설명"} + </Label> + <SearchInput + className={"w-full h-full text-2xl"} + label={""} + textValue={fcltNm || ""} + setText={setFcltNm} + /> + </div> + </div> + </SearchFormLeft> + <SearchFormRight + className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2 items-center"> + <Button + size={"sm"} + onClick={() => { + const con = getConValue(); + rainSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd); + }} + > + 조회 + </Button> + <Button + size={"sm"} + className={`${btnClass} green`} + onClick={excelClick} + > + 다운로드 + </Button> + <Button + size={"sm"} + className={btnClass} + onClick={() => { + setIsChHead(true); + }} + > + 조회항목설정 + </Button> + </div> + </SearchFormRight> + </SearchDiv> </div> </div> <div className="grid grid-cols-6 gap-4 "> <div className="col-span-6"> <ListDiv> <UiTable - headName={[]} + headName={undefined} tableData={bdstTable || []} children={ <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx index f9b3c6187..ee7a344f8 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx @@ -5,23 +5,31 @@ import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import { excelDownload, + getCity, getCityOrSgg, tableData, } from "@/components/lib/func/commom"; import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal"; import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; import { ContentsDiv, SearchBaseForm, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, Title, UiModal, UiTable, type ReturnType, + type SelectDataType, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { Button } from "@common/components/ui"; +import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; export default function RswtSttn() { @@ -34,13 +42,14 @@ export default function RswtSttn() { const [isChHead, setIsChHead] = useState(false); const ref = useRef<ReturnType>({} as ReturnType); const [bdstTable, setBdstTable] = useState<customRswtBdst[]>(); + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() + const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false }) const [bdstChgProps, setBdstChgProps] = useState<{ isOpen: boolean; chBuilding: chgBuilding[]; }>({ isOpen: false, chBuilding: [] }); - - const codeCityOrSgg = getCityOrSgg(ref); + const [fcltNm, setFcltNm] = useState<string>(""); const cellClick = (index: number | undefined, headId: string) => { @@ -50,37 +59,67 @@ export default function RswtSttn() { if ( bdstTable[index] && bdstTable[index]?.chBuildingYn === 'Y' - ) { - setBdstChgProps({ isOpen: true, chBuilding: bdstTable[index].chgBuilding }); } } } + const getSelCity = (val: string | number) => { + const cityValue = String(val); + + if (cityValue === "0") { + setSelectSgg([]); + setObjSearch({ city: cityValue, sgg: "" }); + } else { + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + + const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? ""); + setObjSearch({ city: cityValue, sgg: firstSggVal }); + } + }; + + const getSgg = (val: string | number) => { + setObjSearch({ ...objSearch, sgg: String(val) }) + }; + + const getConValue = () => { + if (!objSearch.city || objSearch.city === "0") { + return "0"; + } + if (objSearch.sgg && objSearch.sgg !== "0") { + return objSearch.sgg; + } + return objSearch.city; + }; + useEffect(() => { if (!rswtSttn.isInit) { - rswtSttnInit("0"); + rswtSttnInit(1, "20", "0", fcltNm, code.cityCd, code.sggCd); } }, [rswtSttn.isInit, rswtSttnInit]); useEffect(() => { - if (rswtSttnRes?.length > 0 && code.cityCd.length > 0) { - const data = tableData(rswtSttnRes, { code }); - const chData = data - .map((item: customRswtBdst) => ({ + const data = tableData(rswtSttnRes, { code }); + const chData = data + .map((item: customRswtBdst) => { + return { ...item, ...item.reuseBuilding[0], ...item.reuseBuilding[0]?.rswtrObj, - chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N' - })) - .filter( - (item: customRswtBdst) => - item.reuseBuilding[0]?.rswtrObj !== undefined - ); + chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N', + instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst, + instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt, + archArea : item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가' + } + }) + .filter( + (item: customRswtBdst) => + item.reuseBuilding[0]?.rswtrObj !== undefined + ); - setBdstTable(chData); - } + setBdstTable(chData); }, [code, rswtSttnRes]); useEffect(() => { @@ -95,16 +134,14 @@ export default function RswtSttn() { } }, [rswtSttn.excelList]); - const excelClick = useCallback( - (returnType: ReturnType) => { - if (codeCityOrSgg) - rswtSttnSearch(1, "10000", codeCityOrSgg, code.cityCd, code.sggCd); - }, - [rswtSttnSearch, code.cityCd, code.sggCd, codeCityOrSgg] - ); + const excelClick = useCallback(() => { + // 최신 검색 조건 반영 + const con = getConValue(); + rswtSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd); + }, [rswtSttnSearch, objSearch, code.cityCd, code.sggCd]); useEffect(() => { - if (codeCityOrSgg != null) rswtSttnSearch(pageNation, "20", codeCityOrSgg, code.cityCd, code.sggCd); + rswtSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); }, [pageNation]); return ( @@ -113,38 +150,75 @@ export default function RswtSttn() { <div className="grid grid-cols-4 gap-4 "> <div className="col-span-4"> <Title title={"중수도시설 현황"} /> - <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', …}' - if (codeCityOrSgg) - rswtSttnSearch(1, "20", codeCityOrSgg, code.cityCd, code.sggCd); - } } - excelClick={excelClick} - initClick={function (): void { } } - btnClass={btnClass} - ref={ref} isAdmin={false} /> + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd} + onSelectValue={getSelCity} + /> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + value={objSearch.sgg} // value props 추가 + onSelectValue={getSgg} + /> + <div className="col-span-2 flex flex-row space-x-2"> + <Label className="w-28 mt-2 text-xl text-gray-600"> + {"시설명"} + </Label> + <SearchInput + className={"w-full h-full text-2xl"} + label={""} + textValue={fcltNm || ""} + setText={setFcltNm} + /> + </div> + </div> + </SearchFormLeft> + <SearchFormRight + className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2 items-center"> + <Button + size={"sm"} + onClick={() => { + const con = getConValue(); + rswtSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd); + }} + > + 조회 + </Button> + <Button + size={"sm"} + className={`${btnClass} green`} + onClick={excelClick} + > + 다운로드 + </Button> + <Button + size={"sm"} + className={btnClass} + onClick={() => { + setIsChHead(true); + }} + > + 조회항목설정 + </Button> + </div> + </SearchFormRight> + </SearchDiv> </div> </div> <div className="grid grid-cols-6 gap-4 "> <div className="col-span-6"> <ListDiv> <UiTable - headName={[]} + headName={undefined} tableData={bdstTable || []} children={ <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx index 10a0bf85f..28ba6c512 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx @@ -26,10 +26,10 @@ export const headMakeprfmnc = ( key={head.id} rowSpan={1} colSpan={ - makeHeadNm.find((ch) => ch.headNm === head.upName)?.length + makeHeadNm?.find((ch) => ch.headNm === head.upName)?.length } > - {makeHeadNm.find((ch) => ch.headNm === head.upName)?.text} + {makeHeadNm?.find((ch) => ch.headNm === head.upName)?.text} </TableHead> ) : null )} @@ -39,7 +39,7 @@ export const headMakeprfmnc = ( {upHeadList .filter((data) => data.visible != false) .map((head: TableUpperProps) => - makeHeadNm.find((ch) => ch.headNm === head.upName) ? ( + makeHeadNm?.find((ch) => ch.headNm === head.upName) ? ( <TableHead className={`border border-gray-600 px-2 py-1 `} key={head.id} diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index fd8e2a6d6..0ac9145a5 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -1,10 +1,14 @@ "use client"; import { useWrStore } from "@/app/store"; -import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import type { - rswtChkZodType, - rswtrChkDetailsZodType, +import { + commonCd, + rainPageSize, + type rainChkZodType, +} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { + rswtPageSize, + type rswtrChkDetailsZodType, } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { excelArrayDownload, @@ -15,23 +19,27 @@ import ChkgdExcel from "@/components/ui/modal/chkgd/chkgdExcel/chkgdExcel"; import ChkgdModal from "@/components/ui/modal/chkgd/chkgdModal/chkgdModal"; import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable"; import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable"; +import { SearchInput } from "@common/business_components"; import { ContentsDiv, SearchDiv, SearchFormLeft, SearchFormRight, - SearchInput, SelectBox, Title, UiModal, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Label } from "@common/components/ui"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@common/components/ui/tooltip"; import { useCallback, useEffect, useState } from "react"; -import { Toaster } from "react-hot-toast"; -import { shallow } from "zustand/shallow"; +import toast, { Toaster } from "react-hot-toast"; -//----------------------- export default function Page() { const { code, @@ -42,9 +50,10 @@ export default function Page() { rainChkDelete, rainChkExcelDownload, rainChkHeadChange, + rainChkNmSearch, isRainSttn, - rswtChkgdnInit, + rswtChkNmSearch, rswtChkPolInit, rswtChkDetilsUpdate, rswtChkDelete, @@ -61,39 +70,84 @@ export default function Page() { rswtrChkDetailsZodType[] >([]); const [deleteIdx, setDeleteIdx] = useState<number[]>([]); - + const [rainPageNation, setRainPageNation] = useState(1); + const [rswtPageNation, setRswtPageNation] = useState(1); + const [fcltNm, setFcltNm] = useState<string>(""); const [selFcltDiv, setSelFcltDiv] = useState("RNB"); const [isModal, setIsModal] = useState({ open: false, data: {}, }); - const cellClick = () => { - if (searchYear) - if (selFcltDiv === "RNB") { - rainChkInit(searchYear, "0"); - } else { - rswtChkgdnInit(searchYear, "0"); - } - }; - const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); + const cellClick = () => { + if (searchYear) + if (selFcltDiv === "RNB") { + if (fcltNm) { + rainChkNmSearch( + rainPageNation, + rainPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rainChkInit(rainPageNation, rainPageSize, searchYear, commonCd); + } + } else { + if (fcltNm) { + rswtChkNmSearch( + rainPageNation, + rainPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rswtChkgdnInit(rswtPageNation, rswtPageSize, searchYear, commonCd); + } + } + }; + const rainPageChange = (pageNo: number) => { + if (pageNo > 0) { + setRainPageNation(pageNo); + rainChkInit(pageNo, rainPageSize, searchYear, commonCd); + } + }; + const rswtPageChange = (pageNo: number) => { + if (pageNo > 0) { + setRswtPageNation(pageNo); + rswtChkgdnInit(pageNo, rswtPageSize, searchYear, commonCd); + } + }; useEffect(() => { if (!rainChkgdn.isInit) { - rainChkInit(new Date().getFullYear().toString(), "0"); + rainChkInit( + 1, + rainPageSize, + new Date().getFullYear().toString(), + commonCd + ); isRainSttn(false); setIsModal({ data: {}, open: false }); setIsRegExcel(false); } + }, [rainChkgdn.isInit, rainChkInit, rainPageSize]); + useEffect(() => { if (!rswtChkgdn.isInit) { - rswtChkgdnInit(new Date().getFullYear().toString(), "0"); + rswtChkgdnInit( + 1, + rswtPageSize, + new Date().getFullYear().toString(), + commonCd + ); setIsModal({ data: {}, open: false }); setIsRegExcel(false); } - }, [rainChkgdn.isInit, rainChkInit]); + }, [rswtChkgdn.isInit, rswtChkgdnInit, rswtPageSize]); useEffect(() => { if (rswtChkgdn.excelList[0] && rswtChkgdn.excelList[0]?.data.length > 1) { @@ -156,9 +210,17 @@ export default function Page() { }; const chkUpdateTable = (selFcltDiv: string) => { if (selFcltDiv === "RNB") { + if (updateRainDetail && updateRainDetail.length > 0) { rainChkDetilUpdate(updateRainDetail); } else { + toast.error("수정을 원하는 행을 선택하고 저장버튼을 눌러주세요 "); + } + } else { + if (updateRswtDetail && updateRswtDetail.length > 0) { rswtChkDetilsUpdate(updateRswtDetail); + } else { + toast.error("수정을 원하는 행을 선택하고 저장버튼을 눌러주세요 "); + } } }; @@ -179,9 +241,9 @@ export default function Page() { selectClass={""} selectArray={yearOptions} value={searchYear} - onSelectValue={(val: string | number) => - setSearchYear(String(val)) - } + onSelectValue={(val: string | number) => { + setSearchYear(String(val)); + }} /> </div> <div className="col-span-2 flex flex-row space-x-2"> @@ -195,12 +257,22 @@ export default function Page() { selectArray={rainChkgdn.fcltDiv} onSelectValue={(val: string | number) => { if (val === "RST") rswtChkPolInit(); - setSelFcltDiv(String(val)) - } - } + setSelFcltDiv(String(val)); + }} value={selFcltDiv ?? rainChkgdn.fcltDiv[0]?.val} /> </div> + <div className="col-span-2 flex flex-row space-x-2"> + <Label className="w-28 mt-2 text-xl text-gray-600"> + {"시설명"} + </Label> + <SearchInput + className={"w-full h-full text-2xl"} + label={""} + textValue={fcltNm || ""} + setText={setFcltNm} + /> + </div> </SearchFormLeft> <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> <div className="space-y"> @@ -221,6 +293,10 @@ export default function Page() { > 삭제 </Button> + + <TooltipProvider> + <Tooltip> + <TooltipTrigger asChild> <Button size={"sm"} onClick={() => { @@ -229,6 +305,16 @@ export default function Page() { > 저장 </Button> + </TooltipTrigger> + <TooltipContent side="bottom" sideOffset={5}> + <h2 className="text-xl"> + 아래 테이블에 선택을 체크하면 입력셀이 활성화 됩니다. + </h2> + </TooltipContent> + </Tooltip> + </TooltipProvider> + + <Button size={"sm"} onClick={() => { @@ -255,13 +341,18 @@ export default function Page() { detailUp={setUpdateRainDetail} handleClick={handleClick} rainChkData={rainChkgdn.rainChk} - /> + pageNation={rainPageNation} + onPageChange={rainPageChange} + pageCount={rainChkgdn.rainChkCount} /> ) : ( <RswtChkgdTable detaiRswtlUpdate={setUpdateRSwtDetail} deleteRswtData={setDeleteIdx} handleRswtClick={handleClick} rswtChkData={rswtChkgdn.rswtChkRes} + pageNation={rswtPageNation} + onPageChange={rswtPageChange} + pageCount={rswtChkgdn.rswtChkCount} /> )} </ListDiv> @@ -269,17 +360,28 @@ export default function Page() { </div> <UiModal open={isModal.open} - onOpenChange={() => { - setIsModal({ open: !open, data: {} }); + onOpenChange={(open: boolean) => { + setIsModal((prev) => ({ ...prev, open })); }} bodyClass={"w-[80vw] max-w-none"} - body={<ChkgdModal type={selFcltDiv} obj={isModal.data} />} + body={ + <ChkgdModal + type={selFcltDiv} + obj={isModal.data} + setIsModal={(open) => setIsModal((prev) => ({ ...prev, open }))} + /> + } ></UiModal> <UiModal open={isRegExcel} onOpenChange={setIsRegExcel} bodyClass={"w-[30vw] max-w-none"} - body={<ChkgdExcel type={selFcltDiv}></ChkgdExcel>} + body={ + <ChkgdExcel + type={selFcltDiv} + setIsRegExcel={setIsRegExcel} + ></ChkgdExcel> + } /> <Toaster position="top-center" /> </ContentsDiv> diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx index 6be50a8c5..c54725ff2 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx @@ -25,7 +25,7 @@ import { } from "@common/components/ui"; import { useState, useEffect, useCallback } from "react"; import { set } from "react-hook-form"; -import { Toaster } from "react-hot-toast"; +import toast, { Toaster } from "react-hot-toast"; import { headMakeprfmnc } from "../chkgdnReg/TableHead"; import { InputTableBody } from "@/components/lib/func/TableData"; import { @@ -37,6 +37,7 @@ import { type PrfType, } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; import { excelToPbnPrfData } from "@/app/store/prfmncReg/pbnstPrfmncReg/excel"; +import data from "@common/components/ui/icon-finder/data"; export default function prfmncPrfmncReg() { const { code, prfmnc, prfmncHasuInit, prfmnRegData } = useWrStore( @@ -51,11 +52,12 @@ export default function prfmncPrfmncReg() { }>({ isModal: false, data: {} as FcPrfType }); const [inputData, setInputData] = useState<any[]>(); const [pbnstRuseFcltPk, setPbnstRuseFcltPk] = useState<string>(); - const [pageNation , setPageNation] = useState<number>(1); - + const [pageNation, setPageNation] = useState<number>(1); + const [cellNum, setCellNum] = useState<number>(1); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) ); + const excelClick = useCallback(() => { excelDownload( [[]], @@ -65,33 +67,43 @@ export default function prfmncPrfmncReg() { ); }, [prfmnc.excelList]); - const onSave = useCallback(() => { + const onSave = useCallback( + async() => { if (pbnstRuseFcltPk) { - prfmnRegData( + await prfmnRegData(pageNation,'41', excelToPbnPrfData( inputData as unknown as JSON[], searchYear, pbnstRuseFcltPk ) as unknown as PrfType ); - prfmncHasuInit(String(pageNation), "41"); + // cellClick(cellNum) } - }, [inputData, searchYear, pbnstRuseFcltPk,prfmncHasuInit,pageNation]); - - - + }, [inputData, searchYear, pbnstRuseFcltPk, pageNation,cellNum]); const cellClick = useCallback( - (index: number | undefined, headId: string) => { + (index: number | undefined) => { if (index !== undefined) { setIsExcelOPen({ isModal: false, data: prfmncRes[index] || ({} as FcPrfType), }); - const inUsageData = structuredClone(initValInUsage); - const outUsageData = structuredClone(initValOutUsage); - const inSubtotal = structuredClone(subTotalObj); - const outSubtotal = structuredClone(subTotalObj); + const inUsageData = structuredClone(initValInUsage).map((row) => ({ + ...row, + 구분: "장내용수", + })); + const outUsageData = structuredClone(initValOutUsage).map((row) => ({ + ...row, + 구분: "장외용수", + })); + const inSubtotal = { + ...structuredClone(subTotalObj), + 구분: "장내용수", + }; + const outSubtotal = { + ...structuredClone(subTotalObj), + 구분: "장외용수", + }; if (prfmncRes[index]?.prfList) { prfmncRes[index].prfList?.forEach((prfItem) => { const month = Number(prfItem?.ym?.slice(4)); // "MM" @@ -127,7 +139,11 @@ export default function prfmncPrfmncReg() { }); inUsageData.push(inSubtotal); outUsageData.push(outSubtotal); - const usageTotalObj: { [key: string]: any } = structuredClone(totalObj); + const usageTotalObj: { [key: string]: any } = { + ...structuredClone(totalObj), + 구분: "총합계", + 용수명: "", + }; for (const key in usageTotalObj) { if (["usage", "gubun", "edit"].includes(key)) continue; const val = @@ -138,7 +154,6 @@ export default function prfmncPrfmncReg() { } const tableData = [...inUsageData, ...outUsageData, usageTotalObj]; setPbnstRuseFcltPk(prfmncRes[index].pbnstRuseFcltPk); - setInputData(tableData); } else { setInputData([]); @@ -150,19 +165,24 @@ export default function prfmncPrfmncReg() { useEffect(() => { if (!prfmnc.isInit) { - prfmncHasuInit('1', "41"); + prfmncHasuInit(1, "41"); } }, [prfmnc.isInit, prfmncHasuInit]); useEffect(() => { setbdstTable(prfmncRes); - }, [prfmncRes]); + + // cellNum이 0일 경우(첫 번째 행)도 유효한 인덱스이므로 undefined 여부만 체크합니다. + if (cellNum !== undefined) { + cellClick(cellNum); + } + }, [prfmncRes, cellNum, cellClick]); return ( <> <ContentsDiv> <div className="grid grid-cols-4 gap-4"> <div className="col-span-4"> - <Title title={"하수재이용 시설 등록"} /> + <Title title={"하수재이용 실적 등록"} /> <SearchDiv> <SearchFormLeft> <div className="col-span-2 flex flex-row space-x-2"> @@ -211,7 +231,12 @@ export default function prfmncPrfmncReg() { <Button size={"sm"} onClick={() => { - setIsExcelOPen({ ...isExcelOpen, isModal: true }); + if (cellNum === undefined) { + toast.error("하수처리재이용시설을 선택해주세요."); + return; + } else { + setIsExcelOPen({ ...isExcelOpen, isModal: true }); + } }} > 파일등록 @@ -231,13 +256,15 @@ export default function prfmncPrfmncReg() { <ListDiv className="min-h-0"> <ScrollArea className="h-[60vh]"> <UiTable + key={'leftTable'} tableData={bdstTable || []} headlist={pbnstPrfmncHeadList} pageSize={10} total={10000} headName={"하수재이용시설 목록"} cellClick={(index: number | undefined, headId: string) => { - cellClick(index, headId); + cellClick(index); + setCellNum(index ?? 0); }} onPageChange={setPageNation} children={undefined} @@ -257,7 +284,7 @@ export default function prfmncPrfmncReg() { <TableHeader className="font-bold"> {headMakeprfmnc(monthHeadList, [])} </TableHeader> - <TableBody> + <TableBody key={prfmnc.pageKey+'pageKey'}> {InputTableBody(inputData ?? [], monthHeadList, setInputData)} </TableBody> </Table> @@ -266,8 +293,23 @@ export default function prfmncPrfmncReg() { </div> </ContentsDiv> <UiModal - bodyClass={""} - body={<PbnPrfExcelModal data={isExcelOpen.data}></PbnPrfExcelModal>} + bodyClass={"w-[30vw] max-w-none"} + body={ + <PbnPrfExcelModal + data={isExcelOpen.data} + setIsExcelOPen={(open) => { + setIsExcelOPen({ ...isExcelOpen, isModal: open }) + + }} + setModalExcelData={ async(excelData ) =>{ + await prfmnRegData(pageNation,'41', + excelData, + ); + // 데이터 저장 후 UI 업데이트는 useEffect가 감지하여 처리하므로 여기서는 호출하지 않습니다. + } + } + ></PbnPrfExcelModal> + } open={isExcelOpen.isModal} onOpenChange={() => { setIsExcelOPen({ isModal: false, data: {} as FcPrfType }); diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx index 8960f468d..a191de9ee 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx @@ -1,6 +1,8 @@ "use client"; import { useWrStore } from "@/app/store"; +import { commonCd, rainPageSize } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { rswtPageSize } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { excelDownload, yearOptions @@ -13,6 +15,7 @@ import { SearchDiv, SearchFormLeft, SearchFormRight, + SearchInput, SelectBox, Title, UiModal @@ -28,9 +31,9 @@ export default function Page() { rainChkSttn, rswtChkSttn, rainChkSttnInit, - rainChkSttnSearch, - rswtChkSttnSearch, + rainChkSttnNmSearch, rswtChkSttnInit, + rswtChkNmSttnSearch, isRainSttn, isRswtSttn, rswtChkPolInit, @@ -39,6 +42,9 @@ export default function Page() { }); const [selFcltDiv, setSelFcltDiv] = useState("RNB"); + const [rainPageNation, setRainPageNation] = useState(1); + const [rswtPageNation, setRswtPageNation] = useState(1); + const [fcltNm, setFcltNm] = useState<string>(""); const [isModal, setIsModal] = useState({ open: false, data: {}, @@ -47,29 +53,64 @@ export default function Page() { const cellClick = () => { if (searchYear) { if (selFcltDiv === "RNB") { - rainChkSttnSearch(searchYear, "0"); + if (fcltNm) { + rainChkSttnNmSearch( + rainPageNation, + rainPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rainChkSttnInit(rainPageNation, rainPageSize, searchYear, commonCd); + } } else { - rswtChkSttnSearch(searchYear, "0"); + if (fcltNm) { + rswtChkNmSttnSearch( + rswtPageNation, + rswtPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rswtChkSttnInit(rswtPageNation, rswtPageSize, searchYear, commonCd); + } } } }; + const rainPageChange = (pageNo: number) => { + if (pageNo > 0) { + setRainPageNation(pageNo); + rainChkSttnInit(pageNo, rainPageSize, searchYear, commonCd); + } + }; + + const rswtPageChange = (pageNo: number) => { + if (pageNo > 0) { + setRswtPageNation(pageNo); + rswtChkSttnInit(pageNo, rswtPageSize, searchYear, commonCd); + } + }; + useEffect(() => { if (!rainChkSttn.isInit) { isRainSttn(true) - rainChkSttnInit(new Date().getFullYear().toString(), "0"); + console.log("여기", rainPageSize) + rainChkSttnInit(1, rainPageSize, new Date().getFullYear().toString(), commonCd); setIsModal({ data: {}, open: false }); } - }, [rainChkSttn.isInit, rainChkSttnInit]); + }, [rainChkSttn.isInit, rainChkSttnInit, rainPageSize]); useEffect(() => { - if (!rswtChkSttn.isInit) { setIsModal({ data: {}, open: false }); - rswtChkSttnInit(new Date().getFullYear().toString(), "0"); + rswtChkSttnInit(1, rswtPageSize, new Date().getFullYear().toString(), commonCd); isRswtSttn(true) } - }, [rswtChkSttn.isInit, rswtChkSttnInit]) + }, [rswtChkSttn.isInit, rswtChkSttnInit, rswtPageSize]) + const handleClick = useCallback( @@ -133,6 +174,17 @@ export default function Page() { value={selFcltDiv ?? rainChkSttn.fcltDiv[0]?.val} /> </div> + <div className="col-span-2 flex flex-row space-x-2"> + <Label className="w-28 mt-2 text-xl text-gray-600"> + {"시설명"} + </Label> + <SearchInput + className={"w-full text-2xl"} + label={""} + textValue={fcltNm || ""} + setText={setFcltNm} + /> + </div> </SearchFormLeft> <SearchFormRight> <div className="space-y"> @@ -163,6 +215,9 @@ export default function Page() { detailUp={() => { }} handleClick={handleClick} rainChkData={rainChkSttn.rainChkRes} + pageNation={rainPageNation} + onPageChange={rainPageChange} + pageCount={rainChkSttn.rainChkCount} /> ) : ( <RswtChkgdTable @@ -170,6 +225,9 @@ export default function Page() { deleteRswtData={() => { }} handleRswtClick={handleClick} rswtChkData={rswtChkSttn.rswtChkRes} + pageNation={rswtPageNation} + onPageChange={rswtPageChange} + pageCount={rswtChkSttn.rswtChkCount} /> )} </ListDiv> @@ -181,7 +239,7 @@ export default function Page() { setIsModal({ open: !open, data: {} }); }} bodyClass={"w-[80vw] max-w-none"} - body={<ChkgdModal type={selFcltDiv} obj={isModal.data} />} + body={<ChkgdModal type={selFcltDiv} obj={isModal.data} setIsModal={() => { }} />} ></UiModal> <Toaster position="top-center" /> </ContentsDiv> diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx index a50c08071..f689eb745 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx @@ -8,9 +8,11 @@ import { excelDownload, yearOptions } from "@/components/lib/func/commom"; import SearchInputText from "@/components/ui/searchInput/searchInput"; import { CHART_FORM, ContentsDiv, MainChart, ScrollArea, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ChartConfig, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { Button, Label } from "@common/components/ui"; +import { Button, Label, Table, TableBody, TableHeader } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; import toast, { Toaster } from "react-hot-toast"; +import { headMakeprfmnc } from "../../prfmncReg/chkgdnReg/TableHead"; +import { InputTableBody } from "@/components/lib/func/TableData"; export default function PbnstPrfmncSttn() { const { @@ -34,9 +36,9 @@ export default function PbnstPrfmncSttn() { const [swtrmtFcltNm, setSwtrmtFcltNm] = useState<string>(); const [pbnRuseNm, setPbnRuseNm] = useState<string>(""); - const [searchYear, setSearchYear] = useState<string>( - String(new Date().getFullYear()) - ); + const [searchYear, setSearchYear] = useState<string>( + String(new Date().getFullYear()) + ); const [excelData, setExcelData] = useState<any[]>([]); const excelClick = useCallback(() => { excelDownload( @@ -83,15 +85,20 @@ export default function PbnstPrfmncSttn() { type lineChartDataProps = { label: string, val: number, color: string }; const prfTableData = (prfList: PrfType[], year: string) => { - const inUsageData = structuredClone(initValInUsage); - const outUsageData = structuredClone(initValOutUsage); - - const inSubtotal = structuredClone(subTotalObj); - const outSubtotal = structuredClone(subTotalObj); + const inUsageData = structuredClone(initValInUsage).map(row => ({ + ...row, + 구분: "장내용수", + })); + const outUsageData = structuredClone(initValOutUsage).map(row => ({ + ...row, + 구분: "장외용수", + })); + const inSubtotal = { ...structuredClone(subTotalObj), 구분: "장내용수" }; + const outSubtotal = { ...structuredClone(subTotalObj), 구분: "장외용수" }; const prfFilter = prfList?.filter((e) => e.ym.slice(0, 4) === year) if (prfList && prfFilter.length > 0) { - + prfList?.forEach((prfItem) => { const month = Number(prfItem?.ym?.slice(4)); // "MM" const monthKey = `${month}월`; @@ -142,7 +149,7 @@ export default function PbnstPrfmncSttn() { setPrfData([]); } } - + const [chartId, setChartId] = useState<string>(); useEffect(() => { // 누적 변수 초기화 @@ -198,8 +205,8 @@ export default function PbnstPrfmncSttn() { prfTableData([], year) rawData.forEach((item) => { // 실적 테이블 데이터 - if (chartId){ - if(item.prfList?.[0]?.ym.slice(0, 4) === year && item.prfList?.[0]?.pbnstRuseFcltFk === chartId){ + if (chartId) { + if (item.prfList?.[0]?.ym.slice(0, 4) === year && item.prfList?.[0]?.pbnstRuseFcltFk === chartId) { prfTableData(item.prfList, year); } item.prfList.filter((e) => e.ym.slice(0, 4) === year && e.pbnstRuseFcltFk === chartId).forEach((element) => { @@ -265,40 +272,40 @@ export default function PbnstPrfmncSttn() { }); // 도넛차트 데이터 - dnData.push({ label: "세척수", val: wshwtr, fill: "red" }); - dnData.push({ label: "냉각수", val: coolUswtr, fill: "orange" }); - dnData.push({ label: "청소수", val: cleanUswtr, fill: "yellow" }); - dnData.push({ label: "식수대", val: drwtUswtr, fill: "green" }); - dnData.push({ label: "희석용수", val: dltnUswtr, fill: "skyblue" }); - dnData.push({ label: "중수도", val: ithlRswtr, fill: "blue" }); - dnData.push({ label: "기타", val: ithlEtcUswtr, fill: "purple" }); - dnData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "red" }); - dnData.push({ label: "세척살수용수", val: resn, fill: "orange" }); - dnData.push({ label: "조경용수", val: lndwtr, fill: "yellow" }); - dnData.push({ label: "친수용수", val: hydUswtr, fill: "green" }); - dnData.push({ label: "지하수충전", val: ugwtChr, fill: "skyblue" }); - dnData.push({ label: "농업용수", val: farmUswtr, fill: "blue" }); - dnData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "purple" }); - dnData.push({ label: "공업용수", val: indstUswtr, fill: "black" }); + dnData.push({ label: "세척수", val: wshwtr, fill: "#F7CFD8" }); + dnData.push({ label: "냉각수", val: coolUswtr, fill: "#F4F8D3" }); + dnData.push({ label: "청소수", val: cleanUswtr, fill: "#A6D6D6" }); + dnData.push({ label: "식수대", val: drwtUswtr, fill: "#8E7DBE" }); + dnData.push({ label: "희석용수", val: dltnUswtr, fill: "#FF8383" }); + dnData.push({ label: "중수도", val: ithlRswtr, fill: "#FFF574" }); + dnData.push({ label: "기타", val: ithlEtcUswtr, fill: "#A1D6CB" }); + dnData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "#A19AD3" }); + dnData.push({ label: "세척살수용수", val: resn, fill: "#B1F0F7" }); + dnData.push({ label: "조경용수", val: lndwtr, fill: "#81BFDA" }); + dnData.push({ label: "친수용수", val: hydUswtr, fill: "#F5F0CD" }); + dnData.push({ label: "지하수충전", val: ugwtChr, fill: "#FADA7A" }); + dnData.push({ label: "농업용수", val: farmUswtr, fill: "#A6AEBF" }); + dnData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "#C5D3E8" }); + dnData.push({ label: "공업용수", val: indstUswtr, fill: "#D0E8C5" }); // 장내용수 도넛 - dnInData.push({ label: "세척수", val: wshwtr, fill: "yellow" }); - dnInData.push({ label: "냉각수", val: coolUswtr, fill: "green" }); - dnInData.push({ label: "청소수", val: cleanUswtr, fill: "yellow" }); - dnInData.push({ label: "식수대", val: drwtUswtr, fill: "green" }); - dnInData.push({ label: "희석용수", val: dltnUswtr, fill: "yellow" }); - dnInData.push({ label: "중수도", val: ithlRswtr, fill: "green" }); - dnInData.push({ label: "기타", val: ithlEtcUswtr, fill: "yellow" }); - dnInData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "green" }); - dnInData.push({ label: "세척살수용수", val: resn, fill: "yellow" }); + dnInData.push({ label: "세척수", val: wshwtr, fill: "#F7CFD8" }); + dnInData.push({ label: "냉각수", val: coolUswtr, fill: "#F4F8D3" }); + dnInData.push({ label: "청소수", val: cleanUswtr, fill: "#A6D6D6" }); + dnInData.push({ label: "식수대", val: drwtUswtr, fill: "#8E7DBE" }); + dnInData.push({ label: "희석용수", val: dltnUswtr, fill: "#FF8383" }); + dnInData.push({ label: "중수도", val: ithlRswtr, fill: "#FFF574" }); + dnInData.push({ label: "기타", val: ithlEtcUswtr, fill: "#A1D6CB" }); + dnInData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "#A19AD3" }); + dnInData.push({ label: "세척살수용수", val: resn, fill: "#B1F0F7" }); // 장외용수 도넛 - dnOutData.push({ label: "조경용수", val: lndwtr, fill: "yellow" }); - dnOutData.push({ label: "친수용수", val: hydUswtr, fill: "black" }); - dnOutData.push({ label: "지하수충전", val: ugwtChr, fill: "yellow" }); - dnOutData.push({ label: "농업용수", val: farmUswtr, fill: "black" }); - dnOutData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "yellow" }); - dnOutData.push({ label: "공업용수", val: indstUswtr, fill: "black" }); + dnOutData.push({ label: "조경용수", val: lndwtr, fill: "#81BFDA" }); + dnOutData.push({ label: "친수용수", val: hydUswtr, fill: "#F5F0CD" }); + dnOutData.push({ label: "지하수충전", val: ugwtChr, fill: "#FADA7A" }); + dnOutData.push({ label: "농업용수", val: farmUswtr, fill: "#A6AEBF" }); + dnOutData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "#C5D3E8" }); + dnOutData.push({ label: "공업용수", val: indstUswtr, fill: "#D0E8C5" }); // 라인차트 데이터 setInLineData({ @@ -466,7 +473,7 @@ export default function PbnstPrfmncSttn() { useEffect(() => { setbdstTable(prfmncRes); - if(prfmncRes?.[0]?.pbnstRuseFcltPk) setChartId(prfmncRes[0].pbnstRuseFcltPk) + if (prfmncRes?.[0]?.pbnstRuseFcltPk) setChartId(prfmncRes[0].pbnstRuseFcltPk) }, [prfmncRes]); @@ -619,12 +626,12 @@ export default function PbnstPrfmncSttn() { </div> <h1 className="">하수재이용실적 현황</h1> <ListDiv className="col-span-8 pr-6 "> - <ScrollArea className="h-[60vh]"> - <div className="card-header"> + {/* <ScrollArea className="h-[60vh]"> */} + {/* <div className="card-header"> <h3 className="text-2xl font-medium text-label"> {"하수처리수재이용 실적(m3) 등록결과"} </h3> - </div> + </div> */} <UiTable headName={undefined} @@ -637,7 +644,26 @@ export default function PbnstPrfmncSttn() { throw new Error("Function not implemented."); }}> </UiTable> - </ScrollArea> + + {/* <ListDiv className="col-span-8 pr-6 "> + <ScrollArea className="h-[60vh]"> + <div className="card-header"> + <h3 className="text-2xl font-medium text-label"> + {"하수처리수재이용 실적(m3) 등록결과"} + </h3> + </div> + + <Table variant="secondary"> + <TableHeader className="font-bold"> + {headMakeprfmnc(monthHeadList, [])} + </TableHeader> + <TableBody> + {InputTableBody(prfData ?? [], monthHeadList, setPrfData)} + </TableBody> + </Table> + </ScrollArea> + </ListDiv> */} + {/* </ScrollArea> */} </ListDiv> </ListDiv> diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index 08990028f..45d32d3a4 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -210,8 +210,9 @@ export default function RainStat() { ...item, ctpvCd: item.cityText }; - }) + }).filter((item: RainStatProps) => item.cityText !== '없음') : []; + setBdstTable(tbData); }, [code, rainStatList]); diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index c0741433c..997e95ca5 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -46,7 +46,7 @@ export default function RswtStat() { ...item, ctpvCd: item.cityText }; - }) + }).filter((item: RswtStatProps) => item.cityText !== '없음') : []; setRswtTable(tbData); }, [code, rswtStatList]) diff --git a/apps/wr/app/store/common/code/basicCode.tsx b/apps/wr/app/store/common/code/basicCode.tsx new file mode 100644 index 000000000..56c59b502 --- /dev/null +++ b/apps/wr/app/store/common/code/basicCode.tsx @@ -0,0 +1,204 @@ +import type { SelectDataType } from "@common/business_components"; + +export const yn: SelectDataType[] = [ + { val: "Y", text: "Y" }, + { val: "N", text: "N" }, +]; +export const bdstFilterYn: SelectDataType[] = [ + { val: "Y", text: "Y" }, + { val: "N", text: "N" }, + { val: "D", text: "확인불가" }, + { val: "F", text: "미가동" }, +]; +// 최우수(그린1)/우수(그린2), 우량(그린3), 일반(그린4), 확인불가 체크 +export const bdstGrntchClass: SelectDataType[] = [ + { val: "최우수(그린1)", text: "최우수(그린1)" }, + { val: "우수(그린2)", text: "우수(그린2)" }, + { val: "우량(그린3)", text: "우량(그린3)" }, + { val: "일반(그린4)", text: "일반(그린4)" }, + { val: "확인불가", text: "확인불가" }, +]; +export const bdstIncenYn: SelectDataType[] = [ + { val: "Y", text: "Y" }, + { val: "N", text: "N" }, + { val: "D", text: "확인불가" }, +]; +//처리장연계/자체+연계/자체처리 +export const erctUswtrPrcsMeth: SelectDataType[] = [ + { val: "처리장연계", text: "처리장연계" }, + { val: "자체+연계", text: "자체+연계" }, + { val: "자체처리", text: "자체처리" }, +]; + +export const rusePrcsMthdCd: SelectDataType[] = [ + { val: "물리학적처리", text: "물리학적처리" }, + { val: "생물학적처리", text: "생물학적처리" }, +]; + +export const ruseSeCd: SelectDataType[] = [ + { val: "신규", text: "신규" }, + { val: "증설", text: "증설" }, + { val: "관로", text: "관로" }, + { val: "감량", text: "감량" }, + { val: "개량", text: "개량" }, +]; + +export const ruseBizMthdCd: SelectDataType[] = [ + { val: "재정", text: "재정" }, + { val: "민간투자", text: "민간투자" }, + { val: "자체", text: "자체" }, +]; + +//공통 건축물 용도 +export 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 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" }, +]; + +export const orgwtKndCd = [ + { text: "오수(변기 오수 제외)", val: "1" }, + { text: "오수", val: "2" }, + { text: "폐수", val: "3" }, + { text: "오수 및 폐수", val: "4" }, + { text: "기타", val: "5" }, +]; + +export const chBuCd = [ + { val: "증축", text: "증축" }, + { val: "개축", text: "개축" }, + { val: "재축", text: "재축" }, +]; + +export const dmdUszCd = [ + { val: "조경용수", text: "조경용수" }, + { val: "청소화장실용수", text: "청소화장실용수" }, + { val: "농업용수", text: "농업용수" }, + { val: "공업용수", text: "공업용수" }, + { val: "친수용수", text: "친수용수" }, + { val: "기타", text: "기타" }, +]; + +export const ruseMngMtd = [ + { val: "자체운영", text: "자체운영" }, + { val: "공기업", text: "공기업" }, + { val: "민간(대행)", text: "민간(대행)" }, +]; + +export const pplQulity = [ + { val: "도복장강관", text: "도복장강관" }, + { val: "PE관", text: "PE관" }, + { val: "스테인레스관", text: "스테인레스관" }, + { val: "덕타일주철관", text: "덕타일주철관" }, + { val: "유리섬유복합관", text: "유리섬유복합관" }, + { val: "기타", text: "기타" }, +]; +export const pplLenght = [ + { val: "D100", text: "D100" }, + { val: "D200", text: "D200" }, + { val: "D250", text: "D250" }, + { val: "D300", text: "D300" }, + { val: "D350", text: "D350" }, + { val: "D400", text: "D400" }, + { val: "D450", text: "D450" }, + { val: "D500", text: "D500" }, + { val: "D700", text: "D700" }, + { val: "D900", text: "D900" }, + { val: "D1000​", text: "D1000​" }, +]; + +export const rainFcltCd = [ + { val: "지붕", text: "지붕" }, + { val: "건물옥상", text: "건물옥상" }, + { val: "골프장 연못", text: "골프장 연못" }, + { val: "운동장 바닥", text: "운동장 바닥" }, + { val: "운동장 지붕", text: "운동장 지붕" }, + { val: "주차장", text: "주차장" }, + { val: "태양광패널", text: "태양광패널" }, + { val: "연못", text: "연못" }, + { val: "기타", text: "기타" }, + { val: "확인불가", text: "확인불가" }, +]; + +//물리화학적처리(스크린, 응집, 침전)/생물학적처리(활성슬러지법 등)/소독(염소, UV 등)/기타 +export const rswtPrscCdMthdCd = [ + { + val: "물리화학적처리(스크린,응집,침전)", + text: "물리화학적처리(스크린,응집,침전)", + }, + { + val: "생물학적처리(활성슬러지법 등)", + text: "생물학적처리(활성슬러지법 등)", + }, + { val: "소독(염소, UV 등)", text: "소독(염소, UV 등)" }, + { val: "기타", text: "기타" }, +]; + +export const htdPowerMthdCd= [ + { + val: "석탄화력발전", + text: "석탄화력발전", + }, +]; + +//(공업용수/양식장/농업용수) +export const htdUtztnUsgCd= [ + { + val: "공업용수", + text: "공업용수", + }, + { + val: "양식장", + text: "양식장", + }, + { + val: "농업용수", + text: "농업용수", + }, +]; diff --git a/apps/wr/app/store/common/code/index.ts b/apps/wr/app/store/common/code/index.ts index 83d87d738..b3cf48603 100644 --- a/apps/wr/app/store/common/code/index.ts +++ b/apps/wr/app/store/common/code/index.ts @@ -1,214 +1,13 @@ import { getFetch } from "@/components/lib/api"; import type { EnvPartSelectDataType, SelectDataType } from "@common/business_components/ui"; - - - +import { bdstFilterYn, bdstGrntchClass, bdstIncenYn, bdstUsgCd, chBuCd, dmdUszCd, erctUswtrPrcsMeth, htdPowerMthdCd, htdUtztnUsgCd, orgwtKndCd, pplLenght, pplQulity, rainFcltCd, rswtPrscCdMthdCd, ruseBizMthdCd, ruseMngMtd, rusePrcsMthdCd, ruseSeCd, yn } from "./basicCode"; 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' }, -] - -//처리장연계/자체+연계/자체처리 -const erctUswtrPrcsMeth : SelectDataType[]= [ - { val: '처리장연계', text: '처리장연계' }, - { val: '자체+연계', text: '자체+연계' }, - { val: '자체처리', text: '자체처리' }, -] - -const rusePrcsMthdCd : SelectDataType[] = [ - { val: '물리학적처리', text: '물리학적처리' }, - { val: '생물학적처리', text: '생물학적처리' }, -] - -const ruseSeCd : SelectDataType[] = [ - { val: '신규', text: '신규' }, - { val: '증설', text: '증설' }, - { val: '관로', text: '관로' }, - { val: '감량', text: '감량' }, - { val: '개량', text: '개량' }, -] - -const ruseBizMthdCd: SelectDataType[] = [ - { val: '재정', text: '재정' }, - { val: '민간투자', text: '민간투자' }, - { val: '자체', 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: "기타" }, -]; -//빗물 집수면 종류 용도 -// const rainFcltCd = [ -// { 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: "확인불가" }, -// ]; -// 중수도 필수 원수종류 -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 = [ - { text: "오수(변기 오수 제외)", val: "1" }, - { text: "오수", val: "2" }, - { text: "폐수", val: "3" }, - { text: "오수 및 폐수", val: "4" }, - { text: "기타", val: "5" }, -]; - -const chBuCd = [ - { val: "증축", text: "증축" }, - { val: "개축", text: "개축" }, - { val: "재축", text: "재축" }, -] - - - -const dmdUszCd = [ - { val: "조경용수", text: "조경용수" }, - { val: "청소화장실용수", text: "청소화장실용수" }, - { val: "농업용수", text: "농업용수" }, - { val: "공업용수", text: "공업용수" }, - { val: "친수용수", text: "친수용수" }, - { val: "기타", text: "기타" }, - -] - -const ruseMngMtd = [ - { val: "자체운영", text: "자체운영" }, - { val: "공기업", text: "공기업" }, - { val: "민간(대행)", text: "민간(대행)" }, -] - - -const pplQulity = [ - { val: "도복장강관", text: "도복장강관" }, - { val: "PE관", text: "PE관" }, - { val: "스테인레스관", text: "스테인레스관" }, - { val: "덕타일주철관", text: "덕타일주철관" }, - { val: "유리섬유복합관", text: "유리섬유복합관" }, - { val: "기타", text: "기타" }, - -] -const pplLenght = [ - { val: "D100", text: "D100" }, - { val: "D200", text: "D200" }, - { val: "D250", text: "D250" }, - { val: "D300", text: "D300" }, - { val: "D350", text: "D350" }, - { val: "D400", text: "D400" }, - { val: "D450", text: "D450" }, - { val: "D500", text: "D500" }, - { val: "D700", text: "D700" }, - { val: "D900", text: "D900" }, - { val: "D1000​", text: "D1000​" }, - -] export const buildingType = { RST:"RST", RNB:"RNB", HTB:"HTB" } - -const rainFcltCd = [ - { val: "지붕", text: "지붕" }, - { val: "건물옥상", text: "건물옥상" }, - { val: "골프장 연못", text: "골프장 연못" }, - { val: "운동장 바닥", text: "운동장 바닥" }, - { val: "운동장 지붕", text: "운동장 지붕" }, - { val: "주차장", text: "주차장" }, - { val: "태양광패널", text: "태양광패널" }, - { val: "연못", text: "연못" }, - { val: "기타", text: "기타" }, - { val: "확인불가", text: "확인불가" }, -]; - -export type comCodeState = { - code: { - isInit: boolean; - chBuCd: SelectDataType[] - rainFcltCd: SelectDataType[]; - bdstUsgCd: SelectDataType[]; - cityCd: SelectDataType[]; - sggCd: SelectDataType[]; - rvbsnCd: SelectDataType[]; - mdmbsnCd: SelectDataType[]; - lgbsnCd: SelectDataType[]; - lclgvrnmntCd: EnvPartSelectDataType[]; - orgwtKndCd: SelectDataType[]; - yn: SelectDataType[]; - pplQulity: SelectDataType[]; - pplLenght: SelectDataType[]; - dmdUszCd:SelectDataType[] - buildingType: { - RST:string, - RNB:string, - HTB:string - } - ruseMngMtd:SelectDataType[] - ruseSeCd: SelectDataType[]; - ruseBizMthdCd: SelectDataType[]; - rusePrcsMthdCd: SelectDataType[]; - erctUswtrPrcsMeth: SelectDataType[]; - }; -}; - -export type comCodeType = comCodeState & comCodeActions; - export const getSggCd = async (set: any) => { const sgg = await getFetch("common", "/addr/sgg"); /* const sggCd = sgg.map((item: any) => ({ @@ -217,7 +16,7 @@ export const getSggCd = async (set: any) => { })); */ const sggCd = [ - { text: "전체", val: '0' }, + // { text: "전체", val: '0' }, ...sgg .map((item: any) => ({ text: item.gugun || '', @@ -334,6 +133,47 @@ export const getEnvPartCd = async (set: any) => { + +export type comCodeState = { + code: { + isInit: boolean; + chBuCd: SelectDataType[] + rainFcltCd: SelectDataType[]; + bdstUsgCd: SelectDataType[]; + cityCd: SelectDataType[]; + sggCd: SelectDataType[]; + rvbsnCd: SelectDataType[]; + mdmbsnCd: SelectDataType[]; + lgbsnCd: SelectDataType[]; + lclgvrnmntCd: EnvPartSelectDataType[]; + orgwtKndCd: SelectDataType[]; + yn: SelectDataType[]; + pplQulity: SelectDataType[]; + pplLenght: SelectDataType[]; + dmdUszCd:SelectDataType[] + buildingType: { + RST:string, + RNB:string, + HTB:string + } + ruseMngMtd:SelectDataType[] + ruseSeCd: SelectDataType[]; + ruseBizMthdCd: SelectDataType[]; + rusePrcsMthdCd: SelectDataType[]; + erctUswtrPrcsMeth: SelectDataType[]; + bdstFilterYn: SelectDataType[]; + bdstIncenYn: SelectDataType[]; + bdstGrntchClass:SelectDataType[]; + rswtPrscCdMthdCd:SelectDataType[]; + htdPowerMthdCd:SelectDataType[] + htdUtztnUsgCd:SelectDataType[] + }; +}; + +export type comCodeType = comCodeState & comCodeActions; + + + export const comCodeStateExport: comCodeState = { code: { isInit: false, @@ -356,7 +196,13 @@ export const comCodeStateExport: comCodeState = { ruseSeCd:ruseSeCd, ruseBizMthdCd: ruseBizMthdCd, rusePrcsMthdCd:rusePrcsMthdCd, - erctUswtrPrcsMeth:erctUswtrPrcsMeth + erctUswtrPrcsMeth:erctUswtrPrcsMeth, + bdstFilterYn:bdstFilterYn, + bdstIncenYn:bdstIncenYn, + bdstGrntchClass:bdstGrntchClass, + rswtPrscCdMthdCd:rswtPrscCdMthdCd, + htdPowerMthdCd:htdPowerMthdCd, + htdUtztnUsgCd:htdUtztnUsgCd, }, }; @@ -364,9 +210,6 @@ export type comCodeActions = { codeInit: () => void; }; - - - export const codeActionExport: (set: any) => comCodeActions = (set: any) => { return { codeInit: async () => { diff --git a/apps/wr/app/store/common/searchCode/index.ts b/apps/wr/app/store/common/searchCode/index.ts index 51ebda8a5..656bc33d9 100644 --- a/apps/wr/app/store/common/searchCode/index.ts +++ b/apps/wr/app/store/common/searchCode/index.ts @@ -70,6 +70,7 @@ export type comFcltState = { export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { return { getSwtrmtFcltNm: async (searchNm: string) => { + const fcltNm = await getFetch( "common", `/prcsFclt/info/1/11/${searchNm}` @@ -94,10 +95,13 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { `/reuseFc/request/${searchNm}/${cnt}` ); - console.log(coList); - set((state: comFcltState) => { - return (state.demandCompList = [...coList]); - }); + + if(coList&&coList.length>0){ + + set((state: comFcltState) => { + return (state.demandCompList = [...coList]); + }); + } }, regDemandCompany: async (data: DemandCompType) => { try { @@ -112,9 +116,10 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { } else { message = "fail"; } + + set((state: comFcltState) => { - state.dmdIsSucees = message; - return state; + return state.dmdIsSucees = message; }); } catch (err) { console.log(err); @@ -132,8 +137,7 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { } set((state: comFcltState) => { - state.dmdIsSucees = message; - return state; + return state.dmdIsSucees = message; }); } catch (err) { console.log(err); diff --git a/apps/wr/app/store/matDmd/coMatRvw/headList.tsx b/apps/wr/app/store/matDmd/coMatRvw/headList.tsx index 7b43e4b00..6d9bf8862 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/headList.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/headList.tsx @@ -29,12 +29,12 @@ export const coRvwHeadListExport: CommonTableProps[]= [ visible: true, }, { - id: "regDt", //바꾸기 + id: "dmndTmng", title: "신청일자", visible: true, }, { - id: "state", //바꾸기 + id: "splyFcltFlg", title: "진행상태", visible: true, }, diff --git a/apps/wr/app/store/matDmd/coMatRvw/index.tsx b/apps/wr/app/store/matDmd/coMatRvw/index.tsx index 89836957b..21239fce3 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/index.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/index.tsx @@ -1,13 +1,18 @@ -import { constCostHeadListExport, coRvwHeadListExport, coRvwNodeListExport, rateFeeHeadListExport } from "./headList"; +import { + constCostHeadListExport, + coRvwHeadListExport, + coRvwNodeListExport, + rateFeeHeadListExport, +} from "./headList"; import type { CommonTableProps } from "../../common/type/header"; import type { DedMatUpdateType, DmdCoReqType } from "./type"; -import { fetchType, getFetch, putFectch } from "@/components/lib/api"; -import toast from "react-hot-toast/headless"; +import { fetchType, getFetch, getFetchWithCount, putFectch } from "@/components/lib/api"; +import toast from "react-hot-toast"; const coRvwHeadList = coRvwHeadListExport; const coRvwNodeList = coRvwNodeListExport; -const rateFeeHeadList =rateFeeHeadListExport; -const constCostHeadList=constCostHeadListExport +const rateFeeHeadList = rateFeeHeadListExport; +const constCostHeadList = constCostHeadListExport; export type coRvwState = { coRvw: { isInit: boolean; @@ -16,6 +21,7 @@ export type coRvwState = { coRvwNodeList: CommonTableProps[]; rateFeeHeadList: CommonTableProps[]; constCostHeadList: CommonTableProps[]; + coMatRvwCount:number; }; }; @@ -25,8 +31,9 @@ export const coRvwStateExport: coRvwState = { coMatRvwRes: [], coRvwHeadList: coRvwHeadList, coRvwNodeList: coRvwNodeList, - rateFeeHeadList:rateFeeHeadList, - constCostHeadList:constCostHeadList + rateFeeHeadList: rateFeeHeadList, + constCostHeadList: constCostHeadList, + coMatRvwCount:1 }, }; @@ -37,7 +44,7 @@ type coRvwActions = { pageNo: number, pageCnt: number, startYear: string, - endYear: string, + endYear: string ) => void; coMatRvwUpdate: ( splyCd: string, @@ -50,7 +57,7 @@ type coRvwActions = { startYear: string, endYear: string, sggCd: string, - dmdCoNm: string, + dmdCoNm: string ) => void; coMatRvwInqua: ( pageNo: number, @@ -65,10 +72,10 @@ const coMatInit = async ( pageNo: number, pageCnt: number, startYear: string, - endYear: string, + endYear: string ) => { - const url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`; - const coMatRvwRes = await getFetch(fetchType.WR, url); + const url = `/reuseFc/request/infoList/Sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`; + const coMatRvwRes = await getFetchWithCount(fetchType.WR, url); return coMatRvwRes; }; @@ -79,7 +86,7 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { pageNo: number, pageCnt: number, startYear: string, - endYear: string, + endYear: string ) => { const coMatRvwRes = await coMatInit(pageNo, pageCnt, startYear, endYear); @@ -88,7 +95,8 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { coRvw: { ...state.coRvw, init: false, - coMatRvwRes: coMatRvwRes, + coMatRvwRes: coMatRvwRes.data, + coMatRvwCount:coMatRvwRes.count }, })); }, @@ -98,25 +106,37 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { data: DedMatUpdateType ) => { try { - const isUpdate = await putFectch( + const response = await putFectch( `/reuseFc/request/cst/${splyCd}/${dmdCd}`, data ); + if (response.status === 200) { - const coMatRvwRes = coMatInit( - 1, - 10, - new Date().getFullYear().toString(), - new Date().getFullYear().toString(), - ); - return set((state: coRvwState) => ({ - ...state, - coRvw: { - ...state.coRvw, - init: false, - coMatRvwRes: coMatRvwRes, - }, - })); + if(data.flg ==='Sub'){ + + toast.success("매칭 검토로 저장되었습니다."); + }else{ + toast.success("매칭 검토완료로 저장되었습니다."); + } + + const coMatRvwRes = await coMatInit( + 1, + 10, + new Date().getFullYear().toString(), + new Date().getFullYear().toString() + ); + return set((state: coRvwState) => ({ + ...state, + coRvw: { + ...state.coRvw, + coMatRvwRes: coMatRvwRes.data, + coMatRvwCount:coMatRvwRes.count, + init: false, + }, + })); + } else { + toast.error("매칭 검토 저장에 실패했습니다."); + } } catch (e) { toast.error("매칭 검토 저장 오류입니다."); } @@ -127,9 +147,9 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { startYear: string, endYear: string, sggCd: string, - dmdCoNm: string, + dmdCoNm: string ) => { - let url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`; + let url = `/reuseFc/request/infoList/Sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`; if (sggCd.length > 0) { url += `/${sggCd}`; @@ -142,14 +162,15 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { url += `/0`; } - console.log(' url ', url) - const coMatRvwRes = await getFetch(fetchType.WR, url); + console.log(" url ", url); + const coMatRvwRes = await getFetchWithCount(fetchType.WR, url); return set((state: coRvwState) => ({ ...state, coRvw: { ...state.coRvw, - coMatRvwRes: coMatRvwRes, + coMatRvwRes: coMatRvwRes.data, + coMatRvwCount:coMatRvwRes.count, }, })); }, @@ -161,23 +182,24 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { sggCd: string ) => { try { - let url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`; + let url = `/reuseFc/request/infoList/Sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`; if (sggCd.length > 0) { url += `/${sggCd}/0`; - }else if(sggCd ==='0'){ + } else if (sggCd === "0") { url += `/0/0`; } - const coMatRvwRes = await getFetch(fetchType.WR, url); + const coMatRvwRes = await getFetchWithCount(fetchType.WR, url); return set((state: coRvwState) => ({ ...state, coRvw: { ...state.coRvw, - coMatRvwRes: coMatRvwRes, + coMatRvwRes: coMatRvwRes.data, + coMatRvwCount:coMatRvwRes.count, }, })); } catch (e) { console.log(" error ", e); } - } + }, }; }; diff --git a/apps/wr/app/store/matDmd/coMatRvw/type.tsx b/apps/wr/app/store/matDmd/coMatRvw/type.tsx index 9f146c0fb..2121c49fe 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/type.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/type.tsx @@ -1,173 +1,148 @@ import { z } from "zod"; - const DemandInfoSchema = z.object({ - dmdInfoSn: z.number(), - dmdInfoFk: z.string(), - dmndTmng: z.coerce.date(), - dmndQty: z.number(), - wntUntprc: z.number(), - grssClfg: z.number(), - combResdch: z.number(), - trbt: z.number(), - blgcOxygDmndQnt: z.number(), - smll: z.number(), - crmty: z.number().nullish(), - tn: z.number(), - tph: z.number(), - ph: z.number(), - clIonQnt: z.number(), - cdtnv: z.number(), - rmrk: z.string(), - useUsgCd: z.string(), - mtchnCmptnYmd: z.string().nullish(), - rvwCmptnYmd: z.string().nullish() - }); - - const DemandMatchingSchema = z.object({ - dmdInfoFk: z.string().nullish(), - splyFcltFk: z.string().nullish(), - splyFcltFlg: z.string().nullish(), - pbnstRuseFcltBizFk: z.number().nullish(), - splyBgngDay: z.coerce.date().nullish(), - splyEndDay: z.coerce.date().nullish(), - splyCpct: z.number().nullish(), - splyFmYn: z.string().nullish(), - useUsgCd: z.string().nullish(), - dmdInfoSn: z.number().nullish(), - splyCndtList:z.array(z.string().nullish() ).nullish() - }); - - const DemandCoSchema = z.object({ - dmdInfoPk: z.string(), - dmdCoNm: z.string(), - ctpvCd: z.string(), - sggCd: z.string(), - daddr: z.string(), - splyBgngDay: z.coerce.date(), - splyEndDay: z.coerce.date(), - splyCpct: z.number(), - splyFmYn: z.string().nullish(), - telno: z.string(), - useUsgCd: z.string().nullish(), - regDt: z.coerce.date().nullish(), - rgtr: z.string().nullish(), - mdfcnDt: z.coerce.date().nullish(), - mdfr: z.string().nullish(), - dmdAplyPswd: z.string(), - demandInfo: z.array(DemandInfoSchema.nullish()).nullish(), // 안쓰는 거임 - demandMatchings: z.array(DemandMatchingSchema.nullish()).nullish()// 안쓰는 거임 - }); - - const DemandCstSchema = z.object({ - dmdInfoSn: z.number(), - usgPrcsProcs: z.string().nullish(), - cstrnCst: z.number(), - fcltSbsdCstrnCst: z.number(), - prcsFcltCpctCstrnCst: z.number() - }); - - export const DmdCoReqSchema = z.object({ - cityText:z.string().nullish(), - sggText:z.string().nullish(), - dmdInfoSn: z.number(), - dmdInfoFk: z.string(), - dmndTmng: z.coerce.date(), - dmndQty: z.number(), - wntUntprc: z.number().nullish(), - grssClfg: z.number().nullish(), - combResdch: z.number().nullish(), - trbt: z.number().nullish(), - blgcOxygDmndQnt: z.number(), - smll: z.number().nullish(), - crmty: z.number().nullish(), - tn: z.number().nullish(), - tph: z.number().nullish(), - ph: z.number().nullish(), - clIonQnt: z.number().nullish(), - cdtnv: z.number(), - rmrk: z.string().nullish(), - useUsgCd: z.string().nullish(), - mtchnCmptnYmd: z.string().nullish(), - rvwCmptnYmd: z.string().nullish(), - demandCo: DemandCoSchema.nullish(), - demandMatching: DemandMatchingSchema.nullish(), - demandCst: DemandCstSchema, - ruseUtztnFcltNm:z.string().nullish(), - totalConstCost:z.number().nullish(), +const DemandInfoSchema = z.object({ + dmdInfoSn: z.number(), + dmdInfoFk: z.string().nullish(), + dmndTmng: z.coerce.date().nullish(), + dmndQty: z.number().nullish(), + wntUntprc: z.number().nullish(), + grssClfg: z.number().nullish(), + combResdch: z.number().nullish(), + trbt: z.number().nullish(), + blgcOxygDmndQnt: z.number(), + smll: z.number().nullish(), + crmty: z.number().nullish(), + tn: z.number().nullish(), + tph: z.number().nullish(), + ph: z.number(), + clIonQnt: z.number().nullish(), + cdtnv: z.number().nullish(), + rmrk: z.string().nullish(), + useUsgCd: z.string().nullish(), +}); - }); +const DemandMatchingSchema = z.object({ + dmdInfoFk: z.string().nullish(), + splyFcltFk: z.string().nullish(), + splyFcltFlg: z.string().nullish(), + pbnstRuseFcltBizFk: z.number().nullish(), + splyBgngDay: z.coerce.date().nullish(), + splyEndDay: z.coerce.date().nullish(), + splyCpct: z.number().nullish(), + splyFmYn: z.string().nullish(), + useUsgCd: z.string().nullish(), + dmdInfoSn: z.number().nullish(), + splyCndtList: z.array(z.string().nullish()).nullish(), + mtchnCmptnYmd: z.string().nullish(), + rvwCmptnYmd: z.string().nullish(), +}); +const DemandCoSchema = z.object({ + dmdInfoPk: z.string().nullish(), + dmdCoNm: z.string().nullish(), + ctpvCd: z.string().nullish(), + sggCd: z.string().nullish(), + daddr: z.string().nullish(), + splyBgngDay: z.coerce.date().nullish(), + splyEndDay: z.coerce.date().nullish(), + splyCpct: z.number().nullish(), + splyFmYn: z.string().nullish(), + telno: z.string().nullish(), + useUsgCd: z.string().nullish(), + regDt: z.coerce.date().nullish(), + rgtr: z.string().nullish(), + mdfcnDt: z.coerce.date().nullish(), + mdfr: z.string().nullish(), + dmdAplyPswd: z.string().nullish(), + demandInfo: z.array(DemandInfoSchema.nullish()).nullish(), // 안쓰는 거임 + demandMatchings: z.array(DemandMatchingSchema.nullish()).nullish(), // 안쓰는 거임 +}); + +const DemandCstSchema = z.object({ + dmdInfoSn: z.number().nullish(), + usgPrcsProcs: z.string().nullish(), + cstrnCst: z.number().default(0), + fcltSbsdCstrnCst: z.number().default(0), + prcsFcltCpctCstrnCst: z.number().default(0), +}); + +export const DmdCoReqSchema = z.object({ + cityText: z.string().nullish(), + sggText: z.string().nullish(), + dmdInfoSn: z.number().default(0), + dmdInfoFk: z.string().default(''), + dmndTmng: z.coerce.date().nullish(), + dmndQty: z.number().nullish(), // null 또는 undefined 허용 + blgcOxygDmndQnt: z.number().nullish(), + wntUntprc: z.number().nullish(), + grssClfg: z.number().nullish(), + combResdch: z.number().nullish(), + trbt: z.number().nullish(), + smll: z.number().nullish(), + crmty: z.number().nullish(), + tn: z.number().nullish(), + tph: z.number().nullish(), + ph: z.number().nullish(), + clIonQnt: z.number().nullish(), + cdtnv: z.number().nullish(), + rmrk: z.string().nullish(), + useUsgCd: z.string().nullish(), + mtchnCmptnYmd: z.string().nullish(), + rvwCmptnYmd: z.string().nullish(), + demandCo: DemandCoSchema.nullish(), + demandMatching: DemandMatchingSchema.nullish(), + demandCst: DemandCstSchema.nullish(), + ruseUtztnFcltNm: z.string().nullish(), + totalConstCost: z.number().nullish(), +}); export type DmdCoReqType = z.infer<typeof DmdCoReqSchema>; export type DmdMatTableType = { - cityText:string, - sggText:string, - dmdCoNm:string, - daddr:string, - telno:string, - regDt:string, - splyFcltFlg:string -} + cityText: string; + sggText: string; + dmdCoNm: string; + daddr: string; + telno: string; + regDt: string; + splyFcltFlg: string; +}; - -export type DedMatUpdateType = -{ +export type DedMatUpdateType = { dmdInfoSn: number; usgPrcsProcs: string; cstrnCst: number; fcltSbsdCstrnCst: number; prcsFcltCpctCstrnCst: number; rgtr: string; -} - + flg?:string; +}; export type RvwHistTableType = { - cityText:string, - sggText:string, - dmdCoNm:string, - daddr:string, - telno:string, - regDt:string, - rvwCmptnYmd:string, - mtchnCmptnYmd:string, - ruseUtztnFcltNm:string, - dmndQty:string, - useUsgCd:string, - splyFcltFlg:string - completeYn:boolean - dmdInfoSn :string + cityText: string; + sggText: string; + dmdCoNm: string; + daddr: string; + telno: string; + regDt: string; + rvwCmptnYmd: string; + mtchnCmptnYmd: string; + ruseUtztnFcltNm: string; + dmndQty: string; + useUsgCd: string; + splyFcltFlg: string; + completeYn: boolean; + dmdInfoSn: string; +}; -} - -export type RvwHistTableType = { - cityText:string, - sggText:string, - dmdCoNm:string, - daddr:string, - telno:string, - regDt:string, - rvwCmptnYmd:string, - mtchnCmptnYmd:string, - ruseUtztnFcltNm:string, - dmndQty:string, - useUsgCd:string, - splyFcltFlg:string - completeYn:boolean - dmdInfoSn :string - -} - - - -export type conCostFeeType= { - yr: string, - fctCpc: string, - fctCd: string, - stdCost: string -} +export type conCostFeeType = { + yr: string; + fctCpc: string; + fctCd: string; + stdCost: string; +}; export type rateFeeType = { - yr: string, - incExpCd: string, - stdCost: number, - rt: number -} \ No newline at end of file + yr: string; + incExpCd: string; + stdCost: number; + rt: number; +}; diff --git a/apps/wr/app/store/matDmd/coSttn/headList.tsx b/apps/wr/app/store/matDmd/coSttn/headList.tsx index 80fed0d76..62c3002ac 100644 --- a/apps/wr/app/store/matDmd/coSttn/headList.tsx +++ b/apps/wr/app/store/matDmd/coSttn/headList.tsx @@ -44,6 +44,11 @@ export const coSttHeadListExport: z.infer<typeof sttnHeadListType> = [ title: "전화번호", visible: true, }, + { + id: "regDt", + title: "등록일자", + visible: true, + }, ]; export const coSttNodeListExport: CommonTableProps[] = [ diff --git a/apps/wr/app/store/matDmd/coSttn/index.tsx b/apps/wr/app/store/matDmd/coSttn/index.tsx index 0de37bbfc..5e8baf859 100644 --- a/apps/wr/app/store/matDmd/coSttn/index.tsx +++ b/apps/wr/app/store/matDmd/coSttn/index.tsx @@ -2,7 +2,7 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api"; import { coSttHeadListExport, coSttNodeListExport } from "./headList"; import { excelCoSttnParsing } from "./excel"; -import type { DemandCompType } from "@common/business_components/ui"; +import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; // 테이블 헤드 리스트 const coSttNodeList = coSttNodeListExport; diff --git a/apps/wr/app/store/matDmd/drgtSttn/headList.tsx b/apps/wr/app/store/matDmd/drgtSttn/headList.tsx index 1741b7456..dcdc655b5 100644 --- a/apps/wr/app/store/matDmd/drgtSttn/headList.tsx +++ b/apps/wr/app/store/matDmd/drgtSttn/headList.tsx @@ -2,8 +2,8 @@ import { z } from "zod"; import type { CommonTableProps } from "../../common/type/header"; export const drgtZod = z.object({ - ctpvCd: z.string().default(''), - sggNm: z.string().default(''), + ctpvCd: z.string().default('').nullish(), + sggNm: z.string().default('').nullish(), normal: z.string().default(''), attention: z.string().default(''), caution: z.string().default(''), diff --git a/apps/wr/app/store/matDmd/drgtSttn/index.tsx b/apps/wr/app/store/matDmd/drgtSttn/index.tsx index 698ba5984..4211d2d08 100644 --- a/apps/wr/app/store/matDmd/drgtSttn/index.tsx +++ b/apps/wr/app/store/matDmd/drgtSttn/index.tsx @@ -1,4 +1,4 @@ -import { fetchType, getFetch } from "@/components/lib/api"; +import { fetchType, getFetch, postFectch } from "@/components/lib/api"; import type { CommonTableProps } from "../../common/type/header"; import { drgtHeadListExport, drgtZod } from "./headList"; import type { z } from "zod"; @@ -14,11 +14,13 @@ export type drgtState = { drgtHeadList: CommonTableProps[]; drgtRes: customDrgt[]; drgtMoRes: customDrgt[]; + isInit: boolean; } } type drgtActions = { - drgtSearch: (fromDate: string, toDate: string, sido: string, sgg: string) => void + drgtInit: () => void + drgtSearch: (fromDate: string, toDate: string, sido: string[]) => void drgtModalSearch: (fromDate: string, toDate: string, sgg: string) => void }; @@ -29,72 +31,97 @@ export const drgtStateExport: drgtState = { drgtHeadList: drgtHeadList, drgtRes: drgtRes, drgtMoRes: drgtRes, + isInit: false, } } +const initFetch = async (fromDate: string, toDate: string, sido:string[]) => { +console.log("sido",sido) + const drgtData = await postFectch( + `/il/getDataCount/${fromDate}/${toDate}`, + sido, + fetchType.WR + ); + + //주의, 관심, 정상 추출 + const statusData = Array.from( + new Set(drgtData.data.map((e) => e.lvngMfgUswtrDrgtInfo)) + ); + + const statusMap = drgtData.data.reduce((acc: any, { sggNm, lvngMfgUswtrDrgtInfo: status, countDrgt }: { sggNm: string; lvngMfgUswtrDrgtInfo: string; countDrgt: number }) => { + if (!acc[sggNm]) { + acc[sggNm] = { sggNm, ...Object.fromEntries(statusData.map((e) => [e, 0])) }; + } + acc[sggNm][status] = Number(countDrgt); + return acc; + }, {}); + const data = Object.values(statusMap); + + const formatStatus = data.map((item) => { + const attention = item['관심'] || 0; + const caution = item['주의'] || 0; + return { + sggNm: item.sggNm, + normal: String(item['정상'] || 0), + caution: String(caution), + attention: String(attention), + warning: String(attention + caution), + }; + }); + + const ranking = Array.from( + new Set(formatStatus.map(e => Number(e.warning))) + ).sort((a, b) => b - a); + + const rankData = ranking.reduce((acc, val, idx) => { + acc[val] = idx + 1; + return acc; + }, {}); + + const drgtRes = formatStatus.map(item => ({ + ...item, + warning: String(item.warning), + ranking: rankData[Number(item.warning)], + })); + + return drgtRes; + +} + + export const drgtActionsExport: (set: any) => drgtActions = ( set: any ) => { return { - drgtSearch: async (fromDate: string, toDate: string, sido: string, sgg: string) => { + drgtInit: async () => { try { - let searchUrl = ""; + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, '0'); + const formatted = `${year}${month}`; + const fromDate = formatted; + const toDate = formatted; - if (sido === "" || sido === "전체") { - searchUrl = `/il/getDataCount/${fromDate}/${toDate}`; - } else { - searchUrl = `/il/getDataCount/${fromDate}/${toDate}/${sido}/${sgg}`; - } - - console.log("searchUrl", searchUrl); - - const drgtData = await getFetch( - fetchType.WR, - searchUrl - ); - - console.log("drgtRes", drgtData) - - //주의, 관심, 정상 추출 - const statusData = Array.from( - new Set(drgtData.map((e) => e.lvngMfgUswtrDrgtInfo)) - ); - - const statusMap = drgtData.reduce((acc: any, { sggNm, lvngMfgUswtrDrgtInfo: status, countDrgt }: { sggNm: string; lvngMfgUswtrDrgtInfo: string; countDrgt: number }) => { - if (!acc[sggNm]) { - acc[sggNm] = { sggNm, ...Object.fromEntries(statusData.map((e) => [e, 0])) }; - } - acc[sggNm][status] = Number(countDrgt); - return acc; - }, {}); - const data = Object.values(statusMap); - - const formatStatus = data.map((item) => { - const attention = item['관심'] || 0; - const caution = item['주의'] || 0; + //FIXME: 페이지 처음 로딩될때 데이터 보려고 6월로 박아놓음 이거 fromDate로 고치기 + const drgtRes = await initFetch("202506", toDate, []); + set((state: drgtState) => { return { - sggNm: item.sggNm, - normal: String(item['정상'] || 0), - caution: String(caution), - attention: String(attention), - warning: String(attention + caution), - }; + ...state, + drgt: { + ...state.drgt, + drgtRes: drgtRes, + isInit: false, + }, + } }); + } catch (e) { + console.log(e) + } + }, + drgtSearch: async (fromDate: string, toDate: string, sido: string[]) => { + try { + const drgtRes = await initFetch(fromDate, toDate, sido); - const ranking = Array.from( - new Set(formatStatus.map(e => Number(e.warning))) - ).sort((a, b) => b - a); - - const rankData = ranking.reduce((acc, val, idx) => { - acc[val] = idx + 1; - return acc; - }, {}); - - const drgtRes = formatStatus.map(item => ({ - ...item, - warning: String(item.warning), - ranking: rankData[Number(item.warning)], - })); set((state: drgtState) => { return { ...state, @@ -115,10 +142,7 @@ export const drgtActionsExport: (set: any) => drgtActions = ( `/il/getData/${fromDate}/${toDate}/${sgg}/${sgg}` ); - console.log("drgtMoData", drgtMoData) - const drgtMoRes = drgtMoData.map((item) => { - console.log("item", item) const year = item.anlsYmd.slice(0, 4); const month = item.anlsYmd.slice(4, 6); const drgtState = item.lvngMfgUswtrDrgtInfo; diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx index dc0601127..ad7990cfc 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx @@ -46,29 +46,17 @@ export const names: nameMap = { } -export const excelPbnstSttnParsing = (data: any[]): string[][] => { +export const excelLdrmntParsing = (data: any[]): string[][] => { const excelExportData: string[][] = []; - data.forEach((item) => { excelExportData.push([ - item.rvbsn, - String(item.lgbsn), - item.mdmbsn ?? "", - item.rgnNm ?? "", - String(item.sido ?? ""), - String(item.gugun ?? ""), - String(item.bscFctNm ?? ""), - String(item.efflWqltStndrdNm ?? ""), - String(item.fctCpc ?? ""), - String(item.tel ?? ""), - String(item.ruseUtztnFcltNm ?? ""), - String(item.fcltCpct ?? ""), - String(item.splyExtraCpct ?? ""), - String(item.ruseCpct ?? ""), - String(item.usageTotal ?? ""), - String(item.inUsage ?? ""), - String(item.outUsage ?? ""), + item.fctryAddr?.split(" ")[0] || "", + item.fctryAddr?.split(" ")[1] || "", + item.dmdCoNm, + item.fctryAddr, + item.fctryMngNo, + item.telno, ]) }) return excelExportData; diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx index d1176528a..6a5f18247 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx @@ -2,10 +2,8 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; import { deleteFectch, fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api"; import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { z } from "zod"; -import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList"; import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg"; - - +import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList"; // 테이블 헤드 리스트 const ldrmntHeadList = ldrmntHeadListExport; @@ -34,7 +32,7 @@ const excelDownList: ExcelType[] = []; type ldrmntActions = { ldrmntRegData: (data: any[]) => void, ldrmntInit: (con: string) => void - ldrmntSearch: (page: number, sggCd: string, coNm: string) => void; + ldrmntSearch: (page: number, sggCd: string, total: string, coNm: string) => void; ldrmntUpdate: (ldrmntRes: customLdrmnt) => void; ldrmntDelete: () => void; }; @@ -61,6 +59,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( fetchType.WR, `/reuseFc/request/temp/1/20/${con}` ); + set((state: ldrmntState) => { return { ...state, @@ -68,6 +67,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( ...state.ldrmnt, ldrmntRes: ldrmntRes, isInit: false, + excelList: excelDownList, }, } }); @@ -101,44 +101,57 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( } }, - ldrmntSearch: async (page: number, sggCd: string, coNm: string) => { + ldrmntSearch: async (page: number, total: string, sggCd: string, coNm: string) => { let searchUrl = ""; if (sggCd !== "") { if (coNm !== "") { - searchUrl = `/reuseFc/request/temp/${page}/20/${sggCd}/${coNm}`; + searchUrl = `/reuseFc/request/temp/${page}/${total}/${sggCd}/${coNm}`; } else { - searchUrl = `/reuseFc/request/temp/${page}/20/${sggCd}`; + searchUrl = `/reuseFc/request/temp/${page}/${total}/${sggCd}`; } } - try { const ldrmntRes = await getFetch( fetchType.WR, searchUrl ); - ldrmntRes.forEach((item: customLdrmnt) => { - excelDownList.push({ - ctpvCd: item.ctpvCd, - sggCd: item.sggCd, - dmdCoNm: item.dmdCoNm, - fctryAddr: item.fctryAddr, - fctryMngNo: item.fctryMngNo, - telno: item.telno, + if (Number(total) > 5000) { + let excelDownList: ExcelType[] = []; + ldrmntRes.forEach((item: customLdrmnt) => { + excelDownList.push({ + ctpvCd: item.ctpvCd, + sggCd: item.sggCd, + dmdCoNm: item.dmdCoNm, + fctryAddr: item.fctryAddr, + fctryMngNo: item.fctryMngNo, + telno: item.telno, + }) }) - }) + set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + excelList: excelDownList, - set((state: ldrmntState) => { - return { - ...state, - ldrmnt: { - ...state.ldrmnt, - ldrmntRes: ldrmntRes, - excelList: excelDownList, - }, - } - }) + }, + }; + }); + return excelDownList; + } else + set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + ldrmntRes: ldrmntRes, + isInit: false, + }, + }; + }); + return ldrmntRes; } catch (e) { console.log(e) } diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx index 915740f79..5a2ad235e 100644 --- a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx +++ b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx @@ -1,12 +1,13 @@ -import { fetchType, getFetch, postFectch } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount, postFectch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; import { ruseCaseHeadListExport } from "./headList"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; - +import { toast } from "react-hot-toast"; export type ruseCaseState = { ruseCaseMng: { ruseHeadList:TableUpperProps[]; ruseCaseMngList:ruseCaseMngExcelProps[]; + status: number; + count: number; }; }; @@ -64,20 +65,19 @@ export interface ruseCaseMngExcelProps { } type ruseCaseActions = { - selectRuseCaseMng: (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => Promise<void>; + selectRuseCaseMng: (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => Promise<void>; insertRuseCaseMng: (data: any) => Promise<void>; }; -export const fetchSearchRuseCaseMng = async (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => { - - const tailUrl = ((sigunguCd !== '전체' && sigunguCd !=='') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd? `/${usageCd}` : '/0') + (name? `/${name}` : ''); - const resp = await getFetch(fetchType.WR,`/reuseFc/pubFcRuseCase${tailUrl}`); - return resp; +export const fetchSearchRuseCaseMng = async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => { + const tailUrl = '/'+pageNo+'/'+pageSize+ ((sigunguCd !== '전체' && sigunguCd !=='') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd? `/${usageCd}` : '/0') + (name? `/${name}` : ''); + const resp = await getFetchWithCount(fetchType.WR,`/reuseFc/pubFcRuseCase${tailUrl}`); + return {data:resp.data, count:resp.count}; }; export const fetchInsertRuseCaseMng = async (data: any) => { const response = await postFectch('/reuseFc/pubFcRuseCase', data, fetchType.WR); - return response.data; + return {data:response.data, status:response.status}; }; export type ruseCaseType = ruseCaseState & ruseCaseActions; @@ -86,6 +86,8 @@ export const ruseCaseStateExport: ruseCaseState = { ruseCaseMng: { ruseHeadList:ruseCaseHeadListExport, ruseCaseMngList:[], + status: 0, + count: 0, }, }; @@ -93,13 +95,13 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = ( set: any ) => { return { - selectRuseCaseMng: async (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => { - const res = await fetchSearchRuseCaseMng(sidoCd, sigunguCd, usageCd, name); - console.log('res : ', res); + selectRuseCaseMng: async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => { + const res = await fetchSearchRuseCaseMng(pageNo, pageSize, sidoCd, sigunguCd, usageCd, name); set((state: ruseCaseState) => ({ ruseCaseMng: { ...state.ruseCaseMng, - ruseCaseMngList: res, + ruseCaseMngList: res.data, + count: res.count, }, })); }, @@ -107,11 +109,16 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = ( insertRuseCaseMng: async (data: any) => { const response = await fetchInsertRuseCaseMng(data); if(response.status === 200){ - ToastFormUi({ - body: "잠재수요처 등록이 완료되었습니다. ", - title: "잠재수요처 등록", - }); + toast.success("물재이용사례 등록이 완료되었습니다. "); + }else{ + toast.error("물재이용사례 등록에 실패하였습니다. "); } + set((state: ruseCaseState) => ({ + ruseCaseMng: { + ...state.ruseCaseMng, + status: response.status, + }, + })); }, }; -}; +}; \ No newline at end of file diff --git a/apps/wr/app/store/matDmd/ruseRvwHstry/headList.tsx b/apps/wr/app/store/matDmd/ruseRvwHstry/headList.tsx index 90c793c2f..a90f5831b 100644 --- a/apps/wr/app/store/matDmd/ruseRvwHstry/headList.tsx +++ b/apps/wr/app/store/matDmd/ruseRvwHstry/headList.tsx @@ -28,7 +28,7 @@ export const ruseHstryHeadListExport:TableUpperProps[]= [ visible: true, }, { - id: "regDt", //바꾸기 + id: "dmndTmng", //바꾸기 title: "신청일자", visible: true, }, diff --git a/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx b/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx index 3338bc467..cfd991b4d 100644 --- a/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx +++ b/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx @@ -5,7 +5,7 @@ import type { TableUpperProps, } from "../../common/type/header"; import { ruseHstryHeadListExport } from "./headList"; -import { fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; import type { DmdCoReqType } from "../coMatRvw/type"; import toast from "react-hot-toast"; import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg"; @@ -16,6 +16,7 @@ export type ruseHstryState = { ruseHist: { isInit: boolean; rvwHistRes: DmdCoReqType[]; + rvwHistCount:number; ruseHistHeadList: TableUpperProps[]; }; }; @@ -25,6 +26,7 @@ export const ruseHstryStateExport: ruseHstryState = { isInit: false, rvwHistRes: [], ruseHistHeadList: ruseHistHeadList, + rvwHistCount:1, }, }; @@ -79,14 +81,14 @@ const irvwHistInit = async ( startYear: string, endYear: string, ) => { - let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; + let url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; // console.log("sggCd ", sggCd); // if (sggCd) { // url += `/${sggCd}`; // } - const rvwHistRes = await getFetch(fetchType.WR, url); + const rvwHistRes = await getFetchWithCount(fetchType.WR, url); return rvwHistRes; }; @@ -115,7 +117,8 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( ruseHist: { ...state.ruseHist, init: false, - rvwHistRes: rvwHistRes, + rvwHistRes: rvwHistRes.data, + rvwHistCount:rvwHistRes.count }, })); }, @@ -140,8 +143,8 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( ruseHist: { ...state.ruseHist, init: false, - rvwHistRes: rvwHistRes, - }, + rvwHistRes: rvwHistRes.data, + rvwHistCount:rvwHistRes.count }, })); } } catch (e) { @@ -158,7 +161,7 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( dmdCoNm: string, ruseUtztnFcltNm: string ) => { - let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; + let url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; if (sggCd.length > 0) { url += `/${sggCd}`; @@ -175,14 +178,14 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( } else { url += `/0`; } - const rvwHistRes = await getFetch(fetchType.WR, url); + const rvwHistRes = await getFetchWithCount(fetchType.WR, url); return set((state: ruseHstryState) => ({ ...state, ruseHist: { ...state.ruseHist, - rvwHistRes: rvwHistRes, - }, + rvwHistRes: rvwHistRes.data, + rvwHistCount:rvwHistRes.count }, })); }, ruseRvwInqua: async ( @@ -193,16 +196,17 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( sggCd: string ) => { try { - let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; + let url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; if (sggCd.length > 0) { url += `/${sggCd}/0`; } - const rvwHistRes = await getFetch(fetchType.WR, url); + const rvwHistRes = await getFetchWithCount(fetchType.WR, url); return set((state: ruseHstryState) => ({ ...state, ruseHist: { ...state.ruseHist, - rvwHistRes: rvwHistRes, + rvwHistRes: rvwHistRes.data, + rvwHistCount:rvwHistRes.count }, })); } catch (e) { @@ -224,6 +228,15 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( new Date().getFullYear().toString(), new Date().getFullYear().toString(), ); + + return set((state: ruseHstryState) => ({ + ...state, + ruseHist: { + ...state.ruseHist, + rvwHistRes: rvwHistRes.data, + rvwHistCount:rvwHistRes.count + }, + })); } } catch (e) { console.log(" error ", e); diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx index 5754c02fc..58e8d6bf0 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -94,15 +94,15 @@ export const excelToRainChkData = (excelData: any, year: string) => { } const makeGuidDetail = Array.from({ length: 12 }, (_, i) => { let month = `${i + 1}`; - const splyData = item[`보급_${month}월`]; + const splyData = item[`대체_${month}월`]; const ruseData = item[`빗물_${month}월`]; if (month.length < 2) month = "0" + month; return { utztnUsgCd: item["이용용도"], ym: year + month, chckYmd: checkYmd, - splyUswtrUtztnQnt: Number(splyData ?? 0), - ruseFcltUtztnQnt: Number(ruseData ?? 0), + splyUswtrUtztnQnt: Number(splyData) || 0, + ruseFcltUtztnQnt: Number(ruseData) || 0, flg: "RNB", }; }); @@ -120,13 +120,13 @@ export const excelToRainChkData = (excelData: any, year: string) => { rainyDetails: [ { utztnUsgCd: item["이용용도"] ?? "", - ph: Number(item["PH"] ?? 0), - trbt: Number(item["탁도"] ?? 0), - grssClfg: Number(item["총대장균군수"] ?? 0), - etc: item["기타"] ?? "", // 필드 누락 방지 - vltnDt: vltnDt ?? "", - vltnMttr: item["위반사항"] ?? "", - levyAmt: Number(item["과태료부과금액(천원)"] ?? 0), + ph: Number(item["PH"] || 0), + trbt: Number(item["탁도"] || 0), + grssClfg: Number(item["총대장균군수"] || 0), + etc: item["기타"] || "", // 필드 누락 방지 + vltnDt: vltnDt || "-", + vltnMttr: item["위반사항"] || "-", + levyAmt: Number(item["과태료부과금액(천원)"] || 0), rgtr: TEST_UUID, }, ], diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx index d8057cad6..3cf1b5b11 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx @@ -114,10 +114,22 @@ export type splRuseWaterType = { ruse12: number; }; -export const rainHeadNmExport: chHeadType[] = [ +export const rainMainHeadNmExport: chHeadType[] = [ + { headNm: "useQuilty", text: "이용수질(필요시)", length: 3 }, + { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, +]; + +export const rainRuseHeadNmExport: chHeadType[] = [ + { headNm: "useQuilty", text: "이용수질(필요시)", length: 3 }, + { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, + { headNm: "ruseWater", text: "연간대체수 이용량(m³)", length: 13 }, + { headNm: "detailQulity", text: "분기", length: 11 }, +]; + + +export const rainSplHeadNmExport: chHeadType[] = [ { headNm: "useQuilty", text: "이용수질(필요시)", length: 3 }, { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, - { headNm: "ruseWater", text: "연간보급수 이용량(m³)", length: 13 }, { headNm: "detailQulity", text: "분기", length: 11 }, { headNm: "splWater", text: "연간빗물 이용량(m³)", length: 13 }, ]; @@ -134,7 +146,7 @@ export const rainChkgdnHeadListExport: TableUpperProps[] = [ { id: "dtfcltCpct", title: "빗물저류조용량(m³)", mergeCell: true }, { id: "chckYmd", title: "점검일", mergeCell: true }, { id: "utztnUsgCd", title: "이용용도" }, - { id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, + { id: "totalSplyUswtrUtztnQnt", title: "연간대체수이용량(m³)" }, { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" }, { id: "ph", diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index 3bd10169f..069f1f760 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -1,27 +1,31 @@ import { buildingType } from "@/app/store/common/code"; -import { - TEST_UUID, -} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import type { TableUpperProps } from "@/app/store/common/type/header"; +import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { deleteFectch, fetchType, getFetch, + getFetchWithCount, postFectch, putFectch, } from "@/components/lib/api"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import type { SelectDataType } from "@common/business_components/ui"; +import toast from "react-hot-toast"; import { z } from "zod"; import { buildingToExcelType } from "./excel"; import { rainChkgdnHeadListExport, rainChkZod, - rainHeadNmExport, + rainMainHeadNmExport, + rainRuseHeadNmExport, + rainSplHeadNmExport, ruseHeadListExport, splHeadListExport, type chHeadType, } from "./headList"; -import type { TableUpperProps } from "@/app/store/common/type/header"; + +export const rainPageSize = 5; +export const commonCd = "41"; export type rainChkZodType = z.infer<typeof rainChkZod>; const fcltDiv = [ @@ -29,30 +33,41 @@ const fcltDiv = [ { val: "RNB", text: "빗물이용시설" }, ]; -const rainHeadNm = rainHeadNmExport; +const rainRuseHeadNm = rainRuseHeadNmExport; +const rainSplHeadNm = rainSplHeadNmExport; const rainChkgdnHeadList = rainChkgdnHeadListExport; const ruseHeadList = ruseHeadListExport; const splHeadList = splHeadListExport; +const rainMainHeadNm = rainMainHeadNmExport const rainChk: rainChkZodType[] = []; export type rainChkgdnState = { rainChkgdn: { rainChkgdnHeadList: TableUpperProps[]; + rainSplHeadNm: chHeadType[] + rainRuseHeadNm: chHeadType[] rainChk: rainChkZodType[]; - rainHeadNm: chHeadType[]; ruseHeadList: TableUpperProps[]; splHeadList: TableUpperProps[]; isInit: boolean; isModalClose: boolean; fcltDiv: SelectDataType[]; + rainMainHeadNm: chHeadType[] excelList: []; isSttn: boolean; + rainChkCount: number; + isLoading: boolean; }; }; type rainChkgdnActions = { - rainChkInit: (sggCd: string, searchTxt: string) => void; + rainChkInit: ( + pageNo: number, + cnt: number, + sggCd: string, + searchTxt: string + ) => void; rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise<void>; rainChkGuidUpdate(rainChk: rainChkZodType): Promise<void>; rainChkExcelDownload( @@ -62,6 +77,13 @@ type rainChkgdnActions = { rainChkExcelDataUPload(excelData: rainChkZodType[]): Promise<void>; rainChkDelete(chkgdnPks: number[]): Promise<void>; rainChkHeadChange: (rainChkgdn: rainChkgdnState, isEdit: boolean) => void; + rainChkNmSearch: ( + pageNo: number, + cnt: number, + year: string, + sggCd: string, + txt: string + ) => void; }; export type rainChkgdnType = rainChkgdnState & rainChkgdnActions; @@ -69,7 +91,9 @@ export type rainChkgdnType = rainChkgdnState & rainChkgdnActions; export const rainChkgdnStateExport: rainChkgdnState = { rainChkgdn: { rainChkgdnHeadList: rainChkgdnHeadList, - rainHeadNm: rainHeadNm, + rainRuseHeadNm: rainRuseHeadNm, + rainSplHeadNm: rainSplHeadNm, + rainMainHeadNm: rainMainHeadNm, rainChk: rainChk, splHeadList: splHeadList, ruseHeadList: ruseHeadList, @@ -78,6 +102,8 @@ export const rainChkgdnStateExport: rainChkgdnState = { excelList: [], fcltDiv: fcltDiv, isSttn: false, + rainChkCount: 1, + isLoading: false, }, }; @@ -98,12 +124,23 @@ const makeMdfrChk = (data: rainChkZodType[], type: string, toDo: string) => { return chData; }; -const initFetch = async (txt: string | undefined, sgg: string | undefined) => { +const initFetch = async ( + pageNo: number, + cnt: number, + year: string | undefined, + sgg: string | undefined +) => { const currentYear = new Date().getFullYear().toString(); - const rainRes = await getFetch( + + const rainRes = await getFetchWithCount( "wr", - `/reuseChk/rainy` + (txt ? `/${txt}` : currentYear) + (sgg ? `/${sgg}` : "/0") + `/reuseChk/rainy` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/10") + + (year ? `/${year}` : `/${currentYear}`) + + (sgg ? `/${sgg}` : "/0") ); + return rainRes; }; @@ -129,42 +166,89 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( })); }, rainChkExcelDataUPload: async (excelData: rainChkZodType[]) => { + set((state: rainChkgdnType) => ( + { rainChkgdn: { ...state.rainChkgdn, isLoading: true } })); try { const res = await postFectch("/reuseChk/rainy", excelData); - console.log("res", res); - console.log("res.ok", res.ok) - if (res.ok) { - ToastFormUi({ - body: "지도점검 등록이 완료되었습니다. ", - title: "지도점검 등록", - }); + if (res.status === 200) { + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch( + 1, + rainPageSize, + currentYear, + commonCd + ); + set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes.data, + rainChkCount: rainChkRes.count, + }, + })); + toast.success("지도점검 등록이 완료되었습니다."); + } else { + toast.error("지도점검 등록이 실패되었습니다."); } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch(currentYear, "0"); - return set((state: rainChkgdnState) => ({ + } catch (error) { + console.log(error); + toast.error("지도점검 등록이 실패되었습니다."); + } finally { + set((state: rainChkgdnType) => ({ rainChkgdn: { ...state.rainChkgdn, isLoading: false } })); + } + }, + rainChkInit: async ( + pageNo: number, + cnt: number, + year: string, + sggCd: string + ) => { + // set((state: rainChkgdnType) => ({ rainChkgdn: { ...state.rainChkgdn, isLoading: true } })); + try { + const rainChkRes = await initFetch(pageNo, cnt, year, sggCd); + set((state: rainChkgdnState) => ({ ...state, rainChkgdn: { ...state.rainChkgdn, - rainChk: rainChkRes, + rainChk: rainChkRes.data, + rainChkCount: rainChkRes.count, + isInit: false, // 무한 루프 방지를 위해 isInit을 true로 설정 }, })); } catch (error) { console.log(error); - ToastFormUi({ - body: "지도점검 등록이 실패되었습니다.", - title: "지도점검 등록", - }); + // 에러가 발생하더라도 무한 루프에 빠지지 않도록 isInit을 true로 설정합니다. + // set((state: rainChkgdnType) => ({ + // rainChkgdn: { ...state.rainChkgdn, isInit: true }, + // })); + } finally { + // set((state: rainChkgdnType) => ({ rainChkgdn: { ...state.rainChkgdn, isLoading: false } })); } }, - rainChkInit: async (searchTxt: string, sggCd: string) => { + rainChkNmSearch: async ( + pageNo: number, + cnt: number, + year: string, + sggCd: string, + txt: string + ) => { try { - const rainChkRes = await initFetch(searchTxt, sggCd); - + const currentYear = new Date().getFullYear(); + const rainChkRes = await getFetchWithCount( + "wr", + `/reuseChk/rainy` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/10") + + (year ? `/${year}` : `/${currentYear}`) + + (sggCd ? `/${sggCd}` : "/0") + + (txt ? `/${txt}` : "") + ); return set((state: rainChkgdnState) => ({ ...state, rainChkgdn: { ...state.rainChkgdn, - rainChk: rainChkRes, + rainChk: rainChkRes.data, + rainChkCount: rainChkRes.count, }, })); } catch (error) { @@ -175,48 +259,62 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( try { const chData = await makeMdfrChk(rainChk, "rain", "rainDetil"); - const res = await postFectch("/reuseChk/rainy", chData); - if (res.ok) { - ToastFormUi({ - body: "지도점검 보급수 및 밋물이용량 수정이 완료되었습니다. ", - title: "지도점검 수정", - }); + const res = await putFectch("/reuseChk/rainy/list", chData); + if (res) { + toast.success( + "지도점검 대체수 및 밋물이용량 수정이 완료되었습니다. " + ); + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch( + 1, + rainPageSize, + currentYear, + "41" + ); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes.data, + rainChkCount: rainChkRes.count, + }, + })); + } else { + toast.error("지도점검 대체수 및 밋물이용량 수정 오류입니다."); } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch(currentYear, "0"); - return set((state: rainChkgdnState) => ({ - ...state, - rainChkgdn: { - ...state.rainChkgdn, - rainChk: rainChkRes, - }, - })); } catch (error) { console.log(error); - alert("수정에 실패하였습니다."); + toast.error("지도점검 대체수 및 밋물이용량 수정 오류입니다."); } }, rainChkGuidUpdate: async (rainChk: rainChkZodType) => { try { //const chData = await makeMdfrChk(rainChk, "guideDetails", "rainDetil"); const res = await putFectch("/reuseChk/rainy", rainChk); - if (res.ok) { - ToastFormUi({ - body: "지도점검 수질 및 과태료 수정이 완료되었습니다. ", - title: "지도점검 수정", - }); + if (res.status === 200) { + toast.success("지도점검 수질 및 과태료 수정이 완료되었습니다. "); + + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch( + 1, + rainPageSize, + currentYear, + "41" + ); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes.data, + rainChkCount: rainChkRes.count, + }, + })); + } else { + toast.error("지도점검 수질 및 과태료 수정 오류입니다."); + } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch(currentYear, "0"); - return set((state: rainChkgdnState) => ({ - ...state, - rainChkgdn: { - ...state.rainChkgdn, - rainChk: rainChkRes, - }, - })); } catch (error) { - console.log(error); + toast.error("지도점검 수질 및 과태료 수정 오류입니다."); } }, rainChkDelete: async (chkgdnPks: number[]) => { @@ -224,22 +322,29 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( const res = await deleteFectch(`/reuseChk/rainy`, chkgdnPks); if (res) { - ToastFormUi({ - body: "삭제가 완료되었습니다. ", - title: "지도점검 삭제", - }); + toast.success("삭제가 완료되었습니다. "); + + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch( + 1, + rainPageSize, + currentYear, + "41" + ); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes.data, + rainChkCount: rainChkRes.count, + }, + })); + } else { + toast.error("삭제시 오류가 발생하였습니다.. "); + } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch(currentYear, "0"); - return set((state: rainChkgdnState) => ({ - ...state, - rainChkgdn: { - ...state.rainChkgdn, - rainChk: rainChkRes, - }, - })); } catch (error) { - ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" }); + toast.error("삭제시 오류가 발생하였습니다.. "); } }, rainChkHeadChange: async (rainChkgdn: rainChkgdnState, isEdit: boolean) => { @@ -249,16 +354,13 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( const ruseHeadList = rainChkgdn.rainChkgdn.ruseHeadList; rainChkgdnHeadList.forEach((head) => { - if (head.edit !== undefined) - head.edit = isEdit; + if (head.edit !== undefined) head.edit = isEdit; }); splHeadList.forEach((head) => { - if (head.edit !== undefined) - head.edit = isEdit; + if (head.edit !== undefined) head.edit = isEdit; }); ruseHeadList.forEach((head) => { - if (head.edit !== undefined) - head.edit = isEdit; + if (head.edit !== undefined) head.edit = isEdit; }); return set((state: rainChkgdnState) => ({ @@ -267,7 +369,7 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( ...state.rainChkgdn, rainChkgdnHeadList: rainChkgdnHeadList, splHeadList: splHeadList, - ruseHeadList: ruseHeadList + ruseHeadList: ruseHeadList, }, })); } catch (error) { diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx index 0e690dbb9..c9fc9f078 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx @@ -1,6 +1,6 @@ +import type { TableUpperProps } from "@/app/store/common/type/header"; import { z } from "zod"; import { guideDetail, type chHeadType } from "../rainChkgdn/headList"; -import type { TableUpperProps } from "@/app/store/common/type/header"; export type polutionType = { chkgdnDtlFk: number; @@ -109,6 +109,24 @@ export const rswtChkgdZod = z.object({ rswtrPollutions: z.array(rswtrPolutionsZode), }); + + +export const rswtRuseHeadNmExport: chHeadType[] = [ + { headNm: "useQuilty", text: "이용수질(필요시)", length: 3 }, + { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, + { headNm: "ruseWater", text: "연간중수 이용량(m³)", length: 13 }, + { headNm: "detailQulity", text: "분기", length: 11 }, +]; + +export const rswtSplHeadNmExport: chHeadType[] = [ + { headNm: "useQuilty", text: "이용수질(필요시)", length: 3 }, + { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, + { headNm: "detailQulity", text: "분기", length: 11 }, + { headNm: "splWater", text: "연간대체수 이용량(m³)", length: 13 }, +]; + + + export const rswtHeadNmExport: chHeadType[] = [ { headNm: "useQuilty", text: "연간 평균 이용수질", length: 10 }, { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, @@ -126,7 +144,7 @@ export const rswtChkHeadListExport: TableUpperProps[] = [ { id: "spwtPositn", title: "채수지점" ,mergeCell: true}, { id: "chckYmd", title: "점검일" ,mergeCell: true}, { id: "utztnUsgCd", title: "이용용도" }, - { id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)" ,type: "number"}, + { id: "splyUswtrUtztnQnt", title: "연간대체수이용량(m³)" ,type: "number"}, { id: "ruseFcltUtztnQnt", title: "연간중수도이용량(m³)",type: "number"}, { diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx index 1cc7bd766..4f647da1e 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx @@ -1,18 +1,24 @@ +import { buildingType } from "@/app/store/common/code"; +import type { TableUpperProps } from "@/app/store/common/type/header"; import { TEST_UUID, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import type { - SelectDataType, - SheetParameter, -} from "@common/business_components"; import { deleteFectch, fetchType, getFetch, + getFetchWithCount, postFectch, putFectch, } from "@/components/lib/api"; -import { buildingType } from "@/app/store/common/code"; +import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; +import type { + SelectDataType, + SheetParameter, +} from "@common/business_components"; +import toast from "react-hot-toast"; +import { z } from "zod"; +import { type chHeadType } from "../rainChkgdn/headList"; import { rswtMakeExcelSample } from "./excel"; import { rswtChkgdZod, @@ -20,15 +26,19 @@ import { rswtDetailHeadListExport, rswtHeadNmExport, rswtrDetailsZod, + rswtRuseHeadNmExport, + rswtSplHeadNmExport, } from "./headList"; -import { z } from "zod"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; -import { type chHeadType } from "../rainChkgdn/headList"; -import type { TableUpperProps } from "@/app/store/common/type/header"; + +export const rswtPageSize = 5; const rswtChkHeadList = rswtChkHeadListExport; const rswtDetailHeadList = rswtDetailHeadListExport; const rswtHeadNm = rswtHeadNmExport; +const rswtRuseHeadNm =rswtRuseHeadNmExport +const rswtSplHeadNm =rswtSplHeadNmExport + + export type rswtChkZodType = z.infer<typeof rswtChkgdZod>; export type rswtrChkDetailsZodType = z.infer<typeof rswtrDetailsZod>; export type rswtChkgdnState = { @@ -40,13 +50,29 @@ export type rswtChkgdnState = { excelList: SheetParameter[]; rswtChkRes: rswtChkZodType[]; rswtChkPolGuide: rswtChkZodType[]; + rswtSplHeadNm:chHeadType[] + rswtRuseHeadNm:chHeadType[] isInit: boolean; - isSttn:boolean + isSttn: boolean; + isLoading:boolean; + rswtChkCount: number; }; }; type rswtChkgdnActions = { - rswtChkgdnInit: (year: string, sggCd: string) => void; + rswtChkgdnInit: ( + pageNo: number, + cnt: number, + year: string, + sggCd: string + ) => void; + rswtChkNmSearch: ( + pageNo: number, + cnt: number, + year: string, + sggCd: string, + txt: string + ) => void; rswtrChkExcelDownload( sidoCode: SelectDataType[], sggCode: SelectDataType[] @@ -57,7 +83,7 @@ type rswtChkgdnActions = { rswtChkPolAndGuide: (chkGdnPk: number) => void; rswtChkPolInit: () => void; rwstPolAndGuideUpdate: (rswtChk: rswtChkZodType[]) => void; - rswtChkHeadChange: (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => void; + rswtChkHeadChange: (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => void; }; export type rswtChkgdnType = rswtChkgdnState & rswtChkgdnActions; @@ -67,25 +93,41 @@ export const rswtChkgdnStateExport: rswtChkgdnState = { rswtChkHeadList: rswtChkHeadList, rswtDetailHeadList: rswtDetailHeadList, rswtHeadNm: rswtHeadNm, - excelList: [{ - data: [[]], headerNum: 0, headerRange: "A1:V3", + rswtRuseHeadNm:rswtRuseHeadNm, + rswtSplHeadNm:rswtSplHeadNm, + + excelList: [ + { + data: [[]], + headerNum: 0, + headerRange: "A1:V3", sheetName: "", - startCol: '1' - }], + startCol: "1", + }, + ], rswtChkRes: [], rswtChkPolGuide: [], isInit: false, - isSttn:false, + isSttn: false, + isLoading:false, + rswtChkCount: 1, }, }; -const initFetch = async (year: string | undefined, sgg: string | undefined) => { +const initFetch = async ( + pageNo: number, + cnt: number, + year: string | undefined, + sgg: string | undefined +) => { const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await getFetch( + const rswtChkRes = await getFetchWithCount( "wr", - `/reuseChk/reuseWater/` + - (year ? `${year}` : currentYear) + - (sgg ? `/${sgg}` : "/0") + `/reuseChk/reuseWater` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/20") + + (year ? `/${year}` : `/${currentYear}`) + + (sgg ? `/${sgg}` : "/0") ); return rswtChkRes; }; @@ -137,16 +179,63 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( }, })); }, - rswtChkgdnInit: async (year: string, sggCd: string) => { + rswtChkgdnInit: async ( + pageNo: number, + cnt: number, + year: string, + sggCd: string + ) => { + // set((state: rswtChkgdnType) => ({ rswtChkgdn: { ...state.rswtChkgdn, isLoading: true } })); try { - const rswtChkRes = await initFetch(year, sggCd); + const rswtChkRes = await initFetch(pageNo, cnt, year, sggCd); + + console.log("rswtChkRes", rswtChkRes) + + set((state: rswtChkgdnState) => ({ + ...state, + rswtChkgdn: { + ...state.rswtChkgdn, + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, + isInit: true, // 무한 루프를 방지하기 위해 isInit을 true로 설정 + }, + })); + } catch (error) { + // console.log(error); + // set((state: rswtChkgdnType) => ({ + // rswtChkgdn: { ...state.rswtChkgdn, isInit: true }, + // })); + } finally { + // set((state: rswtChkgdnType) => ({ rswtChkgdn: { ...state.rswtChkgdn, isLoading: false } })); + } + }, + rswtChkNmSearch: async ( + pageNo: number, + cnt: number, + year: string, + sggCd: string, + txt: string + ) => { + try { + console.log("여기") + const currentYear = new Date().getFullYear().toString(); + const rswtChkRes = await getFetchWithCount( + "wr", + `/reuseChk/reuseWater` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/20") + + (year ? `/${year}` : `/${currentYear}`) + + (sggCd ? `/${sggCd}` : "/0") + + (txt ? `/${txt}` : "") + ); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { ...state.rswtChkgdn, - rswtChkRes: rswtChkRes, - isInit: false, + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, + // isInit: false, }, })); } catch (error) { @@ -155,6 +244,8 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( }, rswtChkExceDataUpload: async (excelData: rswtChkZodType[]) => { try { + set((state: rswtChkgdnType) => ( + { rswtChkgdn: { ...state.rswtChkgdn, isLoading: true } })); const res = await postFectch("/reuseChk/reuseWater", excelData); if (res.ok) { ToastFormUi({ @@ -163,65 +254,66 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( }); } const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await initFetch(currentYear, "0"); + const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { ...state.rswtChkgdn, - rswtChkRes: rswtChkRes + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, }, })); } catch (error) { console.log(error); + }finally{ + set((state: rswtChkgdnType) => ( + { rswtChkgdn: { ...state.rswtChkgdn, isLoading: false } })); } + }, rswtChkDetilsUpdate: async (rswtChk: rswtrChkDetailsZodType[]) => { try { const chData = await makeMdfrChk(rswtChk); - const res = await putFectch("/reuseChk/reuseWater", chData); if (res.ok) { - ToastFormUi({ - body: "지도점검 과태료 수정 수정이 완료되었습니다. ", - title: "지도점검 수정", - }); + toast.success("지도점검 과태료 수정이 완료되었습니다. ",) } const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await initFetch(currentYear, "0"); + const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { ...state.rswtChkgdn, - rswtChkRes: rswtChkRes, + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, }, })); } catch (error) { console.log(error); - alert("수정에 실패하였습니다."); + toast.error("지도점검 과태료 수정 오류입니다. ",) + } }, rswtChkDelete: async (chkgdnPks: number[]) => { try { const res = await deleteFectch(`/reuseChk/reuseWater`, chkgdnPks); - if (res.ok) { - ToastFormUi({ - body: "삭제가 완료되었습니다. ", - title: "지도점검 삭제", - }); + if (res) { + toast.success("삭제가 완료되었습니다.") } const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await initFetch(currentYear, "0"); + const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { ...state.rswtChkgdn, - rswtChkRes: rswtChkRes, + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, }, })); } catch (error) { - ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" }); + toast.error("삭제 오류입니다.") } }, rswtChkPolAndGuide: async (chkGdnPk: number) => { @@ -238,7 +330,11 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( rswtChkPolGuide: rswtChkPolGuide, }, })); - } catch (error) {} + } catch (error) { + + + + } }, rswtChkPolInit: () => { try { @@ -259,13 +355,10 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( chData[0] ); if (res.ok) { - ToastFormUi({ - body: "지도점검 연간 수질 및 보급수/중수도 수정이 완료되었습니다. ", - title: "지도점검 수정", - }); + toast.success("지도점검 연간 수질 및 대체수/중수도 수정이 완료되었습니다.") } const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await initFetch(currentYear, "0"); + const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { @@ -275,10 +368,9 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( })); } catch (error) { console.log(error); - ToastFormUi({ - body: "지도점검 연간 수질 및 보급수/중수도 수정이 실패하였습니다.. ", - title: "지도점검 수정", - }); + + toast.error("지도점검 연간 수질 및 대체수/중수도 수정 오류입니다.") + } }, rswtChkHeadChange: async (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => { diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx index 544f07516..abde1778f 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx @@ -4,7 +4,7 @@ import type { TableUpperProps } from "../../common/type/header"; export const pbnPrfRegExcelZod = z.object({ ym: z.string().default(""), bscFctNm: z.string().default(""), - pbnstRuseFcltFk:z.string(), + pbnstRuseFcltFk: z.string(), pbnstRuseFcltNm: z.string().default(""), file: z.instanceof(File).optional(), }); @@ -18,20 +18,21 @@ export const pbnstPrfmncHeadListExport: TableUpperProps[] = [ ]; export const monthHeadListExport: TableUpperProps[] = [ + { id: "구분", title: "구분", mergeCell: true }, { id: "용수명", title: "용수명" }, { id: "total", title: "계" }, - { id: "1월", title: "1월" ,edit: true }, - { id: "2월", title: "2월" ,edit: true }, - { id: "3월", title: "3월" ,edit: true }, - { id: "4월", title: "4월" ,edit: true }, - { id: "5월", title: "5월" ,edit: true }, - { id: "6월", title: "6월" ,edit: true }, - { id: "7월", title: "7월" ,edit: true }, - { id: "8월", title: "8월" ,edit: true }, - { id: "9월", title: "9월" ,edit: true }, - { id: "10월", title: "10월" ,edit: true }, - { id: "11월", title: "11월" ,edit: true }, - { id: "12월", title: "12월" ,edit: true }, + { id: "1월", title: "1월", edit: true }, + { id: "2월", title: "2월", edit: true }, + { id: "3월", title: "3월", edit: true }, + { id: "4월", title: "4월", edit: true }, + { id: "5월", title: "5월", edit: true }, + { id: "6월", title: "6월", edit: true }, + { id: "7월", title: "7월", edit: true }, + { id: "8월", title: "8월", edit: true }, + { id: "9월", title: "9월", edit: true }, + { id: "10월", title: "10월", edit: true }, + { id: "11월", title: "11월", edit: true }, + { id: "12월", title: "12월", edit: true }, ]; diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx index 82f2ed59c..387f56eb7 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx @@ -16,6 +16,7 @@ export type pbnstPrfmncState = { monthHeadList: TableUpperProps[]; prfmncRes: FcPrfType[]; excelList: Number[]; + pageKey:number }; }; @@ -26,21 +27,22 @@ export const pbnstPrfmncStateExport: pbnstPrfmncState = { monthHeadList: monthHeadList, prfmncRes: [], excelList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + pageKey:1 }, }; export type pbnstPrfmncType = pbnstPrfmncState & pbnstPrfmncActions; type pbnstPrfmncActions = { - prfmncHasuInit: (page: string, sggOrCity: string) => void; - prfmnRegData: (data: PrfType) => void; + prfmncHasuInit: (page: number, sggOrCity: string) => void; + prfmnRegData: (page:number,sggOrCity:string, data: PrfType) => void; }; const checkWrRegList = async () => { const wrRegList = await getFetch("wr", `/reuseFc/pubDetailList`); return wrRegList; }; -const hasuListFetch = async (page: string, sggOrCity: string) => { +const hasuListFetch = async (page: number, sggOrCity: string) => { const checkWrRegListRes = await checkWrRegList(); const rainRes = await postFectch( `/prcsFclt/ruseInfo/${page ? page : 1}/10/A/${sggOrCity ? sggOrCity : "11"}/0/1/SW`, @@ -74,7 +76,7 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = ( set: any ) => { return { - prfmncHasuInit: async (page: string, sggOrCity: string) => { + prfmncHasuInit: async (page: number, sggOrCity: string) => { try { const prfmncRes = await hasuListFetch(page, sggOrCity); return set((state: pbnstPrfmncState) => ({ @@ -89,7 +91,7 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = ( console.log(errorHasu); } }, - prfmnRegData: async (data: PrfType) => { + prfmnRegData: async (page:number,sggOrCity:string,data: PrfType) => { try { const ressponse = await postFectch( "/reuseFc/pubFcPrf", @@ -100,6 +102,17 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = ( if (ressponse.status === 200) { toast.success("하수재이용 시설 실적 등록이 완료되었습니다."); + const prfmncRes = await hasuListFetch(page, sggOrCity); + return set((state: pbnstPrfmncState) => ({ + ...state, + prfmnc: { + ...state.prfmnc, + prfmncRes: prfmncRes, + isInit: false, + pageKey: state.prfmnc.pageKey + 1 + }, + })); + } } catch (e) { console.log(e); diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx index f112db0bd..8c90e0829 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx @@ -11,7 +11,7 @@ export const rainChkgdnHeadSttnExport: TableUpperProps[] = [ { id: "dtfcltCpct", title: "빗물저류조용량(m³)", mergeCell: true }, { id: "chckYmd", title: "점검일", mergeCell: true }, { id: "utztnUsgCd", title: "이용용도" }, - { id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, + { id: "totalSplyUswtrUtztnQnt", title: "연간대체수이용량(m³)" }, { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" }, { id: "ph", diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx index ea3f58a40..e99bdb7a8 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx @@ -1,11 +1,10 @@ +import type { TableUpperProps } from "@/app/store/common/type/header"; import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import { type TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { getFetch } from "@/components/lib/api"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; +import { rainMainHeadNmExport, type chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; +import { getFetchWithCount } from "@/components/lib/api"; import type { SelectDataType } from "@common/business_components/ui"; -import { rainChkgdnHeadSttnExport, ruseSttnHeadListExport, splSttnHeadListExport } from "./headList"; -import { rainHeadNmExport, type chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { buildingExcelRainSttn } from "./excel"; +import { rainChkgdnHeadSttnExport, ruseSttnHeadListExport, splSttnHeadListExport } from "./headList"; const fcltDiv = [ { val: "RST", text: "중수도시설" }, @@ -16,29 +15,28 @@ const fcltDiv = [ const rainChkgdnHeadList = rainChkgdnHeadSttnExport; const ruseHeadList = ruseSttnHeadListExport; const splHeadList = splSttnHeadListExport; -const rainHeadNm = rainHeadNmExport - -const rainChk: rainChkZodType[] = []; +const rainHeadNm = rainMainHeadNmExport export type rainChkSttnState = { rainChkSttn: { rainChkRes: rainChkZodType[]; fcltDiv: SelectDataType[]; rainChkgdnHeadList: TableUpperProps[]; - rainHeadNm:chHeadType[]; + rainHeadNm: chHeadType[]; ruseHeadList: TableUpperProps[]; splHeadList: TableUpperProps[]; - sttnExcelList:[] + sttnExcelList: [] isInit: boolean; - isSttn:boolean; + isSttn: boolean; + rainChkCount: number; }; }; type rainChkSttnActions = { - rainChkSttnInit: (searchTxt: string, sggCd: string) => void; - rainChkSttnSearch: (searchTxt: string, sggCd: string) => void; - isRainSttn:(isSttn:boolean) => void; - getRainSttnExcel:(excelList:rainChkZodType[]) => void; + rainChkSttnInit: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void; + isRainSttn: (isSttn: boolean) => void; + getRainSttnExcel: (excelList: rainChkZodType[]) => void; + rainChkSttnNmSearch: (pageNo: number, cnt: number, year: string, sggCd: string, txt: string) => void }; export type rainChkSttnType = rainChkSttnState & rainChkSttnActions; @@ -50,18 +48,23 @@ export const rainChkSttnStateExport: rainChkSttnState = { rainChkgdnHeadList: rainChkgdnHeadList, ruseHeadList: ruseHeadList, splHeadList: splHeadList, - rainHeadNm:rainHeadNm, + rainHeadNm: rainHeadNm, isInit: false, - sttnExcelList:[], - isSttn:false, + sttnExcelList: [], + isSttn: false, + rainChkCount: 1, }, }; -const initFetch = async (txt: string | undefined, sgg: string | undefined) => { +const initFetch = async (pageNo: number, cnt: number, txt: string | undefined, sgg: string | undefined) => { const currentYear = new Date().getFullYear().toString(); - const rainRes = await getFetch( + const rainRes = await getFetchWithCount( "wr", - `/reuseChk/rainy/` + (txt ? `${txt}` : currentYear) + (sgg ? `/${sgg}` : "/0") + `/reuseChk/rainy` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/5") + + (txt ? `/${txt}` : `/${currentYear}`) + + (sgg ? `/${sgg}` : "/0") ); return rainRes; }; @@ -69,48 +72,66 @@ export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = ( set: any ) => { return { - rainChkSttnInit: async (searchTxt: string, sggCd: string) => { + rainChkSttnInit: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => { try { - const rainChkRes = await initFetch(searchTxt, sggCd); + const rainChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd); return set((state: rainChkSttnState) => ({ ...state, rainChkSttn: { ...state.rainChkSttn, - rainChkRes:rainChkRes + rainChkRes: rainChkRes.data, + rainChkCount: rainChkRes.count, + isSttn: true }, })); } catch (error) { console.log(error); } }, - rainChkSttnSearch: async (searchTxt: string, sggCd: string) => { + rainChkSttnNmSearch: async ( + pageNo: number, + cnt: number, + year: string, + sggCd: string, + txt: string + ) => { try { - const rainChkRes = await initFetch(searchTxt, sggCd); - + const currentYear = new Date().getFullYear(); + const rainChkRes = await getFetchWithCount( + "wr", + `/reuseChk/rainy` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/5") + + (year ? `/${year}` : `/${currentYear}`) + + (sggCd ? `/${sggCd}` : "/0") + + (txt ? `/${txt}` : "") + ); return set((state: rainChkSttnState) => ({ ...state, rainChkSttn: { ...state.rainChkSttn, - rainChkRes:rainChkRes + rainChkRes: rainChkRes.data, + rainChkCount: rainChkRes.count, }, })); } catch (error) { console.log(error); } - },isRainSttn :(isSttn:boolean) =>{ + }, + isRainSttn: (isSttn: boolean) => { try { return set((state: rainChkSttnState) => ({ ...state, rainChkSttn: { ...state.rainChkSttn, - isSttn:isSttn + isSttn: isSttn }, })); } catch (error) { console.log(error); } - },getRainSttnExcel: async (excelList:rainChkZodType[]) => { + }, getRainSttnExcel: async (excelList: rainChkZodType[]) => { try { const excelData = buildingExcelRainSttn(excelList) @@ -119,7 +140,7 @@ export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = ( ...state, rainChkSttn: { ...state.rainChkSttn, - sttnExcelList:excelData + sttnExcelList: excelData }, })); } catch (error) { diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx index cd95ef1fc..7891d73fb 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx @@ -1,10 +1,10 @@ -import { rswtHeadNmExport } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList"; -import { rswtChkSttnHeadListExport, rswtDetailSttnHeadListExport } from "./headList"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; -import { getFetch } from "@/components/lib/api"; +import { rswtHeadNmExport } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList"; +import { getFetch, getFetchWithCount } from "@/components/lib/api"; import { buildingExcelRswtSttn } from "./excel"; +import { rswtChkSttnHeadListExport, rswtDetailSttnHeadListExport } from "./headList"; const rswtChkHeadList = rswtChkSttnHeadListExport; const rswtDetailHeadList = rswtDetailSttnHeadListExport; @@ -20,14 +20,15 @@ export type rswtChkSttnState = { rswtChkRes: rswtChkZodType[]; isInit: boolean; isSttn: boolean; + rswtChkCount: number; }; }; type rswtChkSttnActions = { - rswtChkSttnInit: (searchTxt: string, sggCd: string) => void; + rswtChkSttnInit: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void; isRswtSttn: (isSttn: boolean) => void; getRswtSttnExcel: (excelList: rswtChkZodType[]) => void; - rswtChkSttnSearch: (searchTxt: string, sggCd: string) => void; + rswtChkNmSttnSearch: (pageNo: number, cnt: number, year: string, sggCd: string, txt: string) => void; }; export type rswtChkSttnType = rswtChkSttnState & rswtChkSttnActions; @@ -41,33 +42,36 @@ export const rswtChkStateExport: rswtChkSttnState = { rswtChkRes: [], isInit: false, isSttn: false, + rswtChkCount: 1, }, }; -const initFetch = async (year: string | undefined, sgg: string | undefined) => { +const initFetch = async (pageNo: number, cnt: number, year: string | undefined, sgg: string | undefined) => { const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await getFetch( + const rswtChkRes = await getFetchWithCount( "wr", - `/reuseChk/reuseWater/` + - (year ? `${year}` : currentYear) + + `/reuseChk/reuseWater` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/20") + + (year ? `/${year}` : `/${currentYear}`) + (sgg ? `/${sgg}` : "/0") ); return rswtChkRes; }; - export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = ( set: any ) => { return { - rswtChkSttnInit: async (searchTxt: string, sggCd: string) => { + rswtChkSttnInit: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => { try { - const rswtChkRes = await initFetch(searchTxt, sggCd); + const rswtChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd); return set((state: rswtChkSttnState) => ({ ...state, rswtChkSttn: { ...state.rswtChkSttn, - rswtChkRes: rswtChkRes, + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, isInit: false, }, })); @@ -104,15 +108,32 @@ export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = ( console.log(error); } }, - rswtChkSttnSearch: async (searchTxt: string, sggCd: string) => { + rswtChkNmSttnSearch: async ( + pageNo: number, + cnt: number, + year: string, + sggCd: string, + txt: string + ) => { try { - const rswtChkRes = await initFetch(searchTxt, sggCd); + const currentYear = new Date().getFullYear().toString(); + const rswtChkRes = await getFetchWithCount( + "wr", + `/reuseChk/reuseWater` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/20") + + (year ? `/${year}` : `/${currentYear}`) + + (sggCd ? `/${sggCd}` : "/0") + + (txt ? `/${txt}` : "") + ); return set((state: rswtChkSttnState) => ({ ...state, rswtChkSttn: { ...state.rswtChkSttn, - rswtChkRes: rswtChkRes + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, + isInit: false, }, })); } catch (error) { diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx index 931cd1305..418f4b45f 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx @@ -79,8 +79,9 @@ const isRswtBdst = (data: any): data is customRswtBdst =>{ data.reuseBuilding=chData; } - if(data?.chgBuilding.length>0){ - const chRgtr = data.chgBuilding.map((item) =>({...item, rgtr:TEST_UUID, mdfr: item.mdfr ?? null })) + + if('chgBuilding' in data && Array.isArray(data.chgBuilding) && data.chgBuilding.length > 0){ + const chRgtr = data.chgBuilding.map((item) =>({...item, rgtr:TEST_UUID, mdfr: item.mdfr ?? null })) data.chgBuilding =chRgtr; } return data; @@ -127,7 +128,7 @@ const isRswtBdst = (data: any): data is customRswtBdst =>{ data.reuseBuilding=chData; } - if(data?.chgBuilding.length>0){ + if('chgBuilding' in data && Array.isArray(data.chgBuilding) && data.chgBuilding.length > 0){ const chMdfr = data.chgBuilding.map((item) =>({...item, mdfr:TEST_UUID, archChgArea: item.archChgArea ?? '' })) data.chgBuilding =chMdfr; } diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx new file mode 100644 index 000000000..da1fa6f09 --- /dev/null +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx @@ -0,0 +1,10 @@ +import type { TableUpperProps } from "@/app/store/common/type/header"; + +export const htdTableHeadList: TableUpperProps[] = [ + { id: "cityText", title: "시도" }, + { id: "sggText", title: "시군구" }, + { id: "bdstNm", title: "발전소명" }, + { id: "daddr", title: "위치" }, + { id: "frstArchPrmsnDt", title: "준공년도" }, + { id: "archArea", title: "건축면적" }, +]; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx index 314d5762b..317f68e10 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx @@ -6,9 +6,12 @@ import { makeMdfr, makeRstr } from "../bdstReg"; import { baseReuseBuildingSchema, chgBuildingSchema, + htdflReuseBuildingSchema, validationMessages, } from "../rainReg/type"; // Import baseReuseBuildingSchema, chgBuildingSchema, validationMessages import type { TableUpperProps } from "@/app/store/common/type/header"; +import { htdTableHeadList } from "./headList"; +import toast from "react-hot-toast"; const hdtflObjSchema = z.object({ htdflFcltPk: z.number().nullish(), @@ -21,8 +24,8 @@ const hdtflObjSchema = z.object({ .positive({ message: validationMessages.required("시설 용량") }), plwtYn: z.enum(["Y", "N"]).default("Y"), orgwtWtritSpt: z - .number() - .positive({ message: validationMessages.required("원수 취수량") }), + .string() + .min(1, { message: validationMessages.required("원수 취수 지점") }), orgwtOcrnProcs: z .string() .min(1, { message: validationMessages.required("원수 발생 공정") }), @@ -53,7 +56,9 @@ const hdtflObjSchema = z.object({ ph: z.number().default(0), // Measurements, 0 is fine as default clIonQnt: z.number().default(0), // Measurements, 0 is fine as default cdtnv: z.number().default(0), // Measurements, 0 is fine as default - emsnExitTp: z.number().default(0), // Measurements, 0 is fine as default + emsnExitTp: z.number() + .max(100, { message: "온도는 100이상이 될 수 없습니다." }) + .default(0), // Changed max to 100 based on message, // Measurements, 0 is fine as default rgtr: z.string().nullish().default(null), mdfr: z.string().nullish().default(null), }); @@ -71,22 +76,21 @@ export const hdtflZod = z.object({ .date() .default(() => new Date()) .nullish(), - archArea: z.number().default(0), + archArea: z.string().default(''), archChgArea: z.number().nullish().default(0), rgtr: z.string().nullish().default(null), mdfr: z.string().nullish().default(null), reuseBuilding: z .array( - baseReuseBuildingSchema.extend({ + htdflReuseBuildingSchema.extend({ htdflObj: hdtflObjSchema, }) ) .default([]), - chgBuilding: z.array(chgBuildingSchema).default([]), // Use imported chgBuildingSchema + //온배수는 건축물은 등록 하는것이 다름 + // chgBuilding: z.array(chgBuildingSchema).nullish(), // Use imported chgBuildingSchema }); - export type customHtdflBdst = z.infer<typeof hdtflZod>; - export type htdflFacState = { htdfl: { isInit: boolean; @@ -95,7 +99,8 @@ export type htdflFacState = { }; }; type htdflFacSActions = { - initHtdfl: (code: string) => void; + initHtdflReg: (code: string) => void; + htdflNmSearch: (code: string | number, fcltNm:string) => void; htdflBdstUpdate: (data: customHtdflBdst, code: string | number) => void; htdflBdstReg: (data: customHtdflBdst, code: string | number) => void; getHtdflBdstData: (pageNation: number, code: string | number) => void; @@ -104,18 +109,24 @@ type htdflFacSActions = { const htdflRes: customHtdflBdst[] = []; export type htdflFacType = htdflFacState & htdflFacSActions; - export const htdflFacStateExport: htdflFacState = { htdfl: { isInit: false, - upHeadList: upHeadList, + upHeadList: htdTableHeadList, htdflRes: htdflRes, }, }; -const initFetch = async (code: string | number) => { - const rswtRes = await getFetch("wr", `/facilityList/1/20/${code}`); +const initFetch = async (code: string) => { + + console.log(' initFetch code ', code) + let url = `/drain/facilityList/1/20` + + url+=`/${code}` + + + const rswtRes = await getFetch("wr", url); return rswtRes; }; export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( @@ -128,8 +139,6 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( "wr", `/drain/facilityList/${pageNation}/20/${code}` ); - console.log(pageNation); - // 여기서 상태 업데이트 return set((state: htdflFacState) => ({ ...state, htdfl: { @@ -142,10 +151,9 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( console.log(e); } }, - - initHtdfl: async (code: string) => { + initHtdflReg: async (code: string) => { try { - const htdflRes = await initFetch(code); + const htdflRes = await initFetch( String(code)); set((state: htdflFacState) => { return { ...state, @@ -162,13 +170,19 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( }, htdflBdstUpdate: async (data: customHtdflBdst, code: string | number) => { try { + + const chData = await makeMdfr(data); - const res = await putFectch("/drain/facility", data); - if (res.ok) { - alert(" 수정이 완료되었습니다."); + const res = await putFectch("/drain/facility", chData); + + if (res.status) { + toast.success("온배수 건축물 수정이 완료되었습니다."); } - const htdflRes = await initFetch(code); + const htdflRes = await getFetch( + "wr", + `/drain/facilityList/1/20/${code}` + ); set((state: htdflFacState) => ({ ...state, htdfl: { @@ -178,42 +192,20 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( }, })); } catch (errorUpdate) { - alert( - "업데이트 오류입니다. " + - (errorUpdate instanceof Error ? errorUpdate.message : "") - ); + toast.error("온배수 건축물 수정 오류입니다.."); } }, htdflBdstReg: async (data: customHtdflBdst, code: string | number) => { try { - const chData = await makeRstr(data); - const res = await postFectch("/drain/facility", data); - 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; - }) - .then((chch: any) => { - if (chch.ok) { - alert("등록이 완료되었습니다."); - } - }); - } else { - alert("등록이 완료되었습니다."); - } + // data는 단일 객체이므로 .map을 사용할 수 없습니다. + // 등록 시에는 건축물 변경 이력이 없으므로 chgBuilding을 빈 배열로 설정하고, + // API가 배열을 기대하므로 단일 객체를 배열로 감싸줍니다. + const chData = makeRstr(data); + const res = await postFectch("/drain/facility", chData); + if (res.status ===200) { + toast.success("온배수 건축물 등록이 완료되었습니다."); } - const htdflRes = await initFetch(code); + const htdflRes = await initFetch(String(code)); set((state: htdflFacState) => ({ ...state, htdfl: { @@ -223,7 +215,25 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( }, })); } catch (errorReg) { - alert("등록 오류입니다."); + toast.error("온배수 건축물 등록 오류입니다.."); + + } + },htdflNmSearch :async(code:string | number, fcltNm:string) =>{ + try { + + const htdflRes = await getFetch("wr", `/drain/facilityList/1/20/${code}/${fcltNm}`); + set((state: htdflFacState) => { + return { + ...state, + htdfl: { + ...state.htdfl, + htdflRes: htdflRes, + isInit: false, + }, + }; + }); + } catch (error) { + console.log(error); } }, }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index ea7eee5c8..e4bedff60 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -54,6 +54,7 @@ export type pubFacState = { pbnsUpdateIndex: pbnstInsertIndex; fcOrgwtsNmList:pubHasuType[]; dmdComList: any[]; + apiMessage:string; }; }; type pubFacActions = { @@ -94,6 +95,7 @@ export const pubFacStateExport: pubFacState = { pbnsUpdateIndex: {} as pbnstInsertIndex, fcOrgwtsNmList:[], dmdComList: [], + apiMessage:'' }, }; @@ -269,8 +271,13 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { ruseRes ); + if(response){ + + toast.success(` 하수재이용 시설 정보가 수정되었습니다.`); + } } catch (error) { console.error("Error pbnstRuseFcltUpdate:", error); + toast.error(` 하수재이용 시설 정보가 수정오류입니다.`); } } ,pbnstRuseBizUpdate : async(ruseRes:fcBizType[])=>{ try { @@ -280,6 +287,10 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { `/reuseFc/pubFcBiz`, ruseRes ); + + if(response){ + toast.success(` 하수재이용 시설 사업이 수정되었습니다.`); + } const pbnstRes = await hasuListFetch("11", "11"); return set((state: pubFacState) => ({ @@ -292,6 +303,7 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { })); } catch (error) { console.error("Error pbnstRuseFcltUpdate:", error); + toast.error(` 하수재이용 시설 사업이 수정이 실패되엇습니다..`); } } , getBizCycle: async (pbnstObj: customPbnst) => { diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx index b908750fd..ad3496a54 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx @@ -163,7 +163,7 @@ export const fcBizSchema = z.object({ etc: z.string().default(""), totalMoney: zNumNullish.default(0), rprcsFcltCpct: zNumDefaultZero, - majorPrcsMsrcCd: z.string().default(""), + majorPrcsMsrcCd: z.string().nullish(), addr: z.string().default(""), rprcsMthdCd: z.string().default(""), inoutYn: z.enum(["Y", "N"]).default("Y"), @@ -236,8 +236,11 @@ export const fcBizSchema = z.object({ export const pbnstRegZod = z.object({ pbnstRuseFcltPk: z.string().default(""), swtrmtFcltFk: z.string().default(""), - ruseUtztnFcltNm: z.string().default(""), - fcltCpct: zNumDefaultZero, + ruseUtztnFcltNm: z + .preprocess( + (v) => (v !== null && v !== undefined ? String(v).trim() : ""), // null/undefined → "", 공백 제거 + z.string().min(1, "시설 이름을 입력하세요")), + fcltCpct: zNumDefaultZero, ruseCpct: zNumDefaultZero, splyExtraCpct: zNumDefaultZero, regDt: zDateDefaultNow, @@ -246,7 +249,12 @@ export const pbnstRegZod = z.object({ mdfr: z.string().default("test"), fcFiles: z.array(fcFileSchema).default([]).nullish(), fcBizs: z.array(fcBizSchema).default([]), - fcOpers: z.array(fcOperSchema).default([]).nullish(), + fcOpers: z + .array(fcOperSchema) + .refine((val) => val.length >= 1, { + message: "재이용시설의 운영정보를 최소 하나를 등록해주세요", + }) + .default([]), // 기본값 설정 }); export const pbnstRegArrayZod = z.array(pbnstRegZod); diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index 372a4bd9a..6ceb75531 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -10,7 +10,7 @@ export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e' const rainyObjSchema = z.object({ bdstReuseFcltFk: z.number().nullish(), pntfColKnd: z.string().min(1, { message: validationMessages.requiredSelect("종류") }), - pntfColArea: z.number().positive({ message: validationMessages.required("면적(m³)") }), + pntfColArea: z.number().nullish() , dtfcltCpct: z.number().default(0), filtrTrtmfctYn: z.string().default("Y"), filtrTrtmfctCpct: z.number().nullish().default(0), @@ -34,7 +34,7 @@ export const rainZod = z.object({ bdstNm: z.string().default(""), frstArchPrmsnDt: z.date().default(() => new Date()), archChgPrmsnDt: z.coerce.date().nullish().default(null), - archArea: z.number().default(0), + archArea: z.string().default(''), archChgArea: z.number().default(0), rgtr:z.string().nullish(), mdfr:z.string().nullish(), @@ -162,29 +162,28 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( const test =await makeRstr(data); const res = await postFectch("/reuseFc/rainyInfo", test); - if(res.ok){ + if(res.status===200){ if(data.chgBuilding.length > 0){ - await res.json().then((resData: any) => { - const chPK = resData?.data?.bdstInfoPk - const makeCh= resData.data.chgBuilding.map((item: chgBuilding) => + + const chPK = res?.data?.bdstInfoPk + const makeCh= res.data.chgBuilding.map((item: chgBuilding) => ( { ...item, bdstInfoFk: chPK, }) ); - const chch= postFectch("/reuseFc/chgBuilding", makeCh); - return chch; - }).then((chch: any) => { + const chch= await postFectch("/reuseFc/chgBuilding", makeCh); - console.log('chch ', chch) if(chch.status ===200) { - toast.success("등록이 완료되었습니다."); - + toast.success("건축물 등록이 완료되었습니다."); + }else{ + toast.error("건축물 증축/개축/중축 오류입니다."); } - }) }else{ - toast.success("등록이 완료되었습니다."); + toast.success("건축물 등록이 완료되었습니다."); } + }else{ + toast.error("건축물 등록이 완료되었습니다."); } const rainRes = await initFetch(code); set((state: rainFacState) => ({ @@ -197,7 +196,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( })); } catch (e) { console.log("e", e); - alert("등록 오류입니다."); + toast.error("등록시 오류가 발생하였습니다."); } finally { } }, @@ -205,9 +204,9 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( try { const chData =await makeMdfr(data); const res = await putFectch("/reuseFc/rainyInfo", chData); - console.log('rainUpdate', res); - if(res.ok){ - alert(" 수정이 완료되었습니다.") + if(res.status === 200){ + toast.success("수정이 완료되었습니다."); + } const rainRes = await initFetch(code); set((state: rainFacState) => ({ @@ -220,7 +219,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( })); } catch (e) { console.log("e", e); - alert("업데이트 오류입니다."); + toast.error("수정시 오류가 발생하였습니다."); } finally { } } diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx index 6e28c3e76..2d17b4601 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx @@ -17,7 +17,10 @@ export const baseReuseBuildingSchema = z.object({ instlCstSprtYn: z.string().default("Y"), instlCstSprtAmt: z.number().nullish(), grntchBdstCertYn: z.string().default("Y"), - grntchBdstCertYr: z.string().default("").refine( + grntchBdstCertYr: z + .string() + .max(4, { message: validationMessages.yearFormat }) + .refine( (year) => year.length === 0 || /^\d{4}$/.test(year), { message: validationMessages.yearFormat, @@ -29,7 +32,12 @@ export const baseReuseBuildingSchema = z.object({ crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값 crgRdctAmt: z.number().default(0), // 안쓰는 값 ruseFcltFlg: z.string().default(""), - bdstUsgCd: z.number().min(1, { message: validationMessages.requiredSelect("건축물용도") }).default(0), + bdstUsgCd: z + .number() + .default(0) + .refine((val) => val === -1 || val >= 1, { + message: validationMessages.requiredSelect("건축물용도"), + }), lawTrgtYn: z.string().default("Y"), rgtr: z.string().nullish(), mdfr: z.string().nullish(), @@ -43,3 +51,40 @@ export const chgBuildingSchema = z.object({ rgtr:z.string().nullish(), mdfr:z.string().nullish(), }); + + + +export const htdflReuseBuildingSchema = z.object({ + bdstRuseFcltPk: z.number().nullish(), + bdstInfoFk: z.number().nullish(), + instlCmptnDt: z.coerce.date().default(() => new Date()), + instlCst: z.number().nullish(), + operMngCd: z.string().optional().nullish(), + anlOperCst: z.number().default(0), + instlCstSprtYn: z.string().default("Y"), + instlCstSprtAmt: z.number().nullish(), + grntchBdstCertYn: z.string().default("Y"), + grntchBdstCertYr: z + .string() + .max(4, { message: validationMessages.yearFormat }) + .refine( + (year) => year.length === 0 || /^\d{4}$/.test(year), + { + message: validationMessages.yearFormat, + } + ) + .nullish(), + grntchBdstCertNo: z.string().default(""), + grntchBdstCertGrd: z.string().default(""), + crgRdctYn: z.string().default("N").nullish(), /// 안쓰는 값 + crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값 + crgRdctAmt: z.number().default(0), // 안쓰는 값 + ruseFcltFlg: z.string().default(""), + bdstUsgCd: z.number().default(0).nullish(), + lawTrgtYn: z.string().default("Y").nullish(), + rgtr: z.string().nullish(), + mdfr: z.string().nullish(), +}); + + + diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx index 178badd3b..d39412d8d 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx @@ -5,13 +5,14 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; import { z } from "zod"; import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "../rainReg/type"; import { makeMdfr, makeRstr } from "../bdstReg"; +import toast from "react-hot-toast"; const rswtrObjSchema = z.object({ bdstRuseFcltFk: z.number().nullish(), - wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }), - oblgTrgtWtrUsqty: z.number().nullish().default(0), + //wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }), + //oblgTrgtWtrUsqty: z.number().nullish().default(0), orgwtKndCd: z.string({ required_error: validationMessages.requiredSelect("원수 종류") }).min(1, { message: validationMessages.requiredSelect("원수 종류") }), - filtrTrtmfctCpct: z.number({ required_error: validationMessages.required("처리시설 용량") }).positive({ message: validationMessages.required("처리시설 용량") }), + filtrTrtmfctCpct: z.number({ required_error: validationMessages.required("처리시설 용량") }), filtrTrtmfctProcs: z.string({ required_error: validationMessages.required("주요처리공정") }).min(1, { message: validationMessages.required("주요처리공정") }), filtrTrtmfctUsgCd: z.string().default("").nullish(), rswtrUsqty: z.number().default(0), @@ -36,7 +37,7 @@ export const rswtZod = z.object({ frstArchPrmsnDt: z.date().default(() => new Date()), archChgPrmsnDt: z.coerce.date().nullish().default(null), chBuildingYn: z.string().nullish(), - archArea: z.number().default(0), + archArea: z.string().default(''), archChgArea: z.number().default(0), rgtr: z.string().nullish().default(null), mdfr: z.string().nullish().default(null), @@ -152,8 +153,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( try { const chData = await makeMdfr(data); const res = await putFectch("/reuseFc/waterreuseFc", chData); - if (res.ok) { - alert("등록이 완료되었습니다."); + if (res.status ===200) { + toast.success("중수도 건축물 수정이 완료되었습니다."); const rswtRes = await initFetch(code); set((state: rswtFacState) => ({ ...state, @@ -165,10 +166,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( })); } } catch (errorUpdate) { - alert( - "업데이트 오류입니다. " + - (errorUpdate instanceof Error ? errorUpdate.message : "") - ); + toast.error("중수도 건축물 수정 오류입니다. "); + } finally { } }, @@ -176,29 +175,28 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( 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; - }) - .then((chch: any) => { - if (chch.ok) { - alert("등록이 완료되었습니다."); - } - }); + if (res.status===200) { + if(data.chgBuilding.length > 0){ + + const chPK = res?.data?.bdstInfoPk + const makeCh= res.data.chgBuilding.map((item: chgBuilding) => + ( { + ...item, + bdstInfoFk: chPK, + }) + ); + const chch= await postFectch("/reuseFc/chgBuilding", makeCh); + + if(chch.status ===200) { + toast.success("건축물 등록이 완료되었습니다."); + }else{ + toast.error("건축물 증축/개축/중축 오류입니다."); + } } else { - alert("등록이 완료되었습니다."); + toast.success("건축물 등록이 완료되었습니다."); } + }else{ + toast.error("건축물 등록이 완료되었습니다."); } const rainRes = await initFetch(code); set((state: rswtFacState) => ({ @@ -211,7 +209,7 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( })); } catch (e) { console.log("e", e); - alert("등록 오류입니다."); + toast.error("등록시 오류가 발생하였습니다."); } finally { } }, diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx index dccc8719c..eb37d0d73 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx @@ -5,6 +5,7 @@ import type { z } from "zod"; import { controlHeadView } from "../rainSttn"; import type { customHtdflBdst } from "../../fcltReg/htdflReg"; import { fetchType, getFetch } from "@/components/lib/api"; +import type { SelectDataType } from "@common/business_components/ui"; const htdflSttHeadList = htdflSttHeadListExport; const htdflSttNodeList = htdflSttNodeListExport; @@ -20,8 +21,12 @@ export type htdflSttnState = { }; }; type htdflSttnActions = { - initHtdfl: (con: string) => void; - htdflSttnSearch: (page: number, total: string, con: string) => void; + initHtdfl: (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; + htdflSttnSearch: (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; htdflChSttnHead: ( headList: z.infer<typeof sttnHeadListType>, ) => void; @@ -38,10 +43,17 @@ export const htdflSttnStateExport: htdflSttnState = { isInit: false, }, }; -const initFetch = async (code: string | number) => { +const initFetch = async (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { const htdflRes = await getFetch( "wr", - `/drain/facilityList/1/20/${code}`) + `/drain/facilityList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") + ); return htdflRes; }; @@ -50,9 +62,11 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = ( set: any ) => { return { - initHtdfl: async (code: string | number) => { + initHtdfl: async (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { try { - const htdflSttnRes = await initFetch(code); + const htdflSttnRes = await initFetch(page, total, con, txt, sidoCode, sggCode); set((state: htdflSttnState) => { return { ...state, @@ -67,17 +81,22 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = ( console.log(error); } }, - htdflSttnSearch: async (page: number, total: string, con: string) => { + htdflSttnSearch: async (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { try { + console.log("page", page) const htdflSttnRes = await getFetch( fetchType.WR, - `/drain/facilityList/${page}/${total}/${con}` + `/drain/facilityList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") ); + if (Number(total) > 9000) { - - set((state: htdflSttnState) => { - return { ...state, htdflSttn: { diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx index 7db00678d..8dd2a4d6f 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx @@ -31,8 +31,8 @@ export const rainSttHeadListExport: z.infer<typeof sttnHeadListType> = [ visible: true, }, { - id: "bdstUsgCd", - title: "건축물용도코드", + id: "bdsgUsgText", + title: "건축물용도", visible: true, }, { @@ -209,8 +209,8 @@ export const rainSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "bdstUsgCd", - title: "건축물용도코드", + id: "bdsgUsgText", + title: "건축물용도", upName: "bdnstInfo", visible: true, row: 2, diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx index 5aa54ee48..eb2c08d37 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx @@ -1,4 +1,4 @@ -import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import { fetchType, getFetch } from "@/components/lib/api"; import { type customRainBdst, @@ -16,34 +16,34 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; import type { SelectDataType } from "@common/business_components/ui"; // 테이블 헤드 리스트 -const rainSttHeadList = rainSttHeadListExport; +const rainSttHeadList = rainSttHeadListExport; const rainSttNodeList = rainSttNodeListExport; const rainSttnDetailNodeList = rainSttnDetailNodeListExport; const rainSttnDetailHeadList = rainSttnDetailHeadListExport; const rainSttnRes: customRainBdst[] = []; -const rainChkRes : rainChkZodType ={} as rainChkZodType +const rainChkRes: rainChkZodType = {} as rainChkZodType -const visibleHeadList = (falseHeads:CommonTableProps[], orgNodeList:CommonTableProps[])=>{ +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 + 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> = {}; +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) { + if (node.row && node.row >= 3) { const upperUpName = orgList.find(n => n.id === node.upName)?.upName; if (upperUpName) { reduceMap[upperUpName] = (reduceMap[upperUpName] || 0) + 1; @@ -78,35 +78,37 @@ const applyColspanReduction = ( }); }; // 일단 헤더가 3개 이상인경우 visible 처리를 위해서 공통함수로 작업 -export const controlHeadView = (headList:CommonTableProps[], orgNodeList:CommonTableProps[] ) =>{ +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); + const reduceMap = getColspanReductionMap(falseHeads, viewHeadList) + return applyColspanReduction(viewHeadList, reduceMap); } - - export type rainSttnState = { rainSttn: { rainSttnRes: customRainBdst[]; rainSttHeadList: CommonTableProps[]; rainSttNodeList: CommonTableProps[]; - rainSttnDetailHeadList:CommonTableProps[] - rainSttnDetailNodeList:CommonTableProps[] - rainChkRes:rainChkZodType + rainSttnDetailHeadList: CommonTableProps[] + rainSttnDetailNodeList: CommonTableProps[] + rainChkRes: rainChkZodType excelList: []; isInit: boolean; }; }; type rainSttnActions = { - rainSttnInit:(con:string) => void - rainSttnSearch: (page: number, total: string, con: string, sidoCode: SelectDataType[], sggCode: SelectDataType[]) => void; + rainSttnInit: (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void + rainSttnSearch: (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; rainChSttnHead: ( headList: z.infer<typeof sttnHeadListType>, ) => void; - rainSttnChkSearch:(rusePk:string) => void; + rainSttnChkSearch: (rusePk: string) => void; }; export type rainSttnType = rainSttnState & rainSttnActions; @@ -115,10 +117,10 @@ export const rainSttnStateExport: rainSttnState = { rainSttn: { rainSttHeadList: rainSttHeadList, rainSttNodeList: rainSttNodeList, - rainSttnDetailHeadList:rainSttnDetailHeadList, - rainSttnDetailNodeList:rainSttnDetailNodeList, + rainSttnDetailHeadList: rainSttnDetailHeadList, + rainSttnDetailNodeList: rainSttnDetailNodeList, rainSttnRes: rainSttnRes, - rainChkRes:rainChkRes, + rainChkRes: rainChkRes, excelList: [], isInit: false, }, @@ -128,12 +130,18 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( set: any ) => { return { - rainSttnInit: async( con:string)=>{ - try{ + rainSttnInit: async (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { + try { - const rainSttnRes = await getFetch( + const rainSttnRes = await getFetch( fetchType.WR, - `/reuseFc/rainyInfoList/1/20/${con}` + `/reuseFc/rainyInfoList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") ); set((state: rainSttnState) => { return { @@ -145,17 +153,21 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( }, }; }); - }catch(e){ + } catch (e) { console.log(e) } }, - rainSttnSearch: async (page: number, total: string, con: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => { + rainSttnSearch: async (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { try { const rainSttnRes = await getFetch( fetchType.WR, - `/reuseFc/rainyInfoList/${page}/${total}/${con}` + `/reuseFc/rainyInfoList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") ); if (Number(total) > 9000) { const rainExcel = excelRainSttnParsing(rainSttnRes, sidoCode, sggCode); @@ -186,7 +198,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( rainChSttnHead: async ( headList: z.infer<typeof sttnHeadListType> ) => { - const changeNodeList= controlHeadView(headList,rainSttNodeList) + const changeNodeList = controlHeadView(headList, rainSttNodeList) return set((state: rainSttnState) => ({ rainSttn: { @@ -196,21 +208,21 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( }, })); }, - rainSttnChkSearch: async( - rusePk:string - )=>{ + rainSttnChkSearch: async ( + rusePk: string + ) => { const rainChkRes = await getFetch( fetchType.WR, `/reuseChk/rainy/${rusePk}` ); - - return set((state: rainSttnState) =>({ + + return set((state: rainSttnState) => ({ rainSttn: { ...state.rainSttn, - rainChkRes:rainChkRes + rainChkRes: rainChkRes }, - }) ) + })) } }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx index 301cd965e..8fbe2c26d 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx @@ -28,9 +28,12 @@ export type rswtSttnState = { }; type rswtSttnActions = { - rswtSttnInit: (con: string) => void; - rswtSttnSearch: (page: number, total: string, con: string, sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => void; + rswtSttnInit: (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; + rswtSttnSearch: (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; rswtChSttnHead: ( headList: z.infer<typeof sttnHeadListType>, ) => void; @@ -54,12 +57,18 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = ( set: any ) => { return { - rswtSttnInit: async (con: string) => { + rswtSttnInit: async (page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { try { const rswtSttnRes = await getFetch( fetchType.WR, - `/reuseFc/waterreuseFc/1/20/${con}` + `/reuseFc/waterreuseFc` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") ); set((state: rswtSttnState) => { return { @@ -75,13 +84,18 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = ( console.log(e) } }, - rswtSttnSearch: async (page: number, total: string, con: string, + rswtSttnSearch: async (page: number, total: string, con: string, txt: string, sidoCode: SelectDataType[], sggCode: SelectDataType[]) => { try { + console.log("헐", page) const rswtSttnRes = await getFetch( fetchType.WR, - `/reuseFc/waterreuseFc/${page}/${total}/${con}` + `/reuseFc/waterreuseFc` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") ); if (Number(total) > 9000) { const rswtExcel = excelRSwtSttnParsing(rswtSttnRes, sidoCode, sggCode); diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index dbb3aa7a6..8bed17187 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -2,6 +2,7 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui"; +import { useEffect } from "react"; export const rainChkTableData = (chkData: rainChkZodType[]) => { // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 @@ -54,27 +55,32 @@ export const rainChkTableData = (chkData: rainChkZodType[]) => { export const rswtChkTableData = (chkData: rswtChkZodType[]) => { // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 const makeRswtData: any[] = []; - chkData.forEach((root) => { - root.rswtrDetails.forEach((detail) => { - let flatRswtChk = {}; - const findGuide = root.guideDetails.find( - (guide) => guide.utztnUsgCd === detail.utztnUsgCd - ); - const findPoluttion = root.rswtrPollutions.find( - (polution) => polution.utztnUsgCd === detail.utztnUsgCd - ); - const operMngCd = root?.reuseBuilding.operMngCd; - flatRswtChk = { - ...root, - ...detail, - ...findGuide, - ...findPoluttion, - ...flatRswtChk, - operMngCd: operMngCd, - }; - makeRswtData.push(flatRswtChk); + + + if(chkData&&chkData.length>0){ + + chkData?.forEach((root) => { + root.rswtrDetails.forEach((detail) => { + let flatRswtChk = {}; + const findGuide = root.guideDetails.find( + (guide) => guide.utztnUsgCd === detail.utztnUsgCd + ); + const findPoluttion = root.rswtrPollutions.find( + (polution) => polution.utztnUsgCd === detail.utztnUsgCd + ); + const operMngCd = root?.reuseBuilding.operMngCd; + flatRswtChk = { + ...root, + ...detail, + ...findGuide, + ...findPoluttion, + ...flatRswtChk, + operMngCd: operMngCd, + }; + makeRswtData.push(flatRswtChk); + }); }); - }); + } return makeRswtData; }; @@ -93,6 +99,7 @@ export const chRowspanTable = ( let order = 0 // rowspan된 셀 렌더링 여부 추적용 const renderedMap = new Map<string, Set<number>>(); + return ( <> {makeTableData.map((row, rowIndex) => ( @@ -103,6 +110,7 @@ export const chRowspanTable = ( const key = head.id; const isMerged = head.mergeCell; const value = row[key]; + // 병합 대상이면 중복 렌더링 여부 판단 if (isMerged) { const renderedSet = renderedMap.get(key) ?? new Set<number>(); @@ -152,7 +160,7 @@ export const chRowspanTable = ( onChange={(e) => { handleChange(rowIndex, head.id, e.target.value); }} - value={value ?? ""} + value={value || ""} disabled={!selectedIds.includes(row.chkgdnPk)} /> ) : ( @@ -174,8 +182,6 @@ export const chRowspanTable = ( ); }; - - export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean) => { return headList.forEach((head) => { if (head.edit !== undefined) @@ -187,63 +193,123 @@ export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean) }); } - const handleChange = ( rowIndex: number, field: any, value: string | number, - setInputData: (data:any) => void + setInputData: (data: any) => void ) => { - if(Number(value) < 0 ||! Number(value)){ - value = 0; - }else{ + if (Number(value) < 0 || !Number(value)) { + value = 0; + } else { value = Number(value); } - setInputData((prevData:any) => - prevData?.map((row:any, index: number) => { - if (index === rowIndex) { - return { - ...row, - [field ]: value, - }; - } - return row; - }) - ); + setInputData((prevData: any) => + prevData?.map((row: any, index: number) => { + if (index === rowIndex) { + return { + ...row, + [field]: value, + }; + } + return row; + }) + ); }; ; - - -export const InputTableBody = (chgRes: any[] | [] ,headList:TableUpperProps[], setInputData: (data: any[]) => void) => { - return ( +export const InputTableBody = ( + chgRes: any[] | [], + headList: TableUpperProps[], + setInputData: (data: any[]) => void +) => { + // mergeCell 처리용 + const getRowSpan = (data: any[], key: string, rowIndex: number) => { + if (rowIndex > 0 && data[rowIndex][key] === data[rowIndex - 1][key]) { + return 0; // 이전과 같으면 셀을 그리지 않음 + } + let span = 1; + for (let i = rowIndex + 1; i < data.length; i++) { + if (data[i][key] === data[rowIndex][key]) span++; + else break; + } + return span; + }; + return ( <> - {chgRes.map((data, dataIndex) => ( - <TableRow key={dataIndex + "row"}> - {headList.map((head, headIndex) => ( - <TableCell key={head.id + headIndex} className="w-36" > - {head.edit ===true && data.edit !==false? - <Input - className={`${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} !text-xl h-10 w-full`} - onChange={(e) => - handleChange(dataIndex, head.id, e.target.value,setInputData) - } - value={data[head.id as keyof any] ?? ""} - /> : ( - <div - className={` - ${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} - !text-xl w-full h-10 - `} + {chgRes.map((data, dataIndex) => { + // 소계/총합계 행 판별 + const isSubTotal = data["용수명"] === "소계"; + const isTotal = data["구분"] === 0; + + const bgClass = isTotal + ? "bg-[#d5e1eb] font-bold" + : isSubTotal + ? "bg-[#e6eef5] font-semibold" + : ""; + + return ( + <TableRow key={dataIndex + "row"}> + {headList.map((head, headIndex) => { + // 총합계 행이면 "구분"에서 colSpan=2로 병합 + if ( + data["구분"] === 0 && + head.id === "구분" + ) { + return ( + <TableCell + key={head.id + headIndex} + colSpan={2} + className="font-bold text-center bg-[#d5e1eb]" > - {data[head.id as keyof any] ?? ""} - </div> - ) + 총합계 + </TableCell> + ); + } + // 총합계(합계) 행이면 "용수명" 컬럼은 렌더링하지 않음 + if ( + data["구분"] === 0 && + head.id === "용수명" + ) { + return null; + } + // mergeCell 처리 + if (head.mergeCell) { + const rowSpan = getRowSpan(chgRes, head.id, dataIndex); + if (rowSpan === 0) return null; + return ( + <TableCell key={head.id + headIndex} rowSpan={rowSpan} className={`w-36 align-middle text-center whitespace-nowrap ${bgClass}`}> + {data[head.id as keyof any] ?? ""} + </TableCell> + ); } - </TableCell> - ))} - </TableRow> - ))} + // 기본 셀 + return head.edit === true && data.edit !== false ? ( + <TableCell key={head.id + headIndex} className={`w-36 ${bgClass}`}> + <Input + className={`${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} !text-xl h-10 w-full`} + onChange={(e) => + handleChange(dataIndex, head.id, e.target.value, setInputData) + } + value={data[head.id as keyof any] ?? ""} + /> + </TableCell> + ) : ( + <TableCell key={head.id + headIndex} className={`w-36 ${bgClass}`}> + <div + className={` + ${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} + !text-xl w-full h-10 + `} + > + {data[head.id as keyof any] ?? ""} + </div> + </TableCell> + ); + })} + </TableRow> + ); + })} </> ); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/apps/wr/components/lib/func/commom.tsx b/apps/wr/components/lib/func/commom.tsx index e5dfc8c0c..7d8c2ffcc 100644 --- a/apps/wr/components/lib/func/commom.tsx +++ b/apps/wr/components/lib/func/commom.tsx @@ -9,12 +9,22 @@ import { import type { RefObject } from "react"; export const getCity = (val: string, sggCd: SelectDataType[]) => { - const data = sggCd - .filter((item) => String(item.val).substring(0, 2) === val) + + let data:any + if(val !=='0'){ + data = sggCd + .filter((item) => String(item.val).substring(0, 2) === val) + .map((item) => ({ + val: item.val, + text: item.text, // 한국어 텍스트 + })); + }else{ + data = sggCd .map((item) => ({ val: item.val, text: item.text, // 한국어 텍스트 })); + } data.unshift({ val: "0", text: "전체" }); return data; }; @@ -103,7 +113,18 @@ export const handleCommaNumberChange = ( ) => { const raw = e.target.value.replace(/,/g, ""); if (!/^\d*$/.test(raw)) return; - onChange(raw === "" ? "" : Number(raw)); + onChange(raw === "" ? "" : Number(raw)); +}; + + +// onchange 텍스트를 숫자로 and ,제거 +export const handleMinusNumberChange = ( + e: React.ChangeEvent<HTMLInputElement>, + onChange: (value: number | "") => void +) => { + const raw = e.target.value.replace(/,/g, ""); + if (!/^\d*$/.test(raw)) return; + onChange(raw === "" ? -1 : Number(raw)); }; // 숫자입력시 , 삽입 @@ -144,18 +165,30 @@ export const yearOptions: { val: string; text: string }[] = Array.from( }) ); -export const getdmdMatFlag = (flag: string|undefined) => { - let flagMat = ""; +export const getdmdMatFlag = (flag: string | undefined | null) => { + const cleanFlag = (flag ?? "").trim(); - if(flag === undefined || flag === null) { - flagMat = "신청"; - }else if(flag.trim() === "Sub") { - flagMat = "검토"; - }else if(flag.trim() === "matched") { - flagMat = "매칭완료"; - }else { - flagMat = "신청"; + switch (cleanFlag) { + case "Sub": + return "검토"; + case "Matched": + return "매칭완료"; + case "Checked": + return '검토완료'; + default: + return "신청"; } - return flagMat; }; + + +export const formatPhoneNumber=(tel:string) => { + const onlyNums = tel.replace(/[^0-9]/g, ''); + if (onlyNums.length === 10) { + return onlyNums.replace(/(\d{2})(\d{4})(\d{4})/, '$1-$2-$3'); + } else if (onlyNums.length === 11) { + return onlyNums.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3'); + } else { + return tel; // 유효하지 않으면 빈 문자열 + } +} \ No newline at end of file diff --git a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx index b22f9474e..bb70cb7ec 100644 --- a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx +++ b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx @@ -22,8 +22,7 @@ import { UiTable, } from "@common/business_components/ui"; import PopoverUi from "@common/business_components/ui/popover_ui"; -import { Button, Input, Label } from "@common/components/ui"; -import type { read } from "fs"; +import { Button, Checkbox, Input, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; import { type UseFormReturn } from "react-hook-form"; import toast from "react-hot-toast"; @@ -31,9 +30,11 @@ import toast from "react-hot-toast"; export default function ConCostForm({ form, type, + selectionVersion, }: { form: UseFormReturn<DmdCoReqType>; type: string; + selectionVersion: number; }) { const { constCostRes, @@ -46,6 +47,8 @@ export default function ConCostForm({ const ref = useRef<boolean>(false); + const [checkFinish, setCheckFinish] = useState<boolean>(false); + useEffect(() => { if (!ref.current) { const currentYear = new Date().getFullYear(); @@ -55,6 +58,13 @@ export default function ConCostForm({ } }, [ref, getConstCostFee, getRateFee]); + + useEffect(() => { + // 다른 행을 선택하면(selectionVersion 변경) 체크박스 상태를 초기화합니다. + setCheckFinish(false); + }, [selectionVersion]); + + const zipDowonLoad = () => { fetch(`/2024_constarctFeeProgram.zip`, {}).then(async (response) => { const blobRet = await response.blob(); @@ -70,26 +80,40 @@ export default function ConCostForm({ const dmndQtyWatch = form.watch("dmndQty"); const totalConstCost = form.watch("totalConstCost"); const cstrnCst = form.watch("demandCst.cstrnCst"); + const useUsgCdWatch = form.watch("useUsgCd"); const calculateConstCost = useCallback(() => { const usgPrcsProcs = usgPrcsProcsWatch; + if (!dmndQtyWatch) { + toast.error("요구수량(M3/d)을 확인해주세요 계산할수 없습니다. "); + return; + } + if (usgPrcsProcs === null || usgPrcsProcs === undefined) { + toast.error( + "용도에 따른 처리공정을 확인할수 없습니다. 용도를 확인해주세요. " + ); + return; + } + const dmndQtyYear = dmndQtyWatch * 365; if (usgPrcsProcs && usgPrcsProcs?.length > 0) { - const firstProc = getConstFctCode(usgPrcsProcs?.split("+")[0] || "") || ""; - const secondProc = getConstFctCode(usgPrcsProcs?.split("+")[1] || "") || ""; + const firstProc = + getConstFctCode(usgPrcsProcs?.split("+")[0] || "") || ""; + const secondProc = + getConstFctCode(usgPrcsProcs?.split("+")[1] || "") || ""; const { lower: firstLower, upper: firstUpper } = findBounds( constCostRes, firstProc || "", - 'fctCd', - 'fctCpc', + "fctCd", + "fctCpc", Number(dmndQtyYear) ); const { lower: secondLower, upper: secondUpper } = findBounds( constCostRes, secondProc || "", - 'fctCd', - 'fctCpc', + "fctCd", + "fctCpc", Number(dmndQtyYear) ); @@ -108,48 +132,62 @@ export default function ConCostForm({ const groupCodes = ["BD", "CE", "SE", "WD"]; const groupedBounds: { [key: string]: { lower?: any; upper?: any } } = {}; for (const code of groupCodes) { - - groupedBounds[code] = findBounds(rateFeeRes, code, 'incExpCd', 'stdCost',result); + groupedBounds[code] = findBounds( + rateFeeRes, + code, + "incExpCd", + "stdCost", + result + ); } const resultRate = transformAndInterpolate(groupedBounds, result); - const fcltSbsdCstrnCst = (result* (resultRate.BD + resultRate.CE + resultRate.SE + resultRate.WD) / 100); + const fcltSbsdCstrnCst = + (result * + (resultRate.BD + resultRate.CE + resultRate.SE + resultRate.WD)) / + 100; const realResult = result + fcltSbsdCstrnCst; - form.setValue("demandCst.prcsFcltCpctCstrnCst", Math.round(result) ); - form.setValue("demandCst.fcltSbsdCstrnCst", Math.round(fcltSbsdCstrnCst)) ; - form.setValue("totalConstCost", Math.round(realResult)); + form.setValue("demandCst.prcsFcltCpctCstrnCst", Math.round(result)); + form.setValue("demandCst.fcltSbsdCstrnCst", Math.round(fcltSbsdCstrnCst)); + form.setValue("totalConstCost", Math.round(realResult)); } }, [constCostRes, rateFeeRes, usgPrcsProcsWatch, dmndQtyWatch]); const onSubmit = (value: DmdCoReqType) => { - - if( !form.getValues('demandCst.prcsFcltCpctCstrnCst') ){ - toast.error('공사비 계산 진행 후 저장을 눌러주새요') - return + if (value.demandCst && !value.demandCst.prcsFcltCpctCstrnCst) { + toast.error("공사비 계산 진행 후 저장을 눌러주새요"); + return; } if (type === "mat") { - const data: DedMatUpdateType = { - dmdInfoSn: form.getValues("dmdInfoSn"), - usgPrcsProcs: form.getValues("demandCst.usgPrcsProcs"), - cstrnCst: form.getValues("demandCst.cstrnCst"), - fcltSbsdCstrnCst: form.getValues("demandCst.fcltSbsdCstrnCst"), - prcsFcltCpctCstrnCst: form.getValues("demandCst.prcsFcltCpctCstrnCst"), - rgtr: TEST_UUID, - }; - coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoFk"), data); + if (value.demandCst) { + const data: DedMatUpdateType = { + dmdInfoSn: value.dmdInfoSn, + usgPrcsProcs: value.demandCst.usgPrcsProcs || "", + cstrnCst: value.demandCst.cstrnCst || 0, + fcltSbsdCstrnCst: value.demandCst.fcltSbsdCstrnCst || 0, + prcsFcltCpctCstrnCst: value.demandCst.prcsFcltCpctCstrnCst || 0, + flg: checkFinish?'Checked':'Sub', + rgtr: TEST_UUID, + }; + coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoFk"), data); + } } else if (type === "hist") { - - delete value.totalConstCost - delete value.ruseUtztnFcltNm - + delete value.totalConstCost; + delete value.ruseUtztnFcltNm; ruseRvwCalUpdate(value); } }; useEffect(() => { - console.log(" form ", form.formState.errors); + console.log(" form ", form.formState.errors); }, [form.formState]); + useEffect(() => { + form.register("dmdInfoSn"); + form.register("dmdInfoFk"); + form.register("ruseUtztnFcltNm"); + }, []); + return ( <> <hr className="mt-8" /> @@ -163,18 +201,30 @@ export default function ConCostForm({ <Button className="mx-3" size={"sm"} onClick={calculateConstCost}> 계산 </Button> - <Button className="mr-3" size={"sm"} onClick={form.handleSubmit(onSubmit)}> + <Button + className="mr-3" + size={"sm"} + onClick={form.handleSubmit(onSubmit)} + > 저장 </Button> - <Label>관로 표준공사비 산정 프로그램</Label> - <Button - color="green" - size={"sm"} - onClick={zipDowonLoad} - className="bg-none ml-6" - > - 다운로드 - </Button> + <Label>검토완료</Label> + <Checkbox + className="ml-3 mr-6" + checked={checkFinish} + onCheckedChange={(checked) => + // 'indeterminate' 상태를 무시하고 순수 boolean 값으로만 상태를 업데이트합니다. + setCheckFinish(checked === true)} + ></Checkbox> + <Label>관로 표준공사비 산정 프로그램</Label> + <Button + color="green" + size={"sm"} + onClick={zipDowonLoad} + className="bg-none ml-6" + > + 다운로드 + </Button> </div> <div className="col-span-12 w-full"> <h1 className={formH1Class}>기본사항</h1> @@ -255,7 +305,7 @@ export default function ConCostForm({ placeholder="" type="text" onChange={field.onChange} - value={form.getValues("demandCst.usgPrcsProcs") ?? ""} + value={field.value ?? ""} className="mt-2" /> </FormUi> @@ -285,13 +335,15 @@ export default function ConCostForm({ <div className="col-span-12 w-full"> <h1 className={formH1Class}>공사비 입력사항</h1> </div> - <div className="col-span-3 mt-4"> + + <div className="col-span-2 mt-4"> <div className="flex items-center justify-between"> <PopoverUi childrenTriger={ <> <Label className="underline"> - 처리시설용량에 따른 공사비(백만원) <i className="diveicon di-search" /> + 처리시설용량에 따른 공사비(백만원){" "} + <i className="diveicon di-search" /> </Label> </> } @@ -324,7 +376,7 @@ export default function ConCostForm({ )} /> </div> - <div className="col-span-3 mt-4"> + <div className="col-span-2 mt-4"> <div className="flex items-center justify-between"> <PopoverUi childrenTriger={ @@ -363,12 +415,13 @@ export default function ConCostForm({ )} /> </div> - <div className="col-span-3 mt-4"> + <div className="col-span-2 mt-4"> <PopoverUi childrenTriger={ <> <Label className="underline"> - 총사업비 (백만원) <i className="diveicon di-search" /> + 처리시설 총사업비(백만원){" "} + <i className="diveicon di-search" /> </Label> </> } @@ -405,7 +458,7 @@ export default function ConCostForm({ )} /> </div> - <div className="col-span-3 mt-4"> + {/* <div className="col-span-3 mt-4"> <div className="flex items-center justify-between"> <Label>공급처 선정</Label> <Button size={"sm"} onClick={(e) => {}} className="bg-none"> @@ -428,8 +481,8 @@ export default function ConCostForm({ </FormUi> )} /> - </div> - <div className="col-span-4 mt-4"> + </div> */} + <div className="col-span-3 mt-4"> <FormField control={form.control} name="demandCst.cstrnCst" @@ -448,7 +501,7 @@ export default function ConCostForm({ )} /> </div> - <div className="col-span-4 mt-4 mb-3"> + <div className="col-span-3 mt-4 mb-3"> <Label className="text-xl"> 처리시설 + 공급관로 총사업비(백만원) </Label> diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx index 0d00454e2..31e8dbacb 100644 --- a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx @@ -16,11 +16,10 @@ import { type SelectDataType, } from "@common/business_components"; import { Button, Checkbox, Input } from "@common/components"; -import { Check } from "lucide-react"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; import { useFieldArray } from "react-hook-form"; -export default function BdstReg({ form }: { form: any }) { +export default function BdstReg({ form, type }: { form: any; type?: string }) { const { code } = useWrStore((state) => { return state; }); @@ -37,23 +36,16 @@ export default function BdstReg({ form }: { form: any }) { bdstUsgCd: "", }); }; -// 잠깐 주석처리 - // const removeLastItem = () => { - // if (fields.length > 0) { - // remove(fields.length - 1); - // } - // }; const removeSelected = () => { - const idxsToRemove = fields - .map((item, idx) => selectedIds.includes(item.id) ? idx : -1) - .filter(index => index > -1) - .sort((prevIndex, nextIndex) => nextIndex - prevIndex); + const idxsToRemove = fields + .map((item, idx) => (selectedIds.includes(item.id) ? idx : -1)) + .filter((index) => index > -1) + .sort((prevIndex, nextIndex) => nextIndex - prevIndex); remove(idxsToRemove); setSelectedIds([]); }; - const [selectSgg, setSelectSgg] = useState<SelectDataType[] | undefined>(); const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", @@ -90,18 +82,14 @@ export default function BdstReg({ form }: { form: any }) { const [selectedIds, setSelectedIds] = useState<string[]>([]); const toggleSelect = (id: string) => { - setSelectedIds(prev => - prev.includes(id) - ? prev.filter(x => x !== id) - : [...prev, id] + setSelectedIds((prev) => + prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id] ); }; return ( <> - <h1 className={formH1Class}> - 건축물 시설 정보 - </h1> + <h1 className={formH1Class}> { type !== "HTB"?"건축물 기본 정보": '발전소 기본 정보'}</h1> <div className="grid grid-cols-6 gap-2 mt-4"> <div className="col-span-3"> <FormField @@ -152,10 +140,10 @@ export default function BdstReg({ form }: { form: any }) { control={form.control} name="bdstNm" render={({ field }) => ( - <FormUi label="건축물명"> + <FormUi label={ type !== "HTB"?"건축물명": '발전소명'}> <Input className={selectClass} - placeholder="1,000,000" + placeholder= {type !== "HTB"?"건축물 명 입력하세요":'발전소명 입력하세요' } type="text" {...field} /> @@ -168,10 +156,10 @@ export default function BdstReg({ form }: { form: any }) { control={form.control} name="daddr" render={({ field }) => ( - <FormUi label="위치"> + <FormUi label= { type !== "HTB"?"건축물 주소": '발전소 주소'} > <Input className={selectClass} - placeholder="" + placeholder="위치를 입력해주세요" type="search" {...field} /> @@ -179,162 +167,176 @@ export default function BdstReg({ form }: { form: any }) { )} /> </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.bdstUsgCd" - render={({ field }) => ( - <FormUi label="건축물용도"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstUsgCd} - onSelectValue={(val) => { - field.onChange(Number(val)); - }} - value={field.value??code.bdstUsgCd[0]?.val} - /> - </FormUi> - )} - /> - </div> + <div className="col-span-2"> <FormField control={form.control} name="frstArchPrmsnDt" render={({ field }) => ( - <FormUi label="최초건축허가일"> + <FormUi label= { type !== "HTB"?"최초건축허가일": '준공년도'} > <DatePicker mode={"single"} field={{ - value: field.value?? new Date(), + value: field.value ?? new Date(), onChange: (date: Date | undefined) => field.onChange(date), }} - selectClass={'w-full'} + selectClass={"w-full"} ></DatePicker> </FormUi> )} /> </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="archArea" - render={({ field }) => ( - <FormUi label="건축면적(m³)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.lawTrgtYn" - render={({ field }) => ( - <FormUi label="법정의무대상여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.yn} - onSelectValue={(val) => { - field.onChange(val); - }} - value={field.value??code.yn[0]?.val } - /> - </FormUi> - )} - /> - </div> </div> - <h1 className={formH1Class}> - 중축, 개축, 재축 - </h1> - <div className="flex justify-end gap-2 mt-4"> - <Button type="button" className="" size={"sm"} onClick={plusHist}> - 이력추가 - </Button> - <Button - type="button" - className="!bg-red-500 text-white" - size={"sm"} - onClick={removeSelected} - > - 삭제 - </Button> - </div> - {fields.map((field, index) => ( - <div key={field.id} className="grid grid-cols-[auto,1fr,1fr,1fr] gap-2 mt-4 items-center"> - <div className="col-span-1 flex justify-center mr-4"> - <Checkbox - checked={selectedIds.includes(field.id)} - onCheckedChange={() => toggleSelect(field.id)} - /> - </div> - <div className=""> - <FormField - control={form.control} - name={`chgBuilding.${index}.bdstChgNm`} - render={({ field: f }) => ( - <FormUi label="구분"> - <SelectBox - selectClass={selectClass} - selectArray={code.chBuCd} - onSelectValue={val => f.onChange(val)} - value={f.value ?? code.chBuCd[0]?.val} className={""} label={""} /> - </FormUi> - )} - /> - </div> - <div className=""> - <FormField - control={form.control} - name={`chgBuilding.${index}.archChgPrmsnDt`} - render={({ field: f }) => ( - <FormUi label="허가일"> - <DatePicker - mode="single" - field={{ - value: safeDate(f.value) || new Date(), - onChange: (date) => f.onChange(date), - }} - selectClass="w-full" + {type !== "HTB" ? ( + <> + <div className="grid grid-cols-6 gap-2 mt-4 "> + <div className="col-span-2"> + <FormField + control={form.control} + name="reuseBuilding.0.bdstUsgCd" + render={({ field }) => ( + <FormUi label="건축물용도"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstUsgCd} + onSelectValue={(val) => { + field.onChange(Number(val)); + }} + value={field.value ?? code.bdstUsgCd[0]?.val} + /> + </FormUi> + )} + /> + </div> + + <div className="col-span-2"> + <FormField + control={form.control} + name="archArea" + render={({ field }) => ( + <FormUi label="건축면적(m³)"> + <Input + className={selectClass} + placeholder="면적을 입력하세요" + type="text" + onChange={(e) => { + field.onChange(e.target.value) + }} + value={field.value} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="reuseBuilding.0.lawTrgtYn" + render={({ field }) => ( + <FormUi label="법정의무대상여부"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.yn} + onSelectValue={(val) => { + field.onChange(val); + }} + value={field.value ?? code.yn[0]?.val} + /> + </FormUi> + )} + /> + </div> + </div> + <h1 className={formH1Class}>중축, 개축, 재축</h1> + <div className="flex justify-end gap-2 mt-4"> + <Button type="button" className="" size={"sm"} onClick={plusHist}> + 이력추가 + </Button> + <Button + type="button" + className="!bg-red-500 text-white" + size={"sm"} + onClick={removeSelected} + > + 삭제 + </Button> + </div> + {fields.map((field, index) => ( + <div + key={field.id} + className="grid grid-cols-[auto,1fr,1fr,1fr] gap-2 mt-4 items-center" + > + <div className="col-span-1 flex justify-center mr-4"> + <Checkbox + checked={selectedIds.includes(field.id)} + onCheckedChange={() => toggleSelect(field.id)} /> - </FormUi> - )} - /> - </div> - <div className=""> - <FormField - control={form.control} - name={`chgBuilding.${index}.archChgArea`} - render={({ field: f }) => ( - <FormUi label="면적"> - <Input - placeholder="-" - type="text" - onChange={e => handleCommaNumberChange(e, f.onChange)} - value={formatCommaNumber(f.value)} - className={selectClass} + </div> + <div className=""> + <FormField + control={form.control} + name={`chgBuilding.${index}.bdstChgNm`} + render={({ field: f }) => ( + <FormUi label="구분"> + <SelectBox + selectClass={selectClass} + selectArray={code.chBuCd} + onSelectValue={(val) => f.onChange(val)} + value={f.value ?? code.chBuCd[0]?.val} + className={""} + label={""} + /> + </FormUi> + )} /> - </FormUi> - )} - /> - </div> - </div> - ))} - <div className="border-b border-gray-300 my-4"> </div> + </div> + <div className=""> + <FormField + control={form.control} + name={`chgBuilding.${index}.archChgPrmsnDt`} + render={({ field: f }) => ( + <FormUi label="허가일"> + <DatePicker + mode="single" + field={{ + value: safeDate(f.value) || new Date(), + onChange: (date) => f.onChange(date), + }} + selectClass="w-full" + /> + </FormUi> + )} + /> + </div> + <div className=""> + <FormField + control={form.control} + name={`chgBuilding.${index}.archChgArea`} + render={({ field: f }) => ( + <FormUi label="면적"> + <Input + placeholder="-" + type="text" + onChange={(e) => f.onChange} + value={f.value} + className={selectClass} + /> + </FormUi> + )} + /> + </div> + </div> + ))} + <div className="border-b border-gray-300 my-4"> </div> + </> + ) : ( + <></> + )} </> ); } diff --git a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx index 70e62eb7f..83051672d 100644 --- a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx @@ -23,15 +23,18 @@ import { handleCommaNumberChange, } from "@/components/lib/func/commom"; import { formH1Class } from "@/components/lib/class/comClass"; +import toast from "react-hot-toast"; export default function HtdflRegForm({ htdflForm, isModal, - readonly = false + readonly = false, + setIsModal, }: { htdflForm: customHtdflBdst; isModal: boolean; readonly?: boolean; + setIsModal?: (modal: boolean) => void; }) { const { code, htdflBdstUpdate, htdflBdstReg } = useWrStore((state) => state); @@ -41,16 +44,24 @@ export default function HtdflRegForm({ resolver: zodResolver(hdtflZod), defaultValues: defaultValues, }); + const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]); const onSubmit = (values: z.infer<typeof hdtflZod>) => { if (isModal) { - htdflBdstReg(values, '41'); + const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd"; + + if (data === "noCd") { + toast.error("시도/시군구 코드를 선택해야합니다."); + return; + } + htdflBdstReg(values,data); + if (setIsModal) setIsModal(false); } else { - htdflBdstUpdate(values, '41'); + + htdflBdstUpdate(values, "41"); } }; - const cleanHtdflData = (raw: any): z.infer<typeof hdtflZod> => { return { ...raw, @@ -80,9 +91,31 @@ export default function HtdflRegForm({ console.log("form errors:", form.formState.errors); }, [form.formState.errors]); + // form.reset은 비동기로 동작할 수 있어, useEffect 하나로 관리하여 의도치 않은 초기화를 방지합니다. useEffect(() => { - if (hdtflZod) form.reset(cleanHtdflData(htdflForm)); - }, [htdflForm]); + // Case 1: 수정 또는 '복사하여 등록' 등 데이터가 주입되는 경우 + if (htdflForm && Object.keys(htdflForm).length > 0) { + form.reset(cleanHtdflData(htdflForm)); + } + // Case 2: 데이터가 없는 순수 신규 등록 모드인 경우 + if(isModal) { + const firstYnValue = code.yn?.[0]?.val; + const firstHtdPowerMthdCd = code.htdPowerMthdCd?.[0]?.val; + const firstHtdUtztnUsgCd = code.htdUtztnUsgCd?.[0]?.val; + + if (firstHtdPowerMthdCd) { + form.setValue('reuseBuilding.0.htdflObj.etgtType', firstHtdPowerMthdCd, { shouldDirty: true }); + } + if (firstYnValue) { + form.setValue('reuseBuilding.0.htdflObj.plwtYn', firstYnValue as "Y" | "N", { shouldDirty: true }); + form.setValue('reuseBuilding.0.htdflObj.prcsProcsYn', firstYnValue as "Y" | "N", { shouldDirty: true }); + form.setValue('reuseBuilding.0.htdflObj.fmYn', firstYnValue as "Y" | "N", { shouldDirty: true }); + } + if (firstHtdUtztnUsgCd) { + form.setValue('reuseBuilding.0.htdflObj.utztnUsg', firstHtdUtztnUsgCd, { shouldDirty: true }); + } + } + }, [htdflForm, code, form]); return ( <div className="!mx-[1.6rem] !p-0r"> @@ -91,20 +124,30 @@ export default function HtdflRegForm({ {/* <div className="flex justify-between items-center mx-3"> */} <div> <div className="grid grid-cols-12 flex items-center card-header"> - <h1 className="text-2xl font-medium text-label col-span-10">온배수 시설 정보</h1> + <h1 className="text-2xl font-medium text-label col-span-10"> + 온배수 시설 등록 + </h1> {!readonly && ( - <Button type="submit" className="col-start-12 col-span-1" size={"sm"}> + <Button + type="submit" + className="col-start-12 col-span-1" + size={"sm"} + > 저장 </Button> )} </div> </div> - {isModal && htdflForm != undefined ? <BdstReg form={form} /> : <></>} + {isModal && htdflForm != undefined ? ( + <BdstReg form={form} type="HTB" /> + ) : ( + <></> + )} {isModal ? ( - <h1 className="text-xl col-span-10 mt-4"> - 온배수 시설 정보{" "} - </h1> + <div className=" my-4"> + <h1 className={formH1Class}>온배수 시설 정보 </h1> + </div> ) : ( <></> )} @@ -115,15 +158,14 @@ export default function HtdflRegForm({ control={form.control} name="reuseBuilding.0.htdflObj.etgtType" render={({ field }) => ( - <FormUi label="발전유형(코드정비후 수정)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" + <FormUi label="발전유형"> + <SelectBox + className={""} + label={""} + selectClass={selectClass} + selectArray={code.htdPowerMthdCd} + onSelectValue={readonly ? () => {} : field.onChange} value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e) - }} readOnly={readonly} /> </FormUi> @@ -136,13 +178,14 @@ export default function HtdflRegForm({ control={form.control} name="reuseBuilding.0.htdflObj.fclCpct" // 이름 이상함. render={({ field }) => ( - <FormUi label="설비용량"> + <FormUi label="설비용량(KW)"> <Input className={selectClass} placeholder="1,000,000" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -162,8 +205,8 @@ export default function HtdflRegForm({ label={""} selectClass={selectClass} selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} - value={field.value ?? code.yn[0]?.val} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value ?? ""} readOnly={readonly} /> </FormUi> @@ -172,9 +215,7 @@ export default function HtdflRegForm({ </div> </div> <div className=" my-4"> - <h1 className={formH1Class}> - 온배수 시설 운영현황 - </h1> + <h1 className={formH1Class}>온배수 시설 운영현황</h1> </div> <div className="grid grid-cols-10 gap-1 mt-4"> @@ -183,14 +224,14 @@ export default function HtdflRegForm({ control={form.control} name="reuseBuilding.0.htdflObj.orgwtWtritSpt" render={({ field }) => ( - <FormUi label="원수취수 지점(코드정비후 수정)"> + <FormUi label="원수취수 지점"> <Input className={selectClass} - placeholder="1,000,000" + placeholder="" type="text" - value={field.value ?? 0} + value={field.value ?? ''} onChange={(e) => { - if (!readonly) field.onChange(Number(e.target.value)); + if (!readonly) field.onChange((e.target.value)); }} readOnly={readonly} /> @@ -206,11 +247,11 @@ export default function HtdflRegForm({ <FormUi label="원수발생 공정"> <Input className={selectClass} - placeholder="1,000,000" - type="" + placeholder="" + type="text" value={field.value ?? ""} onChange={(e) => { - if (!readonly) field.onChange + if (!readonly) field.onChange(e.target.value); }} readOnly={readonly} /> @@ -223,13 +264,35 @@ export default function HtdflRegForm({ control={form.control} name="reuseBuilding.0.htdflObj.wtritEntrcTp" render={({ field }) => ( - <FormUi label="취수구 온도"> + <FormUi label="취수구 온도(℃)"> <Input className={selectClass} placeholder="1,000,000" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.emsnExitTp" + render={({ field }) => ( + <FormUi label="배출구 온도(℃)"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -249,7 +312,8 @@ export default function HtdflRegForm({ placeholder="1,000,000" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -263,14 +327,14 @@ export default function HtdflRegForm({ control={form.control} name="reuseBuilding.0.htdflObj.prcsProcsYn" render={({ field }) => ( - <FormUi label="처리공정"> + <FormUi label="처리공정 유무"> <SelectBox className={""} label={""} selectClass={selectClass} selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} - value={field.value ?? code.yn[0]?.val} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value ?? ""} readOnly={readonly} /> </FormUi> @@ -288,7 +352,8 @@ export default function HtdflRegForm({ placeholder="1,000,000" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -308,8 +373,8 @@ export default function HtdflRegForm({ selectClass={selectClass} label={""} selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} - value={field.value ?? code.yn[0]?.val} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value ?? ""} readOnly={readonly} /> </FormUi> @@ -327,7 +392,8 @@ export default function HtdflRegForm({ placeholder="1,000,000" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -342,14 +408,13 @@ export default function HtdflRegForm({ name="reuseBuilding.0.htdflObj.utztnUsg" render={({ field }) => ( <FormUi label="이용용도"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.htdUtztnUsgCd} + onSelectValue={readonly ? () => {} : field.onChange} value={field.value ?? ""} - onChange={() => { - if (!readonly) field.onChange - }} readOnly={readonly} /> </FormUi> @@ -359,9 +424,7 @@ export default function HtdflRegForm({ </div> <div className=" my-2"> - <h1 className={formH1Class}> - 요구수질 - </h1> + <h1 className={formH1Class}>수질</h1> </div> <div className="grid grid-cols-12 gap-4"> @@ -376,7 +439,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -397,7 +461,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -420,7 +485,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -441,7 +507,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -464,7 +531,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -485,7 +553,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -508,7 +577,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -529,7 +599,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -552,7 +623,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -573,7 +645,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -596,7 +669,8 @@ export default function HtdflRegForm({ placeholder="10" type="text" onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); + if (!readonly) + handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} readOnly={readonly} @@ -606,26 +680,6 @@ export default function HtdflRegForm({ /> </div> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.emsnExitTp" - render={({ field }) => ( - <FormUi label="배출구온도"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> </div> </form> </Form> diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx index 152441c70..a1d433f2d 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx @@ -30,7 +30,11 @@ import { Button, DataTable, Input, Label } from "@common/components"; import { useEffect, useRef, useState } from "react"; import { useFieldArray, useForm, type UseFormReturn } from "react-hook-form"; import MngRegFormDetail from "../mngReg/mngRegFormDetail/mngRegFormDetail"; -import { safeDate } from "@/components/lib/func/commom"; +import { + formatCommaNumber, + handleCommaNumberChange, + safeDate, +} from "@/components/lib/func/commom"; import SearchInputText from "@/components/ui/searchInput/searchInput"; import SdmInsertForm from "@common/business_components/ui/sdmInsertForm"; import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; @@ -82,54 +86,55 @@ export function PbnstBuseForm({ }>({ isMoal: false, data: {} as DemandCompType }); useEffect(() => { - const etc= isNaN(Number(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`))) + const etc = isNaN( + Number(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`)) + ); let total = (form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.gvsbs`) ?? 0) + (form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.lcep`) ?? 0) + - (form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.cusrAlotm`) ?? 0) - - if( !etc ) { - total+=Number(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`)) - } + (form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.cusrAlotm`) ?? 0); + + if (!etc) { + total += Number( + form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`) + ); + } form.setValue(`items.${indexMng}.fcBizs.${indexBiz}.totalMoney`, total); }, [ form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.gvsbs`), form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.lcep`), form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.cusrAlotm`), - form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`) + form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`), ]); + const fcOrgwts = form.watch(`items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`); - const fcOrgwts = form.watch( `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`) + useEffect(() => { + console.log("fcOrgwts", fcOrgwts); + if (fcOrgwts && fcOrgwts?.length > 0) { + const swtrmtFcltFkList = fcOrgwts?.map((item) => item.swtrmtFcltFk); - useEffect(() =>{ + console.log("swtrmtFcltFkList ", swtrmtFcltFkList); - console.log('fcOrgwts ', fcOrgwts) - if(fcOrgwts&&fcOrgwts?.length>0){ - const swtrmtFcltFkList = fcOrgwts.map((item) => item.swtrmtFcltFk); - - console.log('swtrmtFcltFkList ', swtrmtFcltFkList) - - if(swtrmtFcltFkList.length > 0){ - getFcOrgwts(swtrmtFcltFkList.filter((item): item is string => item != null), fcOrgwts?.length) + if (swtrmtFcltFkList.length > 0) { + getFcOrgwts( + swtrmtFcltFkList.filter((item): item is string => item != null), + fcOrgwts?.length + ); } } - },[fcOrgwts]) - - useEffect(() =>{ + }, [fcOrgwts]); + useEffect(() => { if (fcOrgwtsNmList && fcOrgwtsNmList.length > 0) { - console.log('fcOrgwtsNmList ', fcOrgwtsNmList) - console.log('fcOrgwts ', fcOrgwts) - fcOrgwts?.forEach((item, index) => { const orgwtNm = fcOrgwtsNmList.find( (orgwt) => orgwt.bscFctCd === item.swtrmtFcltFk )?.bscFctNm; - console.log('orgwtNm ', orgwtNm) + console.log("orgwtNm ", orgwtNm); if (orgwtNm) { form.setValue( `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts.${index}.ruseUtztnFcltNm`, @@ -137,10 +142,8 @@ export function PbnstBuseForm({ ); } }); - } - - },[fcOrgwtsNmList,fcOrgwts]) - + } + }, [fcOrgwtsNmList, fcOrgwts]); // fcBizs 데이터가 변경될 때마다 차수 선택 목록을 업데이트합니다. useEffect(() => { @@ -189,6 +192,23 @@ export function PbnstBuseForm({ name: `items.${indexMng}.fcBizs.${indexBiz}.fcDemands`, }); + const demandsContainerRef = useRef<HTMLDivElement>(null); + const prevDemandsLengthRef = useRef(fcDemands.length); + + // 수요처 추가 시 새로 추가된 항목으로 스크롤하는 효과 + useEffect(() => { + // 수요처 항목이 추가되었는지 확인 (길이가 이전보다 길어졌는지) + if (fcDemands.length > prevDemandsLengthRef.current) { + // 컨테이너의 마지막 자식 요소(새로 추가된 수요처 폼)로 부드럽게 스크롤 + demandsContainerRef.current?.lastElementChild?.scrollIntoView({ + behavior: "smooth", + block: "end", + }); + } + // 다음 렌더링을 위해 현재 길이를 ref에 저장 + prevDemandsLengthRef.current = fcDemands.length; + }, [fcDemands.length]); + const { fields: fcOrgwtFiled } = useFieldArray({ control: form.control, name: `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`, @@ -294,7 +314,6 @@ export function PbnstBuseForm({ setSumCpct(sum); }, [form.formState, indexMng, indexBiz]); - const pbnstBiz = form.watch(`items.${indexMng}.fcBizs`); return ( <> @@ -347,7 +366,7 @@ export function PbnstBuseForm({ <MngRegFormDetail key={`buziMoney-${indexMng}-${indexBiz}`} formList={businessMoneyInfo} - h1Title={"사업비"} + h1Title={"사업비(원)"} form={form} moClass="grid grid-cols-12 gap-4" sonClass="col-span-4" @@ -400,6 +419,7 @@ export function PbnstBuseForm({ </div> <RuseMngTable key={`fcOrgwts-${indexMng}-${indexBiz}`} // 이게 핵심! + tableData={ form.getValues( `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts` @@ -425,7 +445,7 @@ export function PbnstBuseForm({ <Label className="text-right">합계</Label> <Input type="text" - value={sumCpct} + value={ formatCommaNumber(sumCpct)} readOnly={true} className="w-32 border-gray-300 rounded pr-8 " /> @@ -484,7 +504,8 @@ export function PbnstBuseForm({ <MngRegFormDetail formList={ruseWaterQulityList} - h1Title={"하수처리수 재이용시설 보증수질"} + h1Title={`하수처리수 재이용시설 보증수질 `} + subTitle="※재처리시설이 있는 경우만 작성" form={form} moClass="grid grid-cols-12 gap-4" sonClass="col-span-4" @@ -504,7 +525,7 @@ export function PbnstBuseForm({ size={commonButonSize} className="mt-6 mr-3" > - 수요항목 추가 + 수요처 추가 </Button> <Button type="button" @@ -517,17 +538,14 @@ export function PbnstBuseForm({ size={commonButonSize} className="mt-6" > - 수요처 추가 + 수요처 신규등록 </Button> </div> - {( - form.getValues( - `items.${indexMng}.fcBizs.${indexBiz}.fcDemands` - ) || [] - ).map((field, index) => ( + <div ref={demandsContainerRef}> + {fcDemands.map((field, index) => ( <div - key={`fcDemands-${indexMng}-${indexBiz}=${index}`} // 이게 핵심! - className="grid grid-cols-12 gap-4 mt-3" + key={field.id} // useFieldArray의 고유 id를 key로 사용 + className="grid grid-cols-12 gap-4 mt-3 border-b border-gray-400 pb-3" > <div key={index + "keySon1"} className="col-span-4"> <FormField @@ -658,14 +676,14 @@ export function PbnstBuseForm({ control={form.control} name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyCpct`} render={({ field: f }) => ( - <FormUi label="(계약)공급량(m3/일)"> + <FormUi label="(계약)공급량(m³/일)"> <Input placeholder="" - type="number" - value={f.value ?? 0} + type="text" onChange={(e) => { - f.onChange(Number(e.target.value)); + handleCommaNumberChange(e, f.onChange); }} + value={formatCommaNumber(f.value)} /> </FormUi> )} @@ -691,9 +709,9 @@ export function PbnstBuseForm({ )} /> </div> - <br></br> </div> - ))} + ))} + </div> </div> </form> </Form> @@ -705,6 +723,9 @@ export function PbnstBuseForm({ bodyClass={"w-[70vw] max-w-none max-h-[90vh] overflow-y-auto"} body={ <FcOrgwtsRegModal + initTableData={form.getValues( + `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts` + ) ?? []} closeModal={() => { setIsFcOrgwts(false); }} diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx index 6e13058ab..234efa7c7 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx @@ -14,6 +14,7 @@ import { Input } from "@common/components/ui"; export default function MngRegFormDetail({ formList, h1Title, + subTitle, form, moClass, sonClass, @@ -22,6 +23,7 @@ export default function MngRegFormDetail({ }: { formList: formDetailType[]; h1Title?: string; + subTitle?:string form: any; moClass?: string; indexBiz?: number; @@ -33,6 +35,8 @@ export default function MngRegFormDetail({ return ( <> {h1Title ? <h1 className={formH1Class}>{h1Title}</h1> : <></>} + {subTitle ? <h3 className={'items-center'}>{subTitle}</h3> : <></>} + <div className={moClass}> {formList?.map((formHead, index) => { const fieldId = @@ -97,7 +101,7 @@ export default function MngRegFormDetail({ : [] } onSelectValue={field.onChange} - value={field.value.trim()} + value={field.value?.trim() ?? (Array.isArray(potentialOptions) && potentialOptions[0]?.val )} readOnly={formHead.option === "readOnly"} /> ); diff --git a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx index fc4ed566e..7333f6091 100644 --- a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx @@ -4,29 +4,32 @@ import { useWrStore } from "@/app/store"; import { rainZod, selectClass, - type customRainBdst + type customRainBdst, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { formH1Class, formH2Class } from "@/components/lib/class/comClass"; import { formatCommaNumber, - handleCommaNumberChange, + handleMinusNumberChange, } from "@/components/lib/func/commom"; import { DatePicker, FormUi } from "@common/business_components"; import { Form, FormField, SelectBox } from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; +import { Button, Checkbox, Input, Label } 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"; import BdstReg from "../bdstReg/bdstReg"; +import toast from "react-hot-toast"; export default function RainRegForm({ rainForm, isModal, - readonly = false + readonly = false, + setIsModal, }: { rainForm: customRainBdst; isModal: boolean; + setIsModal?: (modal: boolean) => void; readonly?: boolean; }) { const { code, rainBdstReg, rainBdstUpdate, rain } = useWrStore( @@ -38,6 +41,7 @@ export default function RainRegForm({ resolver: zodResolver(rainZod), defaultValues: defaultValues, }); + const instlCst = form.watch(`reuseBuilding.0.instlCst`); const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn] = form.watch([ "reuseBuilding.0.grntchBdstCertYn", @@ -69,7 +73,7 @@ export default function RainRegForm({ ? item?.grntchBdstCertYr : "", // null → "" instlCstSprtYn: item?.instlCstSprtYn ?? "Y", // null → "Y" - grntchBdstCertYn:item?.grntchBdstCertYn??"Y", + grntchBdstCertYn: item?.grntchBdstCertYn ?? "Y", rainyObj: { ...item?.rainyObj, filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y", @@ -79,7 +83,6 @@ export default function RainRegForm({ }; useEffect(() => { - if (grntchBdstCertYn === "N") { form.setValue("reuseBuilding.0.grntchBdstCertYr", ""); form.setValue("reuseBuilding.0.grntchBdstCertNo", ""); @@ -90,15 +93,24 @@ export default function RainRegForm({ form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctCpct", 0); form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctPrs", ""); } + + if (grntchBdstCertYn === "D") { + form.setValue("reuseBuilding.0.grntchBdstCertYr", "0000"); + form.setValue("reuseBuilding.0.grntchBdstCertNo", "확인불가"); + form.setValue("reuseBuilding.0.grntchBdstCertGrd", "확인불가"); + } else if (instlCstSprtYn === "D") { + form.setValue("reuseBuilding.0.instlCstSprtAmt", -1); + } else if (filtrTrtmfctYn === "D") { + form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctCpct", -1); + form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctPrs", "확인불가"); + } }, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn]); - - + const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]); // form 값이 변경될 때마다 로그 출력 useEffect(() => { - const subscription = form.watch((value) => { - }); + const subscription = form.watch((value) => {}); return () => subscription.unsubscribe(); }, [form]); @@ -108,7 +120,15 @@ export default function RainRegForm({ const onSubmit = (values: z.infer<typeof rainZod>) => { if (isModal) { - rainBdstReg(values, "41"); + const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd"; + + if (data === "noCd") { + toast.error("시도/시군구 코드를 선택해야합니다."); + return; + } + + rainBdstReg(values, data); + if (setIsModal) setIsModal(false); } else { rainBdstUpdate(values, "41"); } @@ -125,10 +145,14 @@ export default function RainRegForm({ <div> <div className="grid grid-cols-12 flex items-center card-header"> <h1 className="text-2xl font-medium text-label col-span-10"> - {isModal ? "건축물 운영정보" : "빗물이용시설 정보"} + {isModal ? "건축물 정보" : "빗물이용시설 정보"} </h1> {!readonly && ( - <Button type="submit" className="col-start-12 col-span-1" size={"sm"}> + <Button + type="submit" + className="col-start-12 col-span-1" + size={"sm"} + > 저장 </Button> )} @@ -142,12 +166,9 @@ export default function RainRegForm({ ) : ( <></> )} - <h1 className={formH1Class}> - 기본정보 - </h1> - - <div className="grid grid-cols-4 gap-2 mt-4"> - <div className="col-span-2"> + <h1 className={formH1Class}>기본정보</h1> + <div className="grid grid-cols-6 gap-2 mt-4"> + <div className="col-span-3"> <FormField control={form.control} name="reuseBuilding.0.instlCmptnDt" @@ -160,7 +181,8 @@ export default function RainRegForm({ field.value && !isNaN(new Date(field.value).getTime()) ? new Date(field.value) : new Date(), - onChange: (date: Date | undefined) => field.onChange(date), + onChange: (date: Date | undefined) => + field.onChange(date), }} selectClass={"w-full"} readOnly={readonly} @@ -170,48 +192,93 @@ export default function RainRegForm({ /> </div> - <div className="col-span-2"> + <div className="col-span-3"> <FormField control={form.control} - name="reuseBuilding.0.instlCst" - render={({ field }) => ( - <FormUi label="설치비"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} + name={`reuseBuilding.0.instlCst`} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="설치비(원)"> + <Input + placeholder="1,000,000" + type="text" + className={selectClass} + readOnly={readonly} + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + /> + </FormUi> + ); + }} /> </div> </div> <div className=""> - <h1 className={formH1Class}> - 빗물이용시설 정보 - </h1> + <h1 className={formH1Class}>빗물이용시설 정보</h1> </div> <div> - <h2 className={formH2Class}>집수면</h2> + <h2 className={formH2Class}>집수면 및 저류조</h2> </div> - <div className="grid grid-cols-10 gap-4 mt-4 "> - <div className="col-span-5"> + <div className="grid grid-cols-12 gap-4 mt-4 "> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rainyObj.dtfcltCpct" + render={({ field }) => { + const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="저류조 용량(m³)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + value={ + isUnknown + ? "확인불가" + : formatCommaNumber(field.value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + /> + </FormUi> + ); + }} + /> + </div> + <div className="col-span-4"> <FormField control={form.control} name="reuseBuilding.0.rainyObj.pntfColKnd" render={({ field }) => ( - <FormUi label="종류"> + <FormUi label="집수면 종류"> <SelectBox className={""} selectClass={selectClass} label={""} selectArray={rainFcltCd} - onSelectValue={readonly ? () => { } : field.onChange} + onSelectValue={readonly ? () => {} : field.onChange} value={field.value ?? rainFcltCd[0]?.val} readOnly={readonly} /> @@ -219,24 +286,39 @@ export default function RainRegForm({ )} /> </div> - <div className="col-span-5"> + <div className="col-span-4"> <FormField control={form.control} name="reuseBuilding.0.rainyObj.pntfColArea" - render={({ field }) => ( - <FormUi label="면적(m³)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <div className="flex items-center gap-2"> + <FormUi label="집수면 용량(m³)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + /> + </FormUi> + </div> + ); + }} /> </div> </div> @@ -255,8 +337,8 @@ export default function RainRegForm({ className={""} selectClass={selectClass} label={""} - selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} + selectArray={code.bdstFilterYn} + onSelectValue={readonly ? () => {} : field.onChange} value={field.value ?? code.yn[0]?.val} readOnly={readonly} /> @@ -268,47 +350,66 @@ export default function RainRegForm({ <FormField control={form.control} name="reuseBuilding.0.rainyObj.filtrTrtmfctCpct" - render={({ field }) => ( - <FormUi label="용량(m³/일)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly } - disabled={filtrTrtmfctYn !== "Y"} - /> - </FormUi> - )} + render={({ field }) => { + const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="용량(m³/일)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + value={ + isUnknown + ? "확인불가" + : formatCommaNumber(field.value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + disabled={filtrTrtmfctYn !== "Y"} + /> + </FormUi> + ); + }} /> </div> <div className="col-span-4"> <FormField control={form.control} name="reuseBuilding.0.rainyObj.filtrTrtmfctPrs" - render={({ field }) => ( - <FormUi label="처리공정"> - <Input - className={selectClass} - placeholder="" - type="text" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={readonly } - disabled={filtrTrtmfctYn !== "Y"} - /> - </FormUi> - )} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === "-"; // 또는 Number(value) === -1 + + return ( + <div className="flex items-center gap-2"> + <FormUi label="처리공정"> + <Input + className={" h-full !text-xl col-span-4"} + placeholder="처리공정 입력" + type="text" + value={field.value ?? ""} + onChange={field.onChange} + readOnly={readonly} + disabled={filtrTrtmfctYn !== "Y"} + /> + </FormUi> + </div> + ); + }} /> </div> </div> <div className=" my-2"> - <h1 className={formH1Class}> - 인센티브 정보 - </h1> + <h1 className={formH1Class}>인센티브 정보</h1> </div> <div> <h2 className={formH2Class}>설치비 지원</h2> @@ -324,8 +425,8 @@ export default function RainRegForm({ className={""} selectClass={selectClass} label={""} - selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => {} : field.onChange} value={field.value ?? code.yn[0]?.val} readOnly={readonly} /> @@ -337,24 +438,37 @@ export default function RainRegForm({ <FormField control={form.control} name="reuseBuilding.0.instlCstSprtAmt" - render={({ field }) => ( - <FormUi label="지원금액(원)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={instlCstSprtYn !== "Y"} - /> - </FormUi> - )} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="지원금액(원)"> + <Input + className={selectClass} + placeholder="" + type="text" + readOnly={readonly || isUnknown} + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + disabled={instlCstSprtYn !== "Y"} + /> + </FormUi> + ); + }} /> </div> </div> - <div> <h2 className={formH2Class}>녹색건축물 인증</h2> </div> @@ -369,8 +483,8 @@ export default function RainRegForm({ className={""} selectClass={selectClass} label={""} - selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => {} : field.onChange} value={field.value ?? code.yn[0]?.val} /> </FormUi> @@ -381,40 +495,72 @@ export default function RainRegForm({ <FormField control={form.control} name="reuseBuilding.0.grntchBdstCertYr" - render={({ field }) => ( - <FormUi label="인증년도"> - <Input - className={selectClass} - placeholder="2024" - type="" - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e); - }} - readOnly={grntchBdstCertYn !== "Y"} - /> - </FormUi> - )} + render={({ field }) => { + const isUnknown = + field.value === null || field.value === "0000"; // 또는 Number(value) === -1 + return ( + <FormUi label="인증년도"> + <Input + className={selectClass} + placeholder="2024" + type="" + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + value={isUnknown ? "확인불가" : (field.value ?? "")} + onChange={(e) => { + if (readonly) return; + if (e.target.value === "확인불가") { + field.onChange("0000"); + } else { + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn !== "Y"} + max={4} + /> + </FormUi> + ); + }} /> </div> <div className="col-span-3 "> <FormField control={form.control} name="reuseBuilding.0.grntchBdstCertNo" - render={({ field }) => ( - <FormUi label="인증번호"> - <Input - className={selectClass} - placeholder="ab1234678" - type="" - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e); - }} - readOnly={grntchBdstCertYn !== "Y"} - /> - </FormUi> - )} + render={({ field }) => { + const isUnknown = + field.value === null || field.value === "0000"; // 또는 Number(value) === -1 + return ( + <FormUi label="인증번호"> + <Input + className={selectClass} + placeholder="ab1234678" + type="" + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + value={isUnknown ? "확인불가" : (field.value ?? "")} + onChange={(e) => { + if (readonly) return; + + if (e.target.value === "확인불가") { + field.onChange(""); + } else { + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn !== "Y"} + /> + </FormUi> + ); + }} /> </div> <div className="col-span-3"> @@ -423,15 +569,14 @@ export default function RainRegForm({ name="reuseBuilding.0.grntchBdstCertGrd" render={({ field }) => ( <FormUi label="인증등급"> - <Input - className={selectClass} - placeholder="A" - type="" - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e); - }} - readOnly={grntchBdstCertYn !== "Y"} + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstGrntchClass} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value ?? code.bdstGrntchClass[0]?.val} + readOnly={readonly} /> </FormUi> )} diff --git a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx index d820bddc1..0fbffbf59 100644 --- a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx @@ -10,6 +10,7 @@ import { formH1Class, formH2Class } from "@/components/lib/class/comClass"; import { formatCommaNumber, handleCommaNumberChange, + handleMinusNumberChange, } from "@/components/lib/func/commom"; import { DatePicker, @@ -21,7 +22,7 @@ import { import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect } from "react"; -import { useForm } from "react-hook-form"; +import { useForm, type UseFormReturn } from "react-hook-form"; import { z } from "zod"; import BdstReg from "../bdstReg/bdstReg"; @@ -29,7 +30,7 @@ export default function RswtrRegForm({ rswtForm, isModal, setIsModal, - readonly = false + readonly = false, }: { rswtForm: customRswtBdst; isModal: boolean; @@ -56,12 +57,16 @@ export default function RswtrRegForm({ const onSubmit = (values: z.infer<typeof rswtZod>) => { if (isModal) { rswtBdstReg(values, "41"); - if(setIsModal) setIsModal(false) + if (setIsModal) setIsModal(false); } else { rswtBdstUpdate(values, "41"); } }; - const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => { + + const filtrTrtmfctCpct = form.watch('reuseBuilding.0.rswtrObj.filtrTrtmfctCpct') + const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => { + + console.log('raw ', raw) return { ...raw, frstArchPrmsnDt: raw?.frstArchPrmsnDt @@ -73,21 +78,28 @@ export default function RswtrRegForm({ reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({ ...item, instlCmptnDt: item?.instlCmptnDt - ? new Date(item.instlCmptnDt) - : new Date(), // item?.instlCmptnDt가 유효하지 않으면 현재 날짜로 초기화 - operMngCd: item?.operMngCd ?? "", // null → "" - instlCstSprtYn: item?.instlCstSprtYn ?? "Y", // null → "Y" - grntchBdstCertYn:item?.grntchBdstCertYn??"Y", - rswtrObj: { + ? new Date(item.instlCmptnDt) + : new Date(), // item?.instlCmptnDt가 유효하지 않으면 현재 날짜로 초기화 + operMngCd: item?.operMngCd ?? "", // null → "" + instlCstSprtYn: item?.instlCstSprtYn || code.yn[0]?.val, // null → "Y" + grntchBdstCertYn: item?.grntchBdstCertYn|| code.yn[0]?.val, + rswtrObj: { ...item?.rswtrObj, - filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y", - + filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn || code.yn[0]?.val, + filtrTrtmfctCpct: item?.rswtrObj?.filtrTrtmfctCpct ?? null, + filtrTrtmfctProcs: item?.rswtrObj?.filtrTrtmfctProcs || code.rswtPrscCdMthdCd[0]?.val, + orgwtKndCd: item?.rswtrObj?.orgwtKndCd || code.orgwtKndCd[0]?.val, }, })), }; }; - - + // useEffect(() =>{ + // console.log(' formform ', form.watch()) + // },[form.formState]) + useEffect(() =>{ + console.log(' filtrTrtmfctCpct ', filtrTrtmfctCpct) + },[filtrTrtmfctCpct]) + useEffect(() => { console.log("form errors:", form.formState.errors); }, [form.formState.errors]); @@ -99,6 +111,16 @@ export default function RswtrRegForm({ } else if (instlCstSprtYn === "N") { form.setValue("reuseBuilding.0.instlCstSprtAmt", 0); } + + + if (grntchBdstCertYn === "D") { + form.setValue("reuseBuilding.0.grntchBdstCertYr", "0000"); + form.setValue("reuseBuilding.0.grntchBdstCertNo", "확인불가"); + form.setValue("reuseBuilding.0.grntchBdstCertGrd", "확인불가"); + } else if (instlCstSprtYn === "D") { + form.setValue("reuseBuilding.0.instlCstSprtAmt", -1); + } + }, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs, form]); useEffect(() => { @@ -116,7 +138,11 @@ export default function RswtrRegForm({ 건축물 운영정보 </h1> {!readonly && ( - <Button type="submit" className="col-start-12 col-span-1" size={"sm"}> + <Button + type="submit" + className="col-start-12 col-span-1" + size={"sm"} + > 저장 </Button> )} @@ -155,68 +181,37 @@ export default function RswtrRegForm({ )} /> </div> - <div className="col-span-2"> <FormField control={form.control} name="reuseBuilding.0.instlCst" - render={({ field }) => ( - <FormUi label="설치비"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> - <div className="grid grid-cols-4 gap-2 mt-4"> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.wtrUsqty" - render={({ field }) => ( - <FormUi label="물사용량(m³)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.oblgTrgtWtrUsqty" - render={({ field }) => ( - <FormUi label="의무대상 물사용량(m³)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="설치비"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + /> + </FormUi> + ); + }} /> </div> </div> @@ -229,20 +224,36 @@ export default function RswtrRegForm({ <FormField control={form.control} name="reuseBuilding.0.rswtrObj.filtrTrtmfctCpct" - render={({ field }) => ( - <FormUi label="처리시설 용량"> - <Input - className={selectClass} - placeholder="" - type="number" - value={field.value ?? 0} - onChange={(e) => { - if (!readonly) field.onChange(Number(e.target.value)); - }} - readOnly={readonly} - /> - </FormUi> - )} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + + return ( + <FormUi label="처리시설 용량"> + <Input + className={selectClass} + placeholder="" + type="text" + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + + console.log('value') + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + /> + </FormUi> + ); + }} /> </div> <div className="col-span-4"> @@ -256,7 +267,7 @@ export default function RswtrRegForm({ label={""} selectClass={selectClass} selectArray={code.orgwtKndCd} - onSelectValue={readonly ? () => { } : field.onChange} + onSelectValue={readonly ? () => {} : field.onChange} value={field.value ?? code.orgwtKndCd[0]?.val} readOnly={readonly} /> @@ -270,14 +281,13 @@ export default function RswtrRegForm({ name="reuseBuilding.0.rswtrObj.filtrTrtmfctProcs" render={({ field }) => ( <FormUi label="주요처리공정"> - <Input - className={selectClass} - placeholder="" - type="" - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange - }} + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.rswtPrscCdMthdCd} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value ?? code.rswtPrscCdMthdCd[0]?.val} readOnly={readonly} /> </FormUi> @@ -303,9 +313,9 @@ export default function RswtrRegForm({ className={""} selectClass={selectClass} label={""} - selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} - value={field.value ?? code.yn[0]?.val} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value ?? code.bdstIncenYn[0]?.val} readOnly={readonly} /> </FormUi> @@ -313,23 +323,37 @@ export default function RswtrRegForm({ /> </div> <div className="col-span-1"> - <FormField + <FormField control={form.control} name="reuseBuilding.0.instlCstSprtAmt" - render={({ field }) => ( - <FormUi label="지원금액(원)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={instlCstSprtYn !== "Y"} - /> - </FormUi> - )} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="지원금액(원)"> + <Input + className={selectClass} + placeholder="" + type="text" + readOnly={readonly || isUnknown} + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + disabled={instlCstSprtYn === "N"||instlCstSprtYn === "D"} + /> + </FormUi> + ); + }} /> </div> </div> @@ -348,9 +372,9 @@ export default function RswtrRegForm({ className={""} selectClass={selectClass} label={""} - selectArray={code.yn} - onSelectValue={readonly ? () => { } : field.onChange} - value={field.value ?? code.yn[0]?.val} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value || code.yn[0]?.val} readOnly={readonly} /> </FormUi> @@ -361,41 +385,75 @@ export default function RswtrRegForm({ <FormField control={form.control} name="reuseBuilding.0.grntchBdstCertYr" - render={({ field }) => ( + render={({ field }) => + { + const isUnknown = field.value === null || field.value === "0000"; // 또는 Number(value) === -1 + return ( <FormUi label="인증년도"> <Input className={selectClass} placeholder="2024" - type="text" - {...field} - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e) + type="" + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } }} - readOnly={grntchBdstCertYn !== "Y"} + value={ + isUnknown?'확인불가':field.value ?? ""} + onChange={(e) => { + if (readonly) return + if (e.target.value === '확인불가') { + field.onChange('0000'); + }else{ + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"} + max={4} /> </FormUi> - )} + )}} /> </div> <div className="col-span-3"> <FormField control={form.control} name="reuseBuilding.0.grntchBdstCertNo" - render={({ field }) => ( + render={({ field }) => + { + const isUnknown = field.value === null || field.value === "0000"; // 또는 Number(value) === -1 + return ( <FormUi label="인증번호"> <Input className={selectClass} placeholder="ab1234678" type="" - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e) + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } }} - readOnly={grntchBdstCertYn !== "Y"} + value={ + isUnknown?'확인불가':field.value ?? ""} + onChange={(e) => { + if (readonly) return + + if (e.target.value === '확인불가') { + field.onChange(''); + }else{ + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"} + + + /> </FormUi> - )} + )}} /> </div> <div className="col-span-3"> @@ -404,15 +462,14 @@ export default function RswtrRegForm({ name="reuseBuilding.0.grntchBdstCertGrd" render={({ field }) => ( <FormUi label="인증등급"> - <Input - className={selectClass} - placeholder="A" - type="" - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e) - }} - readOnly={grntchBdstCertYn !== "Y"} + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstGrntchClass} + onSelectValue={readonly ? () => {} : field.onChange} + value={field.value ?? code.bdstGrntchClass[0]?.val} + readOnly={readonly} /> </FormUi> )} diff --git a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx index 15badc59d..5aa67fd3a 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx @@ -1,41 +1,46 @@ import { useWrStore } from "@/app/store"; import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import { excelToRainChkData } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel"; -import { chkgdRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; +import { chkgdRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { excelToRswtGuideData, excelToRswtPolution, } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { filePicked, filePickedArray, - FileUpload, Form, FormField, FormUi, SelectBox, Title, } from "@common/business_components/ui"; +import { Card } from "@common/business_components/ui/chart/lib/card"; 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 from "react-hot-toast"; import type { z } from "zod"; -export default function ChkgdExcel({ type }: { type: string }) { - const { - rswtChkgdn, - rainChkExcelDataUPload, - rswtChkExceDataUpload, - } = useWrStore((state) => { - return state; - }); - const [files, setFiles] = useState<File[] | null>(null); +export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setIsRegExcel:(open:boolean) =>void }) { + const { rswtChkgdn, rainChkExcelDataUPload, rswtChkExceDataUpload } = + useWrStore((state) => { + return state; + }); const [excelData, setExcelData] = useState< rswtChkZodType[] | rainChkZodType[] >(); + + const [file, setFile] = useState<File | null>(null); + + const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const selectedFile = e.target.files?.[0]; + if (selectedFile) { + setFile(selectedFile); + } + }; const [excelRswtData, setExcelRswtData] = useState<rswtChkZodType[]>(); const currentYear = new Date().getFullYear(); @@ -49,7 +54,7 @@ export default function ChkgdExcel({ type }: { type: string }) { ); const defaultValues: z.infer<typeof chkgdRegExcel> = chkgdRegExcel.parse({ - chckYr: String(currentYear) + chckYr: String(currentYear), }); const form = useForm<z.infer<typeof chkgdRegExcel>>({ @@ -58,14 +63,10 @@ export default function ChkgdExcel({ type }: { type: string }) { }); useEffect(() => { - if (files) { - const file = files[0]; + if (file) { if (form.getValues("chckYr").length < 1) { - ToastFormUi({ - body: "파일업로드 이전에 등록년도를 작성해주세요 ", - title: "지도점검 등록", - }); - setFiles(null); + toast.error("파일업로드 이전에 등록년도를 작성해주세요 "); + setFile(null); return; } if (file) @@ -87,7 +88,6 @@ export default function ChkgdExcel({ type }: { type: string }) { form.getValues("chckYr") ); - const keyGenerator = (item: rswtChkZodType) => `${item.bdstRuseFcltFk}|${item.chckYmd}|${item.utztnUsgCd}`; const totalData: rswtChkZodType[] = guideData.map((guide) => { @@ -98,12 +98,11 @@ export default function ChkgdExcel({ type }: { type: string }) { guide.utztnUsgCd === polution.utztnUsgCd ); - if (fusion) { return { ...guide, rswtrPollutions: fusion?.rswtrPollutions, - rswtrDetails:fusion?.rswtrDetails + rswtrDetails: fusion?.rswtrDetails, }; } else { return { @@ -118,19 +117,17 @@ export default function ChkgdExcel({ type }: { type: string }) { (item) => !guideKey.has(keyGenerator(item)) ); + const listTotalData: rswtChkZodType[] = [ + ...totalData, + ...onlypolution, + ]; - const listTotalData:rswtChkZodType[] =[ - ...totalData, - ...onlypolution - ] - - - setExcelRswtData(listTotalData); + setExcelRswtData(listTotalData); } }); } } - }, [files]); + }, [file]); function findMatchingItems<T>( arrayA: T[], @@ -144,34 +141,31 @@ export default function ChkgdExcel({ type }: { type: string }) { (!condition || condition(item)) && bKeySet.has(keySelector(item)) ); } - const onSubmit = (values: z.infer<typeof chkgdRegExcel>) => { if (values.chckYr === "") { - ToastFormUi({ body: "등록년도를 작성해주세요", title: "지도점검 등록" }); + toast.error("등록년도를 작성해주세요"); return; } if (type === "RNB") { if (excelData === undefined || excelData?.length === 0) { - ToastFormUi({ - body: "빈 파일 및 파일 오류 입니다.", - title: "지도점검 등록", - }); + toast.error("빈 파일 및 파일 오류 입니다."); + return; } else { - rainChkExcelDataUPload(excelData as rainChkZodType[]); + setIsRegExcel(false) } } else if (type === "RST") { if (excelRswtData === undefined || excelRswtData?.length === 0) { - ToastFormUi({ - body: "빈 파일 및 파일 오류 입니다.", - title: "중수지도점검 등록", - }); + toast.error("빈 파일 및 파일 오류 입니다."); + return; } else { rswtChkExceDataUpload(excelRswtData as rswtChkZodType[]); + setIsRegExcel(false) + } } }; @@ -223,13 +217,13 @@ export default function ChkgdExcel({ type }: { type: string }) { name="file" render={({ field }) => ( <FormUi label="점검결과 파일"> - <FileUpload - files={files || []} - setFiles={(files: File[] | null) => { - if (files) setFiles(files); - }} - fileTypes="xlsx" - ></FileUpload> + <div className="space-y-4 p-4"> + <Input + type="file" + onChange={handleFileChange} + accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" + /> + </div> </FormUi> )} /> diff --git a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx index 4e3d61008..edbd9e570 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx @@ -1,16 +1,14 @@ import { useWrStore } from "@/app/store"; -import { ScrollArea, Title } from "@common/business_components/ui"; -import { Button } from "@common/components/ui"; -import { useEffect, useState } from "react"; -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; -import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable"; +import type { TableUpperProps } from "@/app/store/common/type/header"; import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { rswtrPolutionsZode } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList"; +import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable"; +import { ScrollArea, Title } from "@common/business_components/ui"; +import { Button } from "@common/components/ui"; +import React, { useEffect, useState } from "react"; import type { z } from "zod"; -import React from "react"; -import type { TableUpperProps } from "@/app/store/common/type/header"; -export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { +export default function ChkgdModal({ type, obj, setIsModal }: { type: string; obj: any, setIsModal: (open: boolean) => void }) { const { rainChkgdn, rswtChkgdn, @@ -39,7 +37,6 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { "4": [] as z.infer<typeof rswtrPolutionsZode>[], }); - const { rainChk, ruseHeadList, splHeadList } = rainChkgdn; const [updateData, setUpdateData] = useState<splRuseWaterType[]>(); const initStats = (): z.infer<typeof rswtrPolutionsZode> => ({ @@ -97,7 +94,6 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { target = { utztnUsgCd: code, ruseTotal: 0, splTotal: 0 }; acc.push(target); } - // 월별 값 누적 target[ruseMonthKey] = (target[ruseMonthKey] ?? 0) + ruseValue; target[splMonthKey] = (target[splMonthKey] ?? 0) + splValue; @@ -106,7 +102,17 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { target.splTotal += splValue; return acc; }, []); - setGuidData(result); + + if (result) { + // '기타' 항목을 배열의 맨 뒤로 정렬합니다. + result.sort((a: splRuseWaterType, b: splRuseWaterType) => { + if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다. + if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다. + return 0; // 순서를 유지합니다. + }); + } + + setGuidData(result as splRuseWaterType[]); if (obj.rswtrPollutions) { const resultPolution: Record<string, any[]> = { @@ -159,6 +165,14 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { if (!resultPolution[nodeKey]) { resultPolution[nodeKey] = []; } + + // '기타' 항목을 배열의 맨 뒤로 정렬합니다. + resultPolution[nodeKey].sort((a: any, b: any) => { + if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다. + if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다. + return 0; // 순서를 유지합니다. + }); + resultPolution[nodeKey].push(average); }); @@ -200,12 +214,14 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { obj.guideDetails = realGuideDetail; if (type === "RNB") { rainChkGuidUpdate(obj); + setIsModal(false) } else { const polution = Object.values(upPolutionData) .flat() .filter((item) => item.utztnUsgCd !== "평균"); obj.rswtrPollutions = polution; rwstPolAndGuideUpdate([obj]); + setIsModal(false) } }; @@ -231,7 +247,8 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { </div> <div className="flex justify-between"> <h3 className="text-2xl font-bold text-gray-900 mt-2 ml-6"> - {`(${obj.bdstNm})`} + {type === "RNB" + ? `(${obj.bdstNm})` : `(${obj.building.bdstNm})`} </h3> {!rainChkSttn.isSttn ? ( <Button className="" onClick={allDataUpdate}> @@ -245,12 +262,13 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { <ScrollArea className="h-[60vh]"> <div className="card-header"> <h3 className="text-2xl font-medium text-label"> - {`연간보급수이용량`} + {`연간대체수이용량`} </h3> </div> <GuideDetailsTable chgRes={guidData || []} - headList={headList.ruseHeadList} + headList={headList.splHeadList} + upheadList={type === "RNB" ? rainChkgdn.rainSplHeadNm : rswtChkgdn.rswtSplHeadNm} type={""} setChGuidData={(data) => { setChGuidData(data); @@ -263,7 +281,8 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { </div> <GuideDetailsTable chgRes={guidData || []} - headList={headList.splHeadList} + headList={headList.ruseHeadList} + upheadList={type === "RNB" ? rainChkgdn.rainRuseHeadNm : rswtChkgdn.rswtRuseHeadNm} type={""} setChGuidData={(data) => { setChGuidData(data); @@ -285,6 +304,7 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { <GuideDetailsTable chgRes={value} headList={headList?.rswtDetailHeadList} + upheadList={rswtChkgdn.rswtSplHeadNm} type={""} setChGuidData={(data) => { getPolutionData(data); diff --git a/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx b/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx index 28dc882c3..b4b87663e 100644 --- a/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx @@ -18,12 +18,13 @@ 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 from "react-hot-toast"; import type { z } from "zod"; -export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) { +export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelData}: { data: FcPrfType ,setIsExcelOPen:(open:boolean )=>void,setModalExcelData:(excelData :PrfType)=>void }) { const { prfmnRegData } = useWrStore((state) => state); - const [files, setFiles] = useState<File[] | null>(null); + const [file, setFile] = useState<File | null>(null); const [excelData, setExcelData] = useState<PrfType[]>(); const form = useForm<z.infer<typeof pbnPrfRegExcelZod>>({ resolver: zodResolver(pbnPrfRegExcelZod), @@ -31,10 +32,20 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) { ym: String(new Date().getFullYear()), }, }); + + const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const selectedFile = e.target.files?.[0]; + if (selectedFile) { + setFile(selectedFile); + } + }; const onSubmit = (values: z.infer<typeof pbnPrfRegExcelZod>) => { if (excelData) { - prfmnRegData(excelData as unknown as PrfType); + // prfmnRegData(1,'41', excelData as unknown as PrfType); + + setModalExcelData(excelData as unknown as PrfType) + setIsExcelOPen(false) } @@ -46,111 +57,120 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) { form.setValue("pbnstRuseFcltNm", data.ruseUtztnFcltNm); }, [data]); - useEffect(() => { - console.log("excelData", excelData); - }, [excelData]); useEffect(() => { - if (files) { - const file = files[0]; + if (file) { + const isFile = file if (form.getValues("ym").length < 1) { - ToastFormUi({ - body: "파일업로드 이전에 등록년도를 작성해주세요 ", - title: "지도점검 등록", - }); - setFiles(null); + toast.error("파일업로드 이전에 등록년도를 작성해주세요 " ); + setFile(null); return; } - if (file) - filePicked(file, 0).then((res) => { + if (isFile) { + filePicked(isFile, 0).then((res) => { if (res !== undefined) - setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"),form.getValues('pbnstRuseFcltFk') ) as PrfType[]) + setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"), form.getValues('pbnstRuseFcltFk')) as PrfType[]) }); + } } - }, [files]); + }, [file]); return ( <> <div> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> - <div> + <div className="flex justify-between items-center"> <Title title={"하수재이용 실적등록"}> -
-
-

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

- -
+

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

-
+
( field.onChange(val)} /> )} /> +
+
+ ( + + + + )} + /> +
+
+ ( + + + + )} + /> +
+
+
+ ( + + {/* { + if (files) setFiles(files); + }} + fileTypes="xlsx" + maxFiles={1} - ( - - - - )} - /> - ( - - - - )} - /> - ( - - { - if (files) setFiles(files); - }} - fileTypes="xlsx" - maxFiles={1} - > - - )} - /> + + > */} + +
+ +
+
+ )} + /> +
diff --git a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx index 1be95fae6..880c789c3 100644 --- a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx +++ b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx @@ -3,25 +3,38 @@ import { btnClass } from "@/app/store/common/code" import type { customDrgt } from "@/app/store/matDmd/drgtSttn" import { drgtDetailHeadListExport } from "@/app/store/matDmd/drgtSttn/headList" -import { excelDownload } from "@/components/lib/func/commom" -import { Title, UiTable } from "@common/business_components/ui" +import { downloadExcel, Title, UiTable } from "@common/business_components/ui" import ListDiv from "@common/business_components/ui/list_div" -import { Button } from "@common/components/ui" -import { useCallback, useEffect } from "react" +import { Button, ScrollArea } from "@common/components/ui" +import { useEffect, useState } from "react" export default function DrgtDetailModal({ data, }: { data: customDrgt; }) { - const excelClick = useCallback(() => { - excelDownload( - [[]], - "우리동네가뭄", - "sample_drgtSttn.xlsx", - "A1:H1" - ); - }, []); + const [excelData, setExcelData] = useState(); + const excelClick = () => { + downloadExcel({ + data: excelData ?? [], + fileName: "우리동네가뭄 상세현황", + sheetNameArray: ["Sheet1"], + headerRange: "A1:C1" + }) + } + + useEffect(() => { + const resData = Array.isArray(data) ? data : [data]; + const exData = Array.isArray(resData) + ? resData.map((item: customDrgt) => { + return { + "년": item.year, + "월": item.month, + "가뭄상태": item.drgtState, + } + }) : []; + setExcelData(exData) + }, [data]) return ( <> @@ -43,15 +56,17 @@ export default function DrgtDetailModal({
- { }} - onPageChange={() => { }} - > + + { }} + onPageChange={() => { }} + > +
diff --git a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx index 34d46043f..89f15a3cc 100644 --- a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx +++ b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx @@ -4,9 +4,9 @@ import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; import { names } from "@/app/store/matDmd/ldrmntCoSttn/excel"; import { filePicked, FileUpload, FormUi, Title } from "@common/business_components/ui"; import { Form, FormField } from "@common/business_components/ui/form"; -import { Button } from "@common/components/ui"; +import { Button, Progress } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import type { z } from "zod"; @@ -30,20 +30,20 @@ export default function CoRegExcel() { try { let array: { [key: string]: string | number }[] = [] let isError = false; - if (Array.isArray(res)){ + if (Array.isArray(res)) { res.some((item, index) => { let object: { [key: string]: string | number } = {} Object.keys(names).some((key) => { if (item && names[key] !== undefined) { - if (key === "공장관리번호") { - item[key] = String(item[key]) - } else { - object[names[key] as string] = item[key]; - } + // if (key === "공장관리번호") { + // item[key] = String(item[key]) + // } else { + object[names[key] as string] = item[key]; + // } } return false; }) - if(isError === true) + if (isError === true) return true; array.push(object) @@ -55,8 +55,8 @@ export default function CoRegExcel() { return false; }) } - if(isError === false) - ldrmntRegData(array); + if (isError === false) + ldrmntRegData(array); } catch (e) { console.log(e) alert(e) @@ -67,7 +67,6 @@ export default function CoRegExcel() { }; } - return ( <>
@@ -87,7 +86,6 @@ export default function CoRegExcel() {
- { moType: T; + isModal:boolean; setIsModal?: (open: boolean) => void; } -export function BdstReg({ moType,setIsModal }: BdstRegProps) { +export function BdstReg({ moType,setIsModal,isModal }: BdstRegProps) { const { rain, code, bdst,findBdst } = useWrStore((state) => { return state; }); @@ -45,13 +46,13 @@ export function BdstReg({ moType,setIsModal }: BdstRegProps const getSelCity = (val: string | number) => { const cityValue = String(val); // Ensure val is treated as a string const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); - getSgg(data[0]?.val || ""); + // getSgg(data[0]?.val || ""); setObjSearch({ city: cityValue, sgg: '' }); }; const getSgg = (val: string | number) => { - console.log(val); setObjSearch({...objSearch,sgg: String(val)}) }; @@ -85,10 +86,7 @@ export function BdstReg({ moType,setIsModal }: BdstRegProps if (data) { setRainBdstForm(data); } - - } - } useEffect(()=>{ @@ -122,7 +120,12 @@ export function BdstReg({ moType,setIsModal }: BdstRegProps
-

건축물 목록

+

+ 건축물 목록 + + (유의 사항: 신규등록하려는 건축물이 목록에 없을 경우 하단 건축물 정보에 추가하여 주시기 바랍니다.) + +

({ moType,setIsModal }: BdstRegProps
{ moType === 'RNB'? - + :moType==='RST' - ? {setIsModal}}> - : + ? {setIsModal && setIsModal(open)}}> + :{setIsModal && setIsModal(open)}}> }
diff --git a/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx index 9c8f2cdd6..5b1a6f0f6 100644 --- a/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx @@ -14,13 +14,16 @@ import { Button } from "@common/business_components/ui/table/lib/button"; import { Input } from "@common/components/ui"; import { ArrowLeft, ArrowRight } from "lucide-react"; import { useEffect, useRef, useState } from "react"; +import toast from "react-hot-toast"; export default function FcOrgwtsRegModal({ onRightSet, closeModal, + initTableData, }: { onRightSet?: (rightData: fcOrgwtType[]) => void; closeModal?: (val: boolean) => void; + initTableData?: any[]; }) { const { code, pbnst, getSwtrmtFcltNm, searchFclts } = useWrStore( (state) => state @@ -31,6 +34,30 @@ export default function FcOrgwtsRegModal({ const leftRef = useRef([] as pubHasuType[]); const [rightData, setRightData] = useState(); const [inputVal, setInputVal] = useState(""); + const saveData = () => { + if (rightData && rightData?.length > 0) { + if (onRightSet) + onRightSet( + (rightData as pubHasuType[])?.map((item) => { + return { + ...item, + swtrmtFcltFk: item.bscFctCd, // 임시값, 실제 데이터에 맞게 수정 + orgwtWtritQnt: Number(item.fctCpc), // 임시값, 실제 데이터에 맞게 수정 + tmsYn: "N", // 임시값, 실제 데이터에 맞게 수정 + dschgFmYn: "N", // 임시값, 실제 데이터에 맞게 수정 + dtlPstnExpln: item.addr, // 임시값, 실제 데이터에 맞게 수정 + choose: false, // 임시값, 실제 데이터에 맞게 수정 + } + // 필요한 경우 다른 속성들도 추가 + }) as unknown as fcOrgwtType[] + ); + + closeModal?.(false) + } + else { + toast.error("취수하수처리장 목록을 선택해주세요.") + } + } useEffect(() => { if (Array.isArray(searchFclts)) { @@ -48,46 +75,62 @@ export default function FcOrgwtsRegModal({ }, [searchFclts]); useEffect(() => { if (code.sggCd.length > 0 && pbnstHasuRes.length > 0) { - setbdstTable(tableData(pbnstHasuRes, { code })); - - console.log("bdstTable ", bdstTable); + const data = pbnstHasuRes.filter((item) => !initTableData?.find((initItem) => initItem.ruseUtztnFcltNm === item.bscFctNm)) + leftRef.current?.filter((item) => !initTableData?.find((initItem) => initItem.ruseUtztnFcltNm === item.bscFctNm)); + setbdstTable(tableData(data, { code })); } - }, [code, pbnstHasuRes]); + }, [code, pbnstHasuRes, initTableData]); + useEffect(() => { - console.log("rightData ", rightData); - if (onRightSet) - onRightSet( - (rightData as pubHasuType[])?.map((item) => ({ - swtrmtFcltFk: item.bscFctCd, // 임시값, 실제 데이터에 맞게 수정 - orgwtWtritQnt: Number(item.fctCpc), // 임시값, 실제 데이터에 맞게 수정 - tmsYn: "N", // 임시값, 실제 데이터에 맞게 수정 - dschgFmYn: "N", // 임시값, 실제 데이터에 맞게 수정 - dtlPstnExpln: item.addr, // 임시값, 실제 데이터에 맞게 수정 - choose: false, // 임시값, 실제 데이터에 맞게 수정 - // 필요한 경우 다른 속성들도 추가 - })) as unknown as fcOrgwtType[] - ); - }, [rightData]); + if (initTableData && Array.isArray(initTableData)) { + setRightData(initTableData.map(item => ({ + ...item, + choose: item.choose, + sido: item.dtlPstnExpln?.split(" ")[0] || "", + gugun: item.dtlPstnExpln?.split(" ")[1] || "", + bscFctNm: item.ruseUtztnFcltNm, + addr: item.dtlPstnExpln, + orgwtWtritQnt: String(item.orgwtWtritQnt), + fctCpc: String(item.orgwtWtritQnt), + swtrmtFcltFk: item.swtrmtFcltFk, + }))); + rightRef.current = initTableData.map(item => ({ ...item })); + } + }, []); return (
- {/* <Button size="sm" onClick={() => closeModal?.(false)}>저장</Button> */} + <div className="flex items-center gap-2 mt-8"> - <Label className="text-xl text-gray-600">시설명</Label> - <Input - className="w-48 text-xl" - type="text" - value={inputVal} - onChange={(e) => setInputVal(e.target.value)} - /> - <Button size="sm" onClick={() => getSwtrmtFcltNm(inputVal)}> - 조회 - </Button> + + <Label className="text-xl text-gray-600">시설명</Label> + <Input + className="w-48 text-xl" + type="text" + value={inputVal} + onChange={(e) => setInputVal(e.target.value)} + /> + <Button size="sm" onClick={() => { + + if(inputVal){ + + getSwtrmtFcltNm(inputVal) + }else{ + const filterData = pbnstHasuRes.filter((item) => ! rightData?.find(( right) => right.bscFctNm ===item.bscFctNm)) + setbdstTable(tableData(filterData, { code })); + + } + } + + }> + 조회 + </Button> + <Button size="sm" onClick={saveData}>저장</Button> </div> </div> </div> @@ -107,10 +150,10 @@ export default function FcOrgwtsRegModal({ {/* 테이블 영역 */} <div className="flex flex-row gap-4 flex-grow p-4 overflow-x-auto"> - {/* 왼쪽 테이블 */} + {/* 왼쪽 테이블 */} - <div className="w-5/12 min-w-[400px]"> - <Label className="text-2xl text-gray-600 mb-2 block text-right"> + <div className="w-5/12 min-w-[400px]"> + <Label className="text-2xl text-gray-600 mb-2 block text-right"> 공공하수처리시설 목록 </Label> <RuseMngTable @@ -123,7 +166,7 @@ export default function FcOrgwtsRegModal({ {/* 중간 이동 버튼 */} <div className="flex flex-col justify-center items-center gap-4 w-[200px] min-w-[120px]"> - <ArrowRight + <ArrowRight onClick={() => { const checked = leftRef.current?.filter((item) => item.choose); const unchecked = leftRef.current?.filter((item) => !item.choose); @@ -159,7 +202,7 @@ export default function FcOrgwtsRegModal({ {/* 오른쪽 테이블 */} <div className="w-5/12 min-w-[400px]"> - <Label className="text-2xl text-gray-600 mb-2 block text-right"> + <Label className="text-2xl text-gray-600 mb-2 block text-right"> 취수하수처리장 목록 </Label> <RuseMngTable diff --git a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx index cc0eb80bf..846e427c6 100644 --- a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx @@ -1,6 +1,7 @@ "use client"; import { useWrStore } from "@/app/store"; import { + pbnstRegZod, type customPbnst, type PbnstRegArrrayType, type pubHasuType, @@ -16,17 +17,25 @@ import { } from "@common/components/ui"; import { useEffect, useState } from "react"; import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm"; -import { useFieldArray, type UseFormReturn } from "react-hook-form"; +import { + useFieldArray, + type FieldErrors, + type UseFormReturn, +} from "react-hook-form"; import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg"; +import toast from "react-hot-toast"; +import type { z } from "zod"; export function PbnstRegModal({ form, - setPbnstInsert + setPbnstInsert, + onInvalid }: { form: UseFormReturn<{ items: PbnstRegArrrayType }>; - setPbnstInsert: (data: customPbnst) => void + setPbnstInsert: (data: customPbnst) => void; + onInvalid:(errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>) => void }) { - const { pbnstInsert } = useWrStore((state) => { + const { pbnstInsert } = useWrStore((state) => { return state; }); const [pbnstBdstForm, setPbnstBdstForm] = useState<customPbnst>( @@ -35,15 +44,78 @@ export function PbnstRegModal({ const [currentTab, setCurrentTab] = useState<string>("mng"); const [indexMng, setIndexMng] = useState<number>(0); const [indexBiz, setIndexBiz] = useState<number>(0); - const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { - const item = valuse.items[indexMng]; - const data = item ? writeRgtrAndMdfr([item]) : []; - if (data && data[0]) { - // pbnstInsert(data[0]); - setPbnstInsert(data[0]) - } - }; + + const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { + const item = valuse.items[indexMng]; + const data = item ? writeRgtrAndMdfr([item]) : []; + if (data && data[0]) { + setPbnstInsert(data[0]); + } + }; + // const onInvalid = ( + // errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }> + // ) => { + // // 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다. + + + // const findAllErrors = ( + // errorObject: any, + // path: (string | number)[] = [] + // ): { message: string; path: (string | number)[] }[] => { + // if (!errorObject) return []; + + // return Object.keys(errorObject).flatMap((key) => { + // const value = errorObject[key]; + // const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key; + // const newPath = [...path, currentKey]; + // if (value && typeof value === "object") { + // if (typeof value.message === "string") { + // return [{ message: value.message, path: newPath }]; // 에러 메시지와 경로 반환 + // } + // return findAllErrors(value, newPath); + // } + // return []; + // }); + // }; + + + // const errorList = findAllErrors(errors); + + + // if (errorList.length > 0) { + // errorList.forEach((errorInfo) => { + // const { message, path } = errorInfo; + // let prefix = ""; + // const itemsIndex = path.indexOf("items"); + + + // if (itemsIndex > -1 && path.length > itemsIndex + 1) { + // const itemIdx = path[itemsIndex + 1] as number; + // const facilityName = form.getValues( + // `items.${itemIdx}.ruseUtztnFcltNm` + // ); + // if (facilityName) { + // prefix += `[${facilityName}] `; + // } + + // const fcBizsIndex = path.indexOf("fcBizs"); + // if (fcBizsIndex > -1 && path.length > fcBizsIndex + 1) { + // const bizIdx = path[fcBizsIndex + 1] as number; + // const cycle = form.getValues( + // `items.${itemIdx}.fcBizs.${bizIdx}.cycl` + // ); + // if (cycle) { + // prefix += `[${cycle}차수] `; + // } + // } + // } + + + // toast.error(`${prefix}${message}`); + // }); + // } + // }; const handleTabChange = (value: string) => { setCurrentTab(value); @@ -76,7 +148,7 @@ export function PbnstRegModal({ 차수별정보 </TabsTrigger> <Button - onClick={form.handleSubmit(onSubmit)} + onClick={form.handleSubmit(onSubmit, onInvalid)} size={"sm"} className="!justify-end" > diff --git a/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx b/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx index f4a3735a5..cec8babd0 100644 --- a/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx +++ b/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx @@ -13,6 +13,7 @@ import { type customPbnst, type fcBizType, } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +import { formH1Class } from "@/components/lib/class/comClass"; import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm"; import { ScrollArea, Title, UiTable } from "@common/business_components/ui"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; @@ -31,7 +32,7 @@ import { z } from "zod"; export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titleVisible?: boolean }) { const { code, pbnstSttn, prfmnc } = useWrStore((state) => state); const [fcltTab, setFcltTab] = useState<string>("fclt"); - const [ruseTab, setRuseTab] = useState<string>("inoutTotal"); + const [ruseTab, setRuseTab] = useState<string>("totalPrf"); const [ruseBizData, setRuseBizData] = useState<{ data: any[]; head: TableUpperProps[]; @@ -229,7 +230,8 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl (item) => item.pbnstRuseFcltPk === data.pbnstRuseFcltPk )?.prfList; - if (prfList) {console.log("prfList", prfList); + if (prfList) { + console.log("prfList", prfList); getTablePrfData(prfList); } @@ -243,12 +245,12 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl form.reset({ items: [data] }) } - },[data, form]) + }, [data, form]) - useEffect(()=>{ + useEffect(() => { console.log("prfData", prfData); - },[prfData]) + }, [prfData]) return ( <> <div> @@ -264,72 +266,79 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl indexMng={indexMng} setIndexMng={setIndexMng} /> - <Tabs defaultValue="fclt" onValueChange={setFcltTab}> - <TabsList className=""> - <TabsTrigger className="!text-xl" value="fclt"> - 하수처리수 재이용시설 현황 - </TabsTrigger> - <TabsTrigger className="!text-xl" value="sply"> - 재이용 원수 취수 현황 - </TabsTrigger> - <TabsTrigger className="!text-xl" value="ppi"> - 재이용 공급관로 현황 - </TabsTrigger> - <TabsTrigger className="!text-xl" value="guarantee"> - 재이용 보증수질 현황 - </TabsTrigger> - <TabsTrigger className="!text-xl" value="dmdCo"> - 재이용 수요처 현황 - </TabsTrigger> - </TabsList> - <TabsContent className="max-h-full" value={fcltTab}> - <UiTable - headName={undefined} - tableData={ruseTableData || []} - headlist={ruseHeadList || []} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - }} - children={ - fcltTab === "fclt" ? ( - <HeadMakeColSpan upHeadList={pbnstSttn.ruseFcltNodeList} /> - ) : undefined - } - ></UiTable> - </TabsContent> - </Tabs> - - <Tabs onValueChange={setRuseTab}> - <TabsList className=""> - <TabsTrigger className="!text-xl" value="totalPrf"> - 장내외합계 - </TabsTrigger> - <TabsTrigger className="!text-xl" value="inPrf"> - 장내용수 - </TabsTrigger> - <TabsTrigger className="!text-xl" value="outPrf"> - 장외용수 - </TabsTrigger> - </TabsList> - <TabsContent className="max-h-full" value={ruseTab}> - {prfData && ( + <div className="px-6"> + <div className=""> + <h1 className={formH1Class}>하수재이용시설 현황</h1> + </div> + <Tabs defaultValue="fclt" onValueChange={setFcltTab}> + <TabsList className="mt-4"> + <TabsTrigger className="!text-xl" value="fclt"> + 하수처리수 재이용시설 현황 + </TabsTrigger> + <TabsTrigger className="!text-xl" value="sply"> + 재이용 원수 취수 현황 + </TabsTrigger> + <TabsTrigger className="!text-xl" value="ppi"> + 재이용 공급관로 현황 + </TabsTrigger> + <TabsTrigger className="!text-xl" value="guarantee"> + 재이용 보증수질 현황 + </TabsTrigger> + <TabsTrigger className="!text-xl" value="dmdCo"> + 재이용 수요처 현황 + </TabsTrigger> + </TabsList> + <TabsContent className="max-h-full" value={fcltTab}> <UiTable headName={undefined} - tableData={prfData[ruseTab as keyof typeof prfData] || []} - headlist={monthHeadList || []} + tableData={ruseTableData || []} + headlist={ruseHeadList || []} pageSize={0} total={0} cellClick={undefined} onPageChange={function (page: number): void { throw new Error("Function not implemented."); }} + children={ + fcltTab === "fclt" ? ( + <HeadMakeColSpan upHeadList={pbnstSttn.ruseFcltNodeList} /> + ) : undefined + } ></UiTable> - )} - </TabsContent> - </Tabs> + </TabsContent> + </Tabs> + <div className=""> + <h1 className={formH1Class}>하수재이용실적</h1> + </div> + <Tabs defaultValue="totalPrf" onValueChange={setRuseTab}> + <TabsList className="mt-4"> + <TabsTrigger className="!text-xl" value="totalPrf"> + 장내외합계 + </TabsTrigger> + <TabsTrigger className="!text-xl" value="inPrf"> + 장내용수 + </TabsTrigger> + <TabsTrigger className="!text-xl" value="outPrf"> + 장외용수 + </TabsTrigger> + </TabsList> + <TabsContent className="max-h-full" value={ruseTab}> + {prfData && ( + <UiTable + headName={undefined} + tableData={prfData[ruseTab as keyof typeof prfData] || []} + headlist={monthHeadList || []} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }} + ></UiTable> + )} + </TabsContent> + </Tabs> + </div> </ScrollArea> </div> </> diff --git a/apps/wr/components/ui/searchInput/searchInput.tsx b/apps/wr/components/ui/searchInput/searchInput.tsx index 796c8c298..be63b9685 100644 --- a/apps/wr/components/ui/searchInput/searchInput.tsx +++ b/apps/wr/components/ui/searchInput/searchInput.tsx @@ -62,9 +62,6 @@ export default function SearchInputText({ document.removeEventListener("mousedown", handleClickOutside); }; }, []); -useEffect(() =>{ - console.log('searchList ', searchList) -},[searchList]) return ( <div ref={wrapperRef}> diff --git a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx index 94be4ebb6..627537dcb 100644 --- a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx @@ -4,6 +4,7 @@ import { useWrStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { InputTableBody } from "@/components/lib/func/TableData"; import { Input, @@ -13,16 +14,18 @@ import { TableHeader, TableRow, } from "@common/components/ui"; -import { useEffect, useState, type Dispatch, type SetStateAction } from "react"; +import { useEffect, useState, type Dispatch, type SetStateAction } from "react"; export function GuideDetailsTable({ chgRes, headList, + upheadList, type, setChGuidData, }: { chgRes: any[]; - headList: TableUpperProps[]; + headList: TableUpperProps[]; + upheadList: chHeadType[]; type: string; setChGuidData: (chgRes: any[]) => void; }) { @@ -35,21 +38,21 @@ export function GuideDetailsTable({ useEffect(() => { - setChGuidData(inputData??[] ); + setChGuidData(inputData ?? []); }, [inputData]); - + return ( <> - <div className={`card !m-[1.2rem] !p-0r `}> - <Table variant="secondary"> - <TableHeader className="font-bold">{headMakeprfmnc(headList, rainChkgdn?.rainHeadNm)}</TableHeader> - <TableBody > - {InputTableBody(inputData ?? [],headList, setInputData) } - </TableBody> - </Table> - </div> + <div className={`card !m-[1.2rem] !p-0r `}> + <Table variant="secondary"> + <TableHeader className="font-bold">{headMakeprfmnc(headList, upheadList)}</TableHeader> + <TableBody > + {InputTableBody(inputData ?? [], headList, setInputData)} + </TableBody> + </Table> + </div> </> ); } diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx index d0ad437b3..aba225687 100644 --- a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -1,15 +1,16 @@ "use client"; import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; -import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { TableUpperProps } from "@/app/store/common/type/header"; +import { rainPageSize, type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { tableData } from "@/components/lib/func/commom"; import { chRowspanTable, - headVisibleChange, rainChkTableData } from "@/components/lib/func/TableData"; +import LoadingOverlay from "@common/business_components/ui/loadingBar"; +import UiPageNations from "@common/business_components/ui/table/uiPageNations"; import { Table, TableBody, @@ -17,21 +18,27 @@ import { } from "@common/components/ui"; import { useCallback, useEffect, useState } from "react"; export default function RainChkgdTable({ - detailUp, - handleClick=() => {}, + detailUp, + handleClick = () => { }, deleteData, rainChkData, + pageNation, + onPageChange, + pageCount, }: { detailUp: (data: rainChkZodType[]) => void; - handleClick?: (data:any) => void; - deleteData:(selectedIds:number[])=>void + handleClick?: (data: any) => void; + deleteData: (selectedIds: number[]) => void rainChkData?: rainChkZodType[]; + pageNation: number; + onPageChange: (page: number) => void; + pageCount: number; }) { - const { code, rainChkgdn ,rainChkSttn,getRainSttnExcel } = useWrStore((state) => state); + const { code, rainChkgdn, rainChkSttn, getRainSttnExcel } = useWrStore((state) => state); const [makeTableData, setMakeTableData] = useState<any[]>([]); const [selectedIds, setSelectedIds] = useState<number[]>([]); const [upRaintDetail, setUpRaintDetail] = useState<rainChkZodType[]>([]); - const [headList, setHeadList] = useState< {headList:TableUpperProps[],upHeadList:chHeadType[]}>({headList:[], upHeadList:[]}); + const [headList, setHeadList] = useState<{ headList: TableUpperProps[], upHeadList: chHeadType[] }>({ headList: [], upHeadList: [] }); const toggleSelection = (pk: number, checked: boolean) => { @@ -46,30 +53,31 @@ export default function RainChkgdTable({ ) => { setMakeTableData((prev) => - prev.map((row, idx) => { - return idx === rowIndex ? { ...row, [field]: value } : row + prev.map((row, idx) => { + return idx === rowIndex ? { ...row, [field]: value } : row } ) ); }; - const handleCellClick= useCallback((index: number, headId: string) => { + const handleCellClick = useCallback((index: number, headId: string) => { if ( headId === "totalSplyUswtrUtztnQnt" || headId === "totalRuseFcltUtztnQnt" ) { - + handleClick(makeTableData[index]) } - },[makeTableData, handleClick]); + }, [makeTableData, handleClick]); useEffect(() => { setSelectedIds([])// 셀렉트 초기화를 위한 작업 - if(rainChkData){ - const rainChg = rainChkData.map((item: any) => { + if (rainChkData && rainChkData.length > 0) { + + const rainChg = rainChkData?.map((item: any) => { const bud = tableData([item.building], { code }); return { ...item, @@ -77,16 +85,19 @@ export default function RainChkgdTable({ rowspan: item.rainyDetails?.length, }; }); + setMakeTableData(rainChkTableData(rainChg)); + } else { + setMakeTableData([]); } }, [rainChkData, code]); useEffect(() => { //데이터를 평탄화 한것중에 체크박스 선택한 테이블만 선택 - + //현황 페이지에서 필요한 엑셀 데이터를 바뀔때마다 넣기 위해서 getRainSttnExcel(makeTableData); - const selectedData = makeTableData.filter((item) =>selectedIds.includes(item.chkgdnPk)); + const selectedData = makeTableData.filter((item) => selectedIds.includes(item.chkgdnPk)); if (selectedData.length > 0) { const updateTableData = rainChkgdn.rainChk @@ -101,7 +112,6 @@ export default function RainChkgdTable({ ); if (findRain != undefined) { - console.log(findRain) return { ...rd, ph: Number(findRain.ph), @@ -127,63 +137,70 @@ export default function RainChkgdTable({ } }) .filter(Boolean); - + setUpRaintDetail(updateTableData as rainChkZodType[]); } - }, [makeTableData,selectedIds]); + }, [makeTableData, selectedIds]); useEffect(() => { detailUp(upRaintDetail); }, [upRaintDetail]); - useEffect(() =>{ - if(selectedIds.length >0){ + useEffect(() => { + if (selectedIds.length > 0) { // 삭제를 위한 데이터 삽입 - deleteData(selectedIds ) + deleteData(selectedIds) } - },[selectedIds]) + }, [selectedIds]) ///현황일 경우 input 비활성화 한다. - useEffect(() => { - if(rainChkSttn.isSttn){ - + useEffect(() => { + if (rainChkSttn.isSttn) { + setHeadList({ headList: rainChkSttn.rainChkgdnHeadList, upHeadList: rainChkSttn.rainHeadNm }) - }else{ + } else { setHeadList({ headList: rainChkgdn.rainChkgdnHeadList, - upHeadList: rainChkgdn.rainHeadNm + upHeadList: rainChkgdn.rainMainHeadNm }) } - - }, [rainChkSttn.isSttn, rainChkgdn.rainChkgdnHeadList , rainChkSttn.rainChkgdnHeadList]); - + }, [rainChkSttn.isSttn, rainChkgdn.rainChkgdnHeadList, rainChkSttn.rainChkgdnHeadList]); return ( - <Table variant="secondary"> - <TableHeader className="font-bold"> - {headMakeprfmnc( - headList?.headList, - headList?.upHeadList - )} - </TableHeader> + <> + <LoadingOverlay isLoading={rainChkgdn.isLoading}></LoadingOverlay> + <Table variant="secondary"> + <TableHeader className="font-bold"> + {headMakeprfmnc( + headList?.headList, + headList?.upHeadList + )} + </TableHeader> - <TableBody> - {chRowspanTable( - makeTableData, - headList.headList, - handleChange, - toggleSelection, - selectedIds, - handleCellClick - )} - </TableBody> - </Table> + <TableBody> + {chRowspanTable( + makeTableData, + headList.headList, + handleChange, + toggleSelection, + selectedIds, + handleCellClick + )} + </TableBody> + </Table> + <UiPageNations + total={pageCount} + cur={pageNation} + pageSize={rainPageSize} + onPageChange={onPageChange} + /> + </> ); } diff --git a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx index da6cacc9a..7a43df3d8 100644 --- a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx @@ -1,35 +1,44 @@ "use client"; import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; -import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; -import type { - rswtChkZodType, - rswtrChkDetailsZodType, -} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import type { TableUpperProps } from "@/app/store/common/type/header"; +import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; +import { + rswtPageSize, + type rswtChkZodType, + type rswtrChkDetailsZodType, +} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { tableData } from "@/components/lib/func/commom"; import { chRowspanTable, rswtChkTableData, } from "@/components/lib/func/TableData"; +import LoadingOverlay from "@common/business_components/ui/loadingBar"; +import UiPageNations from "@common/business_components/ui/table/uiPageNations"; import { Table, TableBody, TableHeader } from "@common/components/ui"; import { useCallback, useEffect, useState } from "react"; export default function RswtChkgdTable({ detaiRswtlUpdate, - handleRswtClick = () => {}, + handleRswtClick = () => { }, deleteRswtData, rswtChkData, + pageNation, + onPageChange, + pageCount, }: { detaiRswtlUpdate: (data: rswtrChkDetailsZodType[]) => void; handleRswtClick?: (data: any) => void; deleteRswtData: (selectedIds: number[]) => void; rswtChkData: rswtChkZodType[]; + pageNation: number; + onPageChange: (page: number) => void; + pageCount: number; }) { - const { code, rswtChkgdn,rswtChkSttn , rswtChkgdnInit, rswtChkPolAndGuide,getRswtSttnExcel } = useWrStore( + const { code, rswtChkgdn, rswtChkSttn, rswtChkgdnInit, rswtChkPolAndGuide, getRswtSttnExcel } = useWrStore( (state) => state ); - const [headList, setHeadList] = useState< {headList:TableUpperProps[],upHeadList:chHeadType[]}>({headList:[], upHeadList:[]}); + const [headList, setHeadList] = useState<{ headList: TableUpperProps[], upHeadList: chHeadType[] }>({ headList: [], upHeadList: [] }); const [makeTableData, setMakeTableData] = useState<any[]>([]); const [selectedIds, setSelectedIds] = useState<number[]>([]); @@ -67,7 +76,6 @@ export default function RswtChkgdTable({ }, [rswtChkgdn.rswtChkPolGuide]); useEffect(() => { - console.log("makeTableData ", makeTableData) getRswtSttnExcel(makeTableData) const selectedData = makeTableData .map((item) => { @@ -111,25 +119,24 @@ export default function RswtChkgdTable({ }, [selectedIds]); ///현황일 경우 input 비활성화 한다. - useEffect(() => { - if(rswtChkSttn.isSttn){ + useEffect(() => { + if (rswtChkSttn.isSttn) { setHeadList({ headList: rswtChkSttn.rswtChkSttnHeadList, upHeadList: rswtChkSttn.rswtSttnHeadNm }) - }else{ + } else { setHeadList({ headList: rswtChkgdn.rswtChkHeadList, upHeadList: rswtChkgdn.rswtHeadNm }) } - - }, [rswtChkSttn.isSttn, rswtChkgdn.rswtChkHeadList , rswtChkSttn.rswtChkSttnHeadList]); - + }, [rswtChkSttn.isSttn, rswtChkgdn.rswtChkHeadList, rswtChkSttn.rswtChkSttnHeadList]); return ( <> + <LoadingOverlay isLoading={rswtChkgdn.isLoading}></LoadingOverlay> <Table variant="secondary"> <TableHeader className="font-bold"> {headMakeprfmnc(headList?.headList, headList?.upHeadList)} @@ -146,6 +153,12 @@ export default function RswtChkgdTable({ )} </TableBody> </Table> + <UiPageNations + total={pageCount} + cur={pageNation} + pageSize={rswtPageSize} + onPageChange={onPageChange} + /> </> ); } diff --git a/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx b/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx index acb923687..6f4832c68 100644 --- a/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx +++ b/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx @@ -3,6 +3,10 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { customPbnst as OriginalCustomPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { + formatCommaNumber, + handleCommaNumberChange, +} from "@/components/lib/func/commom"; import { DatePicker, @@ -32,12 +36,24 @@ type RuseMngTableProps = { indexMng?: number; indexBiz?: number; form?: any; - formNm?:string + formNm?: string; }; const RuseMngTableForm = React.forwardRef<any, RuseMngTableProps>( - ({ tableData, headList, upHeadList, code, onTableSet, indexMng, form,formNm,indexBiz }, ref) => { - + ( + { + tableData, + headList, + upHeadList, + code, + onTableSet, + indexMng, + form, + formNm, + indexBiz, + }, + ref + ) => { return ( <> <Table key={`table-${indexMng}-${indexBiz}`} variant="secondary"> @@ -73,26 +89,31 @@ const RuseMngTableForm = React.forwardRef<any, RuseMngTableProps>( typeof indexMng === "number" && indexMng >= 0 && typeof indexBiz === "number" && - indexBiz >= 0? - `items.${indexMng}.fcBizs.${indexBiz}.${formNm}.${i}.${head.id}`: - typeof indexMng === "number" && indexMng >= 0? - `items.${indexMng}.${formNm}.${i}.${head.id}`: - `items.${indexMng}.${formNm}.${i}.${head.id}`} + indexBiz >= 0 + ? `items.${indexMng}.fcBizs.${indexBiz}.${formNm}.${i}.${head.id}` + : typeof indexMng === "number" && indexMng >= 0 + ? `items.${indexMng}.${formNm}.${i}.${head.id}` + : `items.${indexMng}.${formNm}.${i}.${head.id}` + } render={({ field }) => ( <FormUi label=""> {head.edit === true ? ( <Input className={`${head.type === "number" ? "text-right" : "text-center"} !text-xl`} - type={head.type} + type="text" onChange={(txt) => { - field.onChange(txt.target.value); + if (head.type === "number") { + handleCommaNumberChange(txt, field.onChange); + } else { + field.onChange(txt.target.value); + } }} value={ head.type === "number" - ? (Number(field.value) ?? 0) + ? formatCommaNumber(field.value) : field.value || "" } - readOnly ={head.readonly ? true : false} + readOnly={head.readonly ? true : false} /> ) : head.type === "select" ? ( <SelectBox @@ -102,43 +123,41 @@ const RuseMngTableForm = React.forwardRef<any, RuseMngTableProps>( (item) => item.name === head.selectData )?.val ?? [] } - value={ - field.value || "" - } + value={field.value || ""} className={""} selectClass={selectClass} onSelectValue={(val) => { - - if(head.readonly === true){ - return - }else{ - + if (head.readonly === true) { + return; + } else { field.onChange(val); } }} - readOnly ={head.readonly ? true : false} + readOnly={head.readonly ? true : false} // Disabled prop removed as SelectBox does not support it ></SelectBox> ) : head.type === "date" ? ( <DatePicker mode="single" field={{ - value:typeof field.value === "string" ? new Date(field.value) : field.value, + value: + typeof field.value === "string" + ? new Date(field.value) + : field.value, onChange: (date: Date | undefined) => { - console.log("date", date); - field.onChange(date); // readonly 상태가 아닐 때만 값 변경 + field.onChange(date); // readonly 상태가 아닐 때만 값 변경 }, }} selectClass={"w-full"} - readOnly ={head.readonly ? true : false} + readOnly={head.readonly ? true : false} /> ) : head.type === "checkbox" ? ( <Checkbox className="" - checked={ field.value || false} + checked={field.value || false} onCheckedChange={(checked) => { - field.onChange(checked); + field.onChange(checked); }} ></Checkbox> ) : ( diff --git a/apps/wr/middleware.ts b/apps/wr/middleware.ts index 3fabc529d..5acc41863 100644 --- a/apps/wr/middleware.ts +++ b/apps/wr/middleware.ts @@ -6,6 +6,7 @@ const CLAIM_NAME = "Authorization"; const AUTH_USER_ID = "token-id"; const serverApiUrl = CS_URL; const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || ""; +const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || ""; export function middleware(req: NextRequest) { const pathname = req.nextUrl.pathname; @@ -55,9 +56,17 @@ export function middleware(req: NextRequest) { return NextResponse.rewrite(new URL(newUrl)); } + if (pathname.startsWith("/sewerage-service")) { + const queryParams = searchParams.toString(); + const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service/api", "")}${queryParams ? `?${queryParams}` : "" + }`; + console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); + return NextResponse.rewrite(new URL(newUrl)); + } + return NextResponse.next(); } export const config = { - matcher: ["/server/:path*", "/attach-service/:path*", "/geoserver/:path*"], + matcher: ["/server/:path*", "/attach-service/:path*", "/geoserver/:path*", "/sewerage-service/:path*"], }; diff --git a/apps/wr/public/sample_pbnstPrfmncReg.xlsx b/apps/wr/public/sample_pbnstPrfmncReg.xlsx index 67f0d559e..1f2ff81aa 100644 Binary files a/apps/wr/public/sample_pbnstPrfmncReg.xlsx and b/apps/wr/public/sample_pbnstPrfmncReg.xlsx differ diff --git a/apps/wr/public/sample_rainy.xlsx b/apps/wr/public/sample_rainy.xlsx index 73a52d89c..ec7577c51 100644 Binary files a/apps/wr/public/sample_rainy.xlsx and b/apps/wr/public/sample_rainy.xlsx differ diff --git a/apps/wr/public/sample_ruseCaseMng.xlsx b/apps/wr/public/sample_ruseCaseMng.xlsx index 3a88e0623..96027d557 100644 Binary files a/apps/wr/public/sample_ruseCaseMng.xlsx and b/apps/wr/public/sample_ruseCaseMng.xlsx differ diff --git a/packages/common/business_components/package.json b/packages/common/business_components/package.json index da6f8c344..2c0b6ea47 100644 --- a/packages/common/business_components/package.json +++ b/packages/common/business_components/package.json @@ -44,6 +44,7 @@ "recharts": "^2.15.1", "sonner": "^2.0.1", "tailwind-merge": "^3.0.1", + "tailwindcss-animate": "^1.0.7", "xlsx": "^0.18.5", "xlsx-populate": "^1.21.0", "zod": "^3.24.2" diff --git a/packages/common/business_components/src/ui/chart/BarChart.tsx b/packages/common/business_components/src/ui/chart/BarChart.tsx index 994feb3b3..0802a72e4 100644 --- a/packages/common/business_components/src/ui/chart/BarChart.tsx +++ b/packages/common/business_components/src/ui/chart/BarChart.tsx @@ -88,12 +88,12 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle=' return ( <> {chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? ( - <div className="!mt-3 text-[2.5rem] font-bold text-center"> + <div className="!mt-3 text-[2.5rem] font-bold"> {chartTitle} </div>): null} - <div className="flex justify-center h-full w-full"> - <ChartContainer config={chartConfig ?? {}} className={chartClassName + " !w-[88%]"}> - <BarChart accessibilityLayer data={chartData} margin={{ top: 5, right: 20, left: 30, bottom: 5 }}> + <div className="flex justify-center"> + <ChartContainer config={chartConfig ?? {}} className={chartClassName + " !w-[90%]"}> + <BarChart accessibilityLayer data={chartData}> <CartesianGrid vertical={false} /> <XAxis dataKey="label" @@ -110,13 +110,8 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle=' axisLine={true} fontSize={12} fontWeight={500} - tickFormatter={(value) => { - // 소수점이 있는 경우 소수점을 유지하고 천단위 콤마 추가 - return value.toString().includes('.') - ? value.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 2 }) - : value.toLocaleString(); - }} - label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideLeft', angle: -90, offset: -24, orientation: "left" } : undefined} + domain={[0, Math.ceil(barMaxValue * 1)]} + label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideLeft', angle: -90, offset: 20 } : undefined} /> <ChartTooltip cursor={false} content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />}/> {chartData && chartData.length > 0 && ( diff --git a/packages/common/business_components/src/ui/chart/DoubleBar.tsx b/packages/common/business_components/src/ui/chart/DoubleBar.tsx index b201b3bf9..9627485aa 100644 --- a/packages/common/business_components/src/ui/chart/DoubleBar.tsx +++ b/packages/common/business_components/src/ui/chart/DoubleBar.tsx @@ -7,7 +7,6 @@ import { } from "./lib/chart"; import type { CSSProperties } from "react"; -/* const customStyles = { legendContainer: { display: "flex", @@ -18,22 +17,6 @@ const customStyles = { marginTop: "10px", } as CSSProperties, }; -*/ - -const customStyles = { - legendContainer: { - display: "flex", - flexWrap: "wrap", - justifyContent: "center", - alignItems: "center", - gap: "12px", - fontSize: "13px", - fontWeight: "normal", - marginTop: "16px", - marginBottom: "8px", - minHeight: "32px", - } as CSSProperties, -}; type BarChartProps = { chartConfig: ChartConfig | undefined; @@ -77,7 +60,7 @@ const CustomTooltip = ({ }; // 커스텀 범례 (글씨 크기 키우기 + 스타일 추가) -/*const CustomLegend = (props: any) => { +const CustomLegend = (props: any) => { const { payload } = props; return ( <div style={customStyles.legendContainer}> @@ -89,38 +72,6 @@ const CustomTooltip = ({ ))} </div> ); -};*/ -const CustomLegend = (props: any) => { - const { payload } = props; - if (!payload) return null; - - return ( - <div style={customStyles.legendContainer}> - {payload.map((entry: any, index: number) => ( - <div - key={`legend-${index}`} - className="flex items-center" - style={{ - minWidth: "90px", - margin: "2px 0", - }} - > - <div - style={{ - width: "14px", - height: "14px", - backgroundColor: entry.color, - borderRadius: "3px", - marginRight: "8px", - minWidth: "14px", - minHeight: "14px", - }} - ></div> - <span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>{entry.value}</span> - </div> - ))} - </div> - ); }; export default function DoubleBarChart({chartConfig=undefined, chartData=[], chartTitle='차트', chartClassName='w-full h-full', graphSize=40, yFieldText='', showLegend=false} : BarChartProps) { @@ -132,7 +83,7 @@ export default function DoubleBarChart({chartConfig=undefined, chartData=[], cha .map(key => item[key]) ).flat()); }; - + console.log(chartData); const barMaxValue = getMaxValue(chartData, 'barVal'); return ( <> diff --git a/packages/common/business_components/src/ui/chart/DoughnutChart.tsx b/packages/common/business_components/src/ui/chart/DoughnutChart.tsx index 99395267a..39dee3d9e 100644 --- a/packages/common/business_components/src/ui/chart/DoughnutChart.tsx +++ b/packages/common/business_components/src/ui/chart/DoughnutChart.tsx @@ -48,7 +48,6 @@ type LegendProps = { }; /** 차트 기본 스타일 */ -/* const customStyles = { legendContainer: { display: "flex", @@ -59,23 +58,6 @@ const customStyles = { marginTop: "10px", } as CSSProperties, }; -*/ - -/** 차트 기본 스타일 (라인차트와 동일하게) */ -const customStyles = { - legendContainer: { - display: "flex", - flexWrap: "wrap", // 여러 줄로 자동 줄바꿈 - justifyContent: "center", - alignItems: "center", - gap: "12px", // 아이템 간 간격 - fontSize: "13px", - fontWeight: "normal", - marginTop: "16px", - marginBottom: "8px", - minHeight: "32px", // 범례 영역 높이 통일 - } as CSSProperties, -}; // 커스텀 툴팁 const CustomTooltip = ({ active, payload, label }: { @@ -100,7 +82,6 @@ const CustomTooltip = ({ active, payload, label }: { }; // 커스텀 범례 -/* const CustomLegend = (props: LegendProps) => { const { payload } = props; if (!payload) return null; @@ -116,52 +97,12 @@ const CustomLegend = (props: LegendProps) => { </div> ); }; -*/ - -const CustomLegend = (props: LegendProps) => { - const { payload } = props; - if (!payload) return null; - - return ( - <div style={customStyles.legendContainer}> - {payload.map((entry: LegendEntry, index: number) => ( - <div - key={`legend-${index}`} - className="flex items-center" - style={{ - minWidth: "90px", - margin: "2px 0", - }} - > - <div - style={{ - width: "14px", - height: "14px", - backgroundColor: entry.fill, - borderRadius: "3px", - marginRight: "8px", - minWidth: "14px", - minHeight: "14px", - }} - ></div> - <span style={{ fontSize: "13px", whiteSpace: "nowrap" }}> - {entry.payload?.label || entry.value} - </span> - </div> - ))} - </div> - ); -}; export default function DoughnutChart(props: { chartConfig: any; chartData: ChartDataItem[] | undefined; chartTitle: string }) { - const legendData = props.chartData?.map(item => ({ - value: item.label, - fill: props.chartConfig?.[item.label]?.fill || 'blue', - })) ?? []; return ( <Card className="flex flex-col"> <CardContent className="flex-1 pb-0"> @@ -189,9 +130,9 @@ export default function DoughnutChart(props: { nameKey="label" innerRadius={60} /> + <CustomLegend /> </PieChart> </ChartContainer> - <CustomLegend payload={legendData} /> </div> </CardContent> </Card> diff --git a/packages/common/business_components/src/ui/chart/LineBarChart.tsx b/packages/common/business_components/src/ui/chart/LineBarChart.tsx index 11984cc14..8c7202104 100644 --- a/packages/common/business_components/src/ui/chart/LineBarChart.tsx +++ b/packages/common/business_components/src/ui/chart/LineBarChart.tsx @@ -127,7 +127,7 @@ export default function LineBarchart({ className="text-[12px] font-bold" tickCount={6} orientation="left" - tickFormatter={(value) => value.toLocaleString()} + domain={[0, Math.ceil(lineMaxValue * 1)]} label={{ value: yFieldText, angle: -90, position: 'insideLeft' }} />} {/* 오른쪽 Y축: barVal */} @@ -136,7 +136,7 @@ export default function LineBarchart({ className="text-[12px] font-bold" tickCount={6} orientation="right" - tickFormatter={(value) => value.toLocaleString()} + domain={[0, Math.ceil(barMaxValue * 1)]} label={{ value: yFieldText2, angle: -90, position: 'insideRight' }} reversed={true} />} diff --git a/packages/common/business_components/src/ui/chart/LineChart.tsx b/packages/common/business_components/src/ui/chart/LineChart.tsx index 6c1b6e7bd..4014702b6 100644 --- a/packages/common/business_components/src/ui/chart/LineChart.tsx +++ b/packages/common/business_components/src/ui/chart/LineChart.tsx @@ -18,7 +18,6 @@ type LineChartProps = { } /** 차트 기본 스타일 */ -/* const customStyles = { legendContainer: { display: "flex", @@ -29,23 +28,6 @@ const customStyles = { marginTop: "10px", } as CSSProperties, }; -*/ - -/** 차트 기본 스타일 */ -const customStyles = { - legendContainer: { - display: "flex", - flexWrap: "wrap", - justifyContent: "center", - alignItems: "center", - gap: "12px", - fontSize: "13px", - fontWeight: "normal", - marginTop: "16px", - marginBottom: "8px", - minHeight: "32px", - } as CSSProperties, -}; type LegendEntry = { value: string; @@ -78,7 +60,7 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: }; // 커스텀 범례 (글씨 크기 키우기 + 스타일 추가) -/*const CustomLegend = (props: LegendProps) => { +const CustomLegend = (props: LegendProps) => { const { payload } = props; if (!payload) return null; @@ -92,40 +74,6 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: ))} </div> ); -};*/ - -// 커스텀 범례 (도넛차트와 동일하게) -const CustomLegend = (props: LegendProps) => { - const { payload } = props; - if (!payload) return null; - - return ( - <div style={customStyles.legendContainer}> - {payload.map((entry: LegendEntry, index: number) => ( - <div - key={`legend-${index}`} - className="flex items-center" - style={{ - minWidth: "90px", - margin: "2px 0", - }} - > - <div - style={{ - width: "14px", - height: "14px", - backgroundColor: entry.color, - borderRadius: "3px", - marginRight: "8px", - minWidth: "14px", - minHeight: "14px", - }} - ></div> - <span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>{entry.value}</span> - </div> - ))} - </div> - ); }; type DataType = {label: string; val: string}; @@ -193,7 +141,7 @@ export default function Linechart({ > <CartesianGrid vertical={false} /> <XAxis dataKey="label" fontSize="8px" fontWeight="bold" /> - <YAxis yAxisId="left" className="text-[12px] font-bold" tickFormatter={(value) => value.toLocaleString()} tickCount={6} orientation="left" label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} /> + <YAxis yAxisId="left" className="text-[12px] font-bold" domain={[0, Math.ceil(lineMaxValue * 1.1)]} tickCount={6} orientation="left" label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} /> <Tooltip content={<CustomTooltip />} /> {showLegend && <Legend content={CustomLegend as ContentType}/>} {Object.keys(chartData).map((key) => { diff --git a/packages/common/business_components/src/ui/date_month_picker/index.tsx b/packages/common/business_components/src/ui/date_month_picker/index.tsx index 1b97d9ce1..d318b561f 100644 --- a/packages/common/business_components/src/ui/date_month_picker/index.tsx +++ b/packages/common/business_components/src/ui/date_month_picker/index.tsx @@ -17,7 +17,6 @@ type MonthPickerProps = { field: { value: string; onChange: (date: string) => void }; // yyyyMM 문자열 selectClass?: string; readOnly?: boolean; - startYear?: number; // 시작 연도 props 추가 }; // yyyyMM → Date 객체 @@ -38,7 +37,6 @@ export const DateMonthPicker = ({ field, selectClass, readOnly = false, - startYear, }: MonthPickerProps) => { const [open, setOpen] = useState(false); @@ -77,7 +75,6 @@ export const DateMonthPicker = ({ <MonthPicker currentMonth={parsedDate} onMonthChange={handleSelect} - startYear={startYear} /> </PopoverContent> </Popover> diff --git a/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx b/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx index 2b64ab439..acf17fba4 100644 --- a/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx +++ b/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx @@ -28,41 +28,35 @@ export type MonthPickerProps = { newMonth: Date | undefined, shouldClosePopover?: boolean ) => void; - startYear?: number; }; -export function MonthPicker({ currentMonth, onMonthChange, startYear }: MonthPickerProps) { +export function MonthPicker({ currentMonth, onMonthChange }: MonthPickerProps) { const today = startOfToday(); - const currentYear = today.getFullYear(); +const currentYear = today.getFullYear(); const yearFromProp = format(currentMonth, "yyyy"); - const selectedYear = parseInt(yearFromProp); +const selectedYear = parseInt(yearFromProp); // 현재 월의 시작 날짜 const fullYearStart = parse(yearFromProp, "yyyy", new Date()); const yearEnd = selectedYear === currentYear ? today : endOfYear(fullYearStart); + + - - - // startYear가 없으면 기존과 동일하게 (현재년도 - 20년부터 현재년도까지) - // startYear가 있으면 해당 년도부터 현재년도까지, 내림차순으로 정렬 - const yearRange = startYear - ? Array.from({ length: currentYear - startYear + 1 }, (_, i) => currentYear - i) - : Array.from({ length: 21 }, (_, i) => currentYear - 20 + i); - + const yearRange = Array.from({ length: 21 }, (_, i) => currentYear - 20 + i); const months = eachMonthOfInterval({ start: fullYearStart, end: yearEnd }); const getMonthButtonClass = (month: Date) => cn( "inline-flex h-9 w-16 items-center justify-center rounded-md p-0 text-sm font-normal ring-offset-white transition-colors hover:bg-slate-100 hover:text-slate-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 aria-selected:opacity-100 dark:ring-offset-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50 dark:focus-visible:ring-slate-800", isEqual(month, currentMonth) && - "bg-slate-900 text-slate-50 hover:bg-slate-900 hover:text-slate-50 focus:bg-slate-900 focus:text-slate-50 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50 dark:hover:text-slate-900 dark:focus:bg-slate-50 dark:focus:text-slate-900", + "bg-slate-900 text-slate-50 hover:bg-slate-900 hover:text-slate-50 focus:bg-slate-900 focus:text-slate-50 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50 dark:hover:text-slate-900 dark:focus:bg-slate-50 dark:focus:text-slate-900", !isEqual(month, currentMonth) && - isEqual(month, getStartOfCurrentMonth()) && - "bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50" + isEqual(month, getStartOfCurrentMonth()) && + "bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50" ); return ( @@ -83,7 +77,7 @@ export function MonthPicker({ currentMonth, onMonthChange, startYear }: MonthPic onMonthChange(newDate, false); }} > - <SelectTrigger className="w-[140px] h-9 text-base"> + <SelectTrigger className="w-[120px] h-7"> <SelectValue placeholder="년도" /> </SelectTrigger> <SelectContent> @@ -118,7 +112,7 @@ export function MonthPicker({ currentMonth, onMonthChange, startYear }: MonthPic onClick={() => onMonthChange(month, true)} > <time dateTime={format(month, "yyyy-MM-dd")}> - {format(month, 'MMM', { locale: ko })} + {format(month, 'MMM', { locale: ko })} </time> </button> </div> diff --git a/packages/common/business_components/src/ui/dialog_ui/index.tsx b/packages/common/business_components/src/ui/dialog_ui/index.tsx index df7fffd3a..bbb27d327 100644 --- a/packages/common/business_components/src/ui/dialog_ui/index.tsx +++ b/packages/common/business_components/src/ui/dialog_ui/index.tsx @@ -1,7 +1,7 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader } from "@common/components"; import { cn } from "../../lib/utils"; -type ModalType = { +type ModalType = { bodyClass: string; body: React.ReactNode; open?: boolean; @@ -10,45 +10,43 @@ type ModalType = { noFooterYn?: 'N' | 'Y'; headerTitle?: string; footerContent?: React.ReactNode; - useDirectRender?: boolean; } -export function UiModal({ - bodyClass, - body, - open, +export function UiModal({ + bodyClass, + body, + open, onOpenChange, noHeaderYn = 'N', noFooterYn = 'N', headerTitle, - footerContent, - useDirectRender = false + footerContent }: ModalType) { - + return ( <> - <Dialog open={open} onOpenChange={onOpenChange}> + <Dialog open={open} onOpenChange={onOpenChange}> <DialogContent className={bodyClass}> - {noHeaderYn === 'N' && ( - <DialogHeader> - <DialogDescription> - {headerTitle} - </DialogDescription> - </DialogHeader> - )} - {(open && body) ? - useDirectRender - ? body - : <div>{body}</div> - : <></> - } - {noFooterYn === 'N' && ( - <DialogFooter className="sm:justify-start"> - {footerContent} - </DialogFooter> - )} - </DialogContent> - </Dialog> + {noHeaderYn === 'N' && ( + <DialogHeader> + <DialogDescription> + {headerTitle} + </DialogDescription> + </DialogHeader> + )} + {(open && body) ? + <div> {body}</div>:<></> + + + + } + {noFooterYn === 'N' && ( + <DialogFooter className="sm:justify-start"> + {footerContent} + </DialogFooter> + )} + </DialogContent> + </Dialog> </> ); } diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index 06c641259..fd1e6fe9e 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -21,5 +21,4 @@ export * from "./table_div"; export * from "./title"; export * from "./sdmInsertForm"; export * from "./popover_ui"; -export * from "./date_month_picker"; -export * from "./loadingBar"; \ No newline at end of file +export * from "./date_month_picker"; \ No newline at end of file diff --git a/packages/common/business_components/src/ui/loadingBar/index.tsx b/packages/common/business_components/src/ui/loadingBar/index.tsx index 37991d1d2..4d637dd25 100644 --- a/packages/common/business_components/src/ui/loadingBar/index.tsx +++ b/packages/common/business_components/src/ui/loadingBar/index.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { LoadingWithAnimation } from '@common/components/ui/loading'; +import React from 'react'; interface LoadingOverlayProps { isLoading: boolean; diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js index d7c013084..cde836627 100644 --- a/packages/common/business_components/src/ui/map/Gis.js +++ b/packages/common/business_components/src/ui/map/Gis.js @@ -47,7 +47,7 @@ function Gis({ const gisCore = useMemo(() => new GisApp.core({ targetId: mapRef.current }), []); const mapInstanceRef = useRef(null); const checkedLayerIds = useRef([]); - + const [viewMode, setViewMode] = useState('list'); // 상태로 관리 // 팝업 데이터를 저장할 상태와 오버레이 참조를 저장할 ref 추가 // const [facilityInfoPopupData, setFacilityInfoPopupData] = useState([]); diff --git a/packages/common/business_components/src/ui/map/lib/gis.core.js b/packages/common/business_components/src/ui/map/lib/gis.core.js index 7488e4b72..ddfcec3a1 100644 --- a/packages/common/business_components/src/ui/map/lib/gis.core.js +++ b/packages/common/business_components/src/ui/map/lib/gis.core.js @@ -1,24 +1,26 @@ import MousePosition from 'ol/control/MousePosition'; import ScaleLine from 'ol/control/ScaleLine'; -import { getTopLeft } from 'ol/extent'; import Feature from 'ol/Feature'; -import GeoSJON from 'ol/format/GeoJSON'; import WKT from 'ol/format/WKT'; -import { Point } from 'ol/geom'; import LinearRing from 'ol/geom/LinearRing'; import Draw from 'ol/interaction/Draw'; import TileLayer from 'ol/layer/Tile'; -import VectorLayer from 'ol/layer/Vector'; import * as olProj from 'ol/proj'; import VectorSource from 'ol/source/Vector'; -import TileWMTS from 'ol/source/WMTS'; import XYZ from 'ol/source/XYZ'; +import GeoSJON from 'ol/format/GeoJSON'; import { Fill, Stroke, Style } from 'ol/style'; import CircleStyle from 'ol/style/Circle'; +import VectorLayer from 'ol/layer/Vector'; +import { Point } from 'ol/geom'; +import { getTopLeft } from 'ol/extent'; +import TileWMTS from 'ol/source/WMTS'; import WMTSTileGrid from 'ol/tilegrid/WMTS'; // import { get as getProjection } from 'ol/proj'; -import { register } from 'ol/proj/proj4'; import proj4 from 'proj4'; +import { register } from 'ol/proj/proj4'; +import olSourceImageWMS from 'ol/source/ImageWMS'; +import { GeoJSON } from 'ol/format'; import GisOlEditLayer from './gis.edit'; import GisOlLayer from './gis.layer'; @@ -560,7 +562,6 @@ GisApp.core.prototype = { * * Returns: */ - // 레이어를 지도에 표시/숨김 setLayerOnMap: function (layerIds, visible, addQurryFlter) { for (let i in layerIds) { let id = layerIds[i]; @@ -571,14 +572,10 @@ GisApp.core.prototype = { const layerCode = GisApp.layerCode[id]; const queryFlter = layerCode?.flterSql || '' + ' ' + (addQurryFlter || ''); layerCode['flterSql'] = queryFlter; - //layer = this.addWmsLayer(layerCode); - - // WFS 레이어 생성 및 지도에 추가 + //layer = this.addWmsLayer(layerCode); layer = this.addWfsLayer(layerCode); } } - - // 선택 인터랙션 및 스냅 기능 설정 if (GisApp.Module.select) { this.setSelectInteraction(); } diff --git a/packages/common/business_components/src/ui/map/lib/gis.layer.js b/packages/common/business_components/src/ui/map/lib/gis.layer.js index d9657c313..097c90ba5 100644 --- a/packages/common/business_components/src/ui/map/lib/gis.layer.js +++ b/packages/common/business_components/src/ui/map/lib/gis.layer.js @@ -77,7 +77,15 @@ GisOlLayer.prototype = { let lyrTyNm = options.lyrTyNm; let typename = this.storageNm + lyrTyNm; - if(options.lyrTyNm == "om_dt_untrt_swg_rain"){ //중점우수토실실 + if(options.lyrTyNm == "om_dt_untrt_swg_rain" //중점우수토실 + || options.lyrTyNm == "om_wqlt_station" //관측소 + || options.lyrTyNm == "tb_wr_bdst_ruse_fclt" //재이용시설 + || options.lyrTyNm == "tb_wr_rnwtr_utztn_fclt" //빗물이용시설 + || options.lyrTyNm == "tb_wr_rswtr_fclt" //중수도시설 + || options.lyrTyNm == "tb_wr_htdfl_fclt" //온배수시설 + || options.lyrTyNm == "tb_wr_tmpr_dmd_co" //잠재수요처 + ) + { url = GisApp.SN_GEOSERVER_URL; typename = lyrTyNm; } diff --git a/packages/common/business_components/src/ui/search_form_left/index.tsx b/packages/common/business_components/src/ui/search_form_left/index.tsx index d0da2cd1a..e7858df2a 100644 --- a/packages/common/business_components/src/ui/search_form_left/index.tsx +++ b/packages/common/business_components/src/ui/search_form_left/index.tsx @@ -301,7 +301,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel resetAllValues(); // 리셋 후 트리거를 false로 설정 if (setRtnPartValue) { - setRtnPartValue('A'); + setRtnPartValue('0'); } } }, [resetTrigger]); diff --git a/packages/common/business_components/src/ui/table/index-2.tsx b/packages/common/business_components/src/ui/table/index-2.tsx index 5961ea396..b6a9750b0 100644 --- a/packages/common/business_components/src/ui/table/index-2.tsx +++ b/packages/common/business_components/src/ui/table/index-2.tsx @@ -110,7 +110,9 @@ export function UiTable2({ ? 'text-right' : head.align === 'center' ? 'text-center' - : 'text-center' + : typeof el[head.id] === 'number' + ? 'text-right' + : 'text-center' } ${cellClick && idx === index ? '!font-[1000] cursor-pointer' : cellClick ? 'cursor-pointer' : ''} diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index bb90153c2..cd25bc8db 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -82,7 +82,7 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr boldArray.includes(index) ? <TableCell - className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : 'text-center'} ${ + className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${ cellClick && idx === index ? '!font-[1000] cursor-pointer' : cellClick ? 'cursor-pointer' : '' } !font-bold`} @@ -97,7 +97,7 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr </TableCell> : <TableCell - className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : 'text-center'} ${ + className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${ cellClick && idx === index ? '!font-[1000] cursor-pointer' : cellClick ? 'cursor-pointer' : '' }`} diff --git a/packages/common/business_components/src/ui/table/uiPageNations.tsx b/packages/common/business_components/src/ui/table/uiPageNations.tsx index a4ee3b4fc..891fc4c81 100644 --- a/packages/common/business_components/src/ui/table/uiPageNations.tsx +++ b/packages/common/business_components/src/ui/table/uiPageNations.tsx @@ -40,8 +40,7 @@ export default function UiPageNations(commonPageNationsProps: CommonPageNationsP <PaginationItem> <PaginationPrevious href="#" - onClick={(e) => { - e.preventDefault(); + onClick={() => { if (startPage > 1) handlePageChange(startPage - 1); }} /> @@ -54,7 +53,7 @@ export default function UiPageNations(commonPageNationsProps: CommonPageNationsP <PaginationLink href="#" isActive={pageNum === pageProps.cur} - onClick={(e) => {e.preventDefault(); handlePageChange(pageNum)}} + onClick={() => handlePageChange(pageNum)} > {pageNum} </PaginationLink> @@ -66,8 +65,7 @@ export default function UiPageNations(commonPageNationsProps: CommonPageNationsP <PaginationItem> <PaginationNext href="#" - onClick={(e) => { - e.preventDefault(); + onClick={() => { if (endPage < totalPages) handlePageChange(endPage + 1); }} />