diff --git a/apps/sn/.env.local b/apps/sn/.env.local index 35c1476f5..d0be4b904 100644 --- a/apps/sn/.env.local +++ b/apps/sn/.env.local @@ -12,4 +12,4 @@ NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API #NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성 부장님 API -#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정 차장님 API +#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.222:8883/sewerage-service/api # 박이정 차장님 API diff --git a/apps/sn/app/(map-layout)/map/SearchModal.tsx b/apps/sn/app/(map-layout)/map/SearchModal.tsx index 73cc5fc8e..a549ece0b 100644 --- a/apps/sn/app/(map-layout)/map/SearchModal.tsx +++ b/apps/sn/app/(map-layout)/map/SearchModal.tsx @@ -1,8 +1,8 @@ import FeatureClickEventPopup from './featureClickEventPopup'; import React, { useEffect, useState } from 'react'; import axios from 'axios'; -import { UiModal, UiTable } from '@common/business_components/ui'; -import { Button, DatePicker, Input, Label } from '@common/components'; +import { UiModal, UiTable, DatePickerRange } from '@common/business_components/ui'; +import { Button, Input, Label } from '@common/components'; import { UiTable2 } from '@common/business_components/ui/table/index-2'; import { UITab2 } from '@common/business_components/ui/tab/index-2'; import { SelectBox2 } from '@common/business_components/ui/select/index-2'; @@ -136,6 +136,21 @@ const SearchModal: React.FC = ({ const todayMonth = (today.getMonth() + 1).toString().padStart(2, "0"); const todayDate = today.getDate().toString().padStart(2, "0"); + const isDateInRanges = (date: Date) => { + const standYear = parseInt(fromDate.getFullYear().toString()); + const dateRanges = []; + dateRanges.push({ + start: new Date(standYear, 0, 1), + end: new Date(standYear, 11, 31) + }); + + return dateRanges.some(range => { + const start = new Date(range.start); + const end = new Date(range.end); + return date >= start && date <= end; + }); + }; + // UiTable2에 넘길 headlist를 BASIC_TYPES 값에 따라 분기 처리 let dynamicHeadlist = MsSwagePplCol2; // default 값 if (activeTab === 'operation') dynamicHeadlist = operationTableHeadlist; // 운영정보 @@ -964,43 +979,23 @@ const SearchModal: React.FC = ({ startLabel="수행기간" endLabel="" /> */} - { if (date) setFromDate(date) }} - modifiers={{ - disabled: { after: new Date() } - }} - zIndex={102} + { if (date) setFromDate(date) }} // 선택했을 때 이벤트 (주로 set) + className="w-full p-1 border rounded bg-white" // 스타일 + disabled={(date) => !isDateInRanges(date)} // 선택못하게 하는 날짜 - 없으면 안넣어도 됨 + defaultMonth={fromDate} // 처음에 시작할 날짜 selected랑 같이 같은 날짜 넣으면 됨 /> - ~ - { if (date) setToDate(date) }} - modifiers={{ - disabled: { after: new Date() } - }} - zIndex={102} + ~ + { if (date) setFromDate(date) }} // 선택했을 때 이벤트 (주로 set) + className="w-full p-1 border rounded bg-white" // 스타일 + disabled={(date) => !isDateInRanges(date)} // 선택못하게 하는 날짜 - 없으면 안넣어도 됨 + defaultMonth={toDate} // 처음에 시작할 날짜 selected랑 같이 같은 날짜 넣으면 됨 /> -
- {/* 경과년도 */} - {/* - { - // 숫자만 입력 허용 - const val = e.target.value.replace(/[^0-9]/g, ""); - setYearFilter({ ...yearFilter, 경과년도: val }); - }} - /> */} -
{/* 조회 버튼 중앙 정렬 */}
diff --git a/apps/sn/app/(map-layout)/map/components/common/index.ts b/apps/sn/app/(map-layout)/map/components/common/index.ts index 51dd450e7..e71e8ba3f 100644 --- a/apps/sn/app/(map-layout)/map/components/common/index.ts +++ b/apps/sn/app/(map-layout)/map/components/common/index.ts @@ -7,9 +7,11 @@ import SwtrmtFclt from "../popupComponent/SwtrmtFclt"; type LayerComponentProps = { featureData: any; - chkMainSsc?: boolean; + isMainSsc?: boolean; + isDrtwSewagePump?: boolean; additionalData?: any; onSaveClick?: () => void; + onFormDataChange?: (data: any) => void; // 추가 }; type LayerContentMap = { [key: string]: { diff --git a/apps/sn/app/(map-layout)/map/components/common/table.ts b/apps/sn/app/(map-layout)/map/components/common/table.ts index f114cf97b..87be5bf6e 100644 --- a/apps/sn/app/(map-layout)/map/components/common/table.ts +++ b/apps/sn/app/(map-layout)/map/components/common/table.ts @@ -55,6 +55,213 @@ export const MsSwagePplCol2 = [ // { id: 'usgCd', title: '용도코드' }, // { id: 'lyrTypeNm', title: '레이어타입명' }, ] +// 하수관로 용도 코드표 +export const MS_SWAGE_PPL_USE_CODES = [ + { val: "SBA000", text: "미분류" }, + { val: "SBA001", text: "합류관" }, + { val: "SBA002", text: "차집관" }, + { val: "SBA003", text: "우수관" }, + { val: "SBA004", text: "오수관" }, + { val: "SBA999", text: "기타" }, + { val: "그 외", text: "미분류" }, +]; +// 하수관로 재질 코드표 +export const MS_SWAGE_PPL_CODES = [ + { val: "MOP000", text: "미분류" }, + { val: "MOP001", text: "닥타일주철관(DCIP)" }, + { val: "MOP002", text: "강관(SP)" }, + { val: "MOP003", text: "아연도강관(GS)" }, + { val: "MOP004", text: "염화비닐관(PVC)" }, + { val: "MOP005", text: "폴리에틸렌관(PE)" }, + { val: "MOP006", text: "스테인레스관(SSP)" }, + { val: "MOP007", text: "동관(COP)" }, + { val: "MOP008", text: "P.S.콘크리트관(PC)" }, + { val: "MOP009", text: "석면시멘트관(AS)" }, + { val: "MOP010", text: "회주철관(CIP)" }, + { val: "MOP011", text: "연관(LP)" }, + { val: "MOP012", text: "흉관(HP)" }, + { val: "MOP013", text: "철근콘크리트관(RC)" }, + { val: "MOP014", text: "강관(ST)" }, + { val: "MOP015", text: "주철관(CI)" }, + { val: "MOP016", text: "화학제품류관(PV)" }, + { val: "MOP017", text: "도관(VC)" }, + { val: "MOP018", text: "석축(SE)" }, + { val: "MOP019", text: "도복장 강관(SP)" }, + { val: "MOP020", text: "흉관(EP)" }, + { val: "MOP021", text: "아연도강관(GP)" }, + { val: "MOP022", text: "청동관(BR)" }, + { val: "MOP023", text: "고무몰딩(RM)" }, + { val: "MOP024", text: "주강(CS)" }, + { val: "MOP025", text: "VR관" }, + { val: "MOP026", text: "HDPE관" }, + { val: "MOP027", text: "시멘트라이닝주철관(C)" }, + { val: "MOP028", text: "수도용 PE관(PE)" }, + { val: "MOP029", text: "석면시멘트관(AC)" }, + { val: "MOP030", text: "폴리에틸렌분체라이닝강관(PEP)" }, + { val: "MOP031", text: "에폭시코팅강관(EPS)" }, + { val: "MOP032", text: "HI-3P" }, + { val: "MOP033", text: "철근콘크리트박스(RCB)" }, + { val: "MOP034", text: "콘크리트중선함(CD)" }, + { val: "MOP035", text: "후랙시불전선함(FP)" }, + { val: "MOP036", text: "전선함(FD)" }, + { val: "MOP038", text: "이중보온관" }, + { val: "MOP039", text: "폴리에틸렌피복강관(PLP)" }, + { val: "MOP041", text: "FRP" }, + { val: "MOP042", text: "강재" }, + { val: "MOP999", text: "기타" }, + { val: "MOP800", text: "2중벽PE관" }, + { val: "MOP801", text: "3중벽PE관" }, + { val: "MOP802", text: "가스배관용 강관" }, + { val: "MOP803", text: "강관(피복 Double, 용접접합)" }, + { val: "MOP804", text: "강관(피복 Single, 용접접합)" }, + { val: "MOP805", text: "강관(CP)" }, + { val: "MOP806", text: "강철" }, + { val: "MOP807", text: "강화플라스틱복합관" }, + { val: "MOP808", text: "경질염화비닐관(HI-VP)" }, + { val: "MOP809", text: "고강성PVC이중벽관" }, + { val: "MOP810", text: "고광도PVC이중벽관" }, + { val: "MOP811", text: "고밀도폴리에틸렌관(THP)" }, + { val: "MOP812", text: "고밀도폴리에틸렌파상형이중벽관" }, + { val: "MOP813", text: "공장제 박스관거" }, + { val: "MOP814", text: "관로없음(알케이블)" }, + { val: "MOP815", text: "나선형강관" }, + { val: "MOP816", text: "내충격수도관" }, + { val: "MOP817", text: "내충격용하수도용경질염화비닐관(HI-VG)" }, + { val: "MOP818", text: "내충격HI-VG2관" }, + { val: "MOP819", text: "내충격PVC하수관" }, + { val: "MOP820", text: "녹석(돌산호과 일종)" }, + { val: "MOP821", text: "동관(구리관, 용접)" }, + { val: "MOP822", text: "둥근잔돌" }, + { val: "MOP823", text: "무근콘크리트" }, + { val: "MOP824", text: "백관" }, + { val: "MOP825", text: "복합철판파형관" }, + { val: "MOP826", text: "분체라이닝관" }, + { val: "MOP827", text: "석축박스" }, + { val: "MOP828", text: "석축철콘" }, + { val: "MOP829", text: "수도용경질염화비관" }, + { val: "MOP830", text: "수도용경질염화비닐이음관" }, + { val: "MOP831", text: "수도용엑포시수지분체내외면코팅강관" }, + { val: "MOP832", text: "수지파형강관(PCS)" }, + { val: "MOP833", text: "수지CSP" }, + { val: "MOP834", text: "스테인레스 주름관" }, + { val: "MOP835", text: "스테인레스관(STS)" }, + { val: "MOP836", text: "스테인레스스틸파이프관" }, + { val: "MOP837", text: "아스콘" }, + { val: "MOP838", text: "아스팔트" }, + { val: "MOP839", text: "아스팔트도복장강관(ASP)" }, + { val: "MOP840", text: "아연" }, + { val: "MOP841", text: "아연도금(백관)" }, + { val: "MOP842", text: "알루미늄" }, + { val: "MOP843", text: "알루미늄합금" }, + { val: "MOP844", text: "압력배관용 탄소강관" }, + { val: "MOP845", text: "양철관" }, + { val: "MOP846", text: "양철주름관(CSP)" }, + { val: "MOP847", text: "연합인슈강판" }, + { val: "MOP848", text: "와사관(GSP)" }, + { val: "MOP849", text: "원심력철근콘크리트" }, + { val: "MOP850", text: "유리섬유관(GRP)" }, + { val: "MOP851", text: "유리섬유복합관(GRP)" }, + { val: "MOP852", text: "이음매없는동및동합금관" }, + { val: "MOP853", text: "일반배관용스테인리스강관" }, + { val: "MOP854", text: "전압 콘크리트관" }, + { val: "MOP855", text: "주름관" }, + { val: "MOP856", text: "주름주철파형강관" }, + { val: "MOP857", text: "지중 저압케이블 입상관" }, + { val: "MOP858", text: "진동및전압철근콘크리트관" }, + { val: "MOP859", text: "철근콘크리트" }, + { val: "MOP860", text: "철근콘크리트 블록" }, + { val: "MOP861", text: "철근콘크리트조립흙막이" }, + { val: "MOP862", text: "철판매입관" }, + { val: "MOP863", text: "청동" }, + { val: "MOP864", text: "코아식프리스트레스트콘크리트관" }, + { val: "MOP865", text: "콘크리트" }, + { val: "MOP866", text: "콘크리트 폴륨관" }, + { val: "MOP867", text: "콘크리트블록" }, + { val: "MOP868", text: "탄소강" }, + { val: "MOP869", text: "탄소강(카본스틸)" }, + { val: "MOP870", text: "탄소주강" }, + { val: "MOP871", text: "트러후" }, + { val: "MOP872", text: "파선형강관(RCF)" }, + { val: "MOP873", text: "파형강관(CSP)" }, + { val: "MOP874", text: "파형관" }, + { val: "MOP875", text: "파형플라스틱관" }, + { val: "MOP876", text: "폴리머관" }, + { val: "MOP877", text: "폴리에스테르수지콘크리트관" }, + { val: "MOP878", text: "폴리에틸렌 전선관" }, + { val: "MOP879", text: "폴리에틸렌 피복강관" }, + { val: "MOP880", text: "폴리에틸렌관 1호관" }, + { val: "MOP881", text: "폴리에틸렌관 2호관" }, + { val: "MOP882", text: "폴리에틸렌관(2중벽)" }, + { val: "MOP883", text: "폴리에틸렌관(3중벽)" }, + { val: "MOP884", text: "폴리에틸렌분체라이닝" }, + { val: "MOP885", text: "폴리에틸렌이중벽하수관" }, + { val: "MOP886", text: "폴리탄산에스테르" }, + { val: "MOP887", text: "프리스트레스트콘크리트실린더관" }, + { val: "MOP888", text: "플라스틱" }, + { val: "MOP889", text: "플라스틱주름관" }, + { val: "MOP890", text: "하수도용고강성경질염화비닐이중벽주름관" }, + { val: "MOP891", text: "현장타설관" }, + { val: "MOP892", text: "현장타설철근콘크리트관" }, + { val: "MOP893", text: "흑관" }, + { val: "MOP894", text: "흙" }, + { val: "MOP895", text: "AP" }, + { val: "MOP896", text: "API관" }, + { val: "MOP897", text: "ASP" }, + { val: "MOP898", text: "CMCIP" }, + { val: "MOP899", text: "CSP" }, + { val: "MOP900", text: "DRP" }, + { val: "MOP901", text: "DSP" }, + { val: "MOP902", text: "DTC관" }, + { val: "MOP903", text: "ELP" }, + { val: "MOP904", text: "EPP" }, + { val: "MOP905", text: "FC관" }, + { val: "MOP906", text: "H" }, + { val: "MOP907", text: "H6" }, + { val: "MOP908", text: "HCP" }, + { val: "MOP909", text: "HI_2P관" }, + { val: "MOP910", text: "HI-KP" }, + { val: "MOP911", text: "HL" }, + { val: "MOP912", text: "IP" }, + { val: "MOP913", text: "KCGP" }, + { val: "MOP914", text: "KP관" }, + { val: "MOP915", text: "P2S관" }, + { val: "MOP916", text: "PC박스(PCB)" }, + { val: "MOP917", text: "PCS" }, + { val: "MOP918", text: "PDP" }, + { val: "MOP919", text: "PE이중벽관" }, + { val: "MOP920", text: "PE적측벽1종관" }, + { val: "MOP921", text: "PFP관" }, + { val: "MOP922", text: "PG관" }, + { val: "MOP923", text: "PIP관(이중보온관)" }, + { val: "MOP924", text: "PLCSP" }, + { val: "MOP925", text: "PS" }, + { val: "MOP926", text: "PUB" }, + { val: "MOP927", text: "PVB" }, + { val: "MOP928", text: "PVC이중벽관(PVC2)" }, + { val: "MOP929", text: "PVC-DC" }, + { val: "MOP930", text: "PVC-DV" }, + { val: "MOP931", text: "SBK" }, + { val: "MOP932", text: "SCP" }, + { val: "MOP933", text: "SEB" }, + { val: "MOP934", text: "SIS관(이중보온관)" }, + { val: "MOP935", text: "SMC" }, + { val: "MOP936", text: "STW" }, + { val: "MOP937", text: "SUS" }, + { val: "MOP938", text: "THP나선관" }, + { val: "MOP939", text: "U관" }, + { val: "MOP940", text: "VG2" }, + { val: "MOP941", text: "WSP(와사피)" }, + { val: "MOP942", text: "Steel Grating" }, + { val: "MOP943", text: "모래" }, + { val: "MOP944", text: "인조석" }, + { val: "MOP945", text: "SPOL" }, + { val: "MOP946", text: "PCF관(강판보강 PE 나선형관)" }, + { val: "MOP947", text: "PVC3(PVC3중벽관)" }, + { val: "MOP948", text: "PE다중벽관" }, + { val: "MOP977", text: "전주용입상관" }, + { val: "MOP978", text: "MD관" }, + { val: "그 외", text: "미분류" }, +]; // 하수처리시설 export const SwtrmtFcltCol = [ @@ -306,7 +513,6 @@ export const ExclnSewagePumpCol2 = [ { id: 'exclnWpmpAblt', title: '우수양수능력(m²/d)' }, // { id: 'instMngNo', title: '기관관리번호' }, ] - // 오수펌프장 export const DrtwSewagePumpCol1 = [ // { id: 'fid', title: 'FID' }, @@ -348,6 +554,17 @@ export const DrtwSewagePumpCol2 = [ { id: 'exclnWpmpAblt', title: '오수양수능력(m²/d)' }, // { id: 'instMngNo', title: '기관관리번호' }, ] +// 펌프장 용도 코드표 +export const DRTW_SEWAGE_PUMP_USE_CODES = [ + { val: "SBE000", text: "미분류" }, + { val: "SBE001", text: "빗물펌프장" }, + { val: "SBE002", text: "오수펌프장" }, + { val: "SBE003", text: "처리장내펌프장" }, + { val: "SBE900", text: "오수배제" }, + { val: "SBE901", text: "우수배제" }, + { val: "SBE999", text: "기타" }, + { val: "그 외", text: "미분류" }, +]; // 우수토실 export const stofcbrCol = [ diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/MsSwagePpl.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/MsSwagePpl.tsx index 26b3a60aa..38b0c25d6 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/MsSwagePpl.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/MsSwagePpl.tsx @@ -1,18 +1,18 @@ 'use client' import { VerticalTable } from '@/components/ui/verticalTable'; -import React, { useState } from 'react' +import React, { useState, useEffect } from 'react' import InputSection from '../InputSection'; import { handleInputChange } from '../common'; // 하수관로 const inputColumn = [ - { id: "title", title: "설치주제", type: "select", options: ["BTL", "재정사업"] }, - { id: "swtrmt_zone_cd", title: "처리구역", type: "input" }, - { id: "basu", title: "배수구역", type: "input" }, - { id: "mltv_dtdv_nm", title: "배수분구", type: "input" }, - { id: "wltjs", title: "지선/간선", type: "select", options: ["지선", "간선"] }, - { id: "flow", title: "흐름방식", type: "select", options: ["자연유하", "압송"] }, - { id: "place", title: "매설위치", type: "select", options: ["도로", "하상"] }, + { id: "instlMbdyCd", title: "설치주제", type: "select", options: ["BTL", "재정사업"] }, + { id: "swtrmtZoneCd", title: "처리구역", type: "input" }, + { id: "mltvZoneNm", title: "배수구역", type: "input" }, + { id: "mltvDtdvNm", title: "배수분구", type: "input" }, + { id: "lineCd", title: "지선/간선", type: "select", options: ["지선", "간선"] }, + { id: "floCd", title: "흐름방식", type: "select", options: ["자연유하", "압송"] }, + { id: "layCd", title: "매설위치", type: "select", options: ["도로", "하상"] }, ]; const MsSwagePpl = ({ featureData, onSaveClick }: { featureData: any, onSaveClick?: () => void }) => { @@ -20,29 +20,48 @@ const MsSwagePpl = ({ featureData, onSaveClick }: { featureData: any, onSaveClic { year: "2025", type: "개대체" }, { year: "2025", type: "보수" }, ]); - const [cleaningData, setCleaningData] = useState([ { year: "2025", type: "청소" }, { year: "2025", type: "준설" }, ]); - const [inspectionData, setInspectionData] = useState([ { year: "2025", type: "관로기술진단" }, { year: "2025", type: "관로기술진단" }, ]); - const dataMap = { repair: { data: repairData, setData: setRepairData }, cleaning: { data: cleaningData, setData: setCleaningData }, inspection: { data: inspectionData, setData: setInspectionData }, }; + const [formData, setFormData] = useState({}); + + // featureData가 변경될 때 formData 초기화 + useEffect(() => { + if (featureData) { + setFormData(featureData); + } + }, [featureData]); + + // 폼 데이터가 변경될 때 호출될 핸들러 + const handleFormDataChange = (newFormData: any) => { + setFormData(newFormData); + }; + + // 저장 버튼 클릭 시 최신 formData를 부모에게 전달 + const handleSaveClick = () => { + if (onSaveClick) { + // 저장 전에 formData를 부모 컴포넌트의 handleSaveClick에 전달 + onSaveClick(); + } + }; + return ( <> void }) => { const [isModalOpen, setIsModalOpen] = useState(false); const [isDataLoaded, setIsDataLoaded] = useState(false); + const [formData, setFormData] = useState({}); console.log('featureData data received:', featureData); // 추가 데이터 확인용 console.log('Additional data received:', additionalData); // 추가 데이터 확인용 + const openModal = () => { setIsModalOpen(true); }; + const closeModal = () => { setIsModalOpen(false); if (!isDataLoaded) { @@ -31,11 +34,25 @@ const Ssc = ({ featureData, chkMainSsc, additionalData, onSaveClick }: { } }; - // 데이터 전처리: 합쳐진 필드 추가 - // const preprocessedData = featureData ? [{ - // ...featureData, - // flwmtr_combined: `${featureData.flwmtr_mesure_tp_etc || '-'} / ${featureData.flwmtr_knd || '-'}` - // }] : []; + // featureData가 변경될 때 formData 초기화 + useEffect(() => { + if (featureData) { + setFormData(featureData); + } + }, [featureData]); + + // 폼 데이터가 변경될 때 호출될 핸들러 + const handleFormDataChange = (newFormData: any) => { + setFormData(newFormData); + }; + + // 저장 버튼 클릭 시 최신 formData를 부모에게 전달 + const handleSaveClick = () => { + if (onSaveClick) { + // 저장 전에 formData를 부모 컴포넌트의 handleSaveClick에 전달 + onSaveClick(); + } + }; const renderModalBody = () => (
@@ -100,23 +117,26 @@ const Ssc = ({ featureData, chkMainSsc, additionalData, onSaveClick }: { return (
- + {!isMainSsc && ( + + )} - {chkMainSsc && ( + {isMainSsc && (

중점우수토실 운영정보

diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/sewagePump.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/sewagePump.tsx index f0c4d21b3..0da4ab31e 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/sewagePump.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/sewagePump.tsx @@ -1,22 +1,46 @@ import { VerticalTable } from '@/components/ui/verticalTable'; -import React from 'react' +import React, { useState, useEffect } from 'react' +// 빗물펌프 자체 입력 정보 const exclnInputColumn = [ - { id: "swtrmt_zone_cd", title: "배수구역", type: "input" }, - { id: "mltv_dtdv_nm", title: "배수분구", type: "input" }, - { id: "freq", title: "설계빈도(년)", type: "input" }, + { id: "swtrmtZoneCd", title: "배수구역", type: "input" }, + { id: "mltvDtdvNm", title: "배수분구", type: "input" }, + { id: "dsgnFrqnc", title: "설계빈도(년)", type: "input" }, ] +// 오수펌프 자체 입력 정보 const drtwInputColumn = [ { id: "swtrmt_zone_cd", title: "배수구역", type: "input" }, { id: "mltv_dtdv_nm", title: "배수분구", type: "input" }, ] // 하수펌프장 -const sewagePump = ({ featureData, onSaveClick }: { featureData: any, onSaveClick?: () => void }) => { +const sewagePump = ({ featureData, isDrtwSewagePump, onSaveClick }: { featureData: any, isDrtwSewagePump: boolean, onSaveClick?: () => void }) => { + const [formData, setFormData] = useState({}); + + // featureData가 변경될 때 formData 초기화 + useEffect(() => { + if (featureData) { + setFormData(featureData); + } + }, [featureData]); + + // 폼 데이터가 변경될 때 호출될 핸들러 + const handleFormDataChange = (newFormData: any) => { + setFormData(newFormData); + }; + + // 저장 버튼 클릭 시 최신 formData를 부모에게 전달 + const handleSaveClick = () => { + if (onSaveClick) { + // 저장 전에 formData를 부모 컴포넌트의 handleSaveClick에 전달 + onSaveClick(); + } + }; + return ( ) } diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/smh.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/smh.tsx index 7f2251063..e2a2cc747 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/smh.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/smh.tsx @@ -1,17 +1,39 @@ // 하수맨홀 import { VerticalTable } from '@/components/ui/verticalTable'; -import React from 'react' +import React, { useState, useEffect } from 'react' const inputColumn = [ - { id: "guyeok", title: "처리구역", type: "input" }, - { id: "basu", title: "배수구역", type: "input" }, - { id: "bungu", title: "배수분구", type: "input" }, - { id: "place", title: "매설위치", type: "select", options: ["도로", "하상"] }, + { id: "swtrmtZoneCd", title: "처리구역", type: "input" }, + { id: "mltvZoneNm", title: "배수구역", type: "input" }, + { id: "mltvDtdvNm", title: "배수분구", type: "input" }, + { id: "layCd", title: "매설위치", type: "select", options: ["도로", "하상"] }, ]; const Smh = ({ featureData, onSaveClick }: { featureData: any, onSaveClick?: () => void }) => { + const [formData, setFormData] = useState({}); + + // featureData가 변경될 때 formData 초기화 + useEffect(() => { + if (featureData) { + setFormData(featureData); + } + }, [featureData]); + + // 폼 데이터가 변경될 때 호출될 핸들러 + const handleFormDataChange = (newFormData: any) => { + setFormData(newFormData); + }; + + // 저장 버튼 클릭 시 최신 formData를 부모에게 전달 + const handleSaveClick = () => { + if (onSaveClick) { + // 저장 전에 formData를 부모 컴포넌트의 handleSaveClick에 전달 + onSaveClick(); + } + }; + return ( ) } diff --git a/apps/sn/app/(map-layout)/map/featureClickEventPopup.tsx b/apps/sn/app/(map-layout)/map/featureClickEventPopup.tsx index 72831902f..95cab06c7 100644 --- a/apps/sn/app/(map-layout)/map/featureClickEventPopup.tsx +++ b/apps/sn/app/(map-layout)/map/featureClickEventPopup.tsx @@ -1,15 +1,16 @@ 'use client' -import { getData, putData } from "@/components/lib/api"; +import { getData, postData } from "@/components/lib/api"; import Modal from "@/components/ui/modal"; import { VerticalTable } from "@/components/ui/verticalTable"; import { useGisContext } from "@common/business_components/ui/map/Gis"; import { Button } from "@common/components/ui"; import { useEffect, useRef, useState, useCallback, useMemo } from "react"; import { getLayerContentComponent } from "./components/common"; -import { SwtrmtFcltCol, SwtrmtPrcsZoneCol, untrtSwgRainCol1, untrtSwgRainCol2, MsSwagePplCol, ExclnSewagePumpCol, MsSwageMhlCol, stofcbrCol, MS_SWAGE_MHL_CODES } from "./components/common/table"; +import { SwtrmtFcltCol, SwtrmtPrcsZoneCol, untrtSwgRainCol1, untrtSwgRainCol2, MsSwagePplCol, ExclnSewagePumpCol, MsSwageMhlCol, stofcbrCol, MS_SWAGE_MHL_CODES, DRTW_SEWAGE_PUMP_USE_CODES } from "./components/common/table"; import InfilChart from './components/popupComponent/chart/infilChart'; import RdiiChart from './components/popupComponent/chart/rdiiChart'; import { useInfilChartModalStore, useRdiiChartModalStore } from "./components/popupComponent/chartModalStore"; +import { set } from "react-hook-form"; // TODO: const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => { @@ -23,7 +24,8 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, const [fetchData, setfetchData] = useState(); // api 호출여부 const contentRef = useRef(null); const [isModalOpen, setIsModalOpen] = useState(false); // 모달 열기 상태 - const [chkMainSsc, setChkMainSsc] = useState(false); // 중점우수토실 여부 + const [isMainSsc, setIsMainSsc] = useState(false); // 중점우수토실 여부 + const [isDrtwSewagePump, setIsDrtwSewagePump] = useState(false); // 오수펌프장 여부 const [isLoading, setIsLoading] = useState(false); // 🎯 추가 데이터 로딩 상태 분리 const [isAdditionalDataLoading, setIsAdditionalDataLoading] = useState(false); @@ -54,17 +56,10 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, try { console.log(`추가 데이터 API 호출 시작: v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs`); - // 🎯 타임아웃 설정 (10초) - const timeoutPromise = new Promise((_, reject) => - setTimeout(() => reject(new Error('API 타임아웃')), 10000) - ); + const result = getData(`v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs`); - const apiPromise = getData(`v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs`); - - const response = await Promise.race([apiPromise, timeoutPromise]) as any; - - console.log('추가 데이터 API 호출 성공:', response); - return response?.content || []; + console.log('추가 데이터 API 호출 성공:', result); + return result || []; } catch (error) { console.error('추가 데이터 로딩 실패:', error); setAdditionalDataError(error instanceof Error ? error.message : '알 수 없는 오류'); @@ -106,7 +101,16 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, else if (featureData.lyrTypeNm === 'tb_ms_stofcbr') result = '우수토실'; else if (featureData.lyrTypeNm === 'om_dt_untrt_swg_rain') result = '중점우수토실'; else if (featureData.lyrTypeNm === 'tb_ms_swage_ppl') result = '하수관로'; - else if (featureData.lyrTypeNm === 'tb_ms_swage_pmstn') result = '하수펌프장'; + else if (featureData.lyrTypeNm === 'tb_ms_swage_pmstn') { + const drtwPumpCode = DRTW_SEWAGE_PUMP_USE_CODES.find(code => code.text === '오수펌프장'); + console.log('값 비교', featureData.values_.usg_cd.trim(), drtwPumpCode?.val); + if (drtwPumpCode && featureData.values_.usg_cd.trim() === drtwPumpCode.val) { + setIsDrtwSewagePump(true); + } else { + setIsDrtwSewagePump(false); + } + result = '하수펌프장'; + } else if (featureData.lyrTypeNm === 'tb_ms_swage_mhl') result = '하수맨홀'; } else { @@ -116,7 +120,16 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, else if (lyrTyNm === 'tb_ms_stofcbr') result = '우수토실'; else if (lyrTyNm === 'om_dt_untrt_swg_rain') result = '중점우수토실'; else if (lyrTyNm === 'tb_ms_swage_ppl') result = '하수관로'; - else if (lyrTyNm === 'tb_ms_swage_pmstn') result = '하수펌프장'; + else if (lyrTyNm === 'tb_ms_swage_pmstn') { + const drtwPumpCode = DRTW_SEWAGE_PUMP_USE_CODES.find(code => code.text === '오수펌프장'); + console.log('값 비교', featureData.values_.usg_cd.trim(), drtwPumpCode?.val); + if (drtwPumpCode && featureData.values_.usg_cd.trim() === drtwPumpCode.val) { + setIsDrtwSewagePump(true); + } else { + setIsDrtwSewagePump(false); + } + result = '하수펌프장'; + } else if (lyrTyNm === 'tb_ms_swage_mhl') result = '하수맨홀'; else result = featureLayer.get('lyrNm'); } @@ -170,7 +183,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, setHeadlist(untrtSwgRainCol1) setHeadlist2(untrtSwgRainCol2) setButtonChk(false) - setChkMainSsc(true) + setIsMainSsc(true) setfetchData([processedData]) setTableData(processedData); @@ -188,11 +201,11 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, setMntrngsData(false); }); } - return; + break; case '우수토실': setHeadlist(stofcbrCol) - setButtonChk(false) - setChkMainSsc(false) + setButtonChk(true) + setIsMainSsc(false) break; case '하수관로': setHeadlist(MsSwagePplCol) @@ -215,6 +228,59 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, default: break; } + + // API 엔드포인트 선택 + let apiEndpoint = ''; + let getFeatureId = featureId.toString().split('.').pop() || null; + if (selectedLayerName === '하수관로') apiEndpoint = `v1/fcltppl/${getFeatureId}`; + else if (selectedLayerName === '우수토실') apiEndpoint = `v1/fcltstofcbr/${getFeatureId}`; + else if (selectedLayerName === '오수펌프' || selectedLayerName === '빗물펌프') apiEndpoint = `v1/fcltpump/${getFeatureId}`; + else if (selectedLayerName === '하수맨홀') apiEndpoint = `v1/fcltmhl/${getFeatureId}`; + + // API에서 상세 데이터 가져오기 + if (apiEndpoint) { + try { + console.log(`API 호출: ${apiEndpoint}`); + const result = await getData(apiEndpoint); + + if (result) { + console.log('API 데이터 로드 성공:', result); + + // 하수맨홀인 경우 용도코드를 텍스트로 변환 + if (selectedLayerName === '하수맨홀') { + const processedData = { ...result }; + + // mqlt_cd 값 변환 (재질코드) + if (processedData.mqlt_cd) { + const materialCodeItem = MS_SWAGE_MHL_CODES.find( + code => code.val === processedData.mqlt_cd.trim() + ); + if (materialCodeItem) { + processedData.mqlt_cd = `${materialCodeItem.text}`; + } + } + + setfetchData(processedData); + } // 🎯 우수토실인 경우 prrtymngYn 값 변환 + else if (selectedLayerName === '우수토실' && data) { + const processedData = { ...result, ...data }; + + // prrtymngYn 값 변환 + if (processedData.prrtymngYn === 'Y') processedData.prrtymngYn = '중점우수토실'; + else if (processedData.prrtymngYn === 'N') processedData.prrtymngYn = '우수토실'; + + console.log('processedData', processedData); + + setfetchData(processedData); + } else { + setfetchData(result); + } + } + } catch (apiError) { + console.error('API 데이터 로딩 중 오류:', apiError); + } + } + console.log('mntrngsData', mntrngsData); } catch (error) { console.error('데이터 로딩 중 오류:', error); } @@ -275,27 +341,50 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, bodyData[camelCaseId] = select.value; }); - // input 태그의 값 가져오기 + // // input 태그의 값 가져오기 inputElements.forEach((input) => { const camelCaseId = toCamelCase(input.id); bodyData[camelCaseId] = input.value; }); - if (layerNm === '하수관로') bodyData['lyrTypeNm'] = 'tb_ms_swage_ppl' - else if (layerNm === '우수토실') bodyData['lyrTypeNm'] = 'tb_ms_stofcbr' - else if (layerNm === '중점우수토실') bodyData['lyrTypeNm'] = 'om_dt_untrt_swg_rain' - else if (layerNm === '오수펌프') bodyData['lyrTypeNm'] = 'tb_ms_swage_pmstn' - else if (layerNm === '빗물펌프') bodyData['lyrTypeNm'] = 'tb_ms_swage_pmstn' - else if (layerNm === '하수맨홀') bodyData['lyrTypeNm'] = 'tb_ms_swage_mnhl' + // 레이어명에 따라 API 엔드포인트 분기처리 + let apiEndpoint = ''; + let result = null; - bodyData['fid'] = featureId + if (layerNm === '하수관로') apiEndpoint = 'v1/fcltppl'; + else if (layerNm === '우수토실') apiEndpoint = 'v1/fcltstofcbr'; + else if (layerNm === '하수펌프장') apiEndpoint = 'v1/fcltpump'; + else if (layerNm === '하수맨홀') apiEndpoint = 'v1/fcltmhl'; - const data = await putData(`v1/fclts/${featureId}`, bodyData); + bodyData['fid'] = featureId.toString().split('.').pop() || null; + // 빈 키 제거 + if (bodyData[""] !== undefined) delete bodyData[""]; - if (data.status == 200) { - alert('저장되었습니다') - setTableData(data) - setfetchData(data) + // 🎯 우수토실일 경우 prrtymngYn 값 변환 + if (layerNm === '우수토실' && bodyData.prrtymngYn) { + if (bodyData.prrtymngYn === '중점우수토실') { + bodyData.prrtymngYn = 'Y'; + } else if (bodyData.prrtymngYn === '우수토실') { + bodyData.prrtymngYn = 'N'; + } + } + console.log('bodyData', bodyData); + console.log('apiEndpoint', apiEndpoint); + + try { + result = await postData(apiEndpoint, bodyData); + console.log('result', result); + + if (result) { + alert('저장되었습니다'); + setfetchData(result.data || result); + } else { + alert('저장에 실패했습니다'); + console.error('API 응답 오류:', result); + } + } catch (error) { + alert('저장 중 오류가 발생했습니다'); + console.error('API 요청 오류:', error); } } } @@ -363,7 +452,8 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, {ContentComponent && diff --git a/apps/sn/app/components/lib/api/index.ts b/apps/sn/app/components/lib/api/index.ts index e4a750ff3..55d111074 100644 --- a/apps/sn/app/components/lib/api/index.ts +++ b/apps/sn/app/components/lib/api/index.ts @@ -9,6 +9,8 @@ export const postData = async (url: string, data: object): Promise => { body: JSON.stringify(data), }; const res = await fetch(`${BASE_URL}/${url}`, options); + console.log('res', res); + console.log('res.status', res.status); if (res.ok) { const resData = await res.json(); return resData; diff --git a/apps/sn/app/components/ui/verticalTable.tsx b/apps/sn/app/components/ui/verticalTable.tsx index 19e302c30..2f8143409 100644 --- a/apps/sn/app/components/ui/verticalTable.tsx +++ b/apps/sn/app/components/ui/verticalTable.tsx @@ -29,6 +29,7 @@ type UiTableProps = { showSecondTable?: boolean; showSaveButton?: boolean; onSaveClick?: () => void; + onFormDataChange?: (formData: { [key: string]: string | number | boolean }) => void; // 추가 }; type UiHeadProps = { @@ -66,6 +67,7 @@ export function VerticalTable({ showSecondTable = false, showSaveButton = false, onSaveClick, + onFormDataChange, }: UiTableProps) { const [cur, setCur] = useState(1); const [formData, setFormData] = useState<{ [key: string]: string | number | boolean }>({}); @@ -78,17 +80,27 @@ export function VerticalTable({ useEffect(() => { if (tableData.length > 0 && tableData[0]) { - setFormData(tableData[0] as { [key: string]: string | number | boolean }); + // 깊은 복사를 통해 새로운 객체 생성 + const newData = JSON.parse(JSON.stringify(tableData[0])); + setFormData(newData); + console.log("Form data initialized:", newData); // 디버깅용 } }, [tableData]); const handleInputChange = (id: string, value: string | number | boolean) => { - setFormData((prev) => ({ - ...prev, + console.log(`Input change: ${id} = ${value}`); // 디버깅용 + const newFormData = { + ...formData, [id]: value, - })); - }; + }; + console.log("New form data:", newFormData); // 디버깅용 + setFormData(newFormData); + // 폼 데이터가 변경될 때마다 부모에게 알림 + if (onFormDataChange) { + onFormDataChange(newFormData); + } + }; const handlePageChange = (page: number) => { setCur(page); onPageChange(page); @@ -100,8 +112,8 @@ export function VerticalTable({

{headName}

{showSaveButton && onSaveClick && ( -