하수재이용 시설 밸류데이션 체크 작업중

This commit is contained in:
leedj312
2025-06-26 16:08:00 +09:00
parent 5288439625
commit cd6568f4df
7 changed files with 75 additions and 31 deletions
@@ -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";
@@ -105,6 +105,53 @@ export default function PublicReuseFaciltyInsert() {
await pbnstRuseBizUpdate(bizs);
};
// 폼 유효성 검사 실패 시 호출될 함수
const onInvalid = (errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[]; }>) => {
// 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다.
const findAllErrors = (
errorObject: any,
path: (string | number)[] = []
): { message: string; path: (string | number)[] }[] => {
if (!errorObject) return [];
return Object.keys(errorObject).flatMap((key) => {
const value = errorObject[key];
const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key;
const newPath = [...path, currentKey];
if (value && typeof value === "object") {
if (typeof value.message === "string") {
return [{ message: value.message, path: newPath }];
}
return findAllErrors(value, newPath);
}
return [];
});
};
const errorList = findAllErrors(errors);
if (errorList.length > 0) {
errorList.forEach((errorInfo) => {
const { message, path } = errorInfo;
let finalMessage = message;
const itemsIndex = path.indexOf("items");
const fcBizsIndex = path.indexOf("fcBizs");
if (itemsIndex > -1 && fcBizsIndex > -1 && path.length > fcBizsIndex + 1) {
const itemIdx = path[itemsIndex + 1] as number;
const bizIdx = path[fcBizsIndex + 1] as number;
const cycle = form.getValues(`items.${itemIdx}.fcBizs.${bizIdx}.cycl`);
if (cycle) {
finalMessage = `[${cycle}차수] ${message}`;
}
}
toast.error(finalMessage);
});
}
};
useEffect(() => {
if (code.sggCd.length) {
if (searchFclts) {
@@ -250,7 +297,7 @@ useEffect(() =>{
<div className="grid grid-cols-6 gap-4 h-full">
<div className="col-span-4 h-full min-h-0">
<ListDiv className="min-h-0">
<ScrollArea className="h-[60vh]">
<ScrollArea className="h-[60vh]"> {/* 높이 조정 */}
<UiTable
tableData={bdstTable || []}
headlist={pubFacHeadList}
@@ -276,8 +323,8 @@ useEffect(() =>{
</TabsTrigger>
<Button
size={"sm"}
onClick={form.handleSubmit(onSubmit)}
className="!justify-end"
onClick={form.handleSubmit(onSubmit,onInvalid)}
className="!justify-end" // 저장 버튼 위치 조정
>
저장
</Button>
@@ -310,7 +357,7 @@ useEffect(() =>{
<UiModal
body={
<PbnstRegModal
form={form}
form={form} // form prop 전달
data={isRuseReg.data || ({} as customPbnst)}
></PbnstRegModal>
}
@@ -80,7 +80,6 @@ export default function Home() {
};
useEffect(() => {
console.log("getPageNation", pageNation);
getRainData(pageNation, "41");
}, [pageNation]);
@@ -17,7 +17,6 @@ import {
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
@@ -148,7 +148,7 @@ 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,
@@ -171,17 +171,17 @@ 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(),
designCst: zNumNullish,
cstrnSpvsCst: zNumNullish,
fcltSbsdCst: zNumNullish,
@@ -241,4 +241,3 @@ export type fcOrgwtType = z.infer<typeof fcOrgwtSchema>;
export type ppInstlType = z.infer<typeof pplInstlSchema>;
export type operType = z.infer<typeof fcOperSchema>;
export type fcFileType = z.infer<typeof fcFileSchema>;
@@ -16,7 +16,7 @@ const rainyObjSchema = z.object({
pntfColKnd: z.string().default(""),
pntfColArea: z.number().default(0),
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),
@@ -59,7 +59,7 @@ const reuseBuildingSchema = z.object({
}).refine((data) => data.bdstUsgCd > 0, {
message: validationMessages.requiredSelect("건축물용도"),
path: ["bdstUsgCd"],
});
}) ;
const chgBuildingSchema = z.object({
bdstInfoFk: z.number().nullish(),
@@ -55,8 +55,6 @@ export function PbnstBuseForm({
code,
pbnst,
demandCompList,
getpbnstInsertIndex,
appendRuseFclt,
getDemandCompList,
regDemandCompany,
} = useWrStore((state) => state);
@@ -65,7 +63,6 @@ export function PbnstBuseForm({
control: form.control,
name: `items.${indexMng}.fcBizs`,
});
const [bizCycle, setBizCycle] = useState("1");
const [ppiSelectList, setPpiSelectList] =
useState<[{ name: string; val: SelectDataType[] }]>();
@@ -499,7 +496,7 @@ export function PbnstBuseForm({
) || []
).map((field, index) => (
<div
key={`fcDemands-${indexMng}-${indexBiz}`} // 이게 핵심!
key={`fcDemands-${indexMng}-${indexBiz}=${index}`} // 이게 핵심!
className="grid grid-cols-12 gap-4 mt-3"
>
<div key={index + "keySon1"} className="col-span-4">
@@ -664,6 +661,7 @@ export function PbnstBuseForm({
)}
/>
</div>
<br></br>
</div>
))}
</div>
@@ -60,10 +60,12 @@ export default function RainRegForm({
typeof item?.grntchBdstCertYr === "string"
? item?.grntchBdstCertYr
: "", // null → ""
instlCstSprtYn:
item?.instlCstSprtYn ?? "Y", // null → "N"
// Ensure enum fields are null if empty string to trigger Zod default
rainyObj: {
...item?.rainyObj,
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn === "" ? null : item?.rainyObj?.filtrTrtmfctYn,
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ??"Y"
},
})),
};
@@ -266,7 +268,7 @@ export default function RainRegForm({
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={filtrTrtmfctYn !== "Y"}
readOnly={filtrTrtmfctYn === "Y"}
/>
</FormUi>
)}
@@ -284,7 +286,7 @@ export default function RainRegForm({
type="text"
value={field.value ?? ""}
onChange={field.onChange}
readOnly={filtrTrtmfctYn !== "Y"}
readOnly={filtrTrtmfctYn === "Y" }
/>
</FormUi>
)}
@@ -333,7 +335,7 @@ export default function RainRegForm({
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={instlCstSprtYn !== "Y"}
readOnly={instlCstSprtYn === "Y"}
/>
</FormUi>
)}