diff --git a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx index e8146b37a..436b77736 100644 --- a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx +++ b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx @@ -1,30 +1,162 @@ "use client"; + import { useWrStore } from "@/app/store"; import { ruseUtzType } from "@/app/store/matDmd/ruseCaseMng/headList"; -import { getCity } from "@/components/lib/func/commom"; +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 { ContentsDiv, SearchDiv, SearchFormLeft, SearchFormRight, SearchInput, SelectBox, Title, UiTable, type SelectDataType } from "@common/business_components/ui"; +import { + ContentsDiv, + filePickedBlobArray, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, + Title, + UiModal, + UiTable, + type SelectDataType, +} from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; import { useState } from "react"; export default function RuseCaseMng() { - const { code,ruseCase} = useWrStore((state) => state); - const [selectSgg, setSelectSgg] = useState() + const { code, ruseCaseMng, selectRuseCaseMng } = useWrStore((state) => state); + const { ruseCaseMngList } = ruseCaseMng; + const [selectSgg, setSelectSgg] = useState([]); const [objSearch, setObjSearch] = useState({ sgg: "", city: "" }); - const [selectUtz, setSelectUtz] = useState() - const [searchTxt, setSearchTxt] = useState() + + const [sidoCd, setSidoCd] = useState(""); + const [sigunguCd, setSigunguCd] = useState(""); + const [selectUtz, setSelectUtz] = useState(["조경용수"]); + const [name, setName] = useState(""); + // 물재이용사례 조회 + const searchRuseCaseMng = async () => { + const res = await selectRuseCaseMng( + sidoCd ?? "", + sigunguCd ?? "", + selectUtz[0] ?? "", + name ?? "" + ); + } + + // 시도 선택 const getSelCity = (val: string | number) => { const cityValue = String(val); + const cityText = code.cityCd.find((item: { val: string; text: string }) => item.val === cityValue)?.text; + setSidoCd(cityText || ""); const data = getCity(cityValue, code.sggCd); setSelectSgg(data); - setObjSearch({ city: cityValue, sgg: '' }); + setObjSearch({ city: cityValue, sgg: "" }); }; + // 시군구 선택 const getSgg = (val: string | number) => { - setObjSearch({ ...objSearch, sgg: String(val) }) + const sggValue = String(val); + const sggText = selectSgg?.find((item: { val: string; text: string }) => item.val === sggValue)?.text; + setSigunguCd(sggText || ""); + setObjSearch({ ...objSearch, sgg: String(val) }); }; + + // 엑셀 등록 모달 + const [isExcelOpen, setIsExcelOpen] = useState<{ + isModal: boolean; + }>({ isModal: false }); + + // 다운로드 + const download = () => { + searchRuseCaseMng(); + + fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => { + if (!response.ok) { + throw Error(response.statusText); + } + // 받은 파일 바인너리 처리 + const blobRet = await response.arrayBuffer(); + + const excelData1 = ruseCaseMngList.map((item) => { + return [ + item.ruseBizNm, + item.bizBgngDate, + item.bizEndDate, + item.splyFcltKnd, + item.splyFcltNm, + item.splyFcltCpct, + item.dmdFcltNm, + item.dmdFcltAddr, + item.ruseFcltCpct, + item.ruseFcltPplLen, + item.ruseFcltUsg, + item.ruseFcltSplyCpct, + item.ruseFcltPrcsMsrc, + item.grnteWqUsg, + item.grnteWqGrssClfg, + item.grnteWqCombResdch, + item.grnteWqTrbt, + item.grnteWqBod, + item.grnteWqSmll, + item.grnteWqCrmty, + item.grnteWqTn, + item.grnteWqTp, + item.grnteWqPh, + item.grnteWqClIonQnt, + item.grnteWqCndctStat, + item.grnteWqRmrk, + item.reqBizGrssCst, + item.reqBizReuseFcltCst, + item.reqBizPplCst, + item.reqBizArchCst, + item.reqBizMchnCst, + item.reqBizMtrngCst, + item.reqBizGisCst, + item.reqBizCctvCst, + item.reqBizCmcnCst, + item.reqBizWstCst, + item.reqBizDesignCst, + item.reqBizSpvsCst, + item.reqBizSbsdCst, + item.reqBizEtc, + item.prcmPlanGrssCst, + item.prcmPlanNlep, + item.prcmPlanLcep, + item.prcmPlanBrdnCst, + item.prcmPlanEcqrRt, + item.clclnGrssCst, + item.clclnNlep, + item.clclnLcep, + item.clclnBrdnCst, + item.clclnEcqrRt, + ]; + }); + + const sheetParameter = [ + { + data: excelData1, + headerNum: 2, + headerRange: 'A1:AX1', + sheetName: '물재이용사례', + startCol: 'A' + } + ]; + // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 + await filePickedBlobArray(blobRet, '시설정보및운영현황황', sheetParameter); + }); + } + + // 양식받기 + const sampleDownLoad = () => { + excelDownload( + [[]], + "물재이용사례 관리", + "sample_ruseCaseMng.xlsx", + "A1:AX1", + 2 + ); + } + return ( <> @@ -54,47 +186,32 @@ export default function RuseCaseMng() { selectClass={""} selectArray={ruseUtzType} onSelectValue={(val) => { - if(val) - setSelectUtz([String(val)])}} + if (val) setSelectUtz([String(val)]); + }} /> - { - setSearchTxt(e) + setName(e); }} /> - - +
- - - -
@@ -103,24 +220,35 @@ export default function RuseCaseMng() {
-
+
- { - }} - onPageChange={() => { }} - > +
+ {}} + onPageChange={() => {}} + /> +
+ + {/* 엑셀 등록 모달 */} + { + setIsExcelOpen({ isModal: !isExcelOpen.isModal }) + }} + bodyClass={"w-[40vw] max-w-none"} + body={} + /> - ) + ); } \ No newline at end of file diff --git a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx index 77bbe4a5a..d7c5170b2 100644 --- a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx @@ -1,32 +1,68 @@ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; -import type { customCoSttnBdst } from "@/app/store/matDmd/coSttn"; +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 DrgtDetailModal from "@/components/ui/modal/coMat/drgtDetailModal"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; -import { ContentsDiv, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiTable, type SelectDataType } from "@common/business_components/ui"; +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 ListDiv from "@common/business_components/ui/list_div"; import { Button, DatePicker, Label } from "@common/components/ui"; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; +import { toast, Toaster } from "react-hot-toast"; export default function DrgtSttn() { - const { code, } = useWrStore((state) => state); - const [fromDate, setFromDate] = useState(new Date()); - const [toDate, setToDate] = useState(new Date()); + const { code, drgt, drgtSearch, drgtModalSearch } = useWrStore((state) => state); + const { drgtRes, drgtMoRes } = drgt; + const [fromDate, setFromDate] = useState(); + const [toDate, setToDate] = useState(); const [selectSgg, setSelectSgg] = useState(); const [objSearch, setObjSearch] = useState({ sgg: "", city: "" }); + const [tableData, setTableData] = useState(); + const [selectedSgg, setSelectedSgg] = useState(''); + const [drgtModal, setDrgtModal] = useState<{ + isOpen: boolean; + data: customDrgt | undefined; + }>({ data: undefined, isOpen: false }); - 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 cellClick = (index: number | undefined, headId: string) => { + if (fromDate && toDate) { + drgtModalSearch(fromDate, toDate, drgtRes[index].sggNm); + } else { + toast.error("조회기간을 선택해주세요."); + } + } + + 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 }); + }; const getSgg = (val: string | number) => { - console.log(val); - setObjSearch({ ...objSearch, sgg: String(val) }) + setSelectedSgg(String(val)); + setObjSearch({ ...objSearch, sgg: String(val) }); }; const excelClick = useCallback(() => { @@ -37,6 +73,17 @@ export default function DrgtSttn() { "A1:H1" ); }, []); + + useEffect(() => { + if (fromDate === undefined && toDate === undefined) { + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, '0'); + const formatted = `${year}${month}`; + setFromDate(formatted); + setToDate(formatted); + } + }, [fromDate, toDate]) return ( <> @@ -59,18 +106,41 @@ export default function DrgtSttn() { selectClass={""} selectArray={selectSgg || []} onSelectValue={getSgg} + value={selectedSgg} />
- { if (date) setFromDate(date) }} /> + { + const year = date.slice(0, 4); + let month = date.slice(4); + if (month.length < 2) { + month = month.padStart(2, "0"); + } + const formatted = `${year}${month}`; + setFromDate(formatted); + } + }} + /> ~ - { if (date) setToDate(date) }} /> + { + const year = date.slice(0, 4); + let month = date.slice(4); + if (month.length < 2) { + month = month.padStart(2, "0"); + } + const formatted = `${year}${month}`; + setToDate(formatted); + } + }} + />
@@ -81,7 +151,22 @@ export default function DrgtSttn() {
@@ -116,16 +201,27 @@ export default function DrgtSttn() { { }} + cellClick={(index: number | undefined, headId: string) => { + cellClick(index ?? undefined, headId); + }} onPageChange={() => { }} >
+ { + setDrgtModal({ ...drgtModal, isOpen: !drgtModal.isOpen }); + }} + bodyClass={"w-[50vw] max-w-none h-[80vh]"} + body={} + /> +
) diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx index f5dffbf8b..c5daee29c 100644 --- a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx @@ -99,8 +99,8 @@ export default function LdrmntCoSttn() { const tbData = Array.isArray(data) ? data.map((item: customLdrmnt) => ({ ...item, - ctpvCd: item.fctryAddr.split(" ")[0] || "", - sggCd: item.fctryAddr.split(" ")[1] || "" + ctpvCd: item.fctryAddr?.split(" ")[0] || "", + sggCd: item.fctryAddr?.split(" ")[1] || "" })) : []; @@ -114,8 +114,8 @@ export default function LdrmntCoSttn() { const data = Array.isArray(exData) ? exData.map((item: customLdrmnt) => { return { - "시도": item.fctryAddr.split(" ")[0] || "", - "시군구": item.fctryAddr.split(" ")[1] || "", + "시도": item.fctryAddr?.split(" ")[0] || "", + "시군구": item.fctryAddr?.split(" ")[1] || "", "회사명": item.dmdCoNm, "공장주소": item.fctryAddr, "공장관리번호": item.fctryMngNo, diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx index 441eabf25..174f268d0 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -29,9 +29,9 @@ import { import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm"; import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm"; import { PbnstRegModal } from "@/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal"; -import toast, { Toaster } from "react-hot-toast"; +import toast, { Toaster } from "react-hot-toast"; // toast 이미 import 되어 있음 import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg"; -import { useFieldArray, useForm } from "react-hook-form"; +import { useFieldArray, useForm, type FieldErrors } from "react-hook-form"; // FieldErrors 타입 추가 import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; @@ -39,8 +39,8 @@ export default function PublicReuseFaciltyInsert() { const { code, pbnst, - searchFclts, pubHasuInit, + pbnstInsert, pbnstRegClick, pbnstRuseFcltUpdate, pubHasuSearch, @@ -50,17 +50,15 @@ export default function PublicReuseFaciltyInsert() { const [currentTab, setCurrentTab] = useState("mng"); const [isRuseReg, setIsRuseReg] = useState<{ isModal: boolean; - data: pubHasuType; - }>({ isModal: false, data: {} as pubHasuType }); + }>({ isModal: false }); const [indexMng, setIndexMng] = useState(0); const [indexBiz, setIndexBiz] = useState(0); const [searchTxt, setSearchTxt] = useState(); const [bdstTable, setbdstTable] = useState(); const [selectRow, setSelectRow] = useState(); + const [pageNation, setPageNation] = useState(1); - - const form = useForm<{ items: z.infer[]; }>({ @@ -76,6 +74,8 @@ export default function PublicReuseFaciltyInsert() { control: form.control, name: `items`, }); + + const formWatch = form.watch("items"); useEffect(() => { if (!pbnst.isInit) { pubHasuInit("1", "41"); @@ -88,32 +88,84 @@ export default function PublicReuseFaciltyInsert() { data.forEach((fclt) => { bizs = [...bizs, ...fclt.fcBizs]; }); - const pbnst =data.map((fclt) => { - return({ - pbnstRuseFcltPk: fclt.pbnstRuseFcltPk, - fcltCpct: fclt.fcltCpct, - ruseCpct: fclt.ruseCpct, - splyExtraCpct: fclt.splyExtraCpct, - rgtr: fclt.rgtr, - mdfr: fclt.mdfr, - fcFiles: fclt.fcFiles, - fcOpers: fclt.fcOpers, - }) - }) + const pbnst = data.map((fclt) => { + return { + pbnstRuseFcltPk: fclt.pbnstRuseFcltPk, + fcltCpct: fclt.fcltCpct, + ruseCpct: fclt.ruseCpct, + splyExtraCpct: fclt.splyExtraCpct, + rgtr: fclt.rgtr, + mdfr: fclt.mdfr, + fcFiles: fclt.fcFiles, + fcOpers: fclt.fcOpers, + }; + }); await pbnstRuseFcltUpdate(pbnst as customPbnst[]); await pbnstRuseBizUpdate(bizs); }; - useEffect(() => { - if (code.sggCd.length) { - if (searchFclts) { - setbdstTable(tableData(searchFclts, { code })); - } else if (code.sggCd.length > 0 && pbnstHasuRes.length > 0) { - setbdstTable(tableData(pbnstHasuRes, { code })); - } + // 폼 유효성 검사 실패 시 호출될 함수 + const onInvalid = ( + errors: FieldErrors<{ items: z.infer[] }> + ) => { + // 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다. + 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}`); + }); } - }, [code, pbnstHasuRes, searchFclts]); + }; + + useEffect(() => { + if (code.sggCd.length && pbnstHasuRes.length > 0) { + setbdstTable(tableData(pbnstHasuRes, { code })); + } + }, [code, pbnstHasuRes]); const cellClick = (val: number | undefined) => { if (val === undefined) return; @@ -121,6 +173,8 @@ export default function PublicReuseFaciltyInsert() { setSelectRow(pbnstHasuRes?.[val]); if (selectRow) { pbnstRegClick(selectRow); + } else { + console.error("선택된 행이 없습니다."); } }; @@ -129,12 +183,9 @@ export default function PublicReuseFaciltyInsert() { }; useEffect(() => { - if (pbnst.pbnstRes&& pbnst.pbnstRes?.length>0) { - console.log("pbnst.pbnstRes", pbnstRes); + if (pbnst.pbnstRes && pbnst.pbnstRes?.length > 0) { form.reset({ items: pbnstRegArrayZod.parse(pbnst.pbnstRes) }); - }else{ - - console.log("pbnst.pbnstRes is null", pbnstRes); + } else { form.reset({ items: [] }); } }, [pbnst.pbnstRes]); @@ -150,11 +201,9 @@ export default function PublicReuseFaciltyInsert() { const appendPbnstRuseFclt = useCallback(() => { const selecTableRow = selectRow; - if (pbnstRes && pbnstRes.length > 0) { const lastPbnst = pbnstRes[pbnstRes.length - 1]; if (lastPbnst && selecTableRow) { - append( pbnstRegZod.parse({ pbnstRuseFcltPk: @@ -170,32 +219,33 @@ export default function PublicReuseFaciltyInsert() { ] as fcBizType[], }) ); - setIsRuseReg({ ...isRuseReg, isModal: true }); + setIsRuseReg({ isModal: true }); } } else { if (selecTableRow) { append( - pbnstRegZod.parse({ - pbnstRuseFcltPk: String(selecTableRow.bscFctCd)+'1', - ruseUtztnFcltNm: "", - regDt: null, - mdfcnDt: null, - fcBizs: [fcBizSchema.parse({pbnstRuseFcltFk:String(selecTableRow.bscFctCd)+'1',cycl:1})] as fcBizType[], - }) - ) - setIsRuseReg({ ...isRuseReg, isModal: true }); + pbnstRegZod.parse({ + pbnstRuseFcltPk: String(selecTableRow.bscFctCd) + "1", + ruseUtztnFcltNm: "", + regDt: null, + mdfcnDt: null, + fcBizs: [ + fcBizSchema.parse({ + pbnstRuseFcltFk: String(selecTableRow.bscFctCd) + "1", + cycl: 1, + }), + ] as fcBizType[], + }) + ); + setIsRuseReg({ isModal: true }); } } }, [pbnstRegZod, pbnstRes, append, selectRow, form]); useEffect(() => { - // console.log(" page getgetvaslue ", form.getValues()); - }, [form.getValues()]); + pubHasuInit(String(pageNation), "41"); + }, [pageNation, pubHasuInit]); -useEffect(() =>{ - pubHasuInit(String(pageNation), "41"); -},[pageNation,pubHasuInit]) - return ( <> @@ -206,7 +256,7 @@ useEffect(() =>{ { setSearchTxt(e); @@ -228,7 +278,7 @@ useEffect(() =>{ size={"sm"} className="" onClick={() => { - // pbnstMngData([] as customPbnst[]); + // pbnstMngData([] as customPbnst[]); if (!selectRow) { toast.error( "하수리시시설을 테이블을 선택하고 등록버튼을 눌러주세요" @@ -251,6 +301,8 @@ useEffect(() =>{
+ {" "} + {/* 높이 조정 */} {
- - - - 시설정보 - - - 차수별정보 - - + + + { + console.log("setIndexMng", index); + setIndexMng(index); + }} + indexMng={indexMng} + /> + + + { + setIndexBiz(index); + }} + indexMng={indexMng} + indexBiz={indexBiz} + /> + + + ) : ( + <> +
+ 등록된 재이용시설 정보가 없습니다. +
+
+

+ 신규등록 버튼을 클릭하여 재이용시설을 등록해주세요. +

+ - - - { - console.log("setIndexMng", index); - setIndexMng(index); - }} - indexMng={indexMng} - /> - - - { - setIndexBiz(index); - }} - indexMng={indexMng} - indexBiz={indexBiz} - /> - - +
+ + + )}
{ + if (data) { + pbnstInsert(data); // pbnstInsert 함수 호출 + setIsRuseReg({ isModal: false }); + } + }} > } - bodyClass="w-[68vw] max-w-none h-[90vh]" + bodyClass="w-[68vw] max-w-none h-[90vh]" open={isRuseReg.isModal} onOpenChange={(open) => { remove(form.getValues("items").length - 1); - setIsRuseReg({ data: {} as pubHasuType, isModal: open }); + setIsRuseReg({ isModal: open }); }} /> diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx index 31743aaa9..2fa8b12b8 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx @@ -38,8 +38,10 @@ export default function Home() { }>({ isOpen: false, chgBuilding: [] }); useEffect(() => { + setIsNewReg( false) if (!rain.isInit) { initRain('41'); + } }, [rain.isInit, initRain]); @@ -80,7 +82,6 @@ export default function Home() { }; useEffect(() => { - console.log("getPageNation", pageNation); getRainData(pageNation, "41"); }, [pageNation]); diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx index 2931690b9..d57c730ce 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx @@ -42,8 +42,8 @@ export default function Home() { } }, [rswt.isInit, initRswt]); useEffect(() => { - if (code.sggCd.length > 0) { - const rswtData = tableData(rswtRes, { code }).map( + if (code.sggCd.length > 0 && rswtRes?.length > 0) { + const rswtData = tableData(rswtRes, { code })?.map( (item: customRswtBdst) => { return { ...item, @@ -151,7 +151,7 @@ export default function Home() { } + body={} bodyClass="w-[68vw] max-w-none h-[90vh]" open={issNewReg} onOpenChange={(open) => { @@ -162,7 +162,7 @@ export default function Home() { bodyClass={""} open={bdstChgProps.isOpen} body={ - + } onOpenChange={(open) => { setBdstChgProps({ ...bdstChgProps, isOpen: open }); diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx index 7a3444a9b..f9b3c6187 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx @@ -65,7 +65,7 @@ export default function RswtSttn() { }, [rswtSttn.isInit, rswtSttnInit]); useEffect(() => { - if (rswtSttnRes.length > 0 && code.cityCd.length > 0) { + if (rswtSttnRes?.length > 0 && code.cityCd.length > 0) { const data = tableData(rswtSttnRes, { code }); const chData = data .map((item: customRswtBdst) => ({ diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index 18dbc7943..fd8e2a6d6 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -68,7 +68,12 @@ export default function Page() { data: {}, }); const cellClick = () => { - if (searchYear) rainChkInit(searchYear, "0"); + if (searchYear) + if (selFcltDiv === "RNB") { + rainChkInit(searchYear, "0"); + } else { + rswtChkgdnInit(searchYear, "0"); + } }; const [searchYear, setSearchYear] = useState( @@ -91,8 +96,7 @@ export default function Page() { }, [rainChkgdn.isInit, rainChkInit]); useEffect(() => { - if (rswtChkgdn.excelList[0]&&rswtChkgdn.excelList[0]?.data.length > 1) { - + if (rswtChkgdn.excelList[0] && rswtChkgdn.excelList[0]?.data.length > 1) { excelArrayDownload( "중수도시설 지도점검", "sample_rs_chk.xlsx", @@ -189,10 +193,10 @@ export default function Page() { label={""} selectClass={""} selectArray={rainChkgdn.fcltDiv} - onSelectValue={(val: string | number) =>{ - if(val === "RST") rswtChkPolInit(); - setSelFcltDiv(String(val)) - } + onSelectValue={(val: string | number) => { + if (val === "RST") rswtChkPolInit(); + setSelFcltDiv(String(val)) + } } value={selFcltDiv ?? rainChkgdn.fcltDiv[0]?.val} /> diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx index f9a799c24..8960f468d 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx @@ -1,14 +1,10 @@ "use client"; import { useWrStore } from "@/app/store"; -import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { - excelArrayDownload, excelDownload, - yearOptions, + yearOptions } from "@/components/lib/func/commom"; -import ChkgdExcel from "@/components/ui/modal/chkgd/chkgdExcel/chkgdExcel"; import ChkgdModal from "@/components/ui/modal/chkgd/chkgdModal/chkgdModal"; import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable"; import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable"; @@ -17,29 +13,27 @@ import { SearchDiv, SearchFormLeft, SearchFormRight, - SearchInput, SelectBox, Title, - UiModal, + UiModal } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useState } from "react"; import { Toaster } from "react-hot-toast"; -//----------------------- export default function Page() { const { code, rainChkSttn, rswtChkSttn, - - rainChkSttnInit, rainChkSttnSearch, + rswtChkSttnSearch, rswtChkSttnInit, isRainSttn, - isRswtSttn + isRswtSttn, + rswtChkPolInit, } = useWrStore((state) => { return state; }); @@ -51,25 +45,31 @@ export default function Page() { }); const [searchYear, setSearchYear] = useState(String(new Date().getFullYear())); const cellClick = () => { - if (searchYear) rainChkSttnSearch(searchYear, "0"); + if (searchYear) { + if (selFcltDiv === "RNB") { + rainChkSttnSearch(searchYear, "0"); + } else { + rswtChkSttnSearch(searchYear, "0"); + } + } }; useEffect(() => { if (!rainChkSttn.isInit) { isRainSttn(true) - rainChkSttnInit( "0"); + rainChkSttnInit(new Date().getFullYear().toString(), "0"); setIsModal({ data: {}, open: false }); } }, [rainChkSttn.isInit, rainChkSttnInit]); - useEffect(() => { + useEffect(() => { if (!rswtChkSttn.isInit) { setIsModal({ data: {}, open: false }); - rswtChkSttnInit( "0"); + rswtChkSttnInit(new Date().getFullYear().toString(), "0"); isRswtSttn(true) } - },[rswtChkSttn.isInit, rswtChkSttnInit]) + }, [rswtChkSttn.isInit, rswtChkSttnInit]) const handleClick = useCallback( @@ -78,25 +78,25 @@ export default function Page() { }, [isModal] ); -const excelDown=() =>{ - if(rainChkSttn.sttnExcelList && selFcltDiv === "RNB"){ - excelDownload( - rainChkSttn.sttnExcelList, - "빗물이용시설 지도점검 현황", - "sample_rainChkSttn.xlsx", - "A1:Q2", - 3 - ); - }else if(rswtChkSttn.sttnExcelList && selFcltDiv === "RST"){ - excelDownload( - rswtChkSttn.sttnExcelList, - "중수도시설 지도점검 현황", - "sample_rswtChkSttn.xlsx", - "A1:X2", - 3 - ); + const excelDown = () => { + if (rainChkSttn.sttnExcelList && selFcltDiv === "RNB") { + excelDownload( + rainChkSttn.sttnExcelList, + "빗물이용시설 지도점검 현황", + "sample_rainChkSttn.xlsx", + "A1:Q2", + 3 + ); + } else if (rswtChkSttn.sttnExcelList && selFcltDiv === "RST") { + excelDownload( + rswtChkSttn.sttnExcelList, + "중수도시설 지도점검 현황", + "sample_rswtChkSttn.xlsx", + "A1:X2", + 3 + ); + } } -} return ( @@ -125,10 +125,12 @@ const excelDown=() =>{ label={""} selectClass={""} selectArray={rainChkSttn.fcltDiv} - onSelectValue={(val: string | number) => - setSelFcltDiv(String(val)) - } - value={selFcltDiv ?? rainChkSttn.fcltDiv[0]?.val} + onSelectValue={(val: string | number) => { + if (val === "RST") rswtChkPolInit(); + setSelFcltDiv(String(val)) + } + } + value={selFcltDiv ?? rainChkSttn.fcltDiv[0]?.val} />
@@ -143,7 +145,7 @@ const excelDown=() =>{ > 조회 - @@ -157,15 +159,15 @@ const excelDown=() =>{ {selFcltDiv === "RNB" ? ( {}} - detailUp={() => {}} + deleteData={() => { }} + detailUp={() => { }} handleClick={handleClick} rainChkData={rainChkSttn.rainChkRes} /> ) : ( {}} - deleteRswtData={() => {}} + detaiRswtlUpdate={() => { }} + deleteRswtData={() => { }} handleRswtClick={handleClick} rswtChkData={rswtChkSttn.rswtChkRes} /> diff --git a/apps/wr/app/store/common/code/index.ts b/apps/wr/app/store/common/code/index.ts index e7fca8180..83d87d738 100644 --- a/apps/wr/app/store/common/code/index.ts +++ b/apps/wr/app/store/common/code/index.ts @@ -10,6 +10,32 @@ const yn: SelectDataType[] = [ { 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: "확인불가" }, @@ -174,6 +200,10 @@ export type comCodeState = { HTB:string } ruseMngMtd:SelectDataType[] + ruseSeCd: SelectDataType[]; + ruseBizMthdCd: SelectDataType[]; + rusePrcsMthdCd: SelectDataType[]; + erctUswtrPrcsMeth: SelectDataType[]; }; }; @@ -323,6 +353,10 @@ export const comCodeStateExport: comCodeState = { dmdUszCd:dmdUszCd, buildingType:buildingType, ruseMngMtd:ruseMngMtd, + ruseSeCd:ruseSeCd, + ruseBizMthdCd: ruseBizMthdCd, + rusePrcsMthdCd:rusePrcsMthdCd, + erctUswtrPrcsMeth:erctUswtrPrcsMeth }, }; diff --git a/apps/wr/app/store/common/searchCode/index.ts b/apps/wr/app/store/common/searchCode/index.ts index 8f05eca09..51ebda8a5 100644 --- a/apps/wr/app/store/common/searchCode/index.ts +++ b/apps/wr/app/store/common/searchCode/index.ts @@ -7,8 +7,50 @@ import { import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; import type { conCostFeeType, rateFeeType } from "./type"; + + +export const comFcltStateExport: comFcltState = { + searchFclts: [] as pubHasuType[], + demandCompList: [], + dmdIsSucees: '', + checkDemand: { + index: 0, + dmdInfoPk: "", + dmdInfoFk: "", + bzmnNo: "", + dmdCoNm: "", + daddr: "", + telno: "", + rgtr: "", + useUsgCd: "", + ctpvCd: "", + sggCd: "", + dmdAplyPswd: "", + wntUntprc: 0, + dmndTmng: "", + dmndQty: 0, + grssClfg: 0, + tn: 0, + combResdch: 0, + tph: 0, + trbt: 0, + ph: 0, + blgcOxygDmndQnt: 0, + clIonQnt: 0, + smll: 0, + cdtnv: 0, + crmty: 0, + rmrk: "", + reqDt: "" + }, + constCostRes:[], + rateFeeRes:[], +}; + +export type comFcltType = comFcltState & comFcltActions; + export type comFcltState = { - searchFclts: pubHasuType; + searchFclts: pubHasuType[]; demandCompList: DemandCompType[]; dmdIsSucees: string; checkDemand: DemandCompType; @@ -16,7 +58,7 @@ export type comFcltState = { rateFeeRes:rateFeeType[], }; -export type comFcltActions = { + type comFcltActions = { getSwtrmtFcltNm: (searchNm: string) => void; getDemandCompList: (searchNm: string, cnt: number) => void; regDemandCompany: (data: DemandCompType) => void; @@ -25,7 +67,7 @@ export type comFcltActions = { getRateFee: (year: string) => void; }; -export const searchActions: (set: any) => comFcltActions = (set: any) => { +export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { return { getSwtrmtFcltNm: async (searchNm: string) => { const fcltNm = await getFetch( @@ -40,6 +82,7 @@ export const searchActions: (set: any) => comFcltActions = (set: any) => { addr: item.addr, fctCpc: item.fctCpc, })); + set((state: comFcltState) => ({ ...state, searchFclts: searchFclts, diff --git a/apps/wr/app/store/matDmd/drgtSttn/headList.tsx b/apps/wr/app/store/matDmd/drgtSttn/headList.tsx index 40eae47e3..1741b7456 100644 --- a/apps/wr/app/store/matDmd/drgtSttn/headList.tsx +++ b/apps/wr/app/store/matDmd/drgtSttn/headList.tsx @@ -1,5 +1,19 @@ +import { z } from "zod"; import type { CommonTableProps } from "../../common/type/header"; +export const drgtZod = z.object({ + ctpvCd: z.string().default(''), + sggNm: z.string().default(''), + normal: z.string().default(''), + attention: z.string().default(''), + caution: z.string().default(''), + warning: z.string().default(''), + ranking: z.string().default(''), + year: z.string().default(''), + month: z.string().default(''), + drgtState: z.string().default('') +}) + export const drgtHeadListExport: CommonTableProps[] = [ { id: "ctpvCd", @@ -10,21 +24,13 @@ export const drgtHeadListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "sggCd", + id: "sggNm", title: "시군구", visible: true, row: 1, rowSpan: 1, colSpan: 1, }, - { - id: "haengjung", - title: "행정동", - visible: true, - row: 1, - rowSpan: 1, - colSpan: 1, - }, { id: "normal", title: "정상(횟수)", @@ -83,16 +89,9 @@ export const drgtDetailHeadListExport: CommonTableProps[] = [ row: 1, rowSpan: 1, colSpan: 1, - },{ - id: "day", - title: "일", - visible: true, - row: 1, - rowSpan: 1, - colSpan: 1, }, { - id: "state", + id: "drgtState", title: "가뭄상태", visible: true, row: 1, diff --git a/apps/wr/app/store/matDmd/drgtSttn/index.tsx b/apps/wr/app/store/matDmd/drgtSttn/index.tsx index edbbc2f28..698ba5984 100644 --- a/apps/wr/app/store/matDmd/drgtSttn/index.tsx +++ b/apps/wr/app/store/matDmd/drgtSttn/index.tsx @@ -1,27 +1,147 @@ +import { fetchType, getFetch } from "@/components/lib/api"; import type { CommonTableProps } from "../../common/type/header"; -import { drgtHeadListExport } from "./headList"; +import { drgtHeadListExport, drgtZod } from "./headList"; +import type { z } from "zod"; const drgtHeadList = drgtHeadListExport; +export type customDrgt = z.infer; + +const drgtRes: customDrgt[] = []; + export type drgtState = { - drgt:{ - drgtHeadList: CommonTableProps[]; - } + drgt: { + drgtHeadList: CommonTableProps[]; + drgtRes: customDrgt[]; + drgtMoRes: customDrgt[]; + } } type drgtActions = { + drgtSearch: (fromDate: string, toDate: string, sido: string, sgg: string) => void + drgtModalSearch: (fromDate: string, toDate: string, sgg: string) => void }; export type drgtType = drgtState & drgtActions; export const drgtStateExport: drgtState = { - drgt: { - drgtHeadList: drgtHeadList, - } + drgt: { + drgtHeadList: drgtHeadList, + drgtRes: drgtRes, + drgtMoRes: drgtRes, + } } export const drgtActionsExport: (set: any) => drgtActions = ( set: any ) => { - return {}; -}; \ No newline at end of file + return { + drgtSearch: async (fromDate: string, toDate: string, sido: string, sgg: string) => { + try { + let searchUrl = ""; + + 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; + 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)], + })); + set((state: drgtState) => { + return { + ...state, + drgt: { + ...state.drgt, + drgtRes: drgtRes, + }, + } + }); + } catch (e) { + console.log(e) + } + }, + drgtModalSearch: async (fromDate: string, toDate: string, sgg: string) => { + try { + const drgtMoData = await getFetch( + fetchType.WR, + `/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; + const sggNm = item.sggNm; + return { + year: year, + month: month, + drgtState: drgtState, + sggNm: sggNm + } + }); + set((state: drgtState) => { + return { + ...state, + drgt: { + ...state.drgt, + drgtMoRes: drgtMoRes, + }, + } + }); + } catch (e) { + console.log(e) + } + }, + } +} \ No newline at end of file diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/excel.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/excel.tsx new file mode 100644 index 000000000..ebbaa8b7a --- /dev/null +++ b/apps/wr/app/store/matDmd/ruseCaseMng/excel.tsx @@ -0,0 +1,109 @@ +import { z } from "zod"; + +export const reUseCaseExcel = z.object({ + file: z.any() +}); + +type nameMap = { + [key: string]: string; +} + +export const reUseCaseNames: nameMap = { + "사업명": "ruseBizNm", + "사업시작일": "bizBgngDate", + "사업종료일": "bizEndtDate", + "공급처_시설종류": "splyFcltKnd", + "공급처명": "splyFcltNm", + "공급처_시설용량(㎥/일)": "splyFcltCpct", + "수요처명": "dmdFcltNm", + "수요처_주소": "dmdFcltAddr", + "재이용시설_시설용량(㎥/일)": "ruseFcltCpct", + "재이용시설_관로(km)": "ruseFcltPplLen", + "재이용시설_용도": "ruseFcltUsg", + "재이용시설_공급량(㎥/일)": "ruseFcltSplyCpct", + "재이용시설_처리공법": "ruseFcltPrcsMsrc", + "보증수질_용도별": "grnteWqUsg", + "보증수질_총대장균군수": "grnteWqGrssClfg", + "보증수질_결합잔류염소": "grnteWqCombResdch", + "보증수질_탁도": "grnteWqTrbt", + "보증수질_생물학적산소요구량(BOD)(mg/L)": "grnteWqBod", + "보증수질_냄새": "grnteWqSmll", + "보증수질_색도(도)": "grnteWqCrmty", + "보증수질_총질소(T-N)(mg/L)": "grnteWqTn", + "보증수질_총인(T-P)(mg/L)": "grnteWqTp", + "보증수질_수소이온농도(pH)": "grnteWqPh", + "보증수질_염화물": "grnteWqClIonQnt", + "보증수질_전기전도도": "grnteWqCndctStat", + "보증수질_비고": "grnteWqRmrk", + "소요사업비_총(백만원)": "reqBizGrssCst", + "소요사업비_토목_재이용시설(백만원)": "reqBizReuseFcltCst", + "소요사업비_토목_관로(백만원)": "reqBizPplCst", + "소요사업비_건축(백만원)": "reqBizArchCst", + "소요사업비_기계(백만원)": "reqBizMchnCst", + "소요사업비_전기.계측(백만원)": "reqBizMtrngCst", + "소요사업비_GIS DB(백만원)": "reqBizGisCst", + "소요사업비_CCTV(백만원)": "reqBizCctvCst", + "소요사업비_시공 및 준공(백만원)": "reqBizCmcnCst", + "소요사업비_폐기물(백만원)": "reqBizWstCst", + "소요사업비_설계비(백만원)": "reqBizDesignCst", + "소요사업비_감리비(백만원)": "reqBizSpvsCst", + "소요사업비_시설부대비(백만원)": "reqBizSbsdCst", + "소요사업비_기타(백만원)": "reqBizEtc", + "재원조달계획_총(백만원)": "prcmPlanGrssCst", + "재원조달계획_국비(백만원)": "prcmPlanNlep", + "재원조달계획_지방비(백만원)": "prcmPlanLcep", + "재원조달계획_원인자부담(백만원)": "prcmPlanBrdnCst", + "재원조달계획_국고비율(백만원)": "prcmPlanEcqrRt", + "사업비 정산_총(백만원)": "clclnGrssCst", + "사업비 정산_국비(백만원)": "clclnNlep", + "사업비 정산_지방비(백만원)": "clclnLcep", + "사업비 정산_원인자부담(백만원)": "clclnBrdnCst", + "사업비 정산_국고비율(백만원)": "clclnEcqrRt" +} + +interface PbnstSttnItem { + rvbsn: string; + lgbsn: number; + mdmbsn?: string; + rgnNm?: string; + sido?: number; + gugun?: number; + bscFctNm?: string; + efflWqltStndrdNm?: string; + fctCpc?: number; + tel?: string; + ruseUtztnFcltNm?: string; + fcltCpct?: number; + splyExtraCpct?: number; + ruseCpct?: number; + usageTotal?: number; + inUsage?: number; + outUsage?: number; +} + +export const excelPbnstSttnParsing = (data: PbnstSttnItem[]): 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 ?? ""), + ]) + }) + return excelExportData; +}; \ No newline at end of file diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx index 125866601..8c3a232e7 100644 --- a/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx +++ b/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx @@ -4,15 +4,22 @@ import type { TableUpperProps } from "../../common/type/header"; //★☆★☆ 여기서부터 수정하기 ★☆★☆ export const ruseCaseHeadListExport: TableUpperProps[] = [ { - id: "a", + id: "ruseBizNm", title: "사업명", visible: true, row: 0, rowSpan: 2, }, { - id: "b", - title: "사업기간", + id: "bizBgngDate", + title: "사업시작일", + visible: true, + row: 0, + rowSpan: 2, + }, + { + id: "bizEndDate", + title: "사업종료일", visible: true, row: 0, rowSpan: 2, @@ -25,19 +32,19 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ colSpan: 3, }, { - id: "d", + id: "splyFcltKnd", title: "시설종류", visible: true, row: 1, }, { - id: "e", + id: "splyFcltNm", title: "공급처명", visible: true, row: 1, }, { - id: "f", + id: "splyFcltCpct", title: "시설용량(m³/일)", visible: true, row: 1, @@ -50,13 +57,13 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ colSpan: 2, }, { - id: "h", + id: "dmdFcltNm", title: "수요처명", visible: true, row: 1, }, { - id: "i", + id: "dmdFcltAddr", title: "주소", visible: true, row: 1, @@ -69,31 +76,31 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ colSpan: 5, }, { - id: "q2", + id: "ruseFcltCpct", title: "시설용량(m³/일)", visible: true, row: 1, }, { - id: "q3", + id: "ruseFcltPplLen", title: "관로(km)", visible: true, row: 1, }, { - id: "q4", + id: "ruseFcltUsg", title: "용도", visible: true, row: 1, }, { - id: "q5", + id: "ruseFcltSplyCpct", title: "공급량(m³/일)", visible: true, row: 1, }, { - id: "q6", + id: "ruseFcltPrcsMsrc", title: "처리공법", visible: true, row: 1, @@ -106,79 +113,79 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ colSpan: 13, }, { - id: "k1", + id: "grnteWqUsg", title: "용도별", visible: true, row: 1, }, { - id: "k2", + id: "grnteWqGrssClfg", title: "총대장균군수​(개/100ml)", visible: true, row: 1, }, { - id: "k3", + id: "grnteWqCombResdch", title: "결합잔류염소(mg/L)", visible: true, row: 1, }, { - id: "k4", + id: "grnteWqTrbt", title: "탁도(NTU)", visible: true, row: 1, }, { - id: "k5", + id: "grnteWqBod", title: "생물학적​산소요구량(BOD)(mg/L)​", visible: true, row: 1, }, { - id: "k6", + id: "grnteWqSmll", title: "냄새​", visible: true, row: 1, }, { - id: "k7", + id: "grnteWqCrmty", title: "색도​", visible: true, row: 1, }, { - id: "k8", + id: "grnteWqTn", title: "총질소(T-N)(mg/L)​", visible: true, row: 1, }, { - id: "k9", + id: "grnteWqTp", title: "총인(T-P)(mg/L)", visible: true, row: 1, }, { - id: "k10", + id: "grnteWqPh", title: "수소이온농도(PH)​", visible: true, row: 1, }, { - id: "k11", - title: "수소이온농도(PH)​", + id: "grnteWqClIonQnt", + title: "염화물", visible: true, row: 1, }, { - id: "k12", - title: "전기전도도​(㎲/cm", + id: "grnteWqCndctStat", + title: "전기전도도​(㎲/cm)", visible: true, row: 1, }, { - id: "k13", + id: "grnteWqRmrk", title: "비고​", visible: true, row: 1, @@ -191,85 +198,85 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ colSpan: 14, }, { - id: "h1", + id: "reqBizGrssCst", title: "총", visible: true, row: 1, }, { - id: "h2", - title: "토목재이용시설", + id: "reqBizReuseFcltCst", + title: "토목재이용시설", visible: true, row: 1, }, { - id: "h3", + id: "reqBizPplCst", title: "토목관로", visible: true, row: 1, }, { - id: "h4", + id: "reqBizArchCst", title: "건축", visible: true, row: 1, }, { - id: "h5", + id: "reqBizMchnCst", title: "기계", visible: true, row: 1, }, { - id: "h6", + id: "reqBizMtrngCst", title: "전기・계측", visible: true, row: 1, }, { - id: "h7", + id: "reqBizGisCst", title: "GIS・DB", visible: true, row: 1, }, { - id: "h8", + id: "reqBizCctvCst", title: "CCTV", visible: true, row: 1, }, { - id: "h9", + id: "reqBizCmcnCst", title: "시공및준공", visible: true, row: 1, }, { - id: "h10", + id: "reqBizWstCst", title: "페기물", visible: true, row: 1, }, { - id: "h11", - title: "설계비", + id: "reqBizDesignCst", + title: "설계비", visible: true, row: 1, }, { - id: "h12", + id: "reqBizSpvsCst", title: "감리비", visible: true, row: 1, }, { - id: "h13", + id: "reqBizSbsdCst", title: "시설부대비", visible: true, row: 1, }, { - id: "h14", + id: "reqBizEtc", title: "기타", visible: true, row: 1, @@ -279,32 +286,38 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ title: "자원조달계획(백만원)", visible: true, row: 0, - colSpan: 4, + colSpan: 5, }, { - id: "i1", + id: "prcmPlanGrssCst", title: "총", visible: true, row: 1, }, { - id: "i2", + id: "prcmPlanNlep", title: "국비", visible: true, row: 1, }, { - id: "i3", + id: "prcmPlanLcep", title: "지방비", visible: true, row: 1, }, { - id: "i4", + id: "prcmPlanBrdnCst", title: "원인자부담", visible: true, row: 1, }, + { + id: "prcmPlanEcqrRt", + title: "국고비율", + visible: true, + row: 1, + }, { id: "j", title: "사업비정산(백만원)", @@ -313,31 +326,31 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ colSpan: 5, }, { - id: "j1", + id: "clclnGrssCst", title: "총", visible: true, row: 1, }, { - id: "j2", + id: "clclnNlep", title: "국비", visible: true, row: 1, }, { - id: "j3", + id: "clclnLcep", title: "지방비", visible: true, row: 1, }, { - id: "j4", + id: "clclnBrdnCst", title: "원인자부담", visible: true, row: 1, }, { - id: "j5", + id: "clclnEcqrRt", title: "국고비율", visible: true, row: 1, diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx index c54b0db1a..915740f79 100644 --- a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx +++ b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx @@ -1,24 +1,117 @@ +import { fetchType, getFetch, postFectch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; import { ruseCaseHeadListExport } from "./headList"; +import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; export type ruseCaseState = { - ruseCase: { - ruseHeadList:TableUpperProps[]; - }; + ruseCaseMng: { + ruseHeadList:TableUpperProps[]; + ruseCaseMngList:ruseCaseMngExcelProps[]; }; -type ruseCaseActions = { }; + +export interface ruseCaseMngExcelProps { + ruseBizNm: string, + bizBgngDate: string, + bizEndDate: string, + splyFcltKnd: string, + splyFcltNm: string, + splyFcltCpct: number | 0 |'', + dmdFcltNm: string, + dmdFcltAddr: string, + ruseFcltCpct: number | 0 |'', + ruseFcltPplLen: string, + ruseFcltUsg: string, + ruseFcltSplyCpct: number | 0 |'', + ruseFcltPrcsMsrc: string, + grnteWqUsg: string, + grnteWqGrssClfg: number | 0 |'', + grnteWqCombResdch: number | 0 |'', + grnteWqTrbt: string, + grnteWqBod: string, + grnteWqSmll: string, + grnteWqCrmty: string, + grnteWqTn: string, + grnteWqTp: string, + grnteWqPh: string, + grnteWqClIonQnt: string, + grnteWqCndctStat: string, + grnteWqRmrk: string, + reqBizReuseFcltCst: number | 0 |'', + reqBizPplCst: number | 0 |'', + reqBizArchCst: number | 0 |'', + reqBizMchnCst: number | 0 |'', + reqBizMtrngCst: number | 0 |'', + reqBizGisCst: number | 0 |'', + reqBizCctvCst: number | 0 |'', + reqBizCmcnCst: number | 0 |'', + reqBizWstCst: number | 0 |'', + reqBizDesignCst: number | 0 |'', + reqBizSpvsCst: number | 0 |'', + reqBizSbsdCst: number | 0 |'', + reqBizEtc: string, + reqBizGrssCst: number | 0 |'', + prcmPlanNlep: number | 0 |'', + prcmPlanLcep: number | 0 |'', + prcmPlanBrdnCst: number | 0 |'', + prcmPlanEcqrRt: number | 0 |'', + prcmPlanGrssCst: number | 0 |'', + clclnNlep: number | 0 |'', + clclnLcep: number | 0 |'', + clclnBrdnCst: number | 0 |'', + clclnEcqrRt: number | 0 |'', + clclnGrssCst: number | 0 |'', +} + +type ruseCaseActions = { + selectRuseCaseMng: (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => Promise; + insertRuseCaseMng: (data: any) => Promise; +}; + +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 fetchInsertRuseCaseMng = async (data: any) => { + const response = await postFectch('/reuseFc/pubFcRuseCase', data, fetchType.WR); + return response.data; +}; + export type ruseCaseType = ruseCaseState & ruseCaseActions; export const ruseCaseStateExport: ruseCaseState = { - ruseCase: { - ruseHeadList:ruseCaseHeadListExport, + ruseCaseMng: { + ruseHeadList:ruseCaseHeadListExport, + ruseCaseMngList:[], }, }; -export const ruseCaseActionsExport: (set: any) => ruseCaseActions = ( + +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); + set((state: ruseCaseState) => ({ + ruseCaseMng: { + ...state.ruseCaseMng, + ruseCaseMngList: res, + }, + })); + }, + + insertRuseCaseMng: async (data: any) => { + const response = await fetchInsertRuseCaseMng(data); + if(response.status === 200){ + ToastFormUi({ + body: "잠재수요처 등록이 완료되었습니다. ", + title: "잠재수요처 등록", + }); + } + }, }; }; diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx index 3cc75d70c..d8057cad6 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx @@ -17,7 +17,7 @@ export const chkgdRegExcel = z.object({ }, { message: "현재 년도보다 높은 수를 입력할 수 없습니다." } ), - file: z.instanceof(File).optional(), + file: z.instanceof(File).nullish(), }); export const guideDetail = z.object({ diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index ff612a0fb..3bd10169f 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -61,7 +61,7 @@ type rainChkgdnActions = { ): Promise; rainChkExcelDataUPload(excelData: rainChkZodType[]): Promise; rainChkDelete(chkgdnPks: number[]): Promise; - rainChkHeadChange: (rainChkgdn: rainChkgdnState, isEdit :boolean) => void; + rainChkHeadChange: (rainChkgdn: rainChkgdnState, isEdit: boolean) => void; }; export type rainChkgdnType = rainChkgdnState & rainChkgdnActions; @@ -99,9 +99,10 @@ const makeMdfrChk = (data: rainChkZodType[], type: string, toDo: string) => { }; const initFetch = async (txt: string | undefined, sgg: string | undefined) => { + const currentYear = new Date().getFullYear().toString(); const rainRes = await getFetch( "wr", - `/reuseChk/rainy` + (txt ? `/${txt}` : "2024") + (sgg ? `/${sgg}` : "/0") + `/reuseChk/rainy` + (txt ? `/${txt}` : currentYear) + (sgg ? `/${sgg}` : "/0") ); return rainRes; }; @@ -130,13 +131,16 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( rainChkExcelDataUPload: async (excelData: rainChkZodType[]) => { try { const res = await postFectch("/reuseChk/rainy", excelData); + console.log("res", res); + console.log("res.ok", res.ok) if (res.ok) { ToastFormUi({ body: "지도점검 등록이 완료되었습니다. ", title: "지도점검 등록", }); } - const rainChkRes = await initFetch("2024", "0"); + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch(currentYear, "0"); return set((state: rainChkgdnState) => ({ ...state, rainChkgdn: { @@ -178,7 +182,8 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( title: "지도점검 수정", }); } - const rainChkRes = await initFetch("2024", "0"); + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch(currentYear, "0"); return set((state: rainChkgdnState) => ({ ...state, rainChkgdn: { @@ -201,7 +206,8 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( title: "지도점검 수정", }); } - const rainChkRes = await initFetch("2024", "0"); + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch(currentYear, "0"); return set((state: rainChkgdnState) => ({ ...state, rainChkgdn: { @@ -223,7 +229,8 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( title: "지도점검 삭제", }); } - const rainChkRes = await initFetch("2024", "0"); + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch(currentYear, "0"); return set((state: rainChkgdnState) => ({ ...state, rainChkgdn: { @@ -235,23 +242,23 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" }); } }, - rainChkHeadChange: async (rainChkgdn: rainChkgdnState , isEdit :boolean) => { + rainChkHeadChange: async (rainChkgdn: rainChkgdnState, isEdit: boolean) => { try { const rainChkgdnHeadList = rainChkgdn.rainChkgdn.rainChkgdnHeadList; const splHeadList = rainChkgdn.rainChkgdn.splHeadList; const ruseHeadList = rainChkgdn.rainChkgdn.ruseHeadList; - rainChkgdnHeadList.forEach(( head) => { - if(head.edit!== undefined) - head.edit=isEdit; + rainChkgdnHeadList.forEach((head) => { + 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) => ({ @@ -259,8 +266,8 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( rainChkgdn: { ...state.rainChkgdn, rainChkgdnHeadList: rainChkgdnHeadList, - splHeadList:splHeadList, - ruseHeadList:ruseHeadList + splHeadList: splHeadList, + ruseHeadList: ruseHeadList }, })); } catch (error) { diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx index eb0010047..1cc7bd766 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx @@ -80,10 +80,11 @@ export const rswtChkgdnStateExport: rswtChkgdnState = { }; const initFetch = async (year: string | undefined, sgg: string | undefined) => { + const currentYear = new Date().getFullYear().toString(); const rswtChkRes = await getFetch( "wr", `/reuseChk/reuseWater/` + - (year ? `${year}` : "2024") + + (year ? `${year}` : currentYear) + (sgg ? `/${sgg}` : "/0") ); return rswtChkRes; @@ -121,12 +122,12 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( excelList.push({ data: exceldata.guideDetail, headerNum: 0, - headerRange: "A1:AI1", + headerRange: "A1:AJ1", }); excelList.push({ data: exceldata.polutions, headerNum: 0, - headerRange: "A1:AZ1", + headerRange: "A1:BB1", }); return set((state: rswtChkgdnState) => ({ @@ -138,7 +139,7 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( }, rswtChkgdnInit: async (year: string, sggCd: string) => { try { - const rswtChkRes = await initFetch("2024", sggCd); + const rswtChkRes = await initFetch(year, sggCd); return set((state: rswtChkgdnState) => ({ ...state, @@ -161,11 +162,13 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( title: "지도점검 등록", }); } - // const rainChkRes = await initFetch('2024', '0'); + const currentYear = new Date().getFullYear().toString(); + const rswtChkRes = await initFetch(currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { ...state.rswtChkgdn, + rswtChkRes: rswtChkRes }, })); } catch (error) { @@ -184,7 +187,8 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( title: "지도점검 수정", }); } - const rswtChkRes = await initFetch("2024", "0"); + const currentYear = new Date().getFullYear().toString(); + const rswtChkRes = await initFetch(currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { @@ -207,7 +211,8 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( title: "지도점검 삭제", }); } - const rswtChkRes = await initFetch("2024", "0"); + const currentYear = new Date().getFullYear().toString(); + const rswtChkRes = await initFetch(currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { @@ -259,7 +264,8 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( title: "지도점검 수정", }); } - const rswtChkRes = await initFetch("2024", "0"); + const currentYear = new Date().getFullYear().toString(); + const rswtChkRes = await initFetch(currentYear, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx index 87e827f60..82f2ed59c 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx @@ -77,7 +77,6 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = ( prfmncHasuInit: async (page: string, sggOrCity: string) => { try { const prfmncRes = await hasuListFetch(page, sggOrCity); - console.log("prfmncRes", prfmncRes); return set((state: pbnstPrfmncState) => ({ ...state, prfmnc: { diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx index 9fd948856..ea3f58a40 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx @@ -35,7 +35,7 @@ export type rainChkSttnState = { }; type rainChkSttnActions = { - rainChkSttnInit: ( sggCd: string) => void; + rainChkSttnInit: (searchTxt: string, sggCd: string) => void; rainChkSttnSearch: (searchTxt: string, sggCd: string) => void; isRainSttn:(isSttn:boolean) => void; getRainSttnExcel:(excelList:rainChkZodType[]) => void; @@ -58,9 +58,10 @@ export const rainChkSttnStateExport: rainChkSttnState = { }; const initFetch = async (txt: string | undefined, sgg: string | undefined) => { + const currentYear = new Date().getFullYear().toString(); const rainRes = await getFetch( "wr", - `/reuseChk/rainy/` + (txt ? `${txt}` : "2024") + (sgg ? `/${sgg}` : "/0") + `/reuseChk/rainy/` + (txt ? `${txt}` : currentYear) + (sgg ? `/${sgg}` : "/0") ); return rainRes; }; @@ -68,9 +69,9 @@ export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = ( set: any ) => { return { - rainChkSttnInit: async ( sggCd: string) => { + rainChkSttnInit: async (searchTxt: string, sggCd: string) => { try { - const rainChkRes = await initFetch(undefined, sggCd); + const rainChkRes = await initFetch(searchTxt, sggCd); return set((state: rainChkSttnState) => ({ ...state, diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx index ff104bc91..6e6b5730c 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx @@ -19,6 +19,7 @@ export const buildingExcelRswtSttn = (excelList: any[]) => { String(item.trbt) ?? "", String(item.bod) ?? "", String(item.smll) ?? "", + String(item.crmty) ?? "", String(item.tn) ?? "", String(item.tph) ?? "", String(item.ph) ?? "", diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx index f67e98101..91f6bf718 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx @@ -1,15 +1,15 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; export const rswtChkSttnHeadListExport: TableUpperProps[] = [ - { id: "order", title: "순번", rowSpan: true }, - { id: "cityText", title: "시도", rowSpan: true }, - { id: "sggText", title: "시군구", rowSpan: true }, - { id: "bdstNm", title: "시설명", rowSpan: true }, - { id: "operMngCd", title: "운영관리형태", rowSpan: true }, - { id: "anlOperCst", title: "연간운영비(원/년)", rowSpan: true }, - { id: "prcsCpct", title: "처리용량(m³)", rowSpan: true }, - { id: "spwtPositn", title: "채수지점", rowSpan: true }, - { id: "chckYmd", title: "점검일", rowSpan: true }, + { id: "order", title: "순번", mergeCell: true }, + { id: "cityText", title: "시도", mergeCell: true }, + { id: "sggText", title: "시군구", mergeCell: true }, + { id: "bdstNm", title: "시설명", mergeCell: true }, + { id: "operMngCd", title: "운영관리형태", mergeCell: true }, + { id: "anlOperCst", title: "연간운영비(원/년)", mergeCell: true }, + { id: "prcsCpct", title: "처리용량(m³)", mergeCell: true }, + { id: "spwtPositn", title: "채수지점", mergeCell: true }, + { id: "chckYmd", title: "점검일", mergeCell: true }, { id: "utztnUsgCd", title: "이용용도" }, { id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)", type: "number" }, { id: "ruseFcltUtztnQnt", title: "연간중수도이용량(m³)", type: "number" }, diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx index b985cd944..cd95ef1fc 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx @@ -24,10 +24,10 @@ export type rswtChkSttnState = { }; type rswtChkSttnActions = { - rswtChkSttnInit: ( sggCd: string) => void; - isRswtSttn: (isSttn:boolean) => void; - getRswtSttnExcel:(excelList:rswtChkZodType[]) => void; - + rswtChkSttnInit: (searchTxt: string, sggCd: string) => void; + isRswtSttn: (isSttn: boolean) => void; + getRswtSttnExcel: (excelList: rswtChkZodType[]) => void; + rswtChkSttnSearch: (searchTxt: string, sggCd: string) => void; }; export type rswtChkSttnType = rswtChkSttnState & rswtChkSttnActions; @@ -40,16 +40,17 @@ export const rswtChkStateExport: rswtChkSttnState = { sttnExcelList: [], rswtChkRes: [], isInit: false, - isSttn:false, + isSttn: false, }, }; const initFetch = async (year: string | undefined, sgg: string | undefined) => { + const currentYear = new Date().getFullYear().toString(); const rswtChkRes = await getFetch( "wr", `/reuseChk/reuseWater/` + - (year ? `${year}` : "2024") + - (sgg ? `/${sgg}` : "/0") + (year ? `${year}` : currentYear) + + (sgg ? `/${sgg}` : "/0") ); return rswtChkRes; }; @@ -59,9 +60,9 @@ export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = ( set: any ) => { return { - rswtChkSttnInit: async ( sggCd: string) => { + rswtChkSttnInit: async (searchTxt: string, sggCd: string) => { try { - const rswtChkRes = await initFetch("2024", sggCd); + const rswtChkRes = await initFetch(searchTxt, sggCd); return set((state: rswtChkSttnState) => ({ ...state, rswtChkSttn: { @@ -73,35 +74,50 @@ export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = ( } catch (error) { console.log(error); } - },isRswtSttn :(isSttn:boolean) =>{ - try { - return set((state: rswtChkSttnState) => ({ - ...state, - rswtChkSttn: { - ...state.rswtChkSttn, - isSttn:isSttn - }, - })); - } catch (error) { - console.log(error); - } - },getRswtSttnExcel: async (excelList:rswtChkZodType []) => { - try { - - const excelData = buildingExcelRswtSttn(excelList) - - return set((state: rswtChkSttnState) => ({ - ...state, - rswtChkSttn: { - ...state.rswtChkSttn, - sttnExcelList:excelData - }, - })); - } catch (error) { - console.log(error); - } - } + }, + isRswtSttn: (isSttn: boolean) => { + try { + return set((state: rswtChkSttnState) => ({ + ...state, + rswtChkSttn: { + ...state.rswtChkSttn, + isSttn: isSttn + }, + })); + } catch (error) { + console.log(error); + } + }, + getRswtSttnExcel: async (excelList: rswtChkZodType[]) => { + try { - + const excelData = buildingExcelRswtSttn(excelList) + + return set((state: rswtChkSttnState) => ({ + ...state, + rswtChkSttn: { + ...state.rswtChkSttn, + sttnExcelList: excelData + }, + })); + } catch (error) { + console.log(error); + } + }, + rswtChkSttnSearch: async (searchTxt: string, sggCd: string) => { + try { + const rswtChkRes = await initFetch(searchTxt, sggCd); + + return set((state: rswtChkSttnState) => ({ + ...state, + rswtChkSttn: { + ...state.rswtChkSttn, + rswtChkRes: rswtChkRes + }, + })); + } catch (error) { + console.log(error); + } + }, }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx index 0a51ebb5d..314d5762b 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx @@ -1,10 +1,63 @@ import { getFetch, postFectch, putFectch } from "@/components/lib/api"; -import { upHeadList, type chgBuilding} from "../rainReg"; +import { upHeadList, type chgBuilding } from "../rainReg"; import { z } from "zod"; import { makeMdfr, makeRstr } from "../bdstReg"; +import { + baseReuseBuildingSchema, + chgBuildingSchema, + validationMessages, +} from "../rainReg/type"; // Import baseReuseBuildingSchema, chgBuildingSchema, validationMessages import type { TableUpperProps } from "@/app/store/common/type/header"; +const hdtflObjSchema = z.object({ + htdflFcltPk: z.number().nullish(), + bdstRuseFcltFk: z.number().nullish(), + etgtType: z + .string() + .min(1, { message: validationMessages.required("에너지원 종류") }), + fclCpct: z + .number() + .positive({ message: validationMessages.required("시설 용량") }), + plwtYn: z.enum(["Y", "N"]).default("Y"), + orgwtWtritSpt: z + .number() + .positive({ message: validationMessages.required("원수 취수량") }), + orgwtOcrnProcs: z + .string() + .min(1, { message: validationMessages.required("원수 발생 공정") }), + wtritEntrcTp: z + .number() + .max(100, { message: "온도는 100이상이 될 수 없습니다." }) + .default(0), // Changed max to 100 based on message + amtgnr: z.number().default(0), + prcsProcsYn: z.enum(["Y", "N"]).default("Y"), + prcsFcltCpct: z + .number() + .positive({ message: validationMessages.required("처리시설 용량") }), + fmYn: z.string().default(""), + utztnCpct: z + .number() + .positive({ message: validationMessages.required("이용 용량") }), + utztnUsg: z + .string() + .min(1, { message: validationMessages.required("이용 용도") }), + grssClfg: z.number().default(0), // Measurements, 0 is fine as default + combResdch: z.number().default(0), // Measurements, 0 is fine as default + trbt: z.number().default(0), // Measurements, 0 is fine as default + bod: z.number().default(0), // Measurements, 0 is fine as default + smll: z.number().default(0), // Measurements, 0 is fine as default + crmty: z.number().default(0), // Measurements, 0 is fine as default + tn: z.number().default(0), // Measurements, 0 is fine as default + tph: z.number().default(0), // Measurements, 0 is fine as default + 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 + rgtr: z.string().nullish().default(null), + mdfr: z.string().nullish().default(null), +}); + export const hdtflZod = z.object({ bdstInfoPk: z.number().nullish(), ctpvCd: z.number().default(0), @@ -14,85 +67,25 @@ export const hdtflZod = z.object({ daddr: z.string().default(" "), bdstNm: z.string().default(" "), frstArchPrmsnDt: z.date().default(() => new Date()), - archChgPrmsnDt: z.date().default(() => new Date()).nullish() , + archChgPrmsnDt: z + .date() + .default(() => new Date()) + .nullish(), archArea: z.number().default(0), archChgArea: z.number().nullish().default(0), - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), + rgtr: z.string().nullish().default(null), + mdfr: z.string().nullish().default(null), reuseBuilding: z .array( - z.object({ - bdstRuseFcltPk: z.number().nullish(), - bdstInfoFk: z.number().nullish(), - instlCmptnDt: z.coerce.date().default(() => new Date()), - instlCst: z.number().nullish().default(0), - operMngCd: z.string().nullish().default(""), - anlOperCst: z.number().default(0), - instlCstSprtYn: z.enum(["Y", "N"]).nullish(), - instlCstSprtAmt: z.number().nullish().default(0), - grntchBdstCertNo: z.string().nullish().default(""), - grntchBdstCertGrd: z.string().nullish().default(""), - ruseFcltFlg: z.string().nullish().default(""), - bdstUsgCd: z.number().default(0), - lawTrgtYn: z.enum(["Y", "N"]).nullish(), - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), - // htdflObj 매핑 - htdflObj: z - .object({ - htdflFcltPk: z.number().nullish(), - bdstRuseFcltFk: z.number().nullish(), - etgtType: z.string().default(""), - fclCpct: z.number().default(0), - plwtYn: z.enum(["Y", "N"]), - orgwtWtritSpt: z.number().default(0), - orgwtOcrnProcs: z.string().default(""), - wtritEntrcTp: z.number().max(4, "온도는 100이상이 될 수 없습니다.") - .default(0), - amtgnr: z.number().default(0), - prcsProcsYn: z.enum(["Y", "N"]), - prcsFcltCpct: z.number().default(0), - fmYn: z.string().default(""), - utztnCpct: z.number().default(0), - utztnUsg: z.string().default(""), - grssClfg: z.number().default(0), - combResdch: z.number().default(0), - trbt: z.number().default(0), - bod: z.number().default(0), - smll: z.number().default(0), - crmty: z.number().default(0), - tn: z.number().default(0), - tph: z.number().default(0), - ph: z.number().default(0), - clIonQnt: z.number().default(0), - cdtnv: z.number().default(0), - emsnExitTp: z.number().default(0), - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), - }) - .default({ - plwtYn: "N", - prcsProcsYn: "N", - }), - }) - ) - .default([]), - chgBuilding: z - .array( - z.object({ - bdstInfoFk: z.number().nullish(), - archChgPrmsnDt: z.coerce.date() , - archChgArea: z.string().default("-").nullish(), - bdstChgNm: z.string().default(""), - rgtr:z.string().nullish().default(null), - mdfr:z.string().nullish().default(null), + baseReuseBuildingSchema.extend({ + htdflObj: hdtflObjSchema, }) ) .default([]), + chgBuilding: z.array(chgBuildingSchema).default([]), // Use imported chgBuildingSchema }); - export type customHtdflBdst = z.infer - +export type customHtdflBdst = z.infer; export type htdflFacState = { htdfl: { @@ -102,11 +95,10 @@ export type htdflFacState = { }; }; type htdflFacSActions = { - initHtdfl: (code: string ) => void; - htdflBdstUpdate:(data: customHtdflBdst, code:string|number) => void; - htdflBdstReg:(data: customHtdflBdst, code:string|number) => void; - getHtdflBdstData:(pageNation:number, code:string|number) =>void; - + initHtdfl: (code: string) => void; + htdflBdstUpdate: (data: customHtdflBdst, code: string | number) => void; + htdflBdstReg: (data: customHtdflBdst, code: string | number) => void; + getHtdflBdstData: (pageNation: number, code: string | number) => void; }; const htdflRes: customHtdflBdst[] = []; @@ -121,25 +113,22 @@ export const htdflFacStateExport: htdflFacState = { }, }; +const initFetch = async (code: string | number) => { + const rswtRes = await getFetch("wr", `/facilityList/1/20/${code}`); -const initFetch = async (code:string|number) => { - const rswtRes = await getFetch( - "wr", - `/facilityList/1/20/${code}`) - return rswtRes; }; export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( set: any ) => { return { - getHtdflBdstData: async (pageNation: number, code: string | number) => { + getHtdflBdstData: async (pageNation: number, code: string | number) => { try { const rswtRes = await getFetch( "wr", `/drain/facilityList/${pageNation}/20/${code}` ); - console.log(pageNation) + console.log(pageNation); // 여기서 상태 업데이트 return set((state: htdflFacState) => ({ ...state, @@ -154,8 +143,7 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( } }, - - initHtdfl: async (code: string ) => { + initHtdfl: async (code: string) => { try { const htdflRes = await initFetch(code); set((state: htdflFacState) => { @@ -172,9 +160,9 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( console.log(error); } }, - htdflBdstUpdate: async (data: customHtdflBdst, code:string|number) => { + htdflBdstUpdate: async (data: customHtdflBdst, code: string | number) => { try { - const chData=await makeMdfr(data) + const chData = await makeMdfr(data); const res = await putFectch("/drain/facility", data); if (res.ok) { alert(" 수정이 완료되었습니다."); @@ -196,18 +184,17 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( ); } }, - htdflBdstReg: async (data: customHtdflBdst , code:string|number) => { + htdflBdstReg: async (data: customHtdflBdst, code: string | number) => { try { - const chData=await makeRstr(data) + const chData = await makeRstr(data); const res = await postFectch("/drain/facility", data); if (res.ok) { - - if(data.chgBuilding.length > 0){ + 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, @@ -222,9 +209,8 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( alert("등록이 완료되었습니다."); } }); - }else{ + } else { alert("등록이 완료되었습니다."); - } } const htdflRes = await initFetch(code); @@ -238,7 +224,7 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( })); } catch (errorReg) { alert("등록 오류입니다."); - } + } }, }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx index 536114f3f..d77f4d7f0 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx @@ -31,8 +31,8 @@ export const pbnstMngUpHeadListExport: TableUpperProps[] = [ export const pplInstlsHeadListExport: TableUpperProps[] = [ { id: "choose", title: "선택", type: "checkbox" }, { id: "ppMqlt", title: "관재질", type: "select", selectData: "pplQulity" }, - { id: "pdmt", title: "관경", type: "select", selectData: "pplLenght" }, - { id: "cpct", title: "연장", edit: true, type: "number" }, + { id: "pdmt", title: "관경(mm)", type: "select", selectData: "pplLenght" }, + { id: "cpct", title: "연장(m)", edit: true, type: "number" }, ]; export const pbnstDemandHeadListExport: TableUpperProps[] = [ @@ -69,20 +69,21 @@ export type formDetailType = { id: string; lable: string; type?: string; + selectData?: string; // select box일 경우 option?:string }; export const wasteWaterFcltINfo: formDetailType[] = [ - { id: "wwtEmsnFcltPrmsnYn", lable: "폐수배출물신고 허가여부", type: "selectYn" }, - { id: "tmsInstlYn", lable: "Tms설치여부", type: "selectYn" }, - { id: "pbnstDrngInflwExclYn", lable: "공공하수도유입제외 허가여부", type: "selectYn" }, + { id: "wwtEmsnFcltPrmsnYn", lable: "폐수배출물신고 허가여부", type: "select" , selectData: "yn"}, + { id: "tmsInstlYn", lable: "Tms설치여부", type: "select" , selectData: "yn" }, + { id: "pbnstDrngInflwExclYn", lable: "공공하수도유입제외 허가여부", type: "select" , selectData: "yn" }, ]; export const concentratedWaterInfo: formDetailType[] = [ { id: "erctWtrOcrnCpct", lable: "눙축수 발생량(m³/일)", type: "number" }, { id: "erctUswtrLinkSpt", lable: "눙축수연계지점" }, { id: "erctUswtrFcltCpct", lable: "시설용량(m³/일)", type: "number" }, - { id: "erctUswtrPrcsMeth", lable: "눙축수처리방식" }, + { id: "erctUswtrPrcsMeth", lable: "눙축수처리방식", type : "select", selectData: "erctUswtrPrcsMeth" }, { id: "erctUswtrPrcsMsrcCd", lable: "눙축수처리공법" }, ]; @@ -90,8 +91,8 @@ export const ruseFcltinfo: formDetailType[] = [ { id: "rprcsFcltCpct", lable: "시설용량(m³/일)", type: "number" }, { id: "majorPrcsMsrcCd", lable: "주처리공법" }, { id: "addr", lable: "위치(주소)" }, - { id: "rprcsMthdCd", lable: "재처리방식" }, - { id: "inoutYn", lable: "위치(처리장 내외)" ,type: "selectYn" }, // 머가 내? 외?, + { id: "rprcsMthdCd", lable: "재처리방식", type: "select", selectData: "rusePrcsMthdCd" }, + { id: "inoutYn", lable: "위치(처리장 내외)" ,type: "select" , selectData: "yn"}, // 머가 내? 외?, { id: "mainSplyPumpCpct", lable: "메인공급펌프 용량", type: "number" }, ]; @@ -100,12 +101,12 @@ export const businessMoneyInfo: formDetailType[] = [ { id: "lcep", lable: "지방비", type: "number" }, { id: "cusrAlotm", lable: "민간투자비", type: "number" }, { id: "etc", lable: "기타" }, - { id: "totalMoney", lable: "합계", type: "number" ,option:"readOnly" }, + { id: "totalMoney", lable: "합계", type: "number" ,option:"disabled" }, ]; export const businessSttnInfo: formDetailType[] = [ - { id: "seCd", lable: "구분" }, - { id: "bizMthdCd", lable: "사업방식" }, + { id: "seCd", lable: "구분", type: "select", selectData: "ruseSeCd" }, + { id: "bizMthdCd", lable: "사업방식", type: "select", selectData: "ruseBizMthdCd" }, { id: "bizCmcnDay", lable: "사업준공일", type: "date" }, { id: "instlAprvSncnDt", lable: "설치승인인가일", type: "date" }, ]; @@ -118,15 +119,15 @@ export const ruseFcltIntakeList: formDetailType[] = [ ]; export const ruseWaterQulityList: formDetailType[] = [ - { id: "bod", lable: "BOD(mg/L)", type: "number" }, - { id: "grssClfg", lable: "총대장균군수(개/mg)", type: "number" }, - { id: "combResdch", lable: "결합잔류염소(mh/L)", type: "number" }, - { id: "trbt", lable: "탁도(NTU)", type: "number" }, - { id: "smll", lable: "냄새", type: "number" }, - { id: "crmty", lable: "색도", type: "number" }, - { id: "tn", lable: "총질소(mg/L)", type: "number" }, - { id: "tph", lable: "총인(mg/L)", type: "number" }, - { id: "ph", lable: "수소이온농도", type: "number" }, - { id: "clIonQnt", lable: "염화물(mg/L)", type: "number" }, - { id: "cdtnv", lable: "전기전도도(μs/cm)​", type: "number" }, + { id: "bod", lable: "BOD(mg/L)", type: "text" }, + { id: "grssClfg", lable: "총대장균군수(개/mg)", type: "text" }, + { id: "combResdch", lable: "결합잔류염소(mh/L)", type: "text" }, + { id: "trbt", lable: "탁도(NTU)", type: "text" }, + { id: "smll", lable: "냄새", type: "text" }, + { id: "crmty", lable: "색도", type: "text" }, + { id: "tn", lable: "총질소(mg/L)", type: "text" }, + { id: "tph", lable: "총인(mg/L)", type: "text" }, + { id: "ph", lable: "수소이온농도", type: "text" }, + { id: "clIonQnt", lable: "염화물(mg/L)", type: "text" }, + { id: "cdtnv", lable: "전기전도도(μs/cm)​", type: "text" }, ]; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index fb799c26c..ea7eee5c8 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -52,6 +52,7 @@ export type pubFacState = { fcOrgwtsHeadList: TableUpperProps[]; pbnstMngRegData: customPbnst[]; pbnsUpdateIndex: pbnstInsertIndex; + fcOrgwtsNmList:pubHasuType[]; dmdComList: any[]; }; }; @@ -70,6 +71,7 @@ type pubFacActions = { pbnstRuseFcltUpdate: (ruseRes: customPbnst[]) => void; pbnstRuseBizUpdate: (ruseRes: fcBizType[]) => void; pubHasuSearch :(page: string, sggOrCity: string , searchTxt:string) => void + getFcOrgwts: (fcltPkList: string[], size:number) => void; }; export type pubFacType = pubFacState & pubFacActions; @@ -90,6 +92,7 @@ export const pubFacStateExport: pubFacState = { pbnstBizCycle: [{ text: "없음", val: "1" }], pbnstMngRegData: [], pbnsUpdateIndex: {} as pbnstInsertIndex, + fcOrgwtsNmList:[], dmdComList: [], }, }; @@ -102,12 +105,10 @@ const checkWrRegList = async () => { const hasuListFetch = async (page: string, sggOrCity: string, searchTxt?:string) => { const checkWrRegListRes = await checkWrRegList(); - console.log(' checkWrRegListRes ', checkWrRegListRes) let url = `/prcsFclt/ruseInfo/${page ? page : 1}/10/A/${sggOrCity? sggOrCity : "11"}/0/1/SW`; const data = checkWrRegListRes.filter((item:string) => item !== "") - console.log(' checkWrRegListRes ' ) if(searchTxt){ url= url +`/${searchTxt}` @@ -177,6 +178,7 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { try { const pbnstHasuRes = await hasuListFetch(page, sggOrCity); + return set((state: pubFacState) => ({ ...state, pbnst: { @@ -399,6 +401,25 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { } catch (e) { console.log(e); } + },getFcOrgwts : async (fcltPkList: string[] ,size:number) => { + let url = `/prcsFclt/ruseInfo/1/${size}/A/0/0/1/SW`; + + const fcOrgwtsNmList = await postFectch( + url, + fcltPkList, + fetchType.COMMON + ); + + return set((state: pubFacState) => ({ + ...state, + pbnst: { + ...state.pbnst, + fcOrgwtsNmList:fcOrgwtsNmList.data??[] + }, + })); + + + } }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx index a34985810..b908750fd 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx @@ -14,10 +14,10 @@ export type selectLabel = { val: string; }; -export type pbnstInsertIndex ={ - mng:number, - biz:number -} +export type pbnstInsertIndex = { + mng: number; + biz: number; +}; export type publicReuseFacilityType = { sido: string; @@ -45,20 +45,20 @@ export type ruseFcltType = { }; export type PbnstDemandComType = { - dmdInfoPk : string | ''; - bzmnNo : string | ''; - dmdCoNm : string | ''; - daddr : string | ''; - telno : string | ''; - rgtr : string | ''; - useUsgCd : string | ''; - ctpvCd : string | ''; - sggCd : string | ''; - dmdAplyPswd: string | ''; + dmdInfoPk: string | ""; + bzmnNo: string | ""; + dmdCoNm: string | ""; + daddr: string | ""; + telno: string | ""; + rgtr: string | ""; + useUsgCd: string | ""; + ctpvCd: string | ""; + sggCd: string | ""; + dmdAplyPswd: string | ""; splyCpct: number | 0; - splyFmYn:string|'Y' -// dmdInfoFk:string|'' -} + splyFmYn: string | "Y"; + // dmdInfoFk:string|'' +}; const pubHasuZod = z.object({ choose: z.boolean().default(false), @@ -68,23 +68,27 @@ const pubHasuZod = z.object({ bscFctNm: z.string().default(""), efflWqltStndrdNm: z.string().default(""), fctCpc: z.number().default(0), - addr:z.string().nullish() + addr: z.string().nullish(), }); - export type pubHasuType = z.infer; -const zDate = z.preprocess((v) => (v ? new Date(v as string) : undefined), z.date()).nullish() ; +const zDate = z + .preprocess((v) => (v ? new Date(v as string) : undefined), z.date()) + .nullish(); const zDateNullish = zDate.nullish(); const zDateDefaultNow = zDate.default(new Date()); -const zNum = z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number()); +const zNum = z.preprocess( + (v) => (v !== null && v !== undefined ? Number(v) : v), + z.number() +); const zNumNullish = zNum.nullish(); const zNumDefaultZero = zNum.default(0).nullish(); const pplInstlSchema = z.object({ ruseFcltBizFk: zNumNullish, choose: z.boolean().default(false), - pdmt: z.string().default(''), + pdmt: z.string().default(""), ppMqlt: z.string().default(""), cpct: zNumDefaultZero, }); @@ -115,22 +119,23 @@ export const fcOperSchema = z.object({ }); const fcOrgwtSchema = z.object({ - pbnstRuseFcltBizFk:zNumNullish, + pbnstRuseFcltBizFk: zNumNullish, swtrmtFcltFk: z.string().nullish(), orgwtWtritQnt: zNum, tmsYn: z.enum(["Y", "N"]).default("N"), dschgFmYn: z.enum(["Y", "N"]).default("N"), - dtlPstnExpln: z.string().default(''), + dtlPstnExpln: z.string().default(""), regDt: zDateNullish, - rgtr: z.string().default(''), + rgtr: z.string().default(""), mdfcnDt: zDateNullish, - mdfr: z.string().default(''), + mdfr: z.string().default(""), choose: z.boolean().default(false), + ruseUtztnFcltNm:z.string().nullish() }); const dmdColist = z.object({ - dmdInfoPk: z.string().default(''), - dmdCoNm: z.string().default(''), + dmdInfoPk: z.string().default(""), + dmdCoNm: z.string().default(""), daddr: z.string(), useUsgCd: z.string().nullish(), splyBgngDay: zDateDefaultNow, @@ -148,18 +153,18 @@ export const fcBizSchema = z.object({ pbnstRuseFcltFk: z.string().nullish(), superkey: z.string().default("").nullish(), cycl: zNum.default(1), - seCd: z.string().default(""), + seCd: z.string().max(10, "구분은 10자를 초과할 수 없습니다.").default(""), bizMthdCd: z.string().default(""), instlAprvSncnDt: zDateDefaultNow, bizCmcnDay: zDateDefaultNow, gvsbs: zNumDefaultZero, lcep: zNumDefaultZero, cusrAlotm: zNumDefaultZero, - etc: z.string().default(''), + etc: z.string().default(""), totalMoney: zNumNullish.default(0), rprcsFcltCpct: zNumDefaultZero, majorPrcsMsrcCd: z.string().default(""), - addr: z.string().default(''), + addr: z.string().default(""), rprcsMthdCd: z.string().default(""), inoutYn: z.enum(["Y", "N"]).default("Y"), mainSplyPumpCpct: zNumNullish, @@ -171,17 +176,29 @@ export const fcBizSchema = z.object({ wwtEmsnFcltPrmsnYn: z.string().default("Y"), tmsInstlYn: z.string().default("Y"), pbnstDrngInflwExclYn: z.string().default("Y"), - bod: zNumDefaultZero, - grssClfg: zNumDefaultZero, - combResdch: zNumDefaultZero, - trbt: zNumDefaultZero, - clIonQnt: zNumDefaultZero, - smll: zNumDefaultZero, - crmty: zNumDefaultZero, - tph: zNumDefaultZero, - tn: zNumDefaultZero, - ph: zNumDefaultZero, - cdtnv: zNumDefaultZero, + // bod: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "BOD 값은 5자리 미만이어야 합니다.")).nullish(), + // grssClfg: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "총대장균군 값은 5자리 미만이어야 합니다.")).nullish(), + // combResdch: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "결합잔류염소 값은 5자리 미만이어야 합니다.")).nullish(), + // trbt: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "탁도 값은 5자리 미만이어야 합니다.")).nullish(), + // clIonQnt: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "염소이온량 값은 5자리 미만이어야 합니다.")).nullish(), + // smll: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "냄새 값은 5자리 미만이어야 합니다.")).nullish(), + // crmty: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "색도 값은 5자리 미만이어야 합니다.")).nullish(), + // tph: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "총인 값은 5자리 미만이어야 합니다.")).nullish(), + // tn: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "총질소 값은 5자리 미만이어야 합니다.")).nullish(), + // ph: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "수소이온농도 값은 5자리 미만이어야 합니다.")).nullish(), + // cdtnv: z.preprocess((v) => (v !== null && v !== undefined ? Number(v) : v), z.number().max(9999, "전기전도도 값은 5자리 미만이어야 합니다.")).nullish(), + bod: z.string().nullish(), + grssClfg: z.string().nullish(), + combResdch: z.string().nullish(), + trbt: z.string().nullish(), + clIonQnt: z.string().nullish(), + smll: z.string().nullish(), + crmty: z.string().nullish(), + tph: z.string().nullish(), + tn: z.string().nullish(), + ph: z.string().nullish(), + cdtnv: z.string().nullish(), + designCst: zNumNullish, cstrnSpvsCst: zNumNullish, fcltSbsdCst: zNumNullish, @@ -217,7 +234,7 @@ export const fcBizSchema = z.object({ }); export const pbnstRegZod = z.object({ - pbnstRuseFcltPk: z.string().default(''), + pbnstRuseFcltPk: z.string().default(""), swtrmtFcltFk: z.string().default(""), ruseUtztnFcltNm: z.string().default(""), fcltCpct: zNumDefaultZero, @@ -232,13 +249,12 @@ export const pbnstRegZod = z.object({ fcOpers: z.array(fcOperSchema).default([]).nullish(), }); -export const pbnstRegArrayZod = z.array(pbnstRegZod) +export const pbnstRegArrayZod = z.array(pbnstRegZod); -export type PbnstRegArrrayType = z.infer +export type PbnstRegArrrayType = z.infer; export type fcBizType = z.infer; export type fcOrgwtType = z.infer; export type ppInstlType = z.infer; export type operType = z.infer; export type fcFileType = z.infer; - diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index 5b3ad6813..372a4bd9a 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -2,76 +2,29 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; import { getFetch, postFectch, putFectch } from "@/components/lib/api"; import { z } from "zod"; import { makeMdfr, makeRstr } from "../bdstReg"; - -const validationMessages = { - required: (field: string) => `${field}을(를) 입력해주세요.`, - requiredSelect: (field: string) => `${field}을(를) 선택해주세요.`, - yearFormat: '4자리 연도만 입력하세요', -}; +import toast from "react-hot-toast"; +import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "./type"; export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e' const rainyObjSchema = z.object({ bdstReuseFcltFk: z.number().nullish(), - pntfColKnd: z.string().default(""), - pntfColArea: z.number().default(0), + pntfColKnd: z.string().min(1, { message: validationMessages.requiredSelect("종류") }), + pntfColArea: z.number().positive({ message: validationMessages.required("면적(m³)") }), dtfcltCpct: z.number().default(0), - filtrTrtmfctYn: z.string().default("Y").nullish(), + filtrTrtmfctYn: z.string().default("Y"), filtrTrtmfctCpct: z.number().nullish().default(0), filtrTrtmfctPrs: z.string().default(""), annRnwtQty: z.number().default(0), oilqMeasMthd: z.string().default("").nullish(), rgtr:z.string().nullish(), mdfr:z.string().nullish(), -}).refine((data) => data.pntfColKnd.length > 0, { - message: validationMessages.requiredSelect("종류"), - path: ["pntfColKnd"], -}).refine((data) => data.pntfColArea > 0, { - message: validationMessages.required("면적(m³)"), - path: ["pntfColArea"], }); -const reuseBuildingSchema = 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().default(""), - anlOperCst: z.number().default(0), - instlCstSprtYn: z.string().default("Y"), - instlCstSprtAmt: z.number().nullish(), - grntchBdstCertYn: z.string().default("Y"), - grntchBdstCertYr: z.string().default("") - .refine((year)=> year.length===0 || /^\d{4}$/.test(year),{ - message: validationMessages.yearFormat - }), - 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), - lawTrgtYn: z.string().default("Y"), - rgtr:z.string().nullish(), - mdfr:z.string().nullish(), - rainyObj: rainyObjSchema.default({}) -}).refine((data) => data.bdstUsgCd > 0, { - message: validationMessages.requiredSelect("건축물용도"), - path: ["bdstUsgCd"], -}); -const chgBuildingSchema = z.object({ - bdstInfoFk: z.number().nullish(), - archChgPrmsnDt: z.coerce.date({required_error: validationMessages.required("허가일")}), - archChgArea: z.string().default("-"), - bdstChgNm: z.string().default(""), - rgtr:z.string().nullish(), - mdfr:z.string().nullish(), -}).refine(data => data.bdstChgNm.length > 0, { - message: validationMessages.requiredSelect("구분"), - path: ["bdstChgNm"] -}); + const rainBuildingSchema = baseReuseBuildingSchema.extend({ + rainyObj: rainyObjSchema, +}) export const rainZod = z.object({ bdstInfoPk: z.number().optional(), @@ -85,7 +38,7 @@ export const rainZod = z.object({ archChgArea: z.number().default(0), rgtr:z.string().nullish(), mdfr:z.string().nullish(), - reuseBuilding: z.array(reuseBuildingSchema).default([]), + reuseBuilding: z.array(rainBuildingSchema).default([]), chgBuilding: z.array(chgBuildingSchema).default([]) }) @@ -219,15 +172,18 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( bdstInfoFk: chPK, }) ); - const chch= postFectch("/reuseFc/chgBuilding", makeCh); + const chch= postFectch("/reuseFc/chgBuilding", makeCh); return chch; }).then((chch: any) => { - if(chch.ok) { - alert("등록이 완료되었습니다."); + + console.log('chch ', chch) + if(chch.status ===200) { + toast.success("등록이 완료되었습니다."); + } }) }else{ - alert("등록이 완료되었습니다."); + toast.success("등록이 완료되었습니다."); } } const rainRes = await initFetch(code); diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx new file mode 100644 index 000000000..6e28c3e76 --- /dev/null +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx @@ -0,0 +1,45 @@ +import { z } from "zod"; + + +export const validationMessages = { + required: (field: string) => `${field}을(를) 입력해주세요.`, + requiredSelect: (field: string) => `${field}을(를) 선택해주세요.`, + yearFormat: '4자리 연도만 입력하세요', + }; + +export const baseReuseBuildingSchema = 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().default(""), + anlOperCst: z.number().default(0), + instlCstSprtYn: z.string().default("Y"), + instlCstSprtAmt: z.number().nullish(), + grntchBdstCertYn: z.string().default("Y"), + grntchBdstCertYr: z.string().default("").refine( + (year) => year.length === 0 || /^\d{4}$/.test(year), + { + message: validationMessages.yearFormat, + } + ), + 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().min(1, { message: validationMessages.requiredSelect("건축물용도") }).default(0), + lawTrgtYn: z.string().default("Y"), + rgtr: z.string().nullish(), + mdfr: z.string().nullish(), +}); + +export const chgBuildingSchema = z.object({ + bdstInfoFk: z.number().nullish(), + archChgPrmsnDt: z.coerce.date({required_error: validationMessages.required("허가일")}), + archChgArea: z.string().default("-"), + bdstChgNm: z.string().min(1, { message: validationMessages.requiredSelect("구분") }), + 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 3c2504b9a..178badd3b 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx @@ -1,10 +1,32 @@ import { getFetch, postFectch, putFectch } from "@/components/lib/api"; -import { upHeadList, type chgBuilding } from "../rainReg"; +import { upHeadList, type chgBuilding } from "../rainReg"; 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"; + 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), + orgwtKndCd: z.string({ required_error: validationMessages.requiredSelect("원수 종류") }).min(1, { message: validationMessages.requiredSelect("원수 종류") }), + filtrTrtmfctCpct: z.number({ required_error: validationMessages.required("처리시설 용량") }).positive({ message: validationMessages.required("처리시설 용량") }), + filtrTrtmfctProcs: z.string({ required_error: validationMessages.required("주요처리공정") }).min(1, { message: validationMessages.required("주요처리공정") }), + filtrTrtmfctUsgCd: z.string().default("").nullish(), + rswtrUsqty: z.number().default(0), + altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(), //안쓰는값 + altUswtrKndCd: z.string().default("").nullish(), //안쓰는값 + altUswtrUtztnQnt: z.number().default(0), //안쓰는값 + altUswtrIdntyMthdCd: z.string().default("").nullish(), //안쓰는값 + rgtr: z.string().nullish().default(null), + mdfr: z.string().nullish().default(null), +}); + + const rswtBuildingSchema = baseReuseBuildingSchema.extend({ + rswtrObj: rswtrObjSchema, +}) + export const rswtZod = z.object({ bdstInfoPk: z.number().nullish(), ctpvCd: z.number().default(0), @@ -21,73 +43,8 @@ export const rswtZod = z.object({ bdstUsgText: z.string().default(""), cityText: z.string().default(""), sggText: z.string().default(""), - - reuseBuilding: z - .array( - z.object({ - bdstRuseFcltPk: z.number().nullish(), - bdstInfoFk: z.number().nullish(), - instlCmptnDt: z.coerce.date().default(() => new Date()), - instlCst: z.number().default(0), - operMngCd: z.string().nullish().default(""), - - anlOperCst: z.number().default(0), - instlCstSprtYn: z.enum(["Y", "N"]), - instlCstSprtAmt: z.number().default(0), - - grntchBdstCertYn: z.enum(["Y", "N"]), - grntchBdstCertYr: z - .string() - .default("") - .refine((year) => year.length === 0 || /^\d{4}$/.test(year), { - message: "4자리 연도만 입력하세요", - }), - grntchBdstCertNo: z.string().default(""), - grntchBdstCertGrd: z.string().default(""), - - crgRdctYn: z.string().default("N").nullish(), // 안쓰는 값 - crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값 - crgRdctAmt: z.number().default(0), // 안쓰는 값 - ruseFcltFlg: z.string().default(""), - bdstUsgCd: z.number().default(0), - lawTrgtYn: z.string().default(""), - rgtr: z.string().nullish().default(null), - mdfr: z.string().nullish().default(null), - - rswtrObj: z - .object({ - bdstRuseFcltFk: z.number().nullish(), - wtrUsqty: z.number().default(0), - oblgTrgtWtrUsqty: z.number().nullish().default(0), - orgwtKndCd: z.string().default(""), - filtrTrtmfctCpct: z.number().default(0), - filtrTrtmfctProcs: z.string().default(""), - filtrTrtmfctUsgCd: z.string().default("").nullish(), - rswtrUsqty: z.number().default(0), - altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(), //안쓰는값 - altUswtrKndCd: z.string().default("").nullish(), //안쓰는값 - altUswtrUtztnQnt: z.number().default(0), //안쓰는값 - altUswtrIdntyMthdCd: z.string().default("").nullish(), //안쓰는값 - rgtr: z.string().nullish().default(null), - mdfr: z.string().nullish().default(null), - }) - .default({}), - }) - ) - .default([]), - - chgBuilding: z - .array( - z.object({ - bdstInfoFk: z.number().nullish(), - archChgPrmsnDt: z.coerce.date(), - archChgArea: z.string().default("-"), - bdstChgNm: z.string().default(""), - rgtr: z.string().nullish().default(null), - mdfr: z.string().nullish().default(null), - }) - ) - .default([]), + reuseBuilding: z.array(rswtBuildingSchema).default([]), + chgBuilding: z.array(chgBuildingSchema).default([]), }); export type customRswtBdst = z.infer; diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx index 4557662f8..7520f7998 100644 --- a/apps/wr/app/store/store.tsx +++ b/apps/wr/app/store/store.tsx @@ -86,7 +86,7 @@ import { import { rswtChkStateExport, rswtChkSttnActionsExport, type rswtChkSttnState, type rswtChkSttnType } from "./prfmncSttn/chkgdnSttn/rswtChkgdnSttn"; import { pbnstSttnActionsExport, pbnstSttnStateExport, type pbnstSttnState, type pbnstSttnType } from "./ruseFcltMng/fcltSttn/pbnstSttn"; import { coSttnActionsExport, coSttnStateExport, type coSttnState, type coSttnType } from "./matDmd/coSttn"; // 옮겨야함 -import { searchActions, type comFcltActions, type comFcltState } from "./common/searchCode"; +import { comFcltStateExport, comFcltSearchAction, type comFcltState, type comFcltType } from "./common/searchCode"; import { pbnstPrfmncActionsExport, pbnstPrfmncStateExport, type pbnstPrfmncState, type pbnstPrfmncType } from "./prfmncReg/pbnstPrfmncReg"; import { coRvwActionsExport, coRvwStateExport, type coRvwState, type coRvwType } from "./matDmd/coMatRvw"; import { ruseHstryActionsExport, ruseHstryStateExport, type ruseHstryState, type ruseHstryType } from "./matDmd/ruseRvwHstry"; @@ -113,7 +113,6 @@ export type WrStore = comCodeType & rainChkSttnType& rswtChkSttnType& pbnstSttnType& - comFcltActions&comFcltState& coSttnType& // 옮겨야함 ldrmntType& // 옮겨야함 pbnstPrfmncType& @@ -124,7 +123,8 @@ export type WrStore = comCodeType & ruseCaseType& rainStatType& rswtStatType& - matStatType + matStatType& + comFcltType ; export const StoreZus = ( @@ -141,6 +141,7 @@ export const StoreZus = ( rswtSttnState & htdflSttnState & rainChkSttnState& + comFcltState& rswtChkSttnState & pbnstSttnState& coSttnState& // 옮겨야함 @@ -180,7 +181,8 @@ export const StoreZus = ( ...ruseCaseStateExport, ...rainStatExport, ...rswtStatExport, - ...matStatExport + ...matStatExport, + ...comFcltStateExport } ) => { return createStore()((set) => { @@ -192,7 +194,7 @@ export const StoreZus = ( getEnvPartCd(set); return { ...initState, - ...searchActions(set), + ...comFcltSearchAction(set), ...pubFacActionsExport(set), ...rainFacActionsExport(set), ...rswtFacActionsExport(set), diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx index 5ab5edf98..0d00454e2 100644 --- a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx @@ -171,7 +171,7 @@ export default function BdstReg({ form }: { form: any }) { @@ -193,7 +193,7 @@ export default function BdstReg({ form }: { form: any }) { onSelectValue={(val) => { field.onChange(Number(val)); }} - value={field.value} + value={field.value??code.bdstUsgCd[0]?.val} /> )} @@ -208,7 +208,7 @@ export default function BdstReg({ form }: { form: any }) { field.onChange(date), }} selectClass={'w-full'} @@ -226,7 +226,7 @@ export default function BdstReg({ form }: { form: any }) { { handleCommaNumberChange(e, field.onChange); }} @@ -250,7 +250,7 @@ export default function BdstReg({ form }: { form: any }) { onSelectValue={(val) => { field.onChange(val); }} - value={field.value} + value={field.value??code.yn[0]?.val } /> )} 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 df63b3520..152441c70 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx @@ -55,18 +55,15 @@ export function PbnstBuseForm({ code, pbnst, demandCompList, - getpbnstInsertIndex, - appendRuseFclt, getDemandCompList, + getFcOrgwts, regDemandCompany, } = useWrStore((state) => state); - const { pbnstBizCycle, pbnstRes } = pbnst; + const { fcOrgwtsNmList } = pbnst; const { fields: fcBizs, append: appendBiz } = useFieldArray({ control: form.control, name: `items.${indexMng}.fcBizs`, }); - - const [bizCycle, setBizCycle] = useState("1"); const [ppiSelectList, setPpiSelectList] = useState<[{ name: string; val: SelectDataType[] }]>(); const [ppiYn, setPpiYn] = useState("Y"); @@ -79,25 +76,72 @@ export function PbnstBuseForm({ >([{ text: "없음", val: 0 }]); const [isFcOrgwts, setIsFcOrgwts] = useState(false); const [sumCpct, setSumCpct] = useState(0); - const [getDmdList, setGetFmdList] = useState(0); const [isDmdModal, setIsDmdModal] = useState<{ isMoal: boolean; data: DemandCompType; }>({ isMoal: false, data: {} as DemandCompType }); useEffect(() => { - const total = + 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); + (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`) ]); + + 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); + + console.log('swtrmtFcltFkList ', swtrmtFcltFkList) + + if(swtrmtFcltFkList.length > 0){ + getFcOrgwts(swtrmtFcltFkList.filter((item): item is string => item != null), fcOrgwts?.length) + } + } + },[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) + if (orgwtNm) { + form.setValue( + `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts.${index}.ruseUtztnFcltNm`, + orgwtNm + ); + } + }); + } + + },[fcOrgwtsNmList,fcOrgwts]) + + // fcBizs 데이터가 변경될 때마다 차수 선택 목록을 업데이트합니다. useEffect(() => { const cycleLength = fcBizs.length; @@ -250,23 +294,6 @@ export function PbnstBuseForm({ setSumCpct(sum); }, [form.formState, indexMng, indexBiz]); - // // 차수별 정보(fcBizs)가 하나도 없을 경우 플레이스홀더 UI를 보여줍니다. - // if (fcBizs.length === 0) { - // return ( - //
- //

등록된 차수별 정보가 없습니다.

- //

아래 버튼을 눌러 신규 차수 정보를 등록해주세요.

- // - //
- // ); - // } const pbnstBiz = form.watch(`items.${indexMng}.fcBizs`); return ( @@ -499,7 +526,7 @@ export function PbnstBuseForm({ ) || [] ).map((field, index) => (
@@ -664,6 +691,7 @@ export function PbnstBuseForm({ )} />
+

))} @@ -674,7 +702,7 @@ export function PbnstBuseForm({ setIsFcOrgwts(open)} - bodyClass={"w-[50vw] max-w-none h-[90vh]"} + bodyClass={"w-[70vw] max-w-none max-h-[90vh] overflow-y-auto"} body={ { diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx index d07d24a23..e1454342b 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx @@ -29,6 +29,10 @@ import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { Label } from "@common/business_components/ui/form/lib/label"; import React from "react"; import RuseMngTableForm from "@/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm"; +import { + handleCommaNumberChange, + formatCommaNumber, +} from "@/components/lib/func/commom"; export type FilesType = { atflCd: string; file: File; @@ -46,13 +50,9 @@ export function PbnstMngForm({ indexMng: number; setIndexMng: (index: number) => void; }) { - const { - code, - pbnst, - pbnstInsert, - fileDelete, - fileDownLoad, - } = useWrStore((state) => state); + const { code, pbnst, pbnstInsert, fileDelete, fileDownLoad } = useWrStore( + (state) => state + ); const { pbnstRes } = pbnst; const [regFileList, setRegFileList] = useState(null); @@ -215,16 +215,14 @@ export function PbnstMngForm({ useEffect(() => { if (pbnst.pbnstRes && pbnst.pbnstRes?.length >= 0) { - const fcltNmList = pbnst.pbnstRes?.map((item, index) => ({ text: item.ruseUtztnFcltNm, val: String(index), })); - - console.log(' fcltNmList ', fcltNmList) + console.log(" fcltNmList ", fcltNmList); if (fcltNmList) setFcltNm(fcltNmList); - }else{ + } else { setFcltNm(null); } }, [pbnst.pbnstRes]); @@ -253,16 +251,14 @@ export function PbnstMngForm({ } }, [code]); - - useEffect(() =>{ - // console.log(' fcltNm ', watchedItem?.ruseUtztnFcltNm) - },[watchedItem]) - + useEffect(() => { + // console.log(' fcltNm ', watchedItem?.ruseUtztnFcltNm) + }, [watchedItem]); useEffect(() => { console.log(" form indexMng ", indexMng); - }, [indexMng]); - + }, [indexMng]); + return (
@@ -297,8 +293,6 @@ export function PbnstMngForm({ render={({ field }) => ( { - field.onChange(Number(e.target.value)); + if (formType !== "sttn") + handleCommaNumberChange(e, field.onChange); }} - value={field.value ?? 0} + value={formatCommaNumber(field.value)} readOnly={formType === "sttn" ? true : false} /> @@ -401,11 +396,12 @@ export function PbnstMngForm({ { - field.onChange(Number(e.target.value)); + if (formType !== "sttn") + handleCommaNumberChange(e, field.onChange); }} - value={field.value ?? 0} + value={formatCommaNumber(field.value)} readOnly={formType === "sttn" ? true : false} /> @@ -422,11 +418,12 @@ export function PbnstMngForm({ { - field.onChange(Number(e.target.value)); + if (formType !== "sttn") + handleCommaNumberChange(e, field.onChange); }} - value={field.value ?? 0} + value={formatCommaNumber(field.value)} readOnly={formType === "sttn" ? true : 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 971888e10..6e13058ab 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 @@ -2,17 +2,14 @@ import { useWrStore } from "@/app/store"; import type { formDetailType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/headList"; import { formH1Class } from "@/components/lib/class/comClass"; -import { safeDate } from "@/components/lib/func/commom"; +import { formatCommaNumber, handleCommaNumberChange, safeDate } from "@/components/lib/func/commom"; import { DatePicker, FormField, FormUi, - SearchInputSelect, SelectBox, - type SelectDataType, } from "@common/business_components/ui"; import { Input } from "@common/components/ui"; -import { useState } from "react"; export default function MngRegFormDetail({ formList, @@ -55,9 +52,7 @@ export default function MngRegFormDetail({ name={fieldId} render={({ field }) => ( - {formHead.type === "select" ? ( - - ) : formHead.type === "date" ? ( + {formHead.type === "date" ? ( ) : formHead.type === "number" ? ( { - field.onChange(Number(e.target.value)); + handleCommaNumberChange( + e, + field.onChange + ); }} - readOnly={formHead.option === "readOnly"?true:false} - /> - ) : formHead.type === "selectYn" ? ( - - field.onChange(val) - } - value={field.value ?? "Y"} + value={formatCommaNumber(field.value)} + readOnly={formHead.option === "readOnly" ? true : false} + disabled={formHead.option === "disabled" ? true : false} + /> + ) : formHead.type === "select" ? ( + (() => { + const potentialOptions = formHead.selectData + ? code[formHead.selectData as keyof typeof code] + : []; + + return ( + + ); + })() ) : ( )} diff --git a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx index 9ec4fc5c0..fc4ed566e 100644 --- a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx @@ -46,30 +46,40 @@ export default function RainRegForm({ ]); const cleanRainData = (raw: any): z.infer => { + const buildings = + raw?.reuseBuilding && raw.reuseBuilding.length > 0 + ? raw.reuseBuilding + : [{}]; return { ...raw, - frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null), + frstArchPrmsnDt: raw?.frstArchPrmsnDt + ? new Date(raw.frstArchPrmsnDt) + : new Date(), // raw?.frstArchPrmsnDt가 유효하지 않으면 현재 날짜로 초기화 archChgPrmsnDt: raw?.archChgPrmsnDt ? new Date(raw?.archChgPrmsnDt) : null, - reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({ + reuseBuilding: buildings.map((item: any) => ({ ...item, - instlCmptnDt: new Date(item?.instlCmptnDt), + instlCmptnDt: item?.instlCmptnDt + ? new Date(item.instlCmptnDt) + : new Date(), // item?.instlCmptnDt가 유효하지 않으면 현재 날짜로 초기화 operMngCd: item?.operMngCd ?? "", // null → "" grntchBdstCertYr: typeof item?.grntchBdstCertYr === "string" ? item?.grntchBdstCertYr : "", // null → "" - // Ensure enum fields are null if empty string to trigger Zod default + instlCstSprtYn: item?.instlCstSprtYn ?? "Y", // null → "Y" + grntchBdstCertYn:item?.grntchBdstCertYn??"Y", rainyObj: { ...item?.rainyObj, - filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn === "" ? null : item?.rainyObj?.filtrTrtmfctYn, + filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y", }, })), }; }; useEffect(() => { + if (grntchBdstCertYn === "N") { form.setValue("reuseBuilding.0.grntchBdstCertYr", ""); form.setValue("reuseBuilding.0.grntchBdstCertNo", ""); @@ -82,6 +92,9 @@ export default function RainRegForm({ } }, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn]); + + + // form 값이 변경될 때마다 로그 출력 useEffect(() => { const subscription = form.watch((value) => { @@ -146,9 +159,8 @@ export default function RainRegForm({ value: field.value && !isNaN(new Date(field.value).getTime()) ? new Date(field.value) - : new Date(), // Provide a default Date value - onChange: (date) => field.onChange(date), - + : new Date(), + onChange: (date: Date | undefined) => field.onChange(date), }} selectClass={"w-full"} readOnly={readonly} @@ -245,7 +257,7 @@ export default function RainRegForm({ label={""} selectArray={code.yn} onSelectValue={readonly ? () => { } : field.onChange} - value={field.value || code.yn[0]?.val} + value={field.value ?? code.yn[0]?.val} readOnly={readonly} /> @@ -266,7 +278,8 @@ export default function RainRegForm({ if (!readonly) handleCommaNumberChange(e, field.onChange); }} value={formatCommaNumber(field.value)} - readOnly={filtrTrtmfctYn !== "Y"} + readOnly={readonly } + disabled={filtrTrtmfctYn !== "Y"} /> )} @@ -284,7 +297,8 @@ export default function RainRegForm({ type="text" value={field.value ?? ""} onChange={field.onChange} - readOnly={filtrTrtmfctYn !== "Y"} + readOnly={readonly } + disabled={filtrTrtmfctYn !== "Y"} /> )} diff --git a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx index a4f29477a..d820bddc1 100644 --- a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx @@ -28,10 +28,12 @@ import BdstReg from "../bdstReg/bdstReg"; export default function RswtrRegForm({ rswtForm, isModal, + setIsModal, readonly = false }: { rswtForm: customRswtBdst; isModal: boolean; + setIsModal?: (isModal: boolean) => void; readonly?: boolean; }) { const { rswt, code, rswtBdstUpdate, rswtBdstReg } = useWrStore( @@ -54,6 +56,7 @@ export default function RswtrRegForm({ const onSubmit = (values: z.infer) => { if (isModal) { rswtBdstReg(values, "41"); + if(setIsModal) setIsModal(false) } else { rswtBdstUpdate(values, "41"); } @@ -61,28 +64,29 @@ export default function RswtrRegForm({ const cleanRswtData = (raw: any): z.infer => { return { ...raw, - frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null), + frstArchPrmsnDt: raw?.frstArchPrmsnDt + ? new Date(raw.frstArchPrmsnDt) + : new Date(), // raw?.frstArchPrmsnDt가 유효하지 않으면 현재 날짜로 초기화 archChgPrmsnDt: raw?.archChgPrmsnDt ? new Date(raw?.archChgPrmsnDt) : null, reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({ ...item, - instlCmptnDt: new Date(item?.instlCmptnDt), - operMngCd: item?.operMngCd ?? "", // null → "" - grntchBdstCertYr: - typeof item?.grntchBdstCertYr === "string" - ? item?.grntchBdstCertYr - : "", // null → "" - rswtrObj: { + 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: { ...item?.rswtrObj, + filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y", + }, })), }; }; - useEffect(()=>{ - console.log("rswtForm:", rswtForm) - }, [rswtForm]) useEffect(() => { console.log("form errors:", form.formState.errors); diff --git a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx index 9572d1228..4e3d61008 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx @@ -144,16 +144,16 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { const average = { utztnUsgCd: "평균", edit: false, - grssClfgUswtr: total.grssClfgUswtr / onlyData.length, - combResdch: total.combResdch / onlyData.length, - trbt: total.trbt / onlyData.length, - bod: total.bod / onlyData.length, - smll: total.smll / onlyData.length, - crmty: total.crmty / onlyData.length, - tph: total.tph / onlyData.length, - tn: total.tn / onlyData.length, - ph: total.ph / onlyData.length, - clIonQnt: total.clIonQnt / onlyData.length, + grssClfgUswtr: (total.grssClfgUswtr / onlyData.length).toFixed(1), + combResdch: (total.combResdch / onlyData.length).toFixed(1), + trbt: (total.trbt / onlyData.length).toFixed(1), + bod: (total.bod / onlyData.length).toFixed(1), + smll: (total.smll / onlyData.length).toFixed(1), + crmty: (total.crmty / onlyData.length).toFixed(1), + tph: (total.tph / onlyData.length).toFixed(1), + tn: (total.tn / onlyData.length).toFixed(1), + ph: (total.ph / onlyData.length).toFixed(1), + clIonQnt: (total.clIonQnt / onlyData.length).toFixed(1), }; if (!resultPolution[nodeKey]) { diff --git a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx index a6b05ca77..1be95fae6 100644 --- a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx +++ b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx @@ -1,48 +1,62 @@ "use client" import { btnClass } from "@/app/store/common/code" +import type { customDrgt } from "@/app/store/matDmd/drgtSttn" import { drgtDetailHeadListExport } from "@/app/store/matDmd/drgtSttn/headList" -import { ContentsDiv, Title, UiTable } from "@common/business_components/ui" +import { excelDownload } from "@/components/lib/func/commom" +import { 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" + +export default function DrgtDetailModal({ + data, +}: { + data: customDrgt; +}) { + const excelClick = useCallback(() => { + excelDownload( + [[]], + "우리동네가뭄", + "sample_drgtSttn.xlsx", + "A1:H1" + ); + }, []); -export default function DrgtDetailModal() { return ( <> - -
-
- - <div 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"} - className={`${btnClass} green`} - onClick={() => { }} - > - 다운로드 - </Button> - </div> - <div className="grid grid-cols-6 gap-4 "> - <div className="col-span-6"> - <ListDiv> - <UiTable - headName={[]} - tableData={[]} - headlist={drgtDetailHeadListExport} - pageSize={10} - total={10000} - cellClick={(index: number | undefined, headId: string) => { }} - onPageChange={() => { }} - ></UiTable> - </ListDiv> - </div> - </div> + <div className="grid grid-cols-4 gap-4 h-full"> + <div className="col-span-4"> + <div className="flex items-center justify-between"> + <Title title={`우리동네가뭄 상세내용 - ${data[0].sggNm}`} /> + <div className="flex flex-row space-x-2"> + <Button + size={"sm"} + className={`${btnClass} green mt-12`} + onClick={excelClick} + > + 다운로드 + </Button> + </div> + </div> + <hr className="mt-2 mb-2" /> + <div className="grid grid-cols-6 gap-4 "> + <div className="col-span-6"> + <ListDiv> + <UiTable + headName={[]} + tableData={data} + headlist={drgtDetailHeadListExport} + pageSize={10} + total={10000} + cellClick={(index: number | undefined, headId: string) => { }} + onPageChange={() => { }} + ></UiTable> + </ListDiv> </div> </div> </div> - - </ContentsDiv> + </div> </> ) } \ No newline at end of file diff --git a/apps/wr/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal.tsx b/apps/wr/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal.tsx new file mode 100644 index 000000000..57424996e --- /dev/null +++ b/apps/wr/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal.tsx @@ -0,0 +1,172 @@ +import { coRegExcel } from "@/app/store/matDmd/coSttn/headList"; +import type { ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/index"; +import { reUseCaseNames } from "@/app/store/matDmd/ruseCaseMng/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 { zodResolver } from "@hookform/resolvers/zod"; +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import type { z } from "zod"; +import { useWrStore } from "@/app/store"; + +export default function RuseCaseMngExcel() { + const { insertRuseCaseMng } = useWrStore((state) => state); + const form = useForm<z.infer<typeof coRegExcel>>({ + resolver: zodResolver(coRegExcel), + }); + + const [file, setFiles] = useState<File | undefined>(); + + const onSubmit = () => { + if (file) { + filePicked(file, 0).then((res: unknown) => { + try { + const newArray: ruseCaseMngExcelProps[] = [] + const dataArray = Array.isArray(res) ? res : []; + dataArray.forEach((item: Record<string, unknown>) => { + const object: ruseCaseMngExcelProps = { + ruseBizNm: '', + bizBgngDate: '', + bizEndDate: '', + splyFcltKnd: '', + splyFcltNm: '', + splyFcltCpct: 0, + dmdFcltNm: '', + dmdFcltAddr: '', + ruseFcltCpct: 0, + ruseFcltPplLen: '', + ruseFcltUsg: '', + ruseFcltSplyCpct: 0, + ruseFcltPrcsMsrc: '', + grnteWqUsg: '', + grnteWqGrssClfg: 0, + grnteWqCombResdch: 0, + grnteWqTrbt: '', + grnteWqBod: '', + grnteWqSmll: '', + grnteWqCrmty: '', + grnteWqTn: '', + grnteWqTp: '', + grnteWqPh: '', + grnteWqClIonQnt: '', + grnteWqCndctStat: '', + grnteWqRmrk: '', + reqBizReuseFcltCst: 0, + reqBizPplCst: 0, + reqBizArchCst: 0, + reqBizMchnCst: 0, + reqBizMtrngCst: 0, + reqBizGisCst: 0, + reqBizCctvCst: 0, + reqBizCmcnCst: 0, + reqBizWstCst: 0, + reqBizDesignCst: 0, + reqBizSpvsCst: 0, + reqBizSbsdCst: 0, + reqBizEtc: '', + reqBizGrssCst: 0, + prcmPlanNlep: 0, + prcmPlanLcep: 0, + prcmPlanBrdnCst: 0, + prcmPlanEcqrRt: 0, + prcmPlanGrssCst: 0, + clclnNlep: 0, + clclnLcep: 0, + clclnBrdnCst: 0, + clclnEcqrRt: 0, + clclnGrssCst: 0, + }; + + Object.keys(reUseCaseNames).forEach((key: string) => { + if (item && reUseCaseNames[key] !== undefined) { + const mappedKey = reUseCaseNames[key]; + if (mappedKey && object.hasOwnProperty(mappedKey)) { + let value; + + if(value === "-"){ + value = ''; + } + if(key === "사업시작일" || key === "사업종료일"){ + if(item[key]?.toString().split(".")[1]?.length === 1){ + value = `${item[key]?.toString().split(".")[0] || ""}${item[key]?.toString().split(".")[1]?.length === 1 ? "0" : ""}${item[key]?.toString().split(".")[1] || ""}` + }else{ + value = `${item[key]?.toString().split(".")[0] || ""}${item[key]?.toString().split(".")[1] || ""}` + } + }else if(key === "재이용시설_관로(km)" || key?.toString().includes("보증수질_")){ + value = item[key]?.toString().trim() || ''; + }else{ + if(item[key]?.toString().includes("%") && Number(item[key]?.toString().replaceAll("%", ""))){ + value = item[key]?.toString().replaceAll("%", ""); + }else{ + value = item[key]; + } + } + + if(value === null || value?.toString().trim() === "-" || value?.toString().trim() === ""){ + if (typeof object[mappedKey as keyof ruseCaseMngExcelProps] === 'number') { + (object as unknown as Record<string, unknown>)[mappedKey] = ''; + } else { + (object as unknown as Record<string, unknown>)[mappedKey] = ''; + } + }else if (typeof object[mappedKey as keyof ruseCaseMngExcelProps] === 'number' && Number(value?.toString().replaceAll("%", "").replaceAll(",", ""))) { + (object as unknown as Record<string, unknown>)[mappedKey] = Number(value?.toString().replaceAll("%", "").replaceAll(",", "")); + }else{ + (object as unknown as Record<string, unknown>)[mappedKey] = value?.toString().trim() || ''; + } + } + } + }); + newArray.push(object); + }); + console.log("newArray : ", newArray); + insertRuseCaseMng(newArray); + } catch (e) { + console.log(e) + } + }); + }; + } + + return ( + <> + <div> + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)}> + <div> + <Title title={"물재이용 사례 등록"}> +
+
+

+ {"물재이용 사례 파일"} +

+ +
+ +
+ ( + + { + console.log("files", files) + if (files && files?.length === 1) setFiles(files[0]); + }} + fileTypes="" + maxFiles={1} + > + + )} + /> +
+ + +
+ + ); +} \ No newline at end of file diff --git a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx index 1fa8fa8f3..34d46043f 100644 --- a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx +++ b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx @@ -1,12 +1,12 @@ import { useWrStore } from "@/app/store"; import { coRegExcel } from "@/app/store/matDmd/coSttn/headList"; import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; -import { excelToLdrmntData, names } from "@/app/store/matDmd/ldrmntCoSttn/excel"; +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, Input } from "@common/components/ui"; +import { Button } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useForm } from "react-hook-form"; import type { z } from "zod"; @@ -26,34 +26,41 @@ export default function CoRegExcel() { ldrmntDelete(); if (file) { filePicked(file, 0).then((res) => { + //TODO:loading try { - console.log("res", res) let array: { [key: string]: string | number }[] = [] - if (Array.isArray(res)) - res.forEach((item, index) => { + let isError = false; + if (Array.isArray(res)){ + res.some((item, index) => { let object: { [key: string]: string | number } = {} - Object.keys(names).forEach((key) => { + Object.keys(names).some((key) => { if (item && names[key] !== undefined) { - if (key === "공장관리번호") + if (key === "공장관리번호") { item[key] = String(item[key]) - object[names[key] as string] = item[key]; + } else { + object[names[key] as string] = item[key]; + } } - + return false; }) + if(isError === true) + return true; array.push(object) if (index != 0 && index % 5000 == 0) { ldrmntRegData(array); - console.log("array", array) array = [] array.length = 0; - // throw new Error("error") } + return false; }) + } + if(isError === false) ldrmntRegData(array); - console.log("array끝", array) } catch (e) { console.log(e) + alert(e) + return true; } }); @@ -61,47 +68,46 @@ export default function CoRegExcel() { } - return ( - <> -
-
- -
- -
-
-

- {"잠재수요처 파일"} -

+ return ( + <> +
+ + +
+ +
+
+

+ {"잠재수요처 파일"} +

- -
+ +
-
+
- ( - - { - console.log("files", files) - if (files && files?.length === 1) setFiles(files[0]); - }} - fileTypes="" - maxFiles={1} - > - - )} - /> -
- - -
- - ); - } + ( + + { + if (files && files?.length === 1) setFiles(files[0]); + }} + fileTypes="" + maxFiles={1} + > + + )} + /> +
+ + +
+ + ); +} diff --git a/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx b/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx index 03c257c59..0b071aa91 100644 --- a/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx @@ -14,7 +14,6 @@ const {bdst,rain} = useWrStore((state) => { return state; }); const { bdstChgHeadList } = bdst; - console.log("chgBuilding", chgBuilding); return ( diff --git a/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx index 315f9397f..205846bb4 100644 --- a/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx @@ -29,9 +29,10 @@ export type objSearchType = { interface BdstRegProps { moType: T; + setIsModal?: (open: boolean) => void; } -export function BdstReg({ moType }: BdstRegProps) { +export function BdstReg({ moType,setIsModal }: BdstRegProps) { const { rain, code, bdst,findBdst } = useWrStore((state) => { return state; }); @@ -143,7 +144,7 @@ export function BdstReg({ moType }: BdstRegProps) { { moType === 'RNB'? :moType==='RST' - ? + ? {setIsModal}}> : } diff --git a/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx index 92b40e146..9c8f2cdd6 100644 --- a/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx @@ -1,6 +1,10 @@ "use client"; import { useWrStore } from "@/app/store"; -import type { pubHasuType, fcBizType, fcOrgwtType,} from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +import type { + pubHasuType, + fcBizType, + fcOrgwtType, +} from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import type { TableUpperProps } from "@/app/store/common/type/header"; import { tableData } from "@/components/lib/func/commom"; import RuseMngTable from "@/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable"; @@ -11,138 +15,161 @@ import { Input } from "@common/components/ui"; import { ArrowLeft, ArrowRight } from "lucide-react"; import { useEffect, useRef, useState } from "react"; -export default function FcOrgwtsRegModal({ onRightSet, closeModal }: { onRightSet?: (rightData:fcOrgwtType[]) => void,closeModal?:(val:boolean) =>void }) { - const { code, pbnst, getSwtrmtFcltNm, searchFclts } = useWrStore((state) => state); +export default function FcOrgwtsRegModal({ + onRightSet, + closeModal, +}: { + onRightSet?: (rightData: fcOrgwtType[]) => void; + closeModal?: (val: boolean) => void; +}) { + const { code, pbnst, getSwtrmtFcltNm, searchFclts } = useWrStore( + (state) => state + ); const { fcOrgwtsHeadList, pbnstHasuRes } = pbnst; const [bdstTable, setbdstTable] = useState(); const rightRef = useRef([] as pubHasuType[]); const leftRef = useRef([] as pubHasuType[]); const [rightData, setRightData] = useState(); const [inputVal, setInputVal] = useState(""); - - useEffect(()=>{ - if(Array.isArray(searchFclts)){ + + useEffect(() => { + if (Array.isArray(searchFclts)) { const filteredData = searchFclts.filter((item) => { - if(rightData){ - if(rightData.find(rightItem =>rightItem.bscFctCd===item.bscFctCd)) + if (rightData) { + if ( + rightData.find((rightItem) => rightItem.bscFctCd === item.bscFctCd) + ) return false; } - return true - }) - setbdstTable(Array.isArray(filteredData) ? [...filteredData] : []) + return true; + }); + setbdstTable(Array.isArray(filteredData) ? [...filteredData] : []); } - - }, [searchFclts]) + }, [searchFclts]); useEffect(() => { if (code.sggCd.length > 0 && pbnstHasuRes.length > 0) { setbdstTable(tableData(pbnstHasuRes, { code })); - console.log('bdstTable ', bdstTable) + console.log("bdstTable ", bdstTable); } }, [code, pbnstHasuRes]); 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]) + 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]); return ( - <> -
-
- - <Button className="m-2" size={"sm"} - onClick={() => {closeModal && closeModal(false) }}>저장</Button> - </div> + <div className="flex flex-col h-[80vh]"> + <div className="shrink-0 p-4 border-b z-10 bg-white"> + <div className="flex items-center"> + <Title title="취수하수처리장 추가" /> + {/* <Button size="sm" onClick={() => closeModal?.(false)}>저장</Button> */} + <div className="flex items-center gap-2 mt-8"> - <div className="flex flex-row flex-grow gap-4 mt-4"> - <div className="w-3/7"> - <div className="flex items-center justify-between"> - <Label className="w-full text-2xl text-gray-600 text-left">공공하수처리시설 목록</Label> - <div className="flex items-center"> - <Label className="w-full text-xl text-gray-600 text-right">시설명</Label> - <Input className="w-1/2 !text-xl ml-2" type="text" value={inputVal} onChange={(e) => {setInputVal(e.target.value)}} /> - <Button className="m-2" size={"sm"} onClick={() => getSwtrmtFcltNm(inputVal)}>조회</Button> - </div> - </div> - <div className="border-t border-gray-300 my-4"></div> - <RuseMngTable - tableData={bdstTable || []} - headList={fcOrgwtsHeadList} - upHeadList={[]} // TODO: Replace with actual upHeadList data if available - ref={leftRef} - /> - </div> - <div className="flex flex-col items-center justify-center w-1/7 gap-2"> - <ArrowRight - type="button" - onClick={() => { - if (leftRef && typeof leftRef === "object" && "current" in leftRef) { - const checked = leftRef.current?.filter((item) => ((item as unknown as pubHasuType)?.choose)) - const unchecked = leftRef.current?.filter((item) => !(item as unknown as pubHasuType)?.choose) - if (checked && checked.length > 0) { - checked.forEach(item=>(item as unknown as pubHasuType).choose = false) - setRightData([...(checked as unknown as pubHasuType[]), - ...((rightRef.current ?? []) as unknown as pubHasuType[]) - ]) - - } - if (unchecked && unchecked.length > 0) { - setbdstTable([...(unchecked as unknown as pubHasuType[])]) - }else{ - setbdstTable([]) - } - } - } - } - className="w-12 h-12 text-gray-500 cursor-pointer" - /> - <ArrowLeft - type="button" - onClick={() => { - if (rightRef && typeof rightRef === "object" && "current" in rightRef) { - const checked = rightRef.current?.filter((item) => ((item as unknown as pubHasuType)?.choose)) - const unchecked = rightRef.current?.filter((item) => !(item as unknown as pubHasuType)?.choose) - if (checked && checked.length > 0) { - checked.forEach(item=>(item as unknown as pubHasuType).choose = false) - setbdstTable([ - ...(checked as unknown as pubHasuType[]), - ...((leftRef.current ?? []) as unknown as pubHasuType[]) - ]) - } - if (unchecked && unchecked.length > 0) { - setRightData([...(unchecked as unknown as pubHasuType[])]) - }else{ - setRightData([]) - } - } - }} - className="w-12 h-12 text-gray-500 cursor-pointer mt-5" /> - </div> - {/* Right Table container: Takes 2/5 of the width */} - <div className="w-3/7"> - <Label className="w-full text-2xl text-gray-600 text-right">취수하수처리장 목록</Label> - <div className="border-t border-gray-300 my-4"></div> - <RuseMngTable - tableData={rightData || []} - headList={fcOrgwtsHeadList} - upHeadList={[]} // TODO: Replace with actual upHeadList data if available - ref={rightRef} - /> + <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> </div> </div> </div> - </> + {/* <div className="flex items-center justify-between"> + <div className="flex items-center gap-2"> + <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> + </div> + </div> + </div> */} + + {/* 테이블 영역 */} + <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"> + 공공하수처리시설 목록 + </Label> + <RuseMngTable + tableData={bdstTable || []} + headList={fcOrgwtsHeadList} + upHeadList={[]} + ref={leftRef} + /> + </div> + + {/* 중간 이동 버튼 */} + <div className="flex flex-col justify-center items-center gap-4 w-[200px] min-w-[120px]"> + <ArrowRight + onClick={() => { + const checked = leftRef.current?.filter((item) => item.choose); + const unchecked = leftRef.current?.filter((item) => !item.choose); + if (checked?.length) { + checked.forEach((item) => (item.choose = false)); + setRightData([ + ...(checked as pubHasuType[]), + ...(rightRef.current ?? []), + ]); + } + setbdstTable(unchecked ?? []); + }} + className="w-8 h-8 text-gray-500 cursor-pointer" + /> + <ArrowLeft + onClick={() => { + const checked = rightRef.current?.filter((item) => item.choose); + const unchecked = rightRef.current?.filter( + (item) => !item.choose + ); + if (checked?.length) { + checked.forEach((item) => (item.choose = false)); + setbdstTable([ + ...(checked as pubHasuType[]), + ...(leftRef.current ?? []), + ]); + } + setRightData(unchecked ?? []); + }} + className="w-8 h-8 text-gray-500 cursor-pointer" + /> + </div> + + {/* 오른쪽 테이블 */} + <div className="w-5/12 min-w-[400px]"> + <Label className="text-2xl text-gray-600 mb-2 block text-right"> + 취수하수처리장 목록 + </Label> + <RuseMngTable + tableData={rightData || []} + headList={fcOrgwtsHeadList} + upHeadList={[]} + ref={rightRef} + /> + </div> + </div> + </div> ); } diff --git a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx index b930a36bb..cc0eb80bf 100644 --- a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx @@ -20,13 +20,13 @@ import { useFieldArray, type UseFormReturn } from "react-hook-form"; import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg"; export function PbnstRegModal({ - data, form, + setPbnstInsert }: { - data: pubHasuType; form: UseFormReturn<{ items: PbnstRegArrrayType }>; + setPbnstInsert: (data: customPbnst) => void }) { - const { pbnst, pbnstInsert } = useWrStore((state) => { + const { pbnstInsert } = useWrStore((state) => { return state; }); const [pbnstBdstForm, setPbnstBdstForm] = useState<customPbnst>( @@ -35,40 +35,30 @@ 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]) : []; + const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { + const item = valuse.items[indexMng]; + const data = item ? writeRgtrAndMdfr([item]) : []; - if(data && data[0]){ - pbnstInsert(data[0]) - } - }; + if (data && data[0]) { + // pbnstInsert(data[0]); + setPbnstInsert(data[0]) + } + }; const handleTabChange = (value: string) => { setCurrentTab(value); - }; - - useEffect(() => { - console.log("form errors:", form.formState.errors); - }, [form.formState.errors]); - - + }; useEffect(() => { - if (data) { - - const firstForm = form.getValues("items"); - setIndexMng(firstForm.length - 1) } - }, [data, form]); - - + console.log("form errors:", form.formState.errors); + }, [form.formState.errors]); useEffect(() => { - console.log(' form.getValues() ' ,form.getValues()) - - }, [form.getValues()]); - + const firstForm = form.getValues("items"); + if (firstForm) { + setIndexMng(firstForm.length - 1); + } + }, [form]); return ( <> <h1 className="text-2xl font-medium text-label pl-8"> @@ -86,7 +76,7 @@ export function PbnstRegModal({ 차수별정보 </TabsTrigger> <Button - onClick={ form.handleSubmit(onSubmit)} + onClick={form.handleSubmit(onSubmit)} size={"sm"} className="!justify-end" > @@ -104,7 +94,7 @@ export function PbnstRegModal({ </TabsContent> <TabsContent className="max-h-full" value="buse"> <PbnstBuseForm - form={form} + form={form} indexMng={indexMng} indexBiz={indexBiz} setIndexBiz={setIndexBiz} diff --git a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx index edffcc71d..b7229a559 100644 --- a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx +++ b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx @@ -7,7 +7,7 @@ import { handleCommaNumberChange } from "@/components/lib/func/commom"; import { DatePicker, Form, FormField, FormUi, ScrollArea } from "@common/business_components/ui"; import { Button, Input } 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 type { z } from "zod"; @@ -33,8 +33,24 @@ export default function SttnDetailModal({ useEffect(() => { if (ldrmntZod) form.reset(formObj); - }, [formObj]); + + useEffect(() => { + const male = Number(form.watch("maleEmpCnt") ?? 0); + const female = Number(form.watch("fmaleEmpCnt") ?? 0); + const frgnrMale = Number(form.watch("frgnrMaleEmpCnt") ?? 0); + const frgnrFemale = Number(form.watch("frgnrFmaleEmpCnt") ?? 0); + + const total = male + female + frgnrMale + frgnrFemale; + + form.setValue("totalEmpCnt", total); + }, [ + form.watch("maleEmpCnt"), + form.watch("fmaleEmpCnt"), + form.watch("frgnrMaleEmpCnt"), + form.watch("frgnrFmaleEmpCnt"), + ]); + return ( <div> <ScrollArea className="h-[85vh]"> @@ -324,6 +340,7 @@ export default function SttnDetailModal({ handleCommaNumberChange(e, field.onChange); }} value={field.value ?? 0} + min={0} /> </FormUi> )} @@ -343,6 +360,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? 0} + min={0} /> </FormUi> )} @@ -362,6 +380,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? 0} + min={0} /> </FormUi> )} @@ -381,6 +400,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? 0} + min={0} /> </FormUi> )} @@ -400,6 +420,8 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? 0} + min={0} + readOnly={true} /> </FormUi> )} diff --git a/apps/wr/public/sample_ruseCaseMng.xlsx b/apps/wr/public/sample_ruseCaseMng.xlsx new file mode 100644 index 000000000..3a88e0623 Binary files /dev/null and b/apps/wr/public/sample_ruseCaseMng.xlsx differ 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 new file mode 100644 index 000000000..d318b561f --- /dev/null +++ b/packages/common/business_components/src/ui/date_month_picker/index.tsx @@ -0,0 +1,82 @@ +'use client'; + +import { cn } from "../../lib/utils"; +import { + Popover, + PopoverTrigger, + PopoverContent, + Button, +} from "@common/components/ui"; +import { ko } from "date-fns/locale"; +import { format } from "date-fns"; +import { useState } from "react"; +import { MonthPicker } from "./mothPicker"; +import { CalendarIcon } from "lucide-react"; + +type MonthPickerProps = { + field: { value: string; onChange: (date: string) => void }; // yyyyMM 문자열 + selectClass?: string; + readOnly?: boolean; +}; + +// yyyyMM → Date 객체 +const parseYYYYMM = (value: string) => { + const year = Number(value.substring(0, 4)); + const month = Number(value.substring(4, 6)) - 1; + return new Date(year, month); +}; + +// Date 객체 → yyyyMM 문자열 +const formatDateToYYYYMM = (date: Date) => { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + return `${year}${month}`; +}; + +export const DateMonthPicker = ({ + field, + selectClass, + readOnly = false, +}: MonthPickerProps) => { + const [open, setOpen] = useState(false); + + const parsedDate = field?.value ? parseYYYYMM(field.value) : new Date(); + + const handleSelect = ( + date: Date | undefined, + shouldClosePopover?: boolean + ) => { + if (!readOnly && date) { + field.onChange(formatDateToYYYYMM(date)); + if (shouldClosePopover) setOpen(false); + } + }; + + return ( + <Popover open={open && !readOnly} onOpenChange={readOnly ? undefined : setOpen}> + <PopoverTrigger asChild> + <Button + variant="outline" + color="white" + disabled={readOnly} + className={cn( + selectClass ?? "w-[240px] justify-between pl-3 text-left font-normal", + !field?.value && "text-muted-foreground", + readOnly && "opacity-60 cursor-not-allowed" + )} + > + {parsedDate + ?format(parsedDate, "yyyy년 M월", { locale: ko }) + : "월을 선택하세요"} + <CalendarIcon className="ml-2 h-4 w-4" /> + </Button> + </PopoverTrigger> + <PopoverContent className="w-auto p-0" align="start"> + <MonthPicker + currentMonth={parsedDate} + onMonthChange={handleSelect} + /> + </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 new file mode 100644 index 000000000..acf17fba4 --- /dev/null +++ b/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx @@ -0,0 +1,125 @@ +import { cn } from "../../lib/utils"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@common/components/ui"; +import { + eachMonthOfInterval, + endOfYear, + format, + isEqual, + isFuture, + parse, + startOfMonth, + startOfToday, +} from "date-fns"; +import { ko } from "date-fns/locale"; + +function getStartOfCurrentMonth() { + return startOfMonth(startOfToday()); +} + +export type MonthPickerProps = { + currentMonth: Date; + onMonthChange: ( + newMonth: Date | undefined, + shouldClosePopover?: boolean + ) => void; +}; + +export function MonthPicker({ currentMonth, onMonthChange }: MonthPickerProps) { + + const today = startOfToday(); +const currentYear = today.getFullYear(); + const yearFromProp = format(currentMonth, "yyyy"); +const selectedYear = parseInt(yearFromProp); + + // 현재 월의 시작 날짜 + const fullYearStart = parse(yearFromProp, "yyyy", new Date()); + + const yearEnd = + selectedYear === currentYear ? today : endOfYear(fullYearStart); + + + + + 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", + !isEqual(month, currentMonth) && + isEqual(month, getStartOfCurrentMonth()) && + "bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50" + ); + + return ( + <div className="p-3"> + <div className="flex flex-col space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0"> + <div className="space-y-4"> + {/* 년도 셀렉트 */} + <div className="flex justify-center pt-1"> + <Select + value={yearFromProp} + onValueChange={(selectedYearStr) => { + const selectedYearNum = parseInt(selectedYearStr); + const newDate = new Date( + selectedYearNum, + currentMonth.getMonth(), + 1 + ); + onMonthChange(newDate, false); + }} + > + <SelectTrigger className="w-[120px] h-7"> + <SelectValue placeholder="년도" /> + </SelectTrigger> + <SelectContent> + {yearRange.map((year) => ( + <SelectItem key={year} value={String(year)}> + {year}년 + </SelectItem> + ))} + </SelectContent> + </Select> + </div> + + {/* 월 그리드 */} + <div + className="grid w-full grid-cols-3 gap-2" + role="grid" + aria-labelledby="month-picker" + > + {months.map((month) => ( + <div + key={month.toString()} + className="relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-slate-100 first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md dark:[&:has([aria-selected])]:bg-slate-800" + role="presentation" + > + <button + name="month" + className={getMonthButtonClass(month)} + disabled={isFuture(month)} + role="gridcell" + tabIndex={-1} + type="button" + onClick={() => onMonthChange(month, true)} + > + <time dateTime={format(month, "yyyy-MM-dd")}> + {format(month, 'MMM', { locale: ko })} + </time> + </button> + </div> + ))} + </div> + </div> + </div> + </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 b9e341279..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,4 +1,5 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader } from "@common/components"; +import { cn } from "../../lib/utils"; type ModalType = { bodyClass: string; @@ -25,15 +26,20 @@ export function UiModal({ return ( <> <Dialog open={open} onOpenChange={onOpenChange}> - <DialogContent className={bodyClass}> - {noHeaderYn === 'N' && ( + <DialogContent className={bodyClass}> + {noHeaderYn === 'N' && ( <DialogHeader> <DialogDescription> {headerTitle} </DialogDescription> </DialogHeader> )} - {(open && body)} + {(open && body) ? + <div> {body}</div>:<></> + + + + } {noFooterYn === 'N' && ( <DialogFooter className="sm:justify-start"> {footerContent} diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index 19d966a53..fd1e6fe9e 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -20,4 +20,5 @@ export * from "./table"; export * from "./table_div"; export * from "./title"; export * from "./sdmInsertForm"; -export * from "./popover_ui" \ No newline at end of file +export * from "./popover_ui"; +export * from "./date_month_picker"; \ No newline at end of file