From aedb173ba7d27c31ad73d28d35b2761cf7976941 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Mon, 2 Jun 2025 11:15:19 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EC=88=98=EC=9A=94=EC=B2=98=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B3=B5=ED=86=B5=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EB=B9=BC=EB=8A=94=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ui/form_ui/index.tsx | 10 ++- .../business_components/src/ui/index.ts | 2 +- .../src/ui/sdmSearchForm/index.tsx | 85 +++++++++++++++++++ 3 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 packages/common/business_components/src/ui/sdmSearchForm/index.tsx diff --git a/packages/common/business_components/src/ui/form_ui/index.tsx b/packages/common/business_components/src/ui/form_ui/index.tsx index b834d5515..de4b37f61 100644 --- a/packages/common/business_components/src/ui/form_ui/index.tsx +++ b/packages/common/business_components/src/ui/form_ui/index.tsx @@ -1,5 +1,5 @@ import { Checkbox } from "@common/components/ui"; -import React, { useCallback, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { FormControl, FormItem, FormLabel, FormMessage } from "../form"; export const BZNM_TOT_NO = '종사업자등록번호'; @@ -17,7 +17,11 @@ interface FormElementProps extends React.HTMLAttributes { const FormUi = React.forwardRef( ({ children, label, onCheckboxChange, isDisabled }, ref) => { - const [isChecked, setIsChecked] = useState(false); + const [isChecked, setIsChecked] = useState(isDisabled); + + useEffect(() => { + setIsChecked(isDisabled); + }, [isDisabled]); const handleCheckboxChange = useCallback((checked: boolean) => { setIsChecked(checked); @@ -50,7 +54,7 @@ const FormUi = React.forwardRef( {React.isValidElement(children) && isDisabled ? React.cloneElement(children, { - disabled: true, + disabled: isDisabled, ...(children.props as FormElementProps) }) : children} diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index 90bf029c0..606852d1e 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -19,4 +19,4 @@ export * from "./tab"; export * from "./table"; export * from "./table_div"; export * from "./title"; - +export * from "./sdmSearchForm"; \ No newline at end of file diff --git a/packages/common/business_components/src/ui/sdmSearchForm/index.tsx b/packages/common/business_components/src/ui/sdmSearchForm/index.tsx new file mode 100644 index 000000000..89edc233c --- /dev/null +++ b/packages/common/business_components/src/ui/sdmSearchForm/index.tsx @@ -0,0 +1,85 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; + +type thisProps = { + label: string | undefined; + initValue: string | undefined; + setRtnData : (rtnData: any[]) => void; +} + +export default function SdmSearchForm({label=undefined, initValue=undefined, setRtnData=()=>{}} :thisProps) { + + /* const { getDemandCompList, Sdm } = useDmStore((state) => state); + + const { + demandCompList + } = Sdm; */ + + const [isOpen, setIsOpen] = useState(false); + const [textValue, setTextValue] = useState(initValue || ''); + const wrapperRef = useRef(null); + const handleInputChange = useCallback((e: React.ChangeEvent) => { + const value = e.target.value; + setTextValue(value); + if (value) { + setIsOpen(true); + } else { + setIsOpen(false); + } + }, []); + + /* const handleSuggestionClick = useCallback((dmdCoNm: string) => { + setTextValue(dmdCoNm); + }, []); */ + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + + return ( +
+ setIsOpen(true)} */ + className="w-full h-[3.2rem] !text-xl pl-3 text-gray-600 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" + placeholder={`${label}을(를) 입력하세요`} + /> + {isOpen && ( +
+
+ {/* {demandCompList && demandCompList.length > 0 ? demandCompList.map((item : DemandCompType, index : number) => ( +
handleSuggestionClick(item.dmdCoNm)} + role="button" + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + handleSuggestionClick(item.dmdCoNm); + } + }} + > + {item.dmdInfoPk.substring(0,10)} {item.dmdCoNm} +
+ )) : ( */} +
+ 검색 결과가 없습니다. +
+ {/* )) : ( */} +
+
+ )} +
+ ) +} \ No newline at end of file From 1eef53fe7dcd6605137b2db80f738df4bf586c72 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Mon, 2 Jun 2025 11:16:48 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=EC=88=98=EC=9A=94=EC=B2=98=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B3=B5=ED=86=B5=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EB=B9=BC=EB=8A=94=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/business_components/src/ui/sdmSearchForm/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/business_components/src/ui/sdmSearchForm/index.tsx b/packages/common/business_components/src/ui/sdmSearchForm/index.tsx index 89edc233c..a724d1d97 100644 --- a/packages/common/business_components/src/ui/sdmSearchForm/index.tsx +++ b/packages/common/business_components/src/ui/sdmSearchForm/index.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; -type thisProps = { +export type thisProps = { label: string | undefined; initValue: string | undefined; setRtnData : (rtnData: any[]) => void; From feb5711ad438c3640d9e6ab6bccfc393778f2613 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Mon, 2 Jun 2025 11:25:31 +0900 Subject: [PATCH 3/6] =?UTF-8?q?export=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/business_components/src/ui/sdmSearchForm/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/business_components/src/ui/sdmSearchForm/index.tsx b/packages/common/business_components/src/ui/sdmSearchForm/index.tsx index a724d1d97..62009826e 100644 --- a/packages/common/business_components/src/ui/sdmSearchForm/index.tsx +++ b/packages/common/business_components/src/ui/sdmSearchForm/index.tsx @@ -6,7 +6,7 @@ export type thisProps = { setRtnData : (rtnData: any[]) => void; } -export default function SdmSearchForm({label=undefined, initValue=undefined, setRtnData=()=>{}} :thisProps) { +export const SdmSearchForm = ({label=undefined, initValue=undefined, setRtnData=()=>{}} :thisProps) => { /* const { getDemandCompList, Sdm } = useDmStore((state) => state); From b96207cced396af35ee526e0883c1f2a0b2b16ab Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Tue, 3 Jun 2025 17:01:43 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=EC=88=98=EC=9A=94=EC=B2=98=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EA=B3=B5=ED=86=B5=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=A7=8C=EB=93=9C=EB=8A=94=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business_components/src/ui/index.ts | 2 +- .../src/ui/sdmInsertForm/form.tsx | 246 ++++++++++++++++++ .../src/ui/sdmInsertForm/index.tsx | 164 ++++++++++++ .../sdmNameBox.tsx} | 46 ++-- 4 files changed, 439 insertions(+), 19 deletions(-) create mode 100644 packages/common/business_components/src/ui/sdmInsertForm/form.tsx create mode 100644 packages/common/business_components/src/ui/sdmInsertForm/index.tsx rename packages/common/business_components/src/ui/{sdmSearchForm/index.tsx => sdmInsertForm/sdmNameBox.tsx} (68%) diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index 606852d1e..0986f7953 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -19,4 +19,4 @@ export * from "./tab"; export * from "./table"; export * from "./table_div"; export * from "./title"; -export * from "./sdmSearchForm"; \ No newline at end of file +export * from "./sdmInsertForm/sdmNameBox"; \ No newline at end of file diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx new file mode 100644 index 000000000..6d3219468 --- /dev/null +++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx @@ -0,0 +1,246 @@ +import { FormField } from "../form"; +import { SelectBox } from "../select"; +import { Input } from "@common/components"; +import { FormUi } from "../form_ui"; +import { useCallback, useState } from "react"; +import type { ControllerRenderProps, UseFormReturn } from "react-hook-form"; +import { SdmSearchForm } from "./sdmNameBox"; +import type { DemandCompType } from "../../../../../../apps/dm/app/store/sdmMng"; + +type SelectDataType = { + text: string; + val: string; +}; + +interface FormSchema { + ctpvCd: string; + sggCd: string; + dmdCoNm: string; + dmdInfoPk: string; + daddr: string; + telno: string; + bznmTotNo?: string; + rgtr?: string; +} + +interface SdmRegFormProps { + form: UseFormReturn; + onCheckboxChange?: (checked: boolean) => void; + selectSidoData: SelectDataType[]; + selectSigunData: SelectDataType[]; + dataList: DemandCompType[]; + rtnValue: (searchText: string, pageCnt: number) => void; + setIsDuplicate: (value: boolean) => void; +} + +type FieldComponent = (field: ControllerRenderProps) => JSX.Element; + +export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigunData, dataList, rtnValue, setIsDuplicate }: SdmRegFormProps) { + const [sidoValue, setSidoValue] = useState(''); + const [sigunValue, setSigunValue] = useState(''); + const [filteredSigunData, setFilteredSigunData] = useState([{ text: "전체", val: '0' }]); + const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(true); + + const initializeSigunData = useCallback((sidoCd: string) => { + if (sidoCd === '0') { + setSigunValue('0'); + setFilteredSigunData([{ text: "전체", val: '0' }]); + } else { + const newFilteredData = [ + { text: "전체", val: '0' }, + ...selectSigunData.filter((item: SelectDataType) => item.val.substring(0, 2) === sidoCd) + ]; + setSigunValue('0'); + setFilteredSigunData(newFilteredData); + } + }, [selectSigunData]); + + const onSelectValue = useCallback(( + val: string, + type: string, + field: ControllerRenderProps | undefined + ) => { + switch (type) { + case "ctpvCd": + initializeSigunData(val); + setSidoValue(val); + field?.onChange(val); + form.setValue('dmdInfoPk', ''); + form.setValue('bznmTotNo', ''); + break; + case "sggCd": + setSigunValue(val); + field?.onChange(val); + form.setValue('dmdInfoPk', ''); + form.setValue('bznmTotNo', ''); + break; + } + }, [initializeSigunData, form]); + + const handleCheckboxChange = useCallback((checked: boolean) => { + setIsBznmTotNoDisabled(checked); + onCheckboxChange?.(checked); + }, [onCheckboxChange]); + + const setRtnValue = useCallback((searchText: string, pageCnt: number) => { + rtnValue(searchText, pageCnt); + }, [rtnValue]); + + const setRtnData = useCallback((item: DemandCompType) => { + const rtnCompData = item; + form.setValue('dmdCoNm', rtnCompData?.dmdCoNm || ''); + form.setValue('dmdInfoPk', rtnCompData?.dmdInfoPk.substring(0,10) || ''); + form.setValue('bznmTotNo', rtnCompData?.dmdInfoPk.substring(10,14)==='0000' ? '' : rtnCompData?.dmdInfoPk.substring(10,14)); + + const sidoCd = rtnCompData?.ctpvCd.trim() || ''; + setSidoValue(sidoCd); + form.setValue('ctpvCd', sidoCd); + initializeSigunData(sidoCd); + + setTimeout(() => { + const sigunCd = rtnCompData?.sggCd.trim() || ''; + setSigunValue(sigunCd); + form.setValue('sggCd', sigunCd); + }, 100); + + if(rtnCompData?.dmdInfoPk.substring(10,14) === '0000') { + handleCheckboxChange(true); + } else { + handleCheckboxChange(false); + } + + form.setValue('daddr', rtnCompData?.daddr || ''); + form.setValue('telno', rtnCompData?.telno || ''); + + // 선택을 했을 때 중복 상태를 true로 설정 + setIsDuplicate(true); + }, [form, handleCheckboxChange, initializeSigunData, setIsDuplicate]); + + const setRtnText = useCallback((text: string) => { + form.setValue('dmdCoNm', text); + }, [form]); + + const formFields: Array<{ + name: keyof FormSchema; + label: string; + component: FieldComponent; + }> = [ + { + name: "ctpvCd", + label: "시도", + component: (field) => ( + onSelectValue(val.toString(), 'ctpvCd', field)} + className="" + value={sidoValue} + /> + ) + }, + { + name: "sggCd", + label: "시군구", + component: (field) => ( + onSelectValue(val.toString(), 'sggCd', field)} + className="" + value={sigunValue} + /> + ) + }, + { + name: "dmdCoNm", + label: "회사명", + component: (field) => ( + + ) + }, + { + name: "dmdInfoPk", + label: "사업자등록번호", + component: (field) => ( + + ) + }, + { + name: "bznmTotNo", + label: "종사업자등록번호", + component: (field) => ( + + + + ) + }, + { + name: "daddr", + label: "사업자주소", + component: (field) => ( + + ) + }, + { + name: "telno", + label: "전화번호", + component: (field) => ( + + ) + } + ]; + + return ( + <> + {formFields.map(({ name, label, component }) => ( + ( + name === 'bznmTotNo' ? component(field) : ( + + {component(field)} + + ) + )} + /> + ))} + + ); +} \ No newline at end of file diff --git a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx new file mode 100644 index 000000000..4a972180a --- /dev/null +++ b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx @@ -0,0 +1,164 @@ +"use client"; + +/* import { useDmStore } from "@/app/store"; */ +import { SdmRegForm } from "./form"; +import type { DemandCompType } from "../../../../../../apps/dm/app/store/sdmMng"; +import { Button } from "@common/components/ui"; +import { zodResolver } from "@hookform/resolvers/zod"; +/* import { useRouter } from "next/navigation"; */ +import { useCallback, useEffect, useState } from "react"; +import { FormProvider, useForm, type SubmitHandler } from "react-hook-form"; +import { toast, Toaster } from "sonner"; +/* import { Toaster, toast } from "react-hot-toast"; */ +import * as z from "zod"; +import type { SelectDataType } from "../search_input_select"; + +type thisProps = { + selectSidoData: SelectDataType[]; + selectSigunData: SelectDataType[]; + dataList: DemandCompType[]; + rtnValue: (searchText: string, pageCnt: number) => void; + rtnInputData: (data: DemandCompType) => void; +} + +const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean) => z.object({ + ctpvCd: z.string().min(1, "시/도를 선택해주세요"), + sggCd: z.string().min(1, "시/군/구를 선택해주세요"), + dmdCoNm: z.string() + .min(1, "회사명을 입력해주세요") + .max(20, "회사명은 20자 이내로 입력해주세요"), + dmdInfoPk: z.string() + .min(1, "사업자등록번호를 입력해주세요") + .regex(/^\d{10}$/, "사업자등록번호는 10자리 숫자만 입력 가능합니다") + .refine(() => !isDuplicate, "이미 등록된 사업자등록번호입니다"), + bznmTotNo: isBznmTotNoDisabled + ? z.string().optional() + : z.string() + .length(4, "종사업자등록번호는 4자리 숫자만 입력 가능합니다"), + daddr: z.string() + .min(1, "주소를 입력해주세요") + .min(6, "주소는 6자 이상 입력해주세요") + .max(40, "주소는 40자 이내로 입력해주세요"), + telno: z.string() + .min(8, "전화번호는 8자 이상 입력해주세요") + .max(12, "전화번호는 12자 이내로 입력해주세요") + .regex(/^[0-9-]+$/, "전화번호는 숫자와 하이픈(-)만 입력 가능합니다"), + rgtr: z.string().optional(), +}); + +type FormSchema = ReturnType; +export type FormData = z.infer; + +const defaultValues: FormData = { + ctpvCd: '', + sggCd: '', + dmdCoNm: '', + dmdInfoPk: '', + bznmTotNo: '', + daddr: '', + telno: '', + rgtr: "3fa85f64-5717-4562-b3fc-2c963f66afa6", +}; + +export default function SdmInsertForm({selectSidoData, selectSigunData, dataList, rtnValue, rtnInputData}: thisProps) { + /* const { insertSdmData } = useDmStore((state) => state); + const router = useRouter(); */ + + const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(true); + const [isDuplicate, setIsDuplicate] = useState(false); + const formSchema = createFormSchema(isBznmTotNoDisabled, isDuplicate); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues, + mode: "onChange", + criteriaMode: "all", + shouldFocusError: false, + shouldUnregister: false + }); + + // 체크박스 상태가 변경될 때마다 bznmTotNo 필드의 에러를 초기화 + useEffect(() => { + if (isBznmTotNoDisabled) { + form.clearErrors('bznmTotNo'); + form.setValue('bznmTotNo', ''); + } + }, [isBznmTotNoDisabled, form]); + + const setRtnValue = useCallback((searchText: string, pageCnt: number) => { + rtnValue(searchText, pageCnt); + }, [rtnValue]); + + const onSubmit: SubmitHandler> = async (data) => { + try { + // form 에러 체크 + const formErrors = form.formState.errors; + if (Object.keys(formErrors).length > 0) { + const errorMessage = Object.values(formErrors)[0]?.message || '입력값을 확인해주세요.'; + toast.error(errorMessage); + return; + } + + const dmdInfoPk = data.dmdInfoPk + (data.bznmTotNo || '0000'); + const formData = { + ...data, + dmdInfoPk, + }; + + console.log(formData); + /* await insertSdmData(formData); */ + rtnInputData(formData as DemandCompType); + + const queryParams = new URLSearchParams({ + dmdCoNm: data.dmdCoNm, + ctpvCd: data.ctpvCd, + sggCd: data.sggCd, + dmdInfoPk, + bznmTotNo: data.bznmTotNo || '', + daddr: data.daddr, + telno: data.telno, + }); + + //router.push(`/pages/sdmMng/sdmInfoInsert?${queryParams.toString()}`); + toast.success('수요처가 성공적으로 등록되었습니다.'); + } catch (error) { + console.error('Error submitting form:', error); + toast.error('수요처 등록에 실패했습니다.'); + } + }; + + return ( + <> +
+

+ 수요처등록 +

+
+ +
+ +
+ +
+ +
+ +
+
+ + + ); +} \ No newline at end of file diff --git a/packages/common/business_components/src/ui/sdmSearchForm/index.tsx b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx similarity index 68% rename from packages/common/business_components/src/ui/sdmSearchForm/index.tsx rename to packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx index 62009826e..18d048692 100644 --- a/packages/common/business_components/src/ui/sdmSearchForm/index.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx @@ -1,18 +1,24 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; +import type { DemandCompType } from "../../../../../../apps/dm/app/store/sdmMng"; export type thisProps = { label: string | undefined; initValue: string | undefined; - setRtnData : (rtnData: any[]) => void; + dataList : DemandCompType[]; + rtnValue : (searchText: string, pageCnt: number) => void; + rtnData : (item: DemandCompType) => void; + rtnText : (text: string) => void; } -export const SdmSearchForm = ({label=undefined, initValue=undefined, setRtnData=()=>{}} :thisProps) => { - - /* const { getDemandCompList, Sdm } = useDmStore((state) => state); - - const { - demandCompList - } = Sdm; */ +/** + * 수요처 검색 컴포넌트 + * @param label 라벨 + * @param initValue 초기값 + * @param rtnValue 검색 결과 반환 함수 + * @param dataList 검색할 때 넘기는 데이터 리스트 + * @param rtnData 검색 결과 반환 함수 + */ +export const SdmSearchForm = ({label=undefined, initValue=undefined, rtnValue=()=>{}, dataList=[], rtnData=()=>{}, rtnText=()=>{} } :thisProps) => { const [isOpen, setIsOpen] = useState(false); const [textValue, setTextValue] = useState(initValue || ''); @@ -20,16 +26,20 @@ export const SdmSearchForm = ({label=undefined, initValue=undefined, setRtnData= const handleInputChange = useCallback((e: React.ChangeEvent) => { const value = e.target.value; setTextValue(value); + rtnValue(value, 10); + rtnText(value); if (value) { setIsOpen(true); } else { setIsOpen(false); } - }, []); + }, [rtnValue, rtnText]); - /* const handleSuggestionClick = useCallback((dmdCoNm: string) => { - setTextValue(dmdCoNm); - }, []); */ + const handleSuggestionClick = useCallback((item: DemandCompType) => { + setTextValue(item.dmdCoNm); + rtnData(item); + setIsOpen(false); + }, [rtnData]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -43,7 +53,7 @@ export const SdmSearchForm = ({label=undefined, initValue=undefined, setRtnData= document.removeEventListener('mousedown', handleClickOutside); }; }, []); - + return (
- {/* {demandCompList && demandCompList.length > 0 ? demandCompList.map((item : DemandCompType, index : number) => ( + {dataList && dataList.length > 0 ? dataList.map((item : DemandCompType, index : number) => (
handleSuggestionClick(item.dmdCoNm)} + onClick={() => handleSuggestionClick(item)} role="button" tabIndex={0} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { - handleSuggestionClick(item.dmdCoNm); + handleSuggestionClick(item); } }} > {item.dmdInfoPk.substring(0,10)} {item.dmdCoNm}
- )) : ( */} + )) : (
검색 결과가 없습니다.
- {/* )) : ( */} + )}
)} From 40f26c77673f68933c33da2124c885affb6e0dd6 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Wed, 4 Jun 2025 11:05:02 +0900 Subject: [PATCH 5/6] =?UTF-8?q?-=EC=88=98=EC=9A=94=EC=B2=98=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=9E=85=EB=A0=A5=ED=8F=BC=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EC=A7=84=ED=96=89=EC=A4=91(=ED=8C=A8=EC=8A=A4=EC=9B=8C?= =?UTF-8?q?=EB=93=9C=EB=A7=8C=20=EB=82=A8=EC=9D=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ui/sdmInsertForm/form.tsx | 43 ++++++++++++++++++- .../src/ui/sdmInsertForm/index.tsx | 20 ++++++++- .../src/ui/sdmInsertForm/sdmNameBox.tsx | 12 +++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx index 6d3219468..d59108c5b 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx @@ -21,6 +21,7 @@ interface FormSchema { telno: string; bznmTotNo?: string; rgtr?: string; + dmdAplyPswd?: string; } interface SdmRegFormProps { @@ -40,7 +41,8 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun const [sigunValue, setSigunValue] = useState(''); const [filteredSigunData, setFilteredSigunData] = useState([{ text: "전체", val: '0' }]); const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(true); - + const [orgBznmNo, setOrgBznmNo] = useState(''); + const initializeSigunData = useCallback((sidoCd: string) => { if (sidoCd === '0') { setSigunValue('0'); @@ -92,6 +94,8 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun form.setValue('dmdInfoPk', rtnCompData?.dmdInfoPk.substring(0,10) || ''); form.setValue('bznmTotNo', rtnCompData?.dmdInfoPk.substring(10,14)==='0000' ? '' : rtnCompData?.dmdInfoPk.substring(10,14)); + // 수요처 불러온 후 사업자번호를 바꿀경우를 대비함 + setOrgBznmNo(rtnCompData?.dmdInfoPk); const sidoCd = rtnCompData?.ctpvCd.trim() || ''; setSidoValue(sidoCd); form.setValue('ctpvCd', sidoCd); @@ -120,6 +124,29 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun form.setValue('dmdCoNm', text); }, [form]); + const bznNoChange = useCallback((e: React.ChangeEvent, noType: string) => { + const value = e.target.value; + console.log('form value : '+form.getValues('dmdInfoPk')); + console.log('org value : '+orgBznmNo); + + if(noType === 'dmdInfoPk') { + if(orgBznmNo.substring(0,10) === value) { + setIsDuplicate(true); + } else { + setIsDuplicate(false); + } + form.setValue('dmdInfoPk', value); + } else { + if(orgBznmNo.substring(10,14) === value) { + setIsDuplicate(true); + } else { + setIsDuplicate(false); + } + form.setValue('bznmTotNo', value); + } + + }, [form, orgBznmNo, setIsDuplicate]); + const formFields: Array<{ name: keyof FormSchema; label: string; @@ -177,6 +204,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun type="text" className="!text-xl text-gray-600" {...field} + onChange={(e) => bznNoChange(e, 'dmdInfoPk')} /> ) }, @@ -195,6 +223,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun className="!mt-5 !text-xl text-gray-600" disabled={isBznmTotNoDisabled} {...field} + onChange={(e) => bznNoChange(e, 'bznmTotNo')} /> ) @@ -222,6 +251,18 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun {...field} /> ) + }, + { + name: "dmdAplyPswd", + label: "패스워드", + component: (field) => ( + + ) } ]; diff --git a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx index 4a972180a..c79712c58 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx @@ -30,11 +30,12 @@ const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean) => dmdInfoPk: z.string() .min(1, "사업자등록번호를 입력해주세요") .regex(/^\d{10}$/, "사업자등록번호는 10자리 숫자만 입력 가능합니다") - .refine(() => !isDuplicate, "이미 등록된 사업자등록번호입니다"), + .refine(() => isBznmTotNoDisabled ? !isDuplicate : true, "이미 등록된 사업자등록번호입니다"), bznmTotNo: isBznmTotNoDisabled ? z.string().optional() : z.string() - .length(4, "종사업자등록번호는 4자리 숫자만 입력 가능합니다"), + .length(4, "종사업자등록번호는 4자리 숫자만 입력 가능합니다") + .refine(() => !isDuplicate, "이미 등록된 사업자등록번호입니다"), daddr: z.string() .min(1, "주소를 입력해주세요") .min(6, "주소는 6자 이상 입력해주세요") @@ -44,6 +45,10 @@ const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean) => .max(12, "전화번호는 12자 이내로 입력해주세요") .regex(/^[0-9-]+$/, "전화번호는 숫자와 하이픈(-)만 입력 가능합니다"), rgtr: z.string().optional(), + dmdAplyPswd : z.string() + .min(1, "패스워드를 입력해주세요") + .min(8, "패스워드는 8자 이상 입력해주세요") + .max(16, "패스워드는 16자 이내로 입력해주세요"), }); type FormSchema = ReturnType; @@ -58,8 +63,19 @@ const defaultValues: FormData = { daddr: '', telno: '', rgtr: "3fa85f64-5717-4562-b3fc-2c963f66afa6", + dmdAplyPswd : '', }; +/** + * 수요처 등록 폼 + * @param selectSidoData 시/도 데이터 + * @param selectSigunData 시/군/구 데이터 + * @param dataList 수요처 목록 + * @param rtnValue 검색 결과(텍스트) 콜백 + * @param rtnInputData 수요처 리스트 콜백 + * @returns + */ + export default function SdmInsertForm({selectSidoData, selectSigunData, dataList, rtnValue, rtnInputData}: thisProps) { /* const { insertSdmData } = useDmStore((state) => state); const router = useRouter(); */ diff --git a/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx index 18d048692..83571b6ff 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx @@ -80,7 +80,17 @@ export const SdmSearchForm = ({label=undefined, initValue=undefined, rtnValue=() } }} > - {item.dmdInfoPk.substring(0,10)} {item.dmdCoNm} + {item.dmdInfoPk.substring(10,14) !== '0000' ? ( + <> + 사업자번호 : {item.dmdInfoPk.substring(0,10)}  + 종사업자번호 : {item.dmdInfoPk.substring(10,14)}  + + ) : ( + <> + 사업자번호 : {item.dmdInfoPk.substring(0,10)}  + + )} + {item.dmdCoNm} )) : (
From 2c773de04f5a4f6a964e3961fe59db5bca7cd110 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Wed, 4 Jun 2025 11:08:00 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=EC=9C=BC=EB=A1=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ui/sdmInsertForm/index.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx index c79712c58..723d87cf6 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx @@ -76,6 +76,32 @@ const defaultValues: FormData = { * @returns */ +/** + * 페이지에서 작업 + const {Common, initializeCommonData, getDemandCompList, insertSdmData, Sdm} = useDmStore((state) => state); + const { selectSidoData, selectSigunData } = Common; + const { demandCompList } = Sdm; + + // 공통데이터 (시도, 시군구 데이터 호출) + useEffect(() => { + initializeCommonData(); + }, [initializeCommonData]); + + // 컴포넌트에서 텍스트 검색 호출 + const callback = useCallback((searchText: string, pageCnt: number) => { + searchText = searchText.trim(); + if(searchText.length > 0) { + getDemandCompList(searchText, pageCnt); + } + }, [getDemandCompList]); + + // 컴포넌트에서 수요처 등록 호출 + const handleInsertSdmData = useCallback((data: DemandCompType) => { + insertSdmData(data); + + }, [insertSdmData]); + */ + export default function SdmInsertForm({selectSidoData, selectSigunData, dataList, rtnValue, rtnInputData}: thisProps) { /* const { insertSdmData } = useDmStore((state) => state); const router = useRouter(); */