572 lines
16 KiB
TypeScript
572 lines
16 KiB
TypeScript
import ModalSimilarPage from "@/app/pages/sdmMng/sdmInfoInsert/modalSimilar/page";
|
|
import type { FormData } from "@/app/pages/sdmMng/sdmInfoInsert/page";
|
|
import { useDmStore } from "@/app/store";
|
|
import { CANDIDATE, DatePicker, FormField, FormLabel, FormUi, SelectBox, UiModal } from "@common/business_components";
|
|
import { Input } from "@common/components";
|
|
import { Button } from "@common/components/ui";
|
|
import { useSearchParams } from "next/navigation";
|
|
import { useCallback, useEffect, useState } from "react";
|
|
import { AccessibleFormField } from "./AccessibleFormField";
|
|
import type { ControllerRenderProps, UseFormReturn } from "react-hook-form";
|
|
import SearchInputText from "../common/searhDemandInput/component";
|
|
import type { DemandCompType } from "@/app/store/sdmMng";
|
|
|
|
export interface SdmInfoRegFormProps {
|
|
form: UseFormReturn<FormData>;
|
|
onCheckboxChange?: (checked: boolean) => void;
|
|
facilityName?: string;
|
|
}
|
|
|
|
type FieldComponent = (field: ControllerRenderProps<FormData, keyof FormData>) => JSX.Element;
|
|
|
|
export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfoRegFormProps) {
|
|
const { initializeCommonData, Sdm } = useDmStore((state) => state);
|
|
const { useTypesData } = Sdm;
|
|
const searchParams = useSearchParams();
|
|
|
|
const [sdmNmValue, setSdmNmValue] = useState<string>(searchParams.get('dmdCoNm') || '');
|
|
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
|
|
const [isSimilarCase, setIsSimilarCase] = useState(false);
|
|
const [key, setKey] = useState(0);
|
|
|
|
//모달 조회에 필요한 데이터
|
|
const [sply, setSply] = useState<number>(0);
|
|
const [usageCd, setUsageCd] = useState<string>('청소');
|
|
const [money, setMoney] = useState<number>(0);
|
|
|
|
useEffect(() => {
|
|
initializeCommonData();
|
|
}, [initializeCommonData]);
|
|
|
|
useEffect(() => {
|
|
if (useTypesData && useTypesData.length > 0) {
|
|
setTimeout(() => {
|
|
form.setValue('usePurpose', useTypesData[0]?.val?.toString() || '');
|
|
}, 500);
|
|
}
|
|
}, [useTypesData, form]);
|
|
|
|
useEffect(() => {
|
|
if (facilityName) {
|
|
setSdmNmValue(facilityName);
|
|
form.setValue('sdmNm', facilityName);
|
|
setKey(prev => prev + 1);
|
|
}
|
|
}, [facilityName, form]);
|
|
|
|
const searchCandidate = (e: React.MouseEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
const searchSimilarCase = (e: React.MouseEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
setIsSimilarCase(true);
|
|
}
|
|
|
|
const handleCheckboxChange = (checked: boolean) => {
|
|
setIsBznmTotNoDisabled(checked);
|
|
onCheckboxChange?.(checked);
|
|
};
|
|
|
|
// 시설 선택시 이벤트
|
|
const selectComp = useCallback((rtnData: DemandCompType[]) => {
|
|
const rtnCompData = rtnData?.[0];
|
|
form.setValue('sdmNm', rtnCompData?.dmdCoNm || '');
|
|
}, [form]);
|
|
|
|
const formFields: Array<{
|
|
name: keyof FormData;
|
|
label: string;
|
|
component: FieldComponent | undefined;
|
|
formIndex: number;
|
|
required?: boolean;
|
|
}> = [
|
|
{
|
|
name: "sdmNm",
|
|
label: "수요처선택",
|
|
formIndex: 0,
|
|
required: true,
|
|
component: (field) => (
|
|
<div key={key}>
|
|
<SearchInputText
|
|
label="수요처명"
|
|
setValue={(val) => {
|
|
setSdmNmValue(val || '');
|
|
field.onChange(val || '');
|
|
}}
|
|
setRtnData={selectComp}
|
|
initValue={facilityName || sdmNmValue}
|
|
{...field}
|
|
/>
|
|
</div>
|
|
)
|
|
},
|
|
{
|
|
name: "demandYmd",
|
|
label: "요구시기",
|
|
formIndex: 0,
|
|
required: true,
|
|
component: (field) => (
|
|
<div className="w-full">
|
|
<DatePicker
|
|
mode="single"
|
|
selected={field.value as Date}
|
|
onSelect={(date) => {
|
|
field.onChange(date as Date);
|
|
}}
|
|
className="w-full"
|
|
defaultMonth={field.value as Date}
|
|
field={{
|
|
value: field.value as Date,
|
|
onChange: (date: Date | undefined) => {
|
|
field.onChange(date as Date);
|
|
}
|
|
}}
|
|
selectClass={undefined}
|
|
/>
|
|
</div>
|
|
)
|
|
},
|
|
{
|
|
name: "demandQnty",
|
|
label: "요구수량(㎥/d)",
|
|
formIndex: 0,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="요구수량(㎥/d)을 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={(e) => {
|
|
field.onChange(e);
|
|
setSply(Number(e.target.value));
|
|
}}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "usePurpose",
|
|
label: "사용용도",
|
|
formIndex: 0,
|
|
required: true,
|
|
component: (field) => (
|
|
<SelectBox
|
|
selectClass={undefined}
|
|
label=""
|
|
selectArray={useTypesData}
|
|
onSelectValue={(val) => {
|
|
field.onChange(val.toString());
|
|
setUsageCd(val.toString());
|
|
}}
|
|
className=""
|
|
value={field.value as string}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "money",
|
|
label: "희망단가(원/m3)",
|
|
formIndex: 0,
|
|
required: true,
|
|
component: (field) => (
|
|
<AccessibleFormField
|
|
field={field}
|
|
label="희망단가(원/㎥)"
|
|
required={true}
|
|
error={form.formState.errors.money}
|
|
inputComponent={
|
|
<FormUi
|
|
onCheckboxChange={handleCheckboxChange}
|
|
isDisabled={isBznmTotNoDisabled}
|
|
>
|
|
<Input
|
|
placeholder="희망단가(원/㎥)을 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={(e) => {
|
|
field.onChange(e);
|
|
setMoney(Number(e.target.value));
|
|
}}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
</FormUi>
|
|
}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "reqWaterQlty",
|
|
label: "요구수질",
|
|
formIndex: 0,
|
|
required: true,
|
|
component: undefined
|
|
},
|
|
{
|
|
name: "grssClfg",
|
|
label: "총대장균군수(개/100ml)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="총대장균군수를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "tn",
|
|
label: "총질소(T-N)(mg/L)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="총질소를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "combResdch",
|
|
label: "결합잔류염소(mg/L)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="결합잔류염소를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "tph",
|
|
label: "총인(T-P)(mg/L)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="총인을 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "trbt",
|
|
label: "탁도(NTU)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="탁도를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "ph",
|
|
label: "수소이온농도(pH)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="수소이온농도를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "bod",
|
|
label: "생물학적 산소요구량(BOD)(mg/L)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="생물학적 산소요구량을 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "clIonQnt",
|
|
label: "염화물(mgCL/L)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="염화물을 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "smll",
|
|
label: "냄새",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="냄새를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "cdtnv",
|
|
label: "전기전도도(㎲/cm)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="전기전도도를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "crmty",
|
|
label: "색도(도)",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="색도를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "rmrk",
|
|
label: "비고",
|
|
formIndex: 1,
|
|
required: true,
|
|
component: (field) => (
|
|
<Input
|
|
placeholder="비고를 입력하세요"
|
|
type="text"
|
|
className="!text-xl text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
name: "candidateTitle",
|
|
label: CANDIDATE || "공급처 후보지 선택(필수아님)",
|
|
formIndex: 2,
|
|
component: (field) => (
|
|
<div>
|
|
<div className="-mt-14 float-right flex gap-10">
|
|
<Button className={'bg-gray-200'} onClick={searchCandidate}>
|
|
후보지 조회
|
|
</Button>
|
|
<Button className={'bg-gray-200'} onClick={searchSimilarCase}>
|
|
유사사례
|
|
</Button>
|
|
</div>
|
|
<div className="flex justify-center gap-10 mt-5">
|
|
<Input
|
|
placeholder="후보지1"
|
|
type="text"
|
|
className="!text-xl w-[130px] text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
<Input
|
|
placeholder="후보지2"
|
|
type="text"
|
|
className="!text-xl w-[130px] text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
<Input
|
|
placeholder="후보지3"
|
|
type="text"
|
|
className="!text-xl w-[130px] text-gray-600"
|
|
value={field.value as string}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
name={field.name}
|
|
ref={field.ref}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)
|
|
},
|
|
];
|
|
|
|
const normalFields = formFields.filter(f => f.formIndex === 0 && f.component);
|
|
const groupFields = formFields.filter(f => f.formIndex === 1 && f.component);
|
|
const candidateFields = formFields.filter(f => f.formIndex === 2 && f.component);
|
|
|
|
return (
|
|
<>
|
|
{normalFields.map(({ name, label, component, required }) => (
|
|
component ? (
|
|
<FormField
|
|
key={name}
|
|
control={form.control}
|
|
name={name}
|
|
render={({ field }) => (
|
|
name === 'money' ? component(field) : (
|
|
// <FormUi label={label}>
|
|
// {component(field)}
|
|
// </FormUi>
|
|
<AccessibleFormField
|
|
field={field}
|
|
label={label}
|
|
required={required}
|
|
error={form.formState.errors[name]}
|
|
inputComponent={component(field)}
|
|
/>
|
|
)
|
|
)}
|
|
/>
|
|
) : null
|
|
))}
|
|
|
|
{groupFields.length > 0 && (
|
|
<div className="mt-10">
|
|
<FormLabel className="text-xl">요구수질</FormLabel>
|
|
<div className="flex flex-wrap justify-start gap-10 mt-3 mb-3">
|
|
{groupFields.map(({ name, label, component, required }) => (
|
|
<div key={name} className="min-w-[180px]">
|
|
<FormField
|
|
control={form.control}
|
|
name={name}
|
|
render={({ field }) => (
|
|
// <FormUi label={label}>
|
|
// {component?.(field)}
|
|
// </FormUi>
|
|
<AccessibleFormField
|
|
field={field}
|
|
label={label}
|
|
required={required}
|
|
error={form.formState.errors[name]}
|
|
inputComponent={component?.(field)}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{candidateFields.map(({ name, label, component, required }, index) => (
|
|
component ? (
|
|
<FormField
|
|
key={name + index}
|
|
control={form.control}
|
|
name={name}
|
|
render={({ field }) => (
|
|
// <FormUi label={label}>
|
|
// {component(field)}
|
|
// </FormUi>
|
|
<AccessibleFormField
|
|
field={field}
|
|
label={label}
|
|
required={required}
|
|
error={form.formState.errors[name]}
|
|
inputComponent={component?.(field)}
|
|
/>
|
|
)}
|
|
/>
|
|
) : null
|
|
))}
|
|
|
|
{isSimilarCase && (
|
|
<UiModal
|
|
body={<ModalSimilarPage sply={sply} usageCd={usageCd} money={money} />}
|
|
bodyClass="sm:max-w-[100vw] w-[1400px] h-[900px]"
|
|
open={isSimilarCase}
|
|
onOpenChange={(open) => !open && setIsSimilarCase(false)}
|
|
noHeaderYn="Y"
|
|
noFooterYn="Y"
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
} |