diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx index 47c09d40c..789b74ab9 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx @@ -1,72 +1,94 @@ -'use client' +"use client"; import { useWrStore } from "@/app/store"; -import type { bdstType, rainRuseBd, TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg" +import type { + RainyBuilding, + TableUpperProps, +} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { RainRegForm } from "@/components/ui/form/fcltReg/rainReg/component"; import { BdstReg } from "@/components/ui/modal/bdstReg/component"; -import { ContentsDiv, ScrollArea, SearchDiv, SearchFormLeft, SearchFormRight, SearchInput, Title, UiModal, UiTable } from "@common/business_components"; +import { + ContentsDiv, + ScrollArea, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + Title, + UiModal, + UiTable, +} from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, TableHead, TableRow } from "@common/components"; -import { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; export const headMakeColSpan = (upHeadList: TableUpperProps[]) => { - return (<> - { - upHeadList.map((head: TableUpperProps) => - (!head.upSequnce ? {head.title} : - head.upName === 'upChangeRe' && head.upSequnce === 1 ? {'중축 개축 증축 '} : null))} - - - {upHeadList.map((head: TableUpperProps) => - (head.upName === 'upChangeRe' ? {head.title} : null))} - - ) -} + return ( + <> + + {upHeadList.map((head: TableUpperProps) => + !head.upSequnce ? ( + + {head.title} + + ) : head.upName === "upChangeRe" && head.upSequnce === 1 ? ( + + {"중축 개축 증축 "} + + ) : null + )} + + + {upHeadList.map((head: TableUpperProps) => + head.upName === "upChangeRe" ? ( + {head.title} + ) : null + )} + + + ); +}; export default function Home() { - const { rain, code,init } = useWrStore((state) => { - return state + const { rain, code, init } = useWrStore((state) => { + return state; }); - const {bdstObj, rainRuseObj } =rain - const [rinBdstForm, setRinBdstForm] = useState (); - const [bdstTable, setbdstTable] = useState (); + const { rainRes } = rain; + const [rainForm, setRainForm] = useState(); + const [bdstTable, setbdstTable] = useState(); const nodeList = headMakeColSpan(rain.upHeadList); + useEffect(() => { + if (!rain.isInit) { + init(); + } + }, [rain.isInit, init]); useEffect(() => { + if (code.sggCd.length > 0) { + const table = rainRes.map((item) => { + const sggText = code.sggCd.find( + (cd) => cd.val.toString() === item.sggCd + )?.text; + const cityText = code.cityCd.find( + (cd) => cd.val.toString() === item.ctpvCd + )?.text; + return { ...item, sggText: sggText, cityText: cityText }; + }); - if (!rain.isInit) { - init(); - - } - }, [rain.isInit,init]); - - useEffect ( () => { - if(code.sggCd.length>0){ - const table= bdstObj.map((item) => { - const sggText= code.sggCd.find((cd)=>cd.val.toString() === item.sggCd )?.text; - const cityText= code.cityCd.find((cd)=>cd.val.toString() === item.ctpvCd )?.text; - return( - {...item, - sggText:sggText, - cityText:cityText - }) - }) - setbdstTable(table) + setbdstTable(table); } -}, [code,bdstObj]); + }, [code, rainRes]); const cellClick: (val: number | undefined) => void = (val) => { - - let data - if((bdstTable ?? []).length > 0) { - data =rainRuseObj.filter((item)=> item.bdstInfoFk===bdstTable?.[val]?.bdstInfoPk) - setRinBdstForm(data) - } - } - + if ((bdstTable ?? []).length > 0 && val !== undefined) { + { + setRainForm(rainRes[val]); + } + } + }; return ( <> -
-
+
+
<SearchDiv> <SearchFormLeft> @@ -74,12 +96,10 @@ export default function Home() { className="col-span-3 my-7" label="건물명" textValue={""} - setText={function (val: string): void { + setText={function (): void { throw new Error("Function not implemented."); }} /> - {/* <div className='w-4/5 grid grid-cols-12 gap-1 mx-4'> - </div> */} </SearchFormLeft> <SearchFormRight> <Button className="mr-4 rounded-lg">조회</Button> @@ -89,13 +109,12 @@ export default function Home() { body={<BdstReg></BdstReg>} bodyClass="sm:max-w-7xl" /> - {/* <Button className='mr-4 rounded-lg' onClick={()=>bdstRegModal('ㅁ',divTest())}>신규등록</Button> */} </SearchFormRight> - {/* <div className='w-1/5 flex items-center justify-end'> - </div> */} </SearchDiv> </div> - <div className="colsapn-1"> + </div> + <div className="grid grid-cols-6 gap-4 "> + <div className="col-span-4"> <ListDiv> <UiTable tableData={bdstTable || []} @@ -109,16 +128,18 @@ export default function Home() { </UiTable> </ListDiv> </div> - <div className="colsapn-1 max-h-full ovreflow-y-scroll"> + <div className="col-span-2 max-h-full ovreflow-y-scroll"> <ListDiv> <ScrollArea> <RainRegForm - data={rinBdstForm || []} + rainForm={rainForm || undefined} isModal={false} ></RainRegForm> </ScrollArea> </ListDiv> </div> + + </div> </ContentsDiv> </> diff --git a/apps/wr/app/store/common/code/index.ts b/apps/wr/app/store/common/code/index.ts index 2bc1784a3..3d1250119 100644 --- a/apps/wr/app/store/common/code/index.ts +++ b/apps/wr/app/store/common/code/index.ts @@ -1,11 +1,17 @@ import { getFectch } from "@/components/lib/api"; // Description: 공통코드 -type selectArray = { +export type selectArray = { text: string; val: string | number; }; +export const yn :selectArray[]=[ + {val:'Y', text:'Y'}, + {val:'N', text:'N'}, +] + + export const bdstUsgCd: selectArray[] = [ { val: 1, text: "운동장" }, { val: 2, text: "체육관" }, @@ -38,13 +44,23 @@ export const rainFcltCd = [ { val: "10", text: "확인불가" }, ]; +export const chBuCd = [ + { val: "1", text: "증축" }, + { val: "2", text: "개축" }, + { val: "3", text: "재축" }, +] + + + export type comCodeState = { code: { isInit: boolean; + chBuCd:selectArray[] rainFcltCd: selectArray[]; bdstUsgCd: selectArray[]; cityCd: selectArray[]; sggCd: selectArray[]; + yn:selectArray[]; }; }; @@ -82,8 +98,10 @@ export const comCodeStateExport: comCodeState = { isInit: false, rainFcltCd: rainFcltCd, bdstUsgCd: bdstUsgCd, + chBuCd:chBuCd, cityCd: [], sggCd: [], + yn:yn }, }; @@ -118,6 +136,7 @@ export const codeActionExport: (set: any) => comCodeActions = (set: any) => { }, })); }, + divCityCd: async(cd: number) => { set((state: comCodeState) => ({ code: { diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx new file mode 100644 index 000000000..ffa920f39 --- /dev/null +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx @@ -0,0 +1,79 @@ +import { getFectch } from "@/components/lib/api"; +import type { RainyBuilding } from "../rainReg"; + +type TableUpperProps = { + id: string; + title: string; + upName?: string; + upSequnce?: number; + }; + const moUpHeadList: TableUpperProps[] = [ + { id: "cityText", title: "시도" }, + { id: "sggText", title: "시군구" }, + { id: "bdstNm", title: "시설명" }, + { id: "daddr", title: "위치" }, + { id: "frstArchPrmsnDt", title: "최초건축허가일" }, + { id: "archArea", title: "건축면적", }, + { id: "archChgYn", title: "여부", upName: "upChangeRe", upSequnce: 1 }, + { id: "archChgPrmsnDt", title: "허가일", upName: "upChangeRe", upSequnce: 2 }, + { id: "archChgArea", title: "면적", upName: "upChangeRe", upSequnce: 3 }, + ]; + +const bdstBase: RainyBuilding[] = []; + + + +export type bdstFulType = bdstState & bdstActions; + + +export type bdstState = { + bdst: { + bdstBase: RainyBuilding[]; + moUpHeadList:TableUpperProps[] + }; +}; + +type bdstActions = { + findBdst: (sggCd:string, searchTxt:string) => void ; + }; + + + const findBdstInfo = async(sggCd:string, searchTxt:string)=>{ + return await getFectch('wr', `/reuseFc/building/${sggCd}`+(searchTxt?`/${searchTxt}`:'')) + + } + +export const bdstStateExport: bdstState = { + bdst: { + bdstBase: bdstBase, // Updated to match the array type + moUpHeadList:moUpHeadList, + }, +}; + +export const bdstActionsExport: (set: any) => bdstActions = ( + set: any +) => { + return { + + findBdst: async(sggCd:string, searchTxt:string) =>{ + try{ + + const bdst = await findBdstInfo(sggCd, searchTxt); + return set((state:bdstState) =>({ + ...state, + bdst:{ + ...state.bdst, + bdstBase:bdst + } + + })) + }catch(error1){ + console.log("error ", error1) + + }finally{ + + } + }, + + }; +}; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index 7624a4ee9..2e06ebe8a 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -1,46 +1,138 @@ -import { bdstUsgCd, comCodeStateExport } from "@/app/store/common/code"; -import { getFectch } from "@/components/lib/api"; +import type { selectArray } from "@/app/store/common/code"; +import { getFectch, postFectch, putFectch } from "@/components/lib/api"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; -type RainyInfoResponse = { - ctpvCd: string; - sggCd: string; + + + +export const rainZod = +{ ctpvCd: z.number(), + sggCd: z.number(), + bdstNm: z.string(), + daddr: z.string(), + frstArchPrmsnDt: z.date(), + archArea: z.number(), + bdstInfoPk: z.number().nullish() , + lawTrgtYn: z.string().nullish(), + bdstUsgCd: z.number(), + bdstRuseFcltPk: z.number().nullish(), + bdstInfoFk: z.number().nullish(), + operMngCd: z.number().nullish(), + anlOperCst: z.number().nullish(), + instlCmptnDt: z.date(), + instlCst: z.number(), + instlCstSprtYn: z.string(), + instlCstSprtAmt: z.number(), + grntchBdstCertYn: z.string(), + grntchBdstCertNo: z.string(), + grntchBdstCertGrd: z.string(), + grntchBdstCertYr: z.string(), + bdstReuseFcltFk:z.number().nullish(), + pntfColKnd: z.string(), + pntfColArea: z.number(), + dtfcltCpct:z.number().nullish(), + filtrTrtmfctCpct: z.number(), + filtrTrtmfctYn: z.string(), + filtrTrtmfctPrs: z.string(), + annRnwtQty:z.number().nullish(), + oilqMeasMthd:z.string().nullish(), + + chgBuilding: z.array( + z.object({ + archChgPrmsnDt: z.date().nullish(), + archChgArea: z.number().nullish(), + bdstChgNm: z.string().nullish(), + }) + ).default([]), // + + } + + +export const rainDefZod= { + instlCmptnDt: new Date(), + instlCst: 0, + pntfColKnd: "", + pntfColArea: 0, + filtrTrtmfctYn: "Y", + filtrTrtmfctCpct: 0, + filtrTrtmfctPrs: "", + instlCstSprtYn: "", + instlCstSprtAmt: 0, + grntchBdstCertYn: "", + grntchBdstCertYr: "", + grntchBdstCertNo: "", + grntchBdstCertGrd: "", +} + + +export const bdstDefZod={ + ctpvCd: 0, // 시도 + sggCd: 0, // 시군구 + daddr: '', // 위치 + bdstUsgCd: 0, // 건축물용도 + frstArchPrmsnDt: new Date(), // 최초건축허가일 + archArea: 0, // 건축면적 + lawTrgtYn: '', // 법적의무대상여부 + bdstNm: '', + + bdstChgnm:'', + archChgPrmsnDt: new Date(), // 건축변경 허가일시 + archChgArea: 0, // 변경 면적 +} + + +export type chgBuilding={ + bdstInfoFk: number, + archChgPrmsnDt: Date, + archChgArea: number, + bdstChgNm: string +} + + +export type RainyBuilding = { + ctpvCd: number; + sggCd: number; bdstNm: string; daddr: string; - bdstUsgCd: string; - frstArchPrmsnDt: string; + frstArchPrmsnDt: Date; archArea: string; - lawTrgtYn: string; - archChgArea: string; + archChgArea: number; bdstInfoPk: number; - reuseBuilding: Array<{ - bdstUsgCd: any; - bdstRuseFcltPk: number; - bdstInfoFk: number; - operMngCd: number | null; - anlOperCst: number | null; - instlCmptnDt: string | null; - instlCst: number | null; - archChgPrmsnDt: string | null; - instlCstSprtYn: string | null; - instlCstSprtAmt: number | null; - grntchBdstCertYn: string | null; - grntchBdstCertNo: string | null; - grntchBdstCertGrd: string | null; - grntchBdstCertYr: string | null; - rainyObj: { - bdstReuseFcltFk:number|null; - pntfColKnd: string | null; - pntfColArea: number | null; - dtfcltCpct:number|null; - filtrTrtmfctCpct: number | null; - filtrTrtmfctYn: string | null; - filtrTrtmfctPrs: number | null; - annRnwtQty:number|null; - oilqMeasMthd:string|null - } | null; - }>; + reuseBuilding: reuseBuilding[]; + chgBuilding:chgBuilding[] }; +export type reuseBuilding = { + lawTrgtYn: string|undefined; + bdstUsgCd: number|undefined; + bdstRuseFcltPk: number; + bdstInfoFk: number; + operMngCd: number; + anlOperCst: number; + instlCmptnDt: Date|undefined; + instlCst: number|undefined; + //archChgPrmsnDt: string; + instlCstSprtYn: string|undefined; + instlCstSprtAmt: number|undefined; + grntchBdstCertYn: string|undefined; + grntchBdstCertNo: string|undefined; + grntchBdstCertGrd: string|undefined; + grntchBdstCertYr: string|undefined; + rainyObj: rainyObj | null; +}; +export type rainyObj = { + bdstReuseFcltFk: number; + pntfColKnd: string | undefined; + pntfColArea: number | undefined; + dtfcltCpct: number; + filtrTrtmfctCpct: number | undefined; + filtrTrtmfctYn: string | undefined; + filtrTrtmfctPrs: string | undefined; + annRnwtQty: number; + oilqMeasMthd: string | undefined; +}; export type TableUpperProps = { id: string; @@ -49,76 +141,6 @@ export type TableUpperProps = { upSequnce?: number; }; - -export type rainRuseBd={ - bdstRuseFcltPk: number, // 건축물 재이용시설 기본키 - bdstInfoFk: number, // 건축물 정보 외부키 - operMngCd:number|null, // 운영관리 코드 tb_wr_bdst_ruse_fclt 삭제 요망 - anlOperCst: number|null, // 연간운영비용 tb_wr_bdst_ruse_fclt 삭제 요망 - instlCmptnDt: Date|null, // 설치완료 일시 tb_wr_bdst_ruse_fclt 1 - instlCst: number|null, // 설치 비용 tb_wr_bdst_ruse_fclt 2 - instlCstSprtAmt: number|null, // 설치비용지원금액 tb_wr_bdst_ruse_fclt 8 - grntchBdstCertYn: string|null, // 녹색 기술 건축물 인증여부 tb_wr_bdst_ruse_fclt 9 - grntchBdstCertNo: string|null, // 녹색 기술 건축물 인증번호 tb_wr_bdst_ruse_fclt 10 - grntchBdstCertGrd: string|null, // 녹색 기술 건축물 인증등급 tb_wr_bdst_ruse_fclt 11 - grntchBdstCertYr: string|null, // 녹색 기술 건축물 인증년도 tb_wr_bdst_ruse_fclt 12 - - bdstReuseFcltFk:number|null; - dtfcltCpct:number|null, // 저류오 용량 tb_wr_rnwtr_utztn_fclt 3-1 - pntfColKnd: string|null, // 접수지점 종류 tb_wr_rnwtr_utztn_fclt 3 - pntfColArea: number|null, // 접수지점 지역 tb_wr_rnwtr_utztn_fclt 4 - filtrTrtmfctCpct: number|null, // 여과 처리시설 용량 tb_wr_rnwtr_utztn_fclt 5 - filtrTrtmfctYn: string|null, // 여과 처리시설 유무 tb_wr_rnwtr_utztn_fclt 6 - filtrTrtmfctPrs: number|null, // 여과 처리시설 공정 tb_wr_rnwtr_utztn_fclt 7 - - annRnwtQty:number|null; //연간 빗물량 - oilqMeasMthd:string|null // 유량측정 방법 -} - - export type reuseBuilding = { - bdstRuseFcltPk: number, // 건축물 재이용시설 기본키 - bdstInfoFk: number, // 건축물 정보 외부키 - operMngCd:number|null, // 운영관리 코드 tb_wr_bdst_ruse_fclt 삭제 요망 - anlOperCst: number|null, // 연간운영비용 tb_wr_bdst_ruse_fclt 삭제 요망 - instlCmptnDt: Date|null, // 설치완료 일시 tb_wr_bdst_ruse_fclt 1 - instlCst: number|null, // 설치 비용 tb_wr_bdst_ruse_fclt 2 - instlCstSprtAmt: number|null, // 설치비용지원금액 tb_wr_bdst_ruse_fclt 8 - grntchBdstCertYn: string|null, // 녹색 기술 건축물 인증여부 tb_wr_bdst_ruse_fclt 9 - grntchBdstCertNo: string|null, // 녹색 기술 건축물 인증번호 tb_wr_bdst_ruse_fclt 10 - grntchBdstCertGrd: string|null, // 녹색 기술 건축물 인증등급 tb_wr_bdst_ruse_fclt 11 - grntchBdstCertYr: string|null, // 녹색 기술 건축물 인증년도 tb_wr_bdst_ruse_fclt 12 - rainyObj:rainyObj - } - - export type rainyObj ={ - bdstReuseFcltFk:number|null; - dtfcltCpct:number|null, // 저류오 용량 tb_wr_rnwtr_utztn_fclt 3-1 - pntfColKnd: string|null, // 접수지점 종류 tb_wr_rnwtr_utztn_fclt 3 - pntfColArea: number|null, // 접수지점 지역 tb_wr_rnwtr_utztn_fclt 4 - filtrTrtmfctCpct: number|null, // 여과 처리시설 용량 tb_wr_rnwtr_utztn_fclt 5 - filtrTrtmfctYn: string|null, // 여과 처리시설 유무 tb_wr_rnwtr_utztn_fclt 6 - filtrTrtmfctPrs: number|null, // 여과 처리시설 공정 tb_wr_rnwtr_utztn_fclt 7 - - annRnwtQty:number|null; //연간 빗물량 - oilqMeasMthd:string|null // 유량측정 방법 - } - - - -export type bdstType = { - ctpvCd: string; // 시도 - sggCd: string; // 시군구 - daddr: string; // 위치 - bdstUsgCd: string; // 건축물용도 - frstArchPrmsnDt: string; // 최초건축허가일 - archArea: string; // 건축면적 - lawTrgtYn: string; // 법적의무대상여부 - archChgPrmsnDt: string; // 건축변경 허가일시 - archChgArea: string; // 변경 면적 - bdstInfoPk: number; - bdstNm: string; -}; - export const upHeadList: TableUpperProps[] = [ { id: "cityText", title: "시도" }, { id: "sggText", title: "시군구" }, @@ -126,21 +148,65 @@ export const upHeadList: TableUpperProps[] = [ { id: "daddr", title: "위치" }, { id: "bdstUsgCd", title: "건축물용도" }, { id: "frstArchPrmsnDt", title: "최초건축허가일" }, - { id: "archArea", title: "건축면적", }, - { id: "lawTrgtYn", title: "법적의무대상여부", }, + { id: "archArea", title: "건축면적" }, + { id: "lawTrgtYn", title: "법적의무대상여부" }, { id: "archChgYn", title: "여부", upName: "upChangeRe", upSequnce: 1 }, { id: "archChgPrmsnDt", title: "허가일", upName: "upChangeRe", upSequnce: 2 }, { id: "archChgArea", title: "면적", upName: "upChangeRe", upSequnce: 3 }, ]; - const bdstObj: bdstType[] =[] - const rainRuseObj: rainRuseBd[] = [] +const rainRes: RainyBuilding[] = []; -export type selectArray = { - text: string; - val: string; + + const regRainForm:RainyBuilding = { + ctpvCd: 0, + sggCd: 0, + bdstNm: "", + daddr: "", + frstArchPrmsnDt:new Date(), + archArea: "", + archChgArea: 0, + bdstInfoPk: 0, + reuseBuilding: [{ + rainyObj: { + bdstReuseFcltFk: 0, + pntfColKnd: undefined, + pntfColArea: undefined, + dtfcltCpct: 0, + filtrTrtmfctCpct: undefined, + filtrTrtmfctYn: undefined, + filtrTrtmfctPrs: undefined, + annRnwtQty: 0, + oilqMeasMthd: undefined + }, + lawTrgtYn: undefined, + bdstUsgCd: undefined, + bdstRuseFcltPk: 0, + bdstInfoFk: 0, + operMngCd: 0, + anlOperCst: 0, + instlCmptnDt: undefined, + instlCst: undefined, + // archChgPrmsnDt: "", + instlCstSprtYn: undefined, + instlCstSprtAmt: undefined, + grntchBdstCertYn: undefined, + grntchBdstCertNo: undefined, + grntchBdstCertGrd: undefined, + grntchBdstCertYr: undefined + }], + //추가됨 + chgBuilding:[{ + bdstInfoFk: 0, + archChgPrmsnDt: new Date(), + archChgArea: 0, + bdstChgNm: "" + + }] }; + + export const selectClass = "w-full h-full text-2xl"; const selectYN = [ { text: "Y", val: "1" }, @@ -150,96 +216,118 @@ export type rainFacState = { rain: { isInit: boolean; upHeadList: TableUpperProps[]; - rainRuseObj: rainRuseBd[]; - bdstObj: bdstType[]; selectYN: selectArray[]; + rainRes: RainyBuilding[]; + regRainForm:RainyBuilding, + }; }; type rainFacSActions = { init: () => void; - dataInit:( )=>void; + dataInit: () => void; + rainReg: (data: RainyBuilding) => void; + rainUpdate: (data: RainyBuilding) => void; }; - export type rainFacType = rainFacState & rainFacSActions; export const rainFacStateExport: rainFacState = { rain: { isInit: false, + rainRes: rainRes, upHeadList: upHeadList, - rainRuseObj: rainRuseObj, - bdstObj: bdstObj, selectYN: selectYN, + regRainForm:regRainForm, + }, }; -console.log(comCodeStateExport.code.sggCd) - -const chBdstUsgCd =(value:string|number)=>{ - const data = bdstUsgCd.find((item)=>item.val===value)?.text - - return data; -} - - -const chCityCd =(value:string|number)=>{ - const data = bdstUsgCd.find((item)=>item.val===value)?.text - - return data; +const findBdstInfo = async(sggCd:string, searchTxt:string)=>{ + return await getFectch('wr', `/reuseFc/building/${sggCd}/${searchTxt}`) + } +const initFetch = async () => { + return await getFectch("wr", "/reuseFc/rainyInfoList/1/20/41"); +}; export const rainFacActionsExport: (set: any) => rainFacSActions = ( set: any ) => { return { - init: async() =>{ + init: async () => { try { // 파라이터 수정 통합관리자 =0, 시관리자=시코드, 시군구 관리자= 시군구 코드 를 세번째 파라미터로 지정 / 건축물 서치가 있을경우 4번째 파라미터로 던지기 즉 1/20/42(서울시)/영현빌딩 이런식으로) - const res = await getFectch('wr', "/reuseFc/rainyInfoList/1/20/42"); - const result = res.flatMap(({ reuseBuilding = [] as RainyInfoResponse["reuseBuilding"], ...item }) => - reuseBuilding.map(rb => { - const { bdstUsgCd, archChgPrmsnDt, rainyObj, ...restRb } = rb; - const bdstObj = { - ...item, - bdstUsgCd: bdstUsgCd ? chBdstUsgCd(bdstUsgCd) ?? '' : '', - archChgPrmsnDt: archChgPrmsnDt ?? '' - } as bdstType; - - const rainRuseObj = { - ...restRb, - ...rainyObj - } as rainRuseBd; - - return { bdstObj, rainRuseObj }; - }) - ); - + const rainRes = await initFetch(); // 여기서 상태 업데이트 return set((state: rainFacState) => ({ ...state, rain: { ...state.rain, - bdstObj: result.map((item: { bdstObj: any; }) => item.bdstObj), - rainRuseObj: result.map((item: { rainRuseObj: any; }) => item.rainRuseObj), - isInit: false - } + rainRes: rainRes, + isInit: false, + }, })); } catch (error) { - console.log('error', error); + console.log("error", error); } finally { - console.log('finally'); + console.log("finally"); } }, dataInit: () => - set(async (state: rainFacState) => { - console.log(" state ", state.rain.bdstObj) - return ({ + set((state: rainFacState) => { + console.log(" state ", state.rain); + return { rain: { ...state.rain, - isInit: false, }, - }) + }; }), - }; -}; + rainReg: async (data: RainyBuilding) => { + try { + const res = await postFectch("/reuseFc/rainyInfo", data); + const rainRes = await initFetch(); + set((state: rainFacState) => ({ + ...state, + rain: { + ...state.rain, + rainRes: rainRes, + isInit: false, + }, + })); + } catch (e) { + console.log("e", e); + alert("등록 오류입니다."); + } finally { + alert("등록이 완료되었습니다."); + } + }, + rainUpdate: async (data: RainyBuilding) => { + try { + console.log("data ", data) + const res = await putFectch("/reuseFc/rainyInfo", data); + console.log('rainUpdate', res); + if(res.ok){ + alert(" 수정이 완료되었습니다.") + } + + const rainRes = await initFetch(); + set((state: rainFacState) => ({ + ...state, + rain: { + ...state.rain, + rainRes: rainRes, + isInit: false, + }, + })); + } catch (e) { + console.log("e", e); + alert("업데이트 오류입니다."); + } finally { + } + } + }} + + + + diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx index 4a94a03fa..91f795ea4 100644 --- a/apps/wr/app/store/store.tsx +++ b/apps/wr/app/store/store.tsx @@ -30,26 +30,30 @@ import { type htdflFacType, } from "./ruseFcltMng/fcltReg/htdflReg"; import { codeActionExport, comCodeStateExport, getCityCd, getSggCd, type comCodeState, type comCodeType } from "./common/code"; +import { bdstActionsExport, bdstStateExport, type bdstFulType, type bdstState } from "./ruseFcltMng/fcltReg/bdstReg"; export type WrStore = comCodeType& pubFacType & rainFacType & rswtFacType & matDmdType & - htdflFacType; + htdflFacType& + bdstFulType; export const StoreZus = ( initState: comCodeState& rainFacState & pubFacState & rswtFacState & matDmdState & - htdflFacState = { + htdflFacState & + bdstState= { ...comCodeStateExport, ...pubFacStateExport, ...rainFacStateExport, ...rswtFacStateExport, ...matDmdStateExport, ...htdflFacStateExport, + ...bdstStateExport, } ) => { return createStore<WrStore>()((set) => { @@ -63,6 +67,7 @@ export const StoreZus = ( ...matDmdActionsExport(set), ...htdflFacActionsExport(set), ...codeActionExport(set), + ...bdstActionsExport(set) }; }); }; diff --git a/apps/wr/components/lib/api/index.ts b/apps/wr/components/lib/api/index.ts index ff690f411..0f7e6c0ee 100644 --- a/apps/wr/components/lib/api/index.ts +++ b/apps/wr/components/lib/api/index.ts @@ -1,6 +1,6 @@ //8880 -import { DEV_URL_COMMON, DEV_URL_WR } from "../config/env"; +import { DEV_URL_COMMON, DEV_URL_WR } from "../config/"; @@ -36,6 +36,7 @@ export const postFectch = async (url: string, params: any) => { export const putFectch = async (url: string, params: any) => { + const response = await fetch(DEV_URL_WR+url, { method: "PUT", headers: { diff --git a/apps/wr/components/lib/config/api.ts b/apps/wr/components/lib/config/api.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/wr/components/lib/config/env.ts b/apps/wr/components/lib/config/env.ts deleted file mode 100644 index 24352c2f3..000000000 --- a/apps/wr/components/lib/config/env.ts +++ /dev/null @@ -1,11 +0,0 @@ - -const LOCAL_PORT = "3000"; -const DEV_PORT = "8880"; - - -const DEV_PORT_COMMON = "8881"; // common - -export const LOCAL_URL_WR = `http://localhost:${LOCAL_PORT}/api/v1`; -export const DEV_URL_WR = `http://192.168.1.193:${DEV_PORT}/api/v1`; - -export const DEV_URL_COMMON = `http:///192.168.1.193:${DEV_PORT_COMMON}/api/v1`; diff --git a/apps/wr/components/lib/config/index.ts b/apps/wr/components/lib/config/index.ts index e7f55b887..24352c2f3 100644 --- a/apps/wr/components/lib/config/index.ts +++ b/apps/wr/components/lib/config/index.ts @@ -1 +1,11 @@ -export * from './env'; \ No newline at end of file + +const LOCAL_PORT = "3000"; +const DEV_PORT = "8880"; + + +const DEV_PORT_COMMON = "8881"; // common + +export const LOCAL_URL_WR = `http://localhost:${LOCAL_PORT}/api/v1`; +export const DEV_URL_WR = `http://192.168.1.193:${DEV_PORT}/api/v1`; + +export const DEV_URL_COMMON = `http:///192.168.1.193:${DEV_PORT_COMMON}/api/v1`; diff --git a/apps/wr/components/lib/func/commom.ts b/apps/wr/components/lib/func/commom.ts new file mode 100644 index 000000000..0351f2fc9 --- /dev/null +++ b/apps/wr/components/lib/func/commom.ts @@ -0,0 +1,16 @@ +import type { selectArray } from "@/app/store/common/code"; + + + + + +export const getCity = (val: string, sggCd: selectArray[]) => { + const data = sggCd + .filter((item) => String(item.val).substring(0, 2) === val) + .map((item) => ({ + val: String(item.val), + text: item.text // 한국어 텍스트 + })); + return data + + }; diff --git a/apps/wr/components/lib/type/zod/fcltReg/controlZod.ts b/apps/wr/components/lib/type/zod/fcltReg/controlZod.ts deleted file mode 100644 index 9c49e56cd..000000000 --- a/apps/wr/components/lib/type/zod/fcltReg/controlZod.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { z } from "zod"; - - -export const rainZod = { - instlCmptnDt: z.date(), - instlCst: z.number(), - pntfColKnd: z.string(), - pntfColArea: z.number(), - filtrTrtmfctPrs: z.string(), - filtrTrtmfctYn: z.string(), - filtrTrtmfctCpct: z.string(), - instlCstSprtYn: z.string(), - instlCstSprtAmt: z.string(), - grntchCstSprtYn: z.string(), - grntchCstSprtCst: z.string(), - grntchBdstCertYn: z.string(), - grntchBdstCertYr: z.string(), - grntchBdstCertNo: z.string(), - grntchBdstCertGrd: z.string(), -} - - -export const rainDefZod= { - instlCmptnDt: new Date(), - instlCst: 0, - pntfColKnd: "", - pntfColArea: 0, - filtrTrtmfctYn: "N", - filtrTrtmfctCpct: "", - filtrTrtmfctPrs: "", - instlCstSprtYn: "", - instlCstSprtAmt: "", - grntchCstSprtYn: "", - grntchCstSprtCst: "", - grntchBdstCertYn: "", - grntchBdstCertYr: "", - grntchBdstCertNo: "", - grntchBdstCertGrd: "", -} -export const bdstZod ={ - ctpvCd: z.string(), // 시도 - sggCd: z.string(), // 시군구 - daddr: z.string(), // 위치 - bdstUsgCd: z.string(), // 건축물용도 - frstArchPrmsnDt: z.string(), // 최초건축허가일 - archArea: z.string(), // 건축면적 - lawTrgtYn: z.string(), // 법적의무대상여부 - archChgPrmsnDt: z.string(), // 건축변경 허가일시 - archChgArea: z.string(), // 변경 면적 - //bdstInfoPk: number; - bdstNm: z.string(), - } - -export const bdstDefZod={ - ctpvCd: '', // 시도 - sggCd: '', // 시군구 - daddr: '', // 위치 - bdstUsgCd: '', // 건축물용도 - frstArchPrmsnDt: '', // 최초건축허가일 - archArea: '', // 건축면적 - lawTrgtYn: '', // 법적의무대상여부 - archChgPrmsnDt: '', // 건축변경 허가일시 - archChgArea: '', // 변경 면적 - //bdstInfoPk: number; - bdstNm: '', -} - diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/component.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/component.tsx index 0a13b41fa..277c1f0cf 100644 --- a/apps/wr/components/ui/form/fcltReg/bdstReg/component.tsx +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/component.tsx @@ -1,68 +1,323 @@ import { useWrStore } from "@/app/store"; -import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { FormField, FormUi, SelectBox } from "@common/business_components"; +import type { selectArray } from "@/app/store/common/code"; +import { selectClass, type RainyBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { getCity } from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/bdstReg/component"; +import { FormField, FormUi, DatePicker, SelectBox } from "@common/business_components"; import { Button, Input } from "@common/components"; +import { useEffect, useRef, useState } from "react"; +import { useFieldArray } from "react-hook-form"; -export default function BdstReg(form: any) { +export default function BdstReg({ form, ud }: { form: any, ud: RainyBuilding }) { const { code } = useWrStore((state) => { return state; }); + const { fields, append, remove } = useFieldArray({ + name: "chgBuilding", + control: form?.control, // Provide a fallback to avoid errors + }); + + const plusHist = () => { + append({ + bdstNm: "", + daddr: "", + bdstUsgCd: "", + }); + }; + + const removeLastItem = () => { + if (fields.length > 0) { + remove(fields.length - 1); + } + }; + + const [selectSgg, setSelectSgg] = useState<selectArray[] | undefined>() + const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""}); + + const getSelCity = (val: string) => { + const data= getCity(val,code.sggCd) + setSelectSgg(data); + const sgg =form.getValues('sggCd') + + setObjSearch({ city:val , sgg:''}) + + }; + + const getSgg = (val: string | number) => { + + const sgg =form.getValues('sggCd') + setObjSearch({...objSearch,sgg: val!=''?String(val):sgg }) + }; + + // useEffect(()=>{ + // console.log("18", ud); + // console.log("form", form.getValues()); + // const city =form?.getValues('ctpvCd') + // const sgg =form?.getValues('sggCd') + // console.log('city ㄴㄴㄴ ', city) + // console.log('sgg ', sgg) + // if(city>0 && sgg>0){ + // console.log(' if city ', city) + + // // form?.setValue('ctpvCd' , city) + // //form?.setValue('sggCd' , sgg) + // //setSelectSgg(getCity(city,code.sggCd)) + // } + // },[ud]) + useEffect(()=>{ + const city =form.getValues('ctpvCd') + const sgg =form.getValues('sggCd') + setObjSearch({city:city , sgg:sgg }) + + }, [selectSgg]) + + useEffect(() => { + const subscription = form.form?.watch((value) => { + console.log('vale', value) + }); + + return () => subscription?.unsubscribe(); + }, [form]); + + + const safeDate = (value: any): Date | undefined => { + const date = new Date(value); + return isNaN(date.getTime()) ? undefined : date; + }; + + return ( <> - - <h1 className="bg-gray-400 text-xl text-center border-2 p-2 mt-4 pl-6"> - 건축물 시설 정보 - </h1> - <div className="grid grid-cols-6 gap-2 mt-4 pl-6"> - <div className="col-span-3"> - <FormField - control={form.control} - name="ctpvCd" - render={({ field }) => ( - <FormUi label="시도"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.cityCd} - onSelectValue={(val) => { - field.onChange(val); - }} - value={field.value} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="sggCd" - render={({ field }) => ( - <FormUi label="시군구"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.cityCd} - onSelectValue={(val) => { - field.onChange(val); - }} - value={field.value} - /> - </FormUi> - )} - /> - </div> + <h1 className="bg-gray-400 text-xl text-center border-2 p-2 mt-4 pl-6"> + 건축물 시설 정보 + </h1> + <div className="grid grid-cols-6 gap-2 mt-4"> + <div className="col-span-3"> + <FormField + control={form.control} + name="ctpvCd" + render={({ field }) => ( + <FormUi label="시도"> + <SelectBox + className="col-span-3 " + label={""} + selectClass={selectClass} + selectArray={code.cityCd} + + onSelectValue={(val)=>{ + getSelCity(String(val)) + field.onChange(Number(val) ); + } + + } + value={field.value} + + /> + </FormUi> + )} + /> </div> - <div className="grid grid-cols-6 gap-2 mt-4 "> + <div className="col-span-3"> + <FormField + control={form.control} + name="sggCd" + render={({ field }) => ( + <FormUi label="시군구"> + <SelectBox + className="col-span-3" + label={""} + selectClass={selectClass} + selectArray={selectSgg? selectSgg:code.sggCd || []} + onSelectValue={(val) =>{ + getSgg(val) + field.onChange(Number(val)) + }} + value={field.value} + + /> + </FormUi> + )} + /> + </div> + </div> + <div className="grid grid-cols-6 gap-2 mt-4 "> + <div className="col-span-2"> + <FormField + control={form.control} + name="bdstNm" + render={({ field }) => ( + <FormUi label="건축물명"> + <Input + className="" + placeholder="1,000,000" + type="text" + {...field} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="daddr" + render={({ field }) => ( + <FormUi label="위치"> + <Input + className="" + placeholder="1,000,000" + type="search" + {...field} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="bdstUsgCd" + render={({ field }) => ( + <FormUi label="건축물용도"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstUsgCd} + onSelectValue={(val) => { + field.onChange(Number(val)); + }} + value={field.value} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="frstArchPrmsnDt" + render={({ field }) => ( + <FormUi label="최초건축허가일"> + <DatePicker + mode={"single"} + field={{ + value: new Date(field.value), + onChange: (date: Date | undefined) => + field.onChange(date), + }} + selectClass={selectClass} + ></DatePicker> + + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="archArea" + render={({ field }) => ( + <FormUi label="건축면적(m³)"> + <Input + className="" + placeholder="1,000,000" + type="number" + {...field} + onChange={(e) => { + const value = e.target.value; + field.onChange(value === "" ? "" : Number(value)); + }} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="" + render={({ field }) => ( + <FormUi label="법정의무대상여부"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.yn} + onSelectValue={(val) => { + field.onChange(val); + }} + value={field.value} + /> + </FormUi> + )} + /> + </div> + </div> + <h1 className="bg-gray-400 text-xl text-center border-2 p-2 mt-4"> + 중축, 개축, 재축 + </h1> + <div className="flex justify-end gap-2"> + <Button type="button" className="rounded-lg" onClick={plusHist}> + 이력추가 + </Button> + <Button + type="button" + className="rounded-lg bg-red-500 text-white" + onClick={removeLastItem} + > + 삭제 + </Button> + </div> + + {fields.map((field, index) => ( + <div key={field.id} className="grid grid-cols-6 gap-2 mt-4"> <div className="col-span-2"> <FormField control={form.control} - name="bdstNm" + name={`chgBuilding.${index}.bdstChgNm`} render={({ field }) => ( - <FormUi label="건축물명"> + <FormUi label="구분"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.chBuCd} + onSelectValue={(val) => { + field.onChange(val); + }} + value={field.value} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name={`chgBuilding.${index}.archChgPrmsnDt`} + render={({ field }) => ( + <FormUi label="허가일"> + <DatePicker + mode={"single"} + field={{ + value: safeDate(field.value) || new Date(), + onChange: (date: Date | undefined) => + field.onChange(date), + }} + selectClass={selectClass} + ></DatePicker> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name={`chgBuilding.${index}.archChgArea`} + render={({ field }) => ( + <FormUi label="면적"> <Input className="" placeholder="1,000,000" @@ -73,102 +328,9 @@ export default function BdstReg(form: any) { )} /> </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="daddr" - render={({ field }) => ( - <FormUi label="위치"> - <Input - className="" - placeholder="1,000,000" - type="search" - {...field} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="bdstUsgCd" - render={({ field }) => ( - <FormUi label="건축물용도"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.cityCd} - onSelectValue={(val) => { - field.onChange(val); - }} - value={field.value} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="frstArchPrmsnDt" - render={({ field }) => ( - <FormUi label="최초건축허가일"> - <Input - className="" - placeholder="1,000,000" - type="date" - {...field} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="archArea" - render={({ field }) => ( - <FormUi label="건축면적(m³)"> - <Input - className="" - placeholder="1,000,000" - type="number" - {...field} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="" - render={({ field }) => ( - <FormUi label="법정의무대상여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.cityCd} - onSelectValue={(val) => { - field.onChange(val); - }} - value={field.value} - /> - </FormUi> - )} - /> - </div> </div> - <h1 className="bg-gray-400 text-xl text-center border-2 p-2 mt-4"> - 중축, 개축, 증축 - </h1> - <div className="flex justify-end"> - <Button className="mr-4 rounded-lg ">이력추가</Button> - </div> - <div className="border-b border-gray-300 my-4"> </div> + ))} + <div className="border-b border-gray-300 my-4"> </div> </> ); } diff --git a/apps/wr/components/ui/form/fcltReg/rainReg/component.tsx b/apps/wr/components/ui/form/fcltReg/rainReg/component.tsx index 98d0e28a9..bf57cc97e 100644 --- a/apps/wr/components/ui/form/fcltReg/rainReg/component.tsx +++ b/apps/wr/components/ui/form/fcltReg/rainReg/component.tsx @@ -1,96 +1,187 @@ "use client"; -import { Form, FormField, SelectBox } from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { FormUi } from "@common/business_components"; import { useWrStore } from "@/app/store"; import { selectClass, - type rainRuseBd, -} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { useEffect } from "react"; -import { bdstDefZod, - bdstZod, rainDefZod, rainZod, -} from "@/components/lib/type/zod/fcltReg/controlZod"; + type RainyBuilding, +} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { DatePicker, FormUi } from "@common/business_components"; +import { Form, FormField, SelectBox } from "@common/business_components/ui"; +import { Button, Input } from "@common/components/ui"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useEffect, useState } from "react"; +import { useForm, type UseFormReturn } from "react-hook-form"; +import { z } from "zod"; import BdstReg from "../bdstReg/component"; -export function RainRegForm({ - data, - isModal, -}: { - data: rainRuseBd[]; - isModal: boolean; -}) { - console.log(isModal); - const formSchema = isModal - ? z.object({ ...rainZod, ...bdstZod }) - : z.object(rainZod); - - const { rain, code } = useWrStore((state) => state); - const { rainFcltCd } = code; - useEffect(() => { - if (data && data.length > 0) { - console.log(data); - const selectedOption = rainFcltCd.find( - (item) => item.val === String(data[0]?.pntfColKnd ?? "") - ); - const formData = { - ...data[0], - pntfColKnd: selectedOption ? selectedOption.val : "", - instlCmptnDt: data[0]?.instlCmptnDt - ? new Date(data[0].instlCmptnDt) - : undefined, - }; - form.reset(formData); - } - }, [data, rainFcltCd]); - - const form = useForm<z.infer<typeof formSchema>>({ +export const formToObj = ( + isModal: boolean, + formSchema: z.ZodObject<any, "strip", z.ZodTypeAny, any, any> +) => { + return useForm<z.infer<typeof formSchema>>({ resolver: zodResolver(formSchema), defaultValues: isModal - ? { ...rainDefZod, ...bdstDefZod } - : { ...rainDefZod }, + ? { + ...rainDefZod, + ...bdstDefZod, + } + : { + ...rainDefZod, + }, }); +}; + +const formSchema = z.object(rainZod); +export type RainFormType = UseFormReturn<z.infer<typeof formSchema>>; + +export function RainRegForm({ + rainForm, + isModal, +}: { + rainForm: RainyBuilding; + isModal: boolean; +}) { + + const form = formToObj(isModal, formSchema); + const { code, rainReg, rainUpdate, rain } = useWrStore((state) => state); + const { rainFcltCd } = code; + + useEffect(() => { + console.log(rainForm); + + if (rainForm != null) { + const data = rainForm; + + const selectedOption = rainFcltCd.find( + (item) => + item.val === + String(data?.reuseBuilding?.at(0)?.rainyObj?.pntfColKnd ?? "") + ); + let formData; + + + if (data?.reuseBuilding?.at(0)) { + const rb = data.reuseBuilding?.at(0); + formData = { + ...data, + ...rb?.rainyObj, + ...data.reuseBuilding?.at(0), + pntfColKnd: selectedOption ? String(selectedOption.val) : undefined, + frstArchPrmsnDt: new Date(data.frstArchPrmsnDt) + }; + form.reset(formData); + } else { + formData = { + ...data + }; + + form.reset(formData); + } + } + }, [rainForm]); // form 값이 변경될 때마다 로그 출력 useEffect(() => { const subscription = form.watch((value) => { - console.log("form values changed:", value); - }); + }); return () => subscription.unsubscribe(); }, [form]); - // 2. Define a submit handler. + const objToForm = (raw: z.infer<typeof formSchema>) => { + let regRainForm: RainyBuilding; + + // 1. 기본 정보 정리 + const obj = !rainForm ? rain.regRainForm : rainForm; + regRainForm = { + ...obj, + ctpvCd: raw?.ctpvCd , + sggCd: raw?.sggCd, + daddr: raw?.daddr, + bdstNm: raw?.bdstNm, + frstArchPrmsnDt: raw?.frstArchPrmsnDt , + archArea: raw?.archArea + "", + // archChgArea: raw?.archChgArea || 0, // Ensure archChgArea is always a string + }; + + const rainObj = regRainForm?.reuseBuilding?.at(0)?.rainyObj; + + if (!regRainForm.reuseBuilding) { + regRainForm.reuseBuilding = []; + } + + regRainForm.reuseBuilding[0] = { + ...rainForm?.reuseBuilding?.at(0), + + instlCmptnDt: raw.instlCmptnDt, + instlCst: raw.instlCst || rainForm?.reuseBuilding?.at(0)?.instlCst, + instlCstSprtYn: + raw.instlCstSprtYn || rainForm?.reuseBuilding?.at(0)?.instlCstSprtYn, + instlCstSprtAmt: + raw.instlCstSprtAmt || rainForm?.reuseBuilding?.at(0)?.instlCstSprtAmt, + grntchBdstCertYn: + raw.grntchBdstCertYn || rainForm?.reuseBuilding?.at(0)?.grntchBdstCertYn, + grntchBdstCertYr: + raw.grntchBdstCertYr || rainForm?.reuseBuilding?.at(0)?.grntchBdstCertYr, + grntchBdstCertNo: + raw.grntchBdstCertNo || rainForm?.reuseBuilding?.at(0)?.grntchBdstCertNo, + grntchBdstCertGrd: + raw.grntchBdstCertGrd || rainForm?.reuseBuilding?.at(0)?.grntchBdstCertGrd, + bdstUsgCd: raw.bdstUsgCd || rainForm?.reuseBuilding?.at(0)?.bdstUsgCd, + lawTrgtYn: raw.lawTrgtYn || rainForm?.reuseBuilding?.at(0)?.lawTrgtYn, + } + regRainForm.reuseBuilding[0].rainyObj = { + ...rainObj, + pntfColKnd: raw.pntfColKnd || rainObj?.pntfColKnd, + pntfColArea: raw.pntfColArea || rainObj?.pntfColArea, + filtrTrtmfctCpct: raw.filtrTrtmfctCpct || rainObj?.filtrTrtmfctCpct, + filtrTrtmfctYn: raw.filtrTrtmfctYn || rainObj?.filtrTrtmfctYn, + filtrTrtmfctPrs: raw.filtrTrtmfctPrs || rainObj?.filtrTrtmfctPrs, + }; + + if (isModal) { + rainReg(regRainForm); + } else { + console.log(" regRainForm ", regRainForm) + rainUpdate(regRainForm); + } + }; + function onSubmit(values: z.infer<typeof formSchema>) { - // Do something with the form values. - // ✅ This will be type-safe and validated. console.log(values); + objToForm(values); } - const onSelectValue = (val: string) => { - console.log(val); - }; + useEffect(() => { + console.log("form errors:", form.formState.errors); + }, [form.formState.errors]); + + + return ( <div className=""> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> - {/* <div className="flex justify-between items-center mx-3"> */} <div> <div className="grid grid-cols-12"> <h1 className="pl-3 text-xl col-span-10"> {isModal ? "○건축물 운영정보" : "○ 빗물이용시설 운영정보"} </h1> - <Button className="mr-4 rounded-lg col-span-2">저장</Button> + <Button type="submit" className="mr-4 rounded-lg col-span-2"> + 저장 + </Button> </div> </div> - {isModal ? <BdstReg form={form}></BdstReg> : <></>} - {isModal ? <h1 className="pl-3 text-xl col-span-10 mt-4 ">○ 빗물이용시설 운영정보 </h1> : <></>} + {isModal&&rainForm!=undefined ? <BdstReg form={form} ud={rainForm}/> : <></>} + {isModal ? ( + <h1 className="pl-3 text-xl col-span-10 mt-4 "> + ○ 빗물이용시설 운영정보{" "} + </h1> + ) : ( + <></> + )} <h1 className="bg-gray-400 text-xl text-center border-2 p-2 mt-4 "> 기본정보 </h1> @@ -102,18 +193,15 @@ export function RainRegForm({ name="instlCmptnDt" render={({ field }) => ( <FormUi label="설치완료일"> - <Input - className="" - type="date" - onChange={(e) => - field.onChange( - e.target.value ? new Date(e.target.value) : undefined - ) - } - value={ - field.value ? field?.value.toString().split("T")[0] : "" - } - /> + <DatePicker + mode={"single"} + field={{ + value: new Date(field.value), + onChange: (date: Date | undefined) => + field.onChange(date), + }} + selectClass={selectClass} + ></DatePicker> </FormUi> )} /> @@ -130,6 +218,10 @@ export function RainRegForm({ placeholder="1,000,000" type="" {...field} + onChange={(e) => { + const value = e.target.value; + field.onChange(value === "" ? "" : Number(value)); + }} /> </FormUi> )} @@ -158,7 +250,6 @@ export function RainRegForm({ selectArray={rainFcltCd} onSelectValue={(val) => { field.onChange(val); - onSelectValue(val); }} value={field.value} /> @@ -177,6 +268,10 @@ export function RainRegForm({ placeholder="1,000,000" type="" {...field} + onChange={(e) => { + const value = e.target.value; + field.onChange(value === "" ? "" : Number(value)); + }} /> </FormUi> )} @@ -198,8 +293,8 @@ export function RainRegForm({ className={""} selectClass={selectClass} label={""} - selectArray={rain.selectYN} - onSelectValue={onSelectValue} + selectArray={code.yn} + onSelectValue={field.onChange} {...field} /> </FormUi> @@ -217,6 +312,10 @@ export function RainRegForm({ placeholder="1,000,000" type="" {...field} + onChange={(e) => { + const value = e.target.value; + field.onChange(value === "" ? "" : Number(value)); + }} /> </FormUi> )} @@ -258,8 +357,8 @@ export function RainRegForm({ className={""} selectClass={selectClass} label={""} - selectArray={rain.selectYN} - onSelectValue={onSelectValue} + selectArray={code.yn} + onSelectValue={field.onChange} value={field.value} /> </FormUi> @@ -277,6 +376,10 @@ export function RainRegForm({ placeholder="1,000,000" type="" {...field} + onChange={(e) => { + const value = e.target.value; + field.onChange(value === "" ? "" : Number(value)); + }} /> </FormUi> )} @@ -291,15 +394,15 @@ export function RainRegForm({ <div className="col-span-3 pl-6"> <FormField control={form.control} - name="grntchCstSprtYn" + name="grntchBdstCertYn" render={({ field }) => ( <FormUi label="인증여부"> <SelectBox className={""} selectClass={selectClass} label={""} - selectArray={rain.selectYN} - onSelectValue={onSelectValue} + selectArray={code.yn} + onSelectValue={field.onChange} value={field.value} /> </FormUi> diff --git a/apps/wr/components/ui/modal/bdstReg/component.tsx b/apps/wr/components/ui/modal/bdstReg/component.tsx index d2693cd35..e0a389182 100644 --- a/apps/wr/components/ui/modal/bdstReg/component.tsx +++ b/apps/wr/components/ui/modal/bdstReg/component.tsx @@ -3,55 +3,94 @@ import { headMakeColSpan } from "@/app/ruseFcltMng/fcltReg/rainReg/page"; import { useWrStore } from "@/app/store"; import { selectClass, - type bdstType, + type RainyBuilding, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { ScrollArea, SearchInput, SelectBox, UiTable } from "@common/business_components"; -import { Button, Input } from "@common/components"; +import { Button, Input, Label } from "@common/components"; import { useEffect, useState } from "react"; import { RainRegForm } from "../../form/fcltReg/rainReg/component"; +import { getCityCd, type selectArray } from "@/app/store/common/code"; +import { getCity } from "@/components/lib/func/commom"; + +export type objSearchType = { + sgg: string|number; + city: string|number; + }; + export function BdstReg() { - const { rain, code, init } = useWrStore((state) => { + const { rain, code, bdst,findBdst } = useWrStore((state) => { return state; }); - const [bdstTable, setbdstTable] = useState<bdstType[]>(); - const [rainBdstForm, setRainBdstForm] = useState<[]>(); - const { bdstObj, rainRuseObj } = rain; - const getCity = (val: string | number) => { - console.log(val); + const [bdstTable, setbdstTable] = useState<RainyBuilding[]>(); + const [rainBdstForm, setRainBdstForm] = useState<RainyBuilding>({} as RainyBuilding); + const [searchTxt, setSearchTxt] = useState<string>() + const [selectSgg, setSelectSgg] = useState<selectArray[] | undefined>() + const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""}); + + const getSelCity = (val: string) => { + const data= getCity(val,code.sggCd) + setSelectSgg(data); + + setObjSearch({ city:val , sgg:''}) + }; const getSgg = (val: string | number) => { console.log(val); + setObjSearch({...objSearch,sgg: String(val)}) }; + const searchBdst=()=>{ + if(objSearch.city===""){ + alert('시도조건은 필수 입니다.') + return + } + let data =objSearch.city; + if(objSearch.sgg !=="" ){ + data = objSearch.sgg + } + + findBdst(String(data), searchTxt || "") + + } + useEffect(() => { if (code.sggCd.length > 0) { - const table = bdstObj.map((item) => { + const table = bdst?.bdstBase?.map((item) => { const sggText = code.sggCd.find( - (cd) => cd.val.toString() === item.sggCd + (cd) => cd.val === Number(item.sggCd) )?.text; const cityText = code.cityCd.find( - (cd) => cd.val.toString() === item.ctpvCd + (cd) => cd.val === Number(item.ctpvCd) )?.text; return { ...item, sggText: sggText, cityText: cityText }; }); + + setbdstTable(table); } - }, [code, bdstObj]); + }, [code, bdst]); - const cellClick = () => {}; - const nodeList = headMakeColSpan(rain.upHeadList); + + const tableClick: (val: number | undefined) => void = (val) => { + + if(val!==undefined && bdst?.bdstBase.length>0){ + const data =bdst?.bdstBase[val] + setRainBdstForm(data); + } + } + const nodeList = headMakeColSpan(bdst.moUpHeadList); return ( <> - <div className="grid grid-cols-12 gap-4 pb-4"> + <div className="grid grid-cols-12 gap-4 mt-4"> <SelectBox - className="col-span-3 col-start-4" + className="col-span-3 " label={"시도"} selectClass={selectClass} selectArray={code.cityCd} - onSelectValue={getCity} + onSelectValue={getSelCity} > {" "} </SelectBox> @@ -59,41 +98,42 @@ export function BdstReg() { className="col-span-3" label={"시군구"} selectClass={selectClass} - selectArray={code.sggCd} + selectArray={selectSgg || []} onSelectValue={getSgg} > {" "} </SelectBox> - <SearchInput - className="col-span-3 col-start-10" + <Label className="w-20 text-base text-gray-600 mt-4 text-right">건축물명</Label> + <Input className="w-full h-full text-2xl col-span-2 col-start-8" type="text" value={searchTxt || ''} onChange={(e) => setSearchTxt(e.target.value)}/> + {/* <SearchInput + className="col-span-3 col-start-8" label="건물명" - textValue={""} - setText={function (val: string): void { - throw new Error("Function not implemented."); - }} - /> + textValue={searchTxt} + setText={ setSearchTxt} + + /> */} + <Button className="rounded-lg" onClick={()=>{searchBdst()}}>조회</Button> </div> + <div className="border-t border-gray-300 my-4"></div> <div className="h-auto"> <div> <UiTable tableData={bdstTable || []} - headlist={rain.upHeadList} + headlist={bdst.moUpHeadList} pageSize={-10} total={-1} headName={undefined} - cellClick={cellClick} + cellClick={tableClick} > {nodeList} </UiTable> </div> - <div > - + <div className="border-t border-gray-300 my-4"></div> <ScrollArea className="h-[60vh]"> <div> - <RainRegForm data={rainBdstForm || []} isModal={true}></RainRegForm> + <RainRegForm rainForm={rainBdstForm } isModal={true}/> </div> </ScrollArea> - </div> </div> </> ); diff --git a/packages/common/business_components/src/ui/alert_dialog_ui/index.tsx b/packages/common/business_components/src/ui/alert_dialog_ui/index.tsx new file mode 100644 index 000000000..8437c87a8 --- /dev/null +++ b/packages/common/business_components/src/ui/alert_dialog_ui/index.tsx @@ -0,0 +1,53 @@ +import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@common/components"; +import React from "react"; + +type ModalType = { + bodyClass: string; + butNm: string; + title: string; + body: React.ReactNode; + open?: boolean; + onOpenChange?: (open: boolean) => void; +} + +export function UiModal({ bodyClass, butNm, title, body, open, onOpenChange }: ModalType) { + const dialogProps = open !== undefined && onOpenChange !== undefined + ? { open, onOpenChange } + : {}; + + return ( + <> + {!open && ( + <Dialog> + <DialogTrigger asChild> + <Button className="mr-4 rounded-lg">{butNm}</Button> + </DialogTrigger> + <DialogContent className={bodyClass}> + <DialogHeader> + <DialogTitle>{title}</DialogTitle> + <DialogDescription> + </DialogDescription> + </DialogHeader> + {body} + <DialogFooter className="sm:justify-start"> + </DialogFooter> + </DialogContent> + </Dialog> + )} + {open && ( + <Dialog {...dialogProps}> + <DialogContent className={bodyClass}> + <DialogHeader> + <DialogTitle>{title}</DialogTitle> + <DialogDescription> + </DialogDescription> + </DialogHeader> + {body} + <DialogFooter className="sm:justify-start"> + </DialogFooter> + </DialogContent> + </Dialog> + )} + </> + ); +} 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 58b69cff6..7609e2908 100644 --- a/packages/common/business_components/src/ui/dialog_ui/index.tsx +++ b/packages/common/business_components/src/ui/dialog_ui/index.tsx @@ -1,33 +1,50 @@ -import { Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@common/components"; +import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTrigger } from "@common/components"; - -type ModalType={ - bodyClass:string - butNm:string - title:string - body:React.ReactNode +type ModalType = { + bodyClass: string; + butNm: string; + title: string | undefined; + body: React.ReactNode; + open?: boolean; + onOpenChange?: (open: boolean) => void; } -export function UiModal({bodyClass,butNm,title ,body}:ModalType ) { + +export function UiModal({ bodyClass, butNm, title, body, open, onOpenChange }: ModalType) { + const dialogProps = open !== undefined && onOpenChange !== undefined && title !== undefined + ? { open, onOpenChange, title } + : {}; + return ( <> - <Dialog > - <DialogTrigger asChild> - <Button className="mr-4 rounded-lg">{butNm}</Button> - </DialogTrigger> - <DialogContent className={bodyClass}> - <DialogHeader> - <DialogTitle>{title}</DialogTitle> - <DialogDescription> - </DialogDescription> - </DialogHeader> - {body} - - - <DialogFooter className="sm:justify-start"> - - </DialogFooter> - </DialogContent> - </Dialog> + {!open && ( + <Dialog> + <DialogTrigger asChild> + <Button className="mr-4 rounded-lg">{butNm}</Button> + </DialogTrigger> + <DialogContent className={bodyClass}> + <DialogHeader> + <DialogDescription> + </DialogDescription> + </DialogHeader> + {body} + <DialogFooter className="sm:justify-start"> + </DialogFooter> + </DialogContent> + </Dialog> + )} + {open && ( + <Dialog {...dialogProps}> + <DialogContent className={bodyClass}> + <DialogHeader> + <DialogDescription> + </DialogDescription> + </DialogHeader> + {body} + <DialogFooter className="sm:justify-start"> + </DialogFooter> + </DialogContent> + </Dialog> + )} </> ); } diff --git a/packages/common/business_components/src/ui/search_input/index.tsx b/packages/common/business_components/src/ui/search_input/index.tsx index 0da6cffdc..bd634aa21 100644 --- a/packages/common/business_components/src/ui/search_input/index.tsx +++ b/packages/common/business_components/src/ui/search_input/index.tsx @@ -3,13 +3,26 @@ import React from "react"; const SearchInput = React.forwardRef<HTMLInputElement, {className:string, label:string, textValue:string, setText:(val:string)=>void}>(({className, label, textValue, setText}, ref) => { const changeText=(e:React.ChangeEvent<HTMLInputElement>)=>{ - if(e?.target?.value) setText(e.target.value) - } + + if(e?.target?.value){ + + setText(e.target.value) + } + + + + } + + const keyUp=(e:any)=>{ + if(e.keyCode===8 && e.target.value.length==1){ + setText('') + } + } return ( <div className={className+" flex items-center"} > {label && <Label className="w-20 text-base text-gray-600">{label}</Label>} - <Input className="flex-1 ml-8 w-3/4 h-10 border rounded" value={textValue} onChange={changeText}></Input> + <Input className="flex-1 ml-8 w-3/4 h-10 border rounded" value={textValue} onChange={changeText} onKeyUp={keyUp}></Input> </div> ) }); diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index b8c2706bc..d536a1f2f 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -3,7 +3,7 @@ import UiPageNations from "./uiPageNations"; type UiTableProps = { headName: React.ReactNode | undefined; - tableData: { [key: string]: string | number | boolean }[]; + tableData: { [key: string]: string | number | boolean | object}[]; headlist: UiHeadProps[]; pageSize: number; total: number; @@ -34,9 +34,9 @@ export function UiTable({ tableData, headlist, pageSize, total, children, headNa </TableRow>} </TableHeader> <TableBody className='text-center'> - {tableData?.map((el: { [key: string]: string | number | boolean }, index) => ( + {tableData?.map((el: { [key: string]: string | number | boolean | object}, index) => ( <TableRow key={index + "row"} > - {headlist.map((head) => ( + {headlist?.map((head) => ( <TableCell className="cursor-pointer" onClick={()=>cellClick && cellClick(index)} key={head.id + index}>{el[head.id]}</TableCell> ))} </TableRow> diff --git a/packages/common/business_components/src/ui/table/uiPageNations.tsx b/packages/common/business_components/src/ui/table/uiPageNations.tsx index a7b788d71..99199d163 100644 --- a/packages/common/business_components/src/ui/table/uiPageNations.tsx +++ b/packages/common/business_components/src/ui/table/uiPageNations.tsx @@ -1,46 +1,78 @@ -'use client' - +'use client'; import { useEffect, useState } from "react"; -import { Pagination, PaginationContent, PaginationItem, PaginationPrevious, PaginationLink, PaginationNext } from "./lib/pagination"; - +import { + Pagination, + PaginationContent, + PaginationItem, + PaginationPrevious, + PaginationLink, + PaginationNext +} from "./lib/pagination"; interface CommonPageNationsProps { - total: number; - cur: number; - pageSize: number; + total: number; + cur: number; + pageSize: number; } export default function UiPageNations(commonPageNationsProps: CommonPageNationsProps) { - - const [pageProps, setPageProps] = useState(commonPageNationsProps); + const [pageProps, setPageProps] = useState(commonPageNationsProps); + useEffect(() => { + setPageProps(commonPageNationsProps); + }, [commonPageNationsProps]); - useEffect(() => { - setPageProps(commonPageNationsProps); - } ,[commonPageNationsProps]); + const totalPages = Math.ceil(pageProps.total / pageProps.pageSize); + const pagesPerGroup = 10; + const currentGroup = Math.floor((pageProps.cur - 1) / pagesPerGroup); + const startPage = currentGroup * pagesPerGroup + 1; + const endPage = Math.min(startPage + pagesPerGroup - 1, totalPages); + const handlePageChange = (page: number) => { + setPageProps({ ...pageProps, cur: page }); + }; - return( - <Pagination> - <PaginationContent> - <PaginationItem> - <PaginationPrevious href="#" /> - </PaginationItem> + return ( + <Pagination> + <PaginationContent> + + {/* 이전 그룹으로 이동 */} + <PaginationItem> + <PaginationPrevious + href="#" + onClick={() => { + if (startPage > 1) handlePageChange(startPage - 1); + }} + /> + </PaginationItem> + + {/* 현재 그룹 페이지들 표시 */} { - Array.from({length:Math.ceil(commonPageNationsProps.total/commonPageNationsProps.pageSize)},(_,i)=>i+1).map((el,index)=>( - <PaginationItem key={index}> - <PaginationLink href= '#'>{el}</PaginationLink> - </PaginationItem> - )) - } - <PaginationItem> - <PaginationNext href="#" /> + Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i).map((pageNum) => ( + <PaginationItem key={pageNum}> + <PaginationLink + href="#" + isActive={pageNum === pageProps.cur} + onClick={() => handlePageChange(pageNum)} + > + {pageNum} + </PaginationLink> </PaginationItem> - - - - </PaginationContent> - </Pagination> - ); + )) + } + + {/* 다음 그룹으로 이동 */} + <PaginationItem> + <PaginationNext + href="#" + onClick={() => { + if (endPage < totalPages) handlePageChange(endPage + 1); + }} + /> + </PaginationItem> + + </PaginationContent> + </Pagination> + ); } \ No newline at end of file