Merge commit '5fd8c6e6a62d056d29682a81143ab43649f5e3a8' into iipbs/wr/dev
iipbs_wr / build (push) Waiting to run

This commit is contained in:
leedj312
2025-07-04 22:35:55 +09:00
21 changed files with 450 additions and 174 deletions
+21 -12
View File
@@ -9,6 +9,7 @@ import {
} from "@/app/store/matDmd/coMatRvw/type";
import { formH1Class, formTableName } from "@/components/lib/class/comClass";
import {
formatPhoneNumber,
getCity,
getdmdMatFlag,
tableData,
@@ -33,7 +34,7 @@ import {
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Input, Label } from "@common/components/ui";
import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { useForm, useWatch } from "react-hook-form";
import toast, { Toaster } from "react-hot-toast";
import { z } from "zod";
import moment from "moment";
@@ -68,6 +69,7 @@ export default function CoMatRvw() {
const [selectData, setSelectData] = useState<DmdCoReqType>(
{} as DmdCoReqType
);
const [selectionVersion, setSelectionVersion] = useState(0);
const getSearch = (
startYear: number,
@@ -91,39 +93,46 @@ export default function CoMatRvw() {
const form = useForm<z.infer<typeof DmdCoReqSchema>>({
resolver: zodResolver(DmdCoReqSchema),
shouldUnregister: true
});
const TableCellClick = (index: number) => {
console.log(coMatRvwRes);
if (coMatRvwRes && coMatRvwRes[index]) {
setSelectData(coMatRvwRes[index]);
setSelectionVersion((v) => v + 1); // 행을 클릭할 때마다 버전을 1씩 증가
}
};
const useUsgCdWatch = useWatch({ control: form.control, name: "useUsgCd" });
useEffect(() => {
if (form?.getValues("useUsgCd")) {
console.log(' useUsgCdWatch page ' ,useUsgCdWatch)
if (useUsgCdWatch) {
form.setValue(
"demandCst.usgPrcsProcs",
usageProcData?.find(
(item) => item.usage === (form?.getValues("useUsgCd") as string)
(item) => item.usage === useUsgCdWatch
)?.process ?? ""
);
}
}, [form.watch("useUsgCd")]);
}, [useUsgCdWatch, form,selectionVersion]);
useEffect(() => {
if (coMatRvwRes.length > 0) {
const data = coMatRvwRes?.map((item, index) => {
let flag = "";
flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ??"");
flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ||undefined);
return {
...item,
ctpvCd: item.demandCo?.ctpvCd,
sggCd: item.demandCo?.sggCd,
dmdCoNm: item.demandCo?.dmdCoNm,
daddr: item.demandCo?.daddr,
telno: item.demandCo?.telno,
regDt: moment(item?.demandCo?.regDt).format("YYYY-MM-DD"),
telno: formatPhoneNumber(item?.demandCo?.telno||''),
dmndTmng: item?.dmndTmng,
splyFcltFlg: flag,
};
});
@@ -151,8 +160,8 @@ export default function CoMatRvw() {
useEffect(() => {
if (selectData) {
console.log(selectData);
form.reset(selectData);
setSelectionVersion((v) => v + 1); // 강제로 바뀌었다고 알리기
}
}, [selectData, form]);
return (
@@ -269,7 +278,7 @@ export default function CoMatRvw() {
></UiTable>
</ListDiv>
<hr />
<ScrollArea className="h-[49vh]">
{/* <ScrollArea className="h-[49vh]"> */}
<ListDiv>
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">
수요신청 상세현황
@@ -660,9 +669,9 @@ export default function CoMatRvw() {
</div>
</div>
</Form>
<ConCostForm form={form} type={"mat"} />
<ConCostForm form={form} type={"mat"} selectionVersion={selectionVersion} />
</ListDiv>
</ScrollArea>
{/* </ScrollArea> */}
</div>
</div>
</ContentsDiv>
@@ -21,9 +21,10 @@ import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg";
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import { Toaster } from "react-hot-toast";
export default function Home() {
const { code, htdfl, initHtdfl, getHtdflBdstData } = useWrStore(
const { code, htdfl, initHtdflReg, getHtdflBdstData ,htdflNmSearch} = useWrStore(
(state) => state
);
const [searchTxt, setSearchTxt] = useState("");
@@ -42,18 +43,27 @@ export default function Home() {
useEffect(() => {
if (!htdfl.isInit) {
initHtdflReg('41')
}
}, [htdfl.isInit, initHtdfl]);
}, [htdfl.isInit, initHtdflReg]);
useEffect(() => {
if (code.sggCd.length > 0) {
if (htdflRes&&htdflRes.length>0) {
console.log('htdflRes ', htdflRes)
const htdflData = tableData(htdflRes, { code }).map(
(item: customHtdflBdst) => {
let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가'
return {
...item,
archArea:archArea
};
}
);
setbdstTable(htdflData);
}else{
setbdstTable([]);
}
}, [code, htdflRes]);
@@ -79,7 +89,7 @@ export default function Home() {
// setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding });
// };
useEffect(() => {
getHtdflBdstData(pageNation, "0");
getHtdflBdstData(pageNation, "41");
}, [pageNation]);
return (
@@ -104,7 +114,12 @@ export default function Home() {
<Button
size={"sm"}
onClick={() => {
initHtdfl(searchTxt || "");
if(searchTxt&&searchTxt.length>0){
htdflNmSearch(String(41),searchTxt)
}else{
initHtdflReg(String(41) );
}
}}
>
조회
@@ -160,7 +175,8 @@ export default function Home() {
}}
/>
{/* <UiModal
<Toaster position="top-center" />
{/* <UiModal
bodyClass={""}
open={bdstChgProps.isOpen}
body={
@@ -35,6 +35,10 @@ import { useFieldArray, useForm, type FieldErrors } from "react-hook-form"; // F
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createDefaultPbnstItem } from "./utilsZod";
export default function PublicReuseFaciltyInsert() {
const {
code,
@@ -100,7 +104,7 @@ export default function PublicReuseFaciltyInsert() {
fcOpers: fclt.fcOpers,
};
});
await pbnstRuseFcltUpdate(pbnst as customPbnst[]);
await pbnstRuseFcltUpdate(pbnst as customPbnst[])
await pbnstRuseBizUpdate(bizs);
};
@@ -115,21 +119,43 @@ export default function PublicReuseFaciltyInsert() {
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);
// Zod에서 배열 에러는 바로 배열로 전달됨 (예: items: [ {}, {...}, ... ])
if (Array.isArray(errorObject)) {
return errorObject.flatMap((entry, index) =>
findAllErrors(entry, [...path, index])
);
}
if (typeof errorObject === "object") {
const entries: { message: string; path: (string | number)[] }[] = [];
if (typeof errorObject.message === "string") {
entries.push({ message: errorObject.message, path });
}
return [];
});
if (Array.isArray(errorObject._errors)) {
for (const msg of errorObject._errors) {
entries.push({ message: msg, path });
}
}
const keys = Object.keys(errorObject).filter(
(k) => k !== "message" && k !== "_errors"
);
for (const key of keys) {
entries.push(...findAllErrors(errorObject[key], [...path, key]));
}
return entries;
}
return [];
};
const errorList = findAllErrors(errors);
console.log(' errors ', errors)
if (errorList.length > 0) {
errorList.forEach((errorInfo) => {
const { message, path } = errorInfo;
@@ -160,6 +186,9 @@ export default function PublicReuseFaciltyInsert() {
});
}
};
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
useEffect(() => {
if (code.sggCd.length && pbnstHasuRes.length > 0) {
@@ -184,6 +213,7 @@ export default function PublicReuseFaciltyInsert() {
useEffect(() => {
if (pbnst.pbnstRes && pbnst.pbnstRes?.length > 0) {
form.reset({ items: pbnstRegArrayZod.parse(pbnst.pbnstRes) });
} else {
form.reset({ items: [] });
@@ -204,21 +234,23 @@ export default function PublicReuseFaciltyInsert() {
if (pbnstRes && pbnstRes.length > 0) {
const lastPbnst = pbnstRes[pbnstRes.length - 1];
if (lastPbnst && selecTableRow) {
append(
pbnstRegZod.parse({
pbnstRuseFcltPk:
String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1),
ruseUtztnFcltNm: "",
fcBizs: [
fcBizSchema.parse({
pbnstRuseFcltFk:
String(lastPbnst.pbnstRuseFcltPk) +
String(pbnstRes.length + 1),
cycl: 1,
}),
] as fcBizType[],
})
);
// append(
// pbnstRegZod.parse({
// pbnstRuseFcltPk:
// String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1),
// ruseUtztnFcltNm: null,
// fcBizs: [
// fcBizSchema.parse({
// pbnstRuseFcltFk:
// String(lastPbnst.pbnstRuseFcltPk) +
// String(pbnstRes.length + 1),
// cycl: 1,
// }),
// ] as fcBizType[],
// })
// );
append(createDefaultPbnstItem(selecTableRow, pbnstRes.length));
setIsRuseReg({ isModal: true });
}
} else {
@@ -396,7 +428,7 @@ export default function PublicReuseFaciltyInsert() {
form={form} // form prop 전달
setPbnstInsert={(data) => {
if (data) {
pbnstInsert(data); // pbnstInsert 함수 호출
// pbnstInsert(data); // pbnstInsert 함수 호출
setIsRuseReg({ isModal: false });
}
}}
@@ -0,0 +1,38 @@
import type { fcBizType, pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
export function createDefaultPbnstItem(
selecTableRow: pubHasuType,
index: number
) {
const pk = String(selecTableRow.bscFctCd) + String(index + 1);
return {
pbnstRuseFcltPk: pk,
swtrmtFcltFk: "",
ruseUtztnFcltNm: "", // 필수 입력이므로 빈 문자열로
fcltCpct: 0,
ruseCpct: 0,
splyExtraCpct: 0,
regDt: null,
rgtr: "test",
mdfcnDt: null,
mdfr: "test",
fcFiles: [],
fcBizs: [
createDefaultBiz(pk, 1), // 첫 차수
],
fcOpers: [],
};
}
export function createDefaultBiz(
pbnstRuseFcltFk: string,
cycl: number
): fcBizType {
return {
pbnstRuseFcltFk,
cycl,
// 필요한 값 있으면 여기에 추가
} as fcBizType;
}
@@ -51,8 +51,11 @@ export default function Home() {
if (code.sggCd.length > 0) {
const rainData = tableData(rainRes, { code }).map(
(item: customRainBdst) => {
let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가'
return {
...item,
archArea:archArea,
bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N",
};
}
@@ -20,6 +20,7 @@ import {
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components";
import { useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
export default function Home() {
const { code, rswt, initRswt, rswtBdstSearch, getRswtBdstData } = useWrStore(
@@ -45,8 +46,13 @@ export default function Home() {
if (code.sggCd.length > 0 && rswtRes?.length > 0) {
const rswtData = tableData(rswtRes, { code })?.map(
(item: customRswtBdst) => {
let archArea =
item?.archArea.split(".")[0] !== "-1"
? item?.archArea.split(".")[0]
: "확인불가";
return {
...item,
archArea: archArea,
bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N",
bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd,
};
@@ -151,7 +157,13 @@ export default function Home() {
</div>
<UiModal
body={<BdstReg moType="RST" setIsModal={setIsNewReg} isModal={issNewReg}></BdstReg>}
body={
<BdstReg
moType="RST"
setIsModal={setIsNewReg}
isModal={issNewReg}
></BdstReg>
}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
@@ -162,12 +174,14 @@ export default function Home() {
bodyClass={""}
open={bdstChgProps.isOpen}
body={
<BdstChgModal chgBuilding={bdstChgProps.chgBuilding} ></BdstChgModal>
<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>
}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}}
/>
<Toaster position="top-center" />
</ContentsDiv>
</>
);
@@ -37,6 +37,7 @@ import {
type PrfType,
} from "@/app/store/prfmncReg/pbnstPrfmncReg/type";
import { excelToPbnPrfData } from "@/app/store/prfmncReg/pbnstPrfmncReg/excel";
import data from "@common/components/ui/icon-finder/data";
export default function prfmncPrfmncReg() {
const { code, prfmnc, prfmncHasuInit, prfmnRegData } = useWrStore(
@@ -78,9 +79,6 @@ export default function prfmncPrfmncReg() {
}
}, [inputData, searchYear, pbnstRuseFcltPk, prfmncHasuInit, pageNation]);
const cellClick = useCallback(
(index: number | undefined, headId: string) => {
if (index !== undefined) {
@@ -88,16 +86,22 @@ export default function prfmncPrfmncReg() {
isModal: false,
data: prfmncRes[index] || ({} as FcPrfType),
});
const inUsageData = structuredClone(initValInUsage).map(row => ({
const inUsageData = structuredClone(initValInUsage).map((row) => ({
...row,
구분: "장내용수",
}));
const outUsageData = structuredClone(initValOutUsage).map(row => ({
const outUsageData = structuredClone(initValOutUsage).map((row) => ({
...row,
구분: "장외용수",
}));
const inSubtotal = { ...structuredClone(subTotalObj), 구분: "장내용수" };
const outSubtotal = { ...structuredClone(subTotalObj), 구분: "장외용수" };
const inSubtotal = {
...structuredClone(subTotalObj),
구분: "장내용수",
};
const outSubtotal = {
...structuredClone(subTotalObj),
구분: "장외용수",
};
if (prfmncRes[index]?.prfList) {
prfmncRes[index].prfList?.forEach((prfItem) => {
const month = Number(prfItem?.ym?.slice(4)); // "MM"
@@ -133,7 +137,11 @@ export default function prfmncPrfmncReg() {
});
inUsageData.push(inSubtotal);
outUsageData.push(outSubtotal);
const usageTotalObj: { [key: string]: any } = { ...structuredClone(totalObj), 구분: "총합계", 용수명: "" };
const usageTotalObj: { [key: string]: any } = {
...structuredClone(totalObj),
구분: "총합계",
용수명: "",
};
for (const key in usageTotalObj) {
if (["usage", "gubun", "edit"].includes(key)) continue;
const val =
@@ -156,7 +164,7 @@ export default function prfmncPrfmncReg() {
useEffect(() => {
if (!prfmnc.isInit) {
prfmncHasuInit('1', "41");
prfmncHasuInit("1", "41");
}
}, [prfmnc.isInit, prfmncHasuInit]);
useEffect(() => {
@@ -203,7 +211,7 @@ export default function prfmncPrfmncReg() {
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="space-y">
<div className="flex flex-row space-x-2">
<Button size={"sm"} onClick={(e) => { }}>
<Button size={"sm"} onClick={(e) => {}}>
조회
</Button>
<Button
@@ -218,7 +226,7 @@ export default function prfmncPrfmncReg() {
size={"sm"}
onClick={() => {
if (cellNum === undefined) {
toast.error("하수처리재이용시설을 선택해주세요.")
toast.error("하수처리재이용시설을 선택해주세요.");
return;
} else {
setIsExcelOPen({ ...isExcelOpen, isModal: true });
@@ -279,7 +287,14 @@ export default function prfmncPrfmncReg() {
</ContentsDiv>
<UiModal
bodyClass={"w-[30vw] max-w-none"}
body={<PbnPrfExcelModal data={isExcelOpen.data}></PbnPrfExcelModal>}
body={
<PbnPrfExcelModal
data={isExcelOpen.data}
setIsExcelOPen={(open) => {
setIsExcelOPen({ ...isExcelOpen, isModal: open })
}}
></PbnPrfExcelModal>
}
open={isExcelOpen.isModal}
onOpenChange={() => {
setIsExcelOPen({ isModal: false, data: {} as FcPrfType });
@@ -29,12 +29,12 @@ export const coRvwHeadListExport: CommonTableProps[]= [
visible: true,
},
{
id: "regDt", //바꾸기
id: "dmndTmng", //바꾸기
title: "신청일자",
visible: true,
},
{
id: "state", //바꾸기
id: "splyFcltFlg", //바꾸기
title: "진행상태",
visible: true,
},
@@ -76,7 +76,7 @@ export const hdtflZod = z.object({
.date()
.default(() => new Date())
.nullish(),
archArea: z.number().default(0),
archArea: z.string().default(''),
archChgArea: z.number().nullish().default(0),
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
@@ -99,7 +99,8 @@ export type htdflFacState = {
};
};
type htdflFacSActions = {
initHtdfl: (code: string) => void;
initHtdflReg: (code: string) => void;
htdflNmSearch: (code: string | number, fcltNm:string) => void;
htdflBdstUpdate: (data: customHtdflBdst, code: string | number) => void;
htdflBdstReg: (data: customHtdflBdst, code: string | number) => void;
getHtdflBdstData: (pageNation: number, code: string | number) => void;
@@ -116,8 +117,16 @@ export const htdflFacStateExport: htdflFacState = {
},
};
const initFetch = async (code: string | number) => {
const rswtRes = await getFetch("wr", `/drain/facilityList/1/20/${code}`);
const initFetch = async (code: string) => {
console.log(' initFetch code ', code)
let url = `/drain/facilityList/1/20`
url+=`/${code}`
const rswtRes = await getFetch("wr", url);
return rswtRes;
};
export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
@@ -142,9 +151,9 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
console.log(e);
}
},
initHtdfl: async (code: string) => {
initHtdflReg: async (code: string) => {
try {
const htdflRes = await initFetch(code);
const htdflRes = await initFetch( String(code));
set((state: htdflFacState) => {
return {
...state,
@@ -162,17 +171,18 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
htdflBdstUpdate: async (data: customHtdflBdst, code: string | number) => {
try {
console.log('data ', data)
const chData = await makeMdfr(data);
console.log('chData ', chData)
const res = await putFectch("/drain/facility", chData);
if (res.ok) {
if (res.status) {
toast.success("온배수 건축물 수정이 완료되었습니다.");
}
const htdflRes = await initFetch(code);
const htdflRes = await getFetch(
"wr",
`/drain/facilityList/1/20/${code}`
);
set((state: htdflFacState) => ({
...state,
htdfl: {
@@ -195,7 +205,7 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
if (res.status ===200) {
toast.success("온배수 건축물 등록이 완료되었습니다.");
}
const htdflRes = await initFetch(code);
const htdflRes = await initFetch(String(code));
set((state: htdflFacState) => ({
...state,
htdfl: {
@@ -208,6 +218,23 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
toast.error("온배수 건축물 등록 오류입니다..");
}
}
},htdflNmSearch :async(code:string | number, fcltNm:string) =>{
try {
const htdflRes = await getFetch("wr", `/drain/facilityList/1/20/${code}/${fcltNm}`);
set((state: htdflFacState) => {
return {
...state,
htdfl: {
...state.htdfl,
htdflRes: htdflRes,
isInit: false,
},
};
});
} catch (error) {
console.log(error);
}
},
};
};
@@ -54,6 +54,7 @@ export type pubFacState = {
pbnsUpdateIndex: pbnstInsertIndex;
fcOrgwtsNmList:pubHasuType[];
dmdComList: any[];
apiMessage:string;
};
};
type pubFacActions = {
@@ -94,6 +95,7 @@ export const pubFacStateExport: pubFacState = {
pbnsUpdateIndex: {} as pbnstInsertIndex,
fcOrgwtsNmList:[],
dmdComList: [],
apiMessage:''
},
};
@@ -269,8 +271,13 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => {
ruseRes
);
if(response){
toast.success(` 하수재이용 시설 정보가 수정되었습니다.`);
}
} catch (error) {
console.error("Error pbnstRuseFcltUpdate:", error);
toast.error(` 하수재이용 시설 정보가 수정오류입니다.`);
}
} ,pbnstRuseBizUpdate : async(ruseRes:fcBizType[])=>{
try {
@@ -280,6 +287,10 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => {
`/reuseFc/pubFcBiz`,
ruseRes
);
if(response){
toast.success(` 하수재이용 시설 사업이 수정되었습니다.`);
}
const pbnstRes = await hasuListFetch("11", "11");
return set((state: pubFacState) => ({
@@ -292,6 +303,7 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => {
}));
} catch (error) {
console.error("Error pbnstRuseFcltUpdate:", error);
toast.error(` 하수재이용 시설 사업이 수정이 실패되엇습니다..`);
}
} ,
getBizCycle: async (pbnstObj: customPbnst) => {
@@ -236,10 +236,17 @@ export const fcBizSchema = z.object({
export const pbnstRegZod = z.object({
pbnstRuseFcltPk: z.string().default(""),
swtrmtFcltFk: z.string().default(""),
ruseUtztnFcltNm: z.string().default(""),
fcltCpct: zNumDefaultZero,
ruseCpct: zNumDefaultZero,
splyExtraCpct: zNumDefaultZero,
ruseUtztnFcltNm: z
.preprocess(
(v) => (v != null ? String(v).trim() : ""),
z.string()
)
.refine((val) => val.length > 0, {
message: "시설 이름을 입력하세요",
}),
fcltCpct: z.number(),
ruseCpct: z.number(),
splyExtraCpct: z.number(),
regDt: zDateDefaultNow,
rgtr: z.string().default("test"),
mdfcnDt: zDateDefaultNow,
@@ -34,7 +34,7 @@ export const rainZod = z.object({
bdstNm: z.string().default(""),
frstArchPrmsnDt: z.date().default(() => new Date()),
archChgPrmsnDt: z.coerce.date().nullish().default(null),
archArea: z.number().default(0),
archArea: z.string().default(''),
archChgArea: z.number().default(0),
rgtr:z.string().nullish(),
mdfr:z.string().nullish(),
@@ -5,13 +5,14 @@ import type { TableUpperProps } from "@/app/store/common/type/header";
import { z } from "zod";
import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "../rainReg/type";
import { makeMdfr, makeRstr } from "../bdstReg";
import toast from "react-hot-toast";
const rswtrObjSchema = z.object({
bdstRuseFcltFk: z.number().nullish(),
wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }),
oblgTrgtWtrUsqty: z.number().nullish().default(0),
//wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }),
//oblgTrgtWtrUsqty: z.number().nullish().default(0),
orgwtKndCd: z.string({ required_error: validationMessages.requiredSelect("원수 종류") }).min(1, { message: validationMessages.requiredSelect("원수 종류") }),
filtrTrtmfctCpct: z.number({ required_error: validationMessages.required("처리시설 용량") }).positive({ message: validationMessages.required("처리시설 용량") }),
filtrTrtmfctCpct: z.number({ required_error: validationMessages.required("처리시설 용량") }),
filtrTrtmfctProcs: z.string({ required_error: validationMessages.required("주요처리공정") }).min(1, { message: validationMessages.required("주요처리공정") }),
filtrTrtmfctUsgCd: z.string().default("").nullish(),
rswtrUsqty: z.number().default(0),
@@ -36,7 +37,7 @@ export const rswtZod = z.object({
frstArchPrmsnDt: z.date().default(() => new Date()),
archChgPrmsnDt: z.coerce.date().nullish().default(null),
chBuildingYn: z.string().nullish(),
archArea: z.number().default(0),
archArea: z.string().default(''),
archChgArea: z.number().default(0),
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
@@ -152,8 +153,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
try {
const chData = await makeMdfr(data);
const res = await putFectch("/reuseFc/waterreuseFc", chData);
if (res.ok) {
alert("등록이 완료되었습니다.");
if (res.status ===200) {
toast.success("중수도 건축물 수정이 완료되었습니다.");
const rswtRes = await initFetch(code);
set((state: rswtFacState) => ({
...state,
@@ -165,10 +166,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
}));
}
} catch (errorUpdate) {
alert(
"업데이트 오류입니다. " +
(errorUpdate instanceof Error ? errorUpdate.message : "")
);
toast.error("중수도 건축물 수정 오류입니다. ");
} finally {
}
},
@@ -176,29 +175,28 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
try {
const chData = await makeRstr(data);
const res = await postFectch("/reuseFc/waterreuseFc", chData);
if (res.ok) {
if (data.chgBuilding.length > 0) {
await res
.json()
.then((resData: any) => {
const chPK = resData?.data?.bdstInfoPk;
const makeCh = resData.data.chgBuilding.map(
(item: chgBuilding) => ({
...item,
bdstInfoFk: chPK,
})
);
const chch = postFectch("/reuseFc/chgBuilding", makeCh);
return chch;
})
.then((chch: any) => {
if (chch.ok) {
alert("등록이 완료되었습니다.");
}
});
if (res.status===200) {
if(data.chgBuilding.length > 0){
const chPK = res?.data?.bdstInfoPk
const makeCh= res.data.chgBuilding.map((item: chgBuilding) =>
( {
...item,
bdstInfoFk: chPK,
})
);
const chch= await postFectch("/reuseFc/chgBuilding", makeCh);
if(chch.status ===200) {
toast.success("건축물 등록이 완료되었습니다.");
}else{
toast.error("건축물 증축/개축/중축 오류입니다.");
}
} else {
alert("등록이 완료되었습니다.");
toast.success("건축물 등록이 완료되었습니다.");
}
}else{
toast.error("건축물 등록이 완료되었습니다.");
}
const rainRes = await initFetch(code);
set((state: rswtFacState) => ({
@@ -211,7 +209,7 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
}));
} catch (e) {
console.log("e", e);
alert("등록 오류입니다.");
toast.error("등록시 오류가 발생하였습니다.");
} finally {
}
},
+22 -11
View File
@@ -165,18 +165,29 @@ export const yearOptions: { val: string; text: string }[] = Array.from(
})
);
export const getdmdMatFlag = (flag: string|undefined) => {
let flagMat = "";
export const getdmdMatFlag = (flag: string | undefined | null) => {
const cleanFlag = (flag ?? "").trim();
if(flag === undefined || flag === null) {
flagMat = "신청";
}else if(flag.trim() === "Sub") {
flagMat = "검토";
}else if(flag.trim() === "matched") {
flagMat = "매칭완료";
}else {
flagMat = "신청";
console.log('cleanFlag ', cleanFlag)
switch (cleanFlag) {
case "Sub":
return "검토";
case "matched":
return "매칭완료";
default:
return "신청";
}
return flagMat;
};
export const formatPhoneNumber=(tel:string) => {
const onlyNums = tel.replace(/[^0-9]/g, '');
if (onlyNums.length === 10) {
return onlyNums.replace(/(\d{2})(\d{4})(\d{4})/, '$1-$2-$3');
} else if (onlyNums.length === 11) {
return onlyNums.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
} else {
return tel; // 유효하지 않으면 빈 문자열
}
}
@@ -31,9 +31,11 @@ import toast from "react-hot-toast";
export default function ConCostForm({
form,
type,
selectionVersion,
}: {
form: UseFormReturn<DmdCoReqType>;
type: string;
selectionVersion: number;
}) {
const {
constCostRes,
@@ -70,7 +72,14 @@ export default function ConCostForm({
const dmndQtyWatch = form.watch("dmndQty");
const totalConstCost = form.watch("totalConstCost");
const cstrnCst = form.watch("demandCst.cstrnCst");
const useUsgCdWatch = form.watch("useUsgCd");
useEffect(() =>{
console.log('usgPrcsProcsWatch ', usgPrcsProcsWatch)
console.log('useUsgCdWatch ' , useUsgCdWatch)
},[usgPrcsProcsWatch, useUsgCdWatch, selectionVersion])
const calculateConstCost = useCallback(() => {
const usgPrcsProcs = usgPrcsProcsWatch;
const dmndQtyYear = dmndQtyWatch * 365;
@@ -255,7 +264,7 @@ export default function ConCostForm({
placeholder=""
type="text"
onChange={field.onChange}
value={form.getValues("demandCst.usgPrcsProcs") ?? ""}
value={field.value ?? ""}
className="mt-2"
/>
</FormUi>
@@ -89,7 +89,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
return (
<>
<h1 className={formH1Class}>건축물 기본 정보</h1>
<h1 className={formH1Class}> { type !== "HTB"?"건축물 기본 정보": '발전소 기본 정보'}</h1>
<div className="grid grid-cols-6 gap-2 mt-4">
<div className="col-span-3">
<FormField
@@ -140,10 +140,10 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
control={form.control}
name="bdstNm"
render={({ field }) => (
<FormUi label="건축물명">
<FormUi label={ type !== "HTB"?"건축물명": '발전소명'}>
<Input
className={selectClass}
placeholder="건축물 명 입력하세요"
placeholder= {type !== "HTB"?"건축물 명 입력하세요":'발전소명 입력하세요' }
type="text"
{...field}
/>
@@ -156,7 +156,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
control={form.control}
name="daddr"
render={({ field }) => (
<FormUi label="건축물 주소">
<FormUi label= { type !== "HTB"?"건축물 주소": '발전소 주소'} >
<Input
className={selectClass}
placeholder="위치를 입력해주세요"
@@ -173,7 +173,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
control={form.control}
name="frstArchPrmsnDt"
render={({ field }) => (
<FormUi label="최초건축허가일">
<FormUi label= { type !== "HTB"?"최초건축허가일": '준공년도'} >
<DatePicker
mode={"single"}
field={{
@@ -223,9 +223,9 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
placeholder="면적을 입력하세요"
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
field.onChange(e.target.value)
}}
value={formatCommaNumber(field.value)}
value={field.value}
/>
</FormUi>
)}
@@ -58,8 +58,6 @@ export default function HtdflRegForm({
if (setIsModal) setIsModal(false);
} else {
console.log(' isModal ' ,isModal)
console.log(' values ' ,values)
htdflBdstUpdate(values, "41");
}
};
@@ -62,7 +62,11 @@ export default function RswtrRegForm({
rswtBdstUpdate(values, "41");
}
};
const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => {
const filtrTrtmfctCpct = form.watch('reuseBuilding.0.rswtrObj.filtrTrtmfctCpct')
const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => {
console.log('raw ', raw)
return {
...raw,
frstArchPrmsnDt: raw?.frstArchPrmsnDt
@@ -77,16 +81,25 @@ export default function RswtrRegForm({
? new Date(item.instlCmptnDt)
: new Date(), // item?.instlCmptnDt가 유효하지 않으면 현재 날짜로 초기화
operMngCd: item?.operMngCd ?? "", // null → ""
instlCstSprtYn: item?.instlCstSprtYn ?? "Y", // null → "Y"
grntchBdstCertYn: item?.grntchBdstCertYn ?? "Y",
instlCstSprtYn: item?.instlCstSprtYn || code.yn[0]?.val, // null → "Y"
grntchBdstCertYn: item?.grntchBdstCertYn|| code.yn[0]?.val,
rswtrObj: {
...item?.rswtrObj,
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y",
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn || code.yn[0]?.val,
filtrTrtmfctCpct: item?.rswtrObj?.filtrTrtmfctCpct ?? null,
filtrTrtmfctProcs: item?.rswtrObj?.filtrTrtmfctProcs || code.rswtPrscCdMthdCd[0]?.val,
orgwtKndCd: item?.rswtrObj?.orgwtKndCd || code.orgwtKndCd[0]?.val,
},
})),
};
};
// useEffect(() =>{
// console.log(' formform ', form.watch())
// },[form.formState])
useEffect(() =>{
console.log(' filtrTrtmfctCpct ', filtrTrtmfctCpct)
},[filtrTrtmfctCpct])
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
@@ -227,6 +240,8 @@ export default function RswtrRegForm({
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
console.log('value')
field.onChange(""); // 초기화
}
}}
@@ -334,7 +349,7 @@ export default function RswtrRegForm({
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
disabled={instlCstSprtYn !== "Y"}
disabled={instlCstSprtYn === "N"||instlCstSprtYn === "D"}
/>
</FormUi>
);
@@ -359,7 +374,7 @@ export default function RswtrRegForm({
label={""}
selectArray={code.bdstIncenYn}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.yn[0]?.val}
value={field.value || code.yn[0]?.val}
readOnly={readonly}
/>
</FormUi>
@@ -395,7 +410,7 @@ export default function RswtrRegForm({
field.onChange(e.target.value);
}
}}
disabled={grntchBdstCertYn !== "Y"}
disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"}
max={4}
/>
</FormUi>
@@ -432,7 +447,7 @@ export default function RswtrRegForm({
field.onChange(e.target.value);
}
}}
disabled={grntchBdstCertYn !== "Y"}
disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"}
@@ -18,12 +18,13 @@ import { Button, Input } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import type { z } from "zod";
export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) {
export default function PbnPrfExcelModal({ data ,setIsExcelOPen }: { data: FcPrfType ,setIsExcelOPen:(open:boolean )=>void }) {
const { prfmnRegData } = useWrStore((state) => state);
const [files, setFiles] = useState<File[] | null>(null);
const [file, setFile] = useState<File | null>(null);
const [excelData, setExcelData] = useState<PrfType[]>();
const form = useForm<z.infer<typeof pbnPrfRegExcelZod>>({
resolver: zodResolver(pbnPrfRegExcelZod),
@@ -31,10 +32,18 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) {
ym: String(new Date().getFullYear()),
},
});
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const selectedFile = e.target.files?.[0];
if (selectedFile) {
setFile(selectedFile);
}
};
const onSubmit = (values: z.infer<typeof pbnPrfRegExcelZod>) => {
if (excelData) {
prfmnRegData(excelData as unknown as PrfType);
setIsExcelOPen(false)
}
@@ -46,31 +55,24 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) {
form.setValue("pbnstRuseFcltNm", data.ruseUtztnFcltNm);
}, [data]);
useEffect(() => {
console.log("excelData", excelData);
}, [excelData]);
useEffect(() => {
if (files) {
console.log("이런")
const file = files[0];
if (file) {
const isFile = file
if (form.getValues("ym").length < 1) {
ToastFormUi({
body: "파일업로드 이전에 등록년도를 작성해주세요 ",
title: "지도점검 등록",
});
setFiles(null);
toast.error("파일업로드 이전에 등록년도를 작성해주세요 " );
setFile(null);
return;
}
if (file) {
filePicked(file, 0).then((res) => {
if (isFile) {
filePicked(isFile, 0).then((res) => {
if (res !== undefined)
setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"), form.getValues('pbnstRuseFcltFk')) as PrfType[])
});
}
}
}, [files]);
}, [file]);
return (
<>
@@ -144,14 +146,25 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) {
name="file"
render={({ field }) => (
<FormUi label="점검결과 파일">
<FileUpload
{/* <FileUpload
files={files || []}
setFiles={(files: File[] | null) => {
if (files) setFiles(files);
}}
fileTypes="xlsx"
maxFiles={1}
></FileUpload>
></FileUpload> */}
<div className="space-y-4 p-4">
<Input
type="file"
onChange={handleFileChange}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
/>
</div>
</FormUi>
)}
/>
@@ -147,8 +147,8 @@ export function BdstReg<T extends MoType>({ moType,setIsModal,isModal }: BdstReg
{ moType === 'RNB'?
<RainRegForm rainForm={rainBdstForm as customRainBdst} isModal={isModal} setIsModal={setIsModal} />
:moType==='RST'
? <RswtrRegForm rswtForm={rainBdstForm as customRswtBdst} isModal={isModal} setIsModal={(open) =>{setIsModal}}></RswtrRegForm>
:<HtdflRegForm htdflForm={rainBdstForm as unknown as customHtdflBdst} isModal={true} setIsModal={(open) =>{setIsModal}}></HtdflRegForm>
? <RswtrRegForm rswtForm={rainBdstForm as customRswtBdst} isModal={isModal} setIsModal={(open) =>{setIsModal && setIsModal(open)}}></RswtrRegForm>
:<HtdflRegForm htdflForm={rainBdstForm as unknown as customHtdflBdst} isModal={true} setIsModal={(open) =>{setIsModal && setIsModal(open)}}></HtdflRegForm>
}
</div>
@@ -1,6 +1,7 @@
"use client";
import { useWrStore } from "@/app/store";
import {
pbnstRegZod,
type customPbnst,
type PbnstRegArrrayType,
type pubHasuType,
@@ -16,17 +17,23 @@ import {
} from "@common/components/ui";
import { useEffect, useState } from "react";
import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm";
import { useFieldArray, type UseFormReturn } from "react-hook-form";
import {
useFieldArray,
type FieldErrors,
type UseFormReturn,
} from "react-hook-form";
import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg";
import toast from "react-hot-toast";
import type { z } from "zod";
export function PbnstRegModal({
form,
setPbnstInsert
setPbnstInsert,
}: {
form: UseFormReturn<{ items: PbnstRegArrrayType }>;
setPbnstInsert: (data: customPbnst) => void
setPbnstInsert: (data: customPbnst) => void;
}) {
const { pbnstInsert } = useWrStore((state) => {
const { pbnstInsert } = useWrStore((state) => {
return state;
});
const [pbnstBdstForm, setPbnstBdstForm] = useState<customPbnst>(
@@ -35,13 +42,65 @@ 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]) {
setPbnstInsert(data[0]);
}
};
const onInvalid = (
errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>
) => {
// 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다.
const findAllErrors = (
errorObject: any,
path: (string | number)[] = []
): { message: string; path: (string | number)[] }[] => {
if (!errorObject) return [];
if (data && data[0]) {
// pbnstInsert(data[0]);
setPbnstInsert(data[0])
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}`);
});
}
};
@@ -76,7 +135,7 @@ export function PbnstRegModal({
차수별정보
</TabsTrigger>
<Button
onClick={form.handleSubmit(onSubmit)}
onClick={form.handleSubmit(onSubmit, onInvalid)}
size={"sm"}
className="!justify-end"
>