From 2f553a0dffd15dfe38e30586b96f4e724cd6655f Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 09:44:09 +0900 Subject: [PATCH 01/13] =?UTF-8?q?fix:=20searchModal.tsx=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=ED=97=A4=EB=8D=94=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A4=84=20=EB=B0=94=EA=BF=88=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/components/common/table.ts | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) 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 84de2b4ab..0cfc261a2 100644 --- a/apps/sn/app/(map-layout)/map/components/common/table.ts +++ b/apps/sn/app/(map-layout)/map/components/common/table.ts @@ -28,20 +28,20 @@ export const MsSwagePplCol = [ // { id: 'lyrTypeNm', title: '레이어타입명' }, ] export const MsSwagePplCol2 = [ - { id: 'rowNumber', title: '일련번호' }, - { id: 'fcltMngNo', title: '시설 관리번호' }, - { id: 'instMngNo', title: '기관 관리번호' }, + { id: 'rowNumber', title: '일련\n번호' }, + { id: 'fcltMngNo', title: '시설\n관리번호' }, + { id: 'instMngNo', title: '기관\n관리번호' }, { id: 'instlYmd', title: '설치일자' }, // { id: 'mapshtNo', title: '도엽번호' }, - { id: 'pdmt', title: '관경(mm)' }, - { id: 'prlg', title: '연장(m)' }, - { id: 'avgGrdn', title: '평균구배(m/m)' }, - { id: 'tmptDpth', title: '시점깊이(m)' }, - { id: 'tmptMhlMngNo', title: '시점맨홀 관리번호' }, - { id: 'scendDpth', title: '종점깊이(m)' }, - { id: 'scendMhlMngNo', title: '종점맨홀 관리번호' }, - { id: 'vrtcLen', title: '세로길이(m)' }, - { id: 'wdthLen', title: '가로길이(m)' }, + { id: 'pdmt', title: '관경\n(mm)' }, + { id: 'prlg', title: '연장\n(m)' }, + { id: 'avgGrdn', title: '평균구배\n(m/m)' }, + { id: 'tmptDpth', title: '시점깊이\n(m)' }, + { id: 'tmptMhlMngNo', title: '시점맨홀\n관리번호' }, + { id: 'scendDpth', title: '종점깊이\n(m)' }, + { id: 'scendMhlMngNo', title: '종점맨홀\n관리번호' }, + { id: 'vrtcLen', title: '세로길이\n(m)' }, + { id: 'wdthLen', title: '가로길이\n(m)' }, // { id: 'fcltyShpCd', title: '시설물형태코드' }, // { id: 'fid', title: 'FID' }, // { id: 'ftreSmbolCd', title: '지형지물부호코드' }, @@ -297,10 +297,10 @@ export const SwtrmtFcltCol = [ // { id: 'obsrvnSptCd', title: '관측지점코드' }, ]; export const SwtrmtFcltCol2 = [ - { id: 'rowNumber', title: '일련번호' }, - { id: 'swtrmtFcltNm', title: '하수처리시설명' }, - { id: 'fcltCpct', title: '시설용량(㎥/d)' }, - { id: 'rgnExpln', title: '지역설명' }, + { id: 'rowNumber', title: '일련\n번호' }, + { id: 'swtrmtFcltNm', title: '하수\n처리\n시설명' }, + { id: 'fcltCpct', title: '시설\n용량\n(㎥/d)' }, + { id: 'rgnExpln', title: '지역\n설명' }, // { id: 'cmcnYmd', title: '준공일자' }, { id: 'oprtngStrtYmd', title: '가동개시일자' }, // { id: 'clsgYmd', title: '폐쇄일자' }, @@ -320,12 +320,12 @@ export const SwtrmtFcltCol2 = [ { id: 'dschgWtstNm', title: '방류수계명' }, // { id: 'pllnArea', title: '부지면적(m²)' }, // { id: 'mngRprtvBzentyNm', title: '관리대행업체명' }, - { id: 'swtrmtPpltnCnt', title: '하수처리인구수(인)' }, + { id: 'swtrmtPpltnCnt', title: '하수\n처리\n인구수\n(인)' }, // { id: 'prcsZoneAreaSum', title: '처리구역면적합계(m²)' }, // { id: 'xcrd', title: 'X좌표' }, // { id: 'ycrd', title: 'Y좌표' }, // { id: 'oprtngSttsCd', title: '가동상태코드' }, - { id: 'rprsMsrcCn', title: '대표공법내용' }, + { id: 'rprsMsrcCn', title: '대표\n공법\n내용' }, // { id: 'sttyCrtrBod', title: '법정기준생물화학적산소요구량(mg/L)' }, // { id: 'sttyCrtrToc', title: '법정기준TOC(mg/L)' }, // { id: 'sttyCrtrSs', title: '법정기준SS(mg/L)' }, From fcfaa23dc398f13614057c587c978da93a457f4e Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 15:35:45 +0900 Subject: [PATCH 02/13] =?UTF-8?q?fix:=20=EA=B2=80=EC=83=89=20=EC=B0=BD=20?= =?UTF-8?q?=EC=9C=84=20=EC=95=84=EB=9E=98=20=EA=B0=84=EA=B2=A9=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx | 2 +- apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx | 2 +- apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx index 310528aed..b91271251 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx @@ -78,7 +78,7 @@ const BasicTab: React.FC = ({ setVar2, }) => { return ( -
+
{/* 구분 */}
diff --git a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx index 5f24c65fa..9a46e2bf8 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx @@ -111,7 +111,7 @@ const OperationTab: React.FC = ({ setYearFilter, }) => { return ( -
+
= ({ open }) => { return ( <> -
+
Date: Wed, 30 Jul 2025 15:42:47 +0900 Subject: [PATCH 03/13] =?UTF-8?q?fix:=20searchModal.tsx=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=ED=97=A4=EB=8D=94=20=EC=A4=84=20=EB=B0=94?= =?UTF-8?q?=EA=BF=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/(map-layout)/map/components/common/table.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 0cfc261a2..51ef93ddf 100644 --- a/apps/sn/app/(map-layout)/map/components/common/table.ts +++ b/apps/sn/app/(map-layout)/map/components/common/table.ts @@ -298,9 +298,9 @@ export const SwtrmtFcltCol = [ ]; export const SwtrmtFcltCol2 = [ { id: 'rowNumber', title: '일련\n번호' }, - { id: 'swtrmtFcltNm', title: '하수\n처리\n시설명' }, + { id: 'swtrmtFcltNm', title: '하수처리\n시설명' }, { id: 'fcltCpct', title: '시설\n용량\n(㎥/d)' }, - { id: 'rgnExpln', title: '지역\n설명' }, + { id: 'rgnExpln', title: '지역설명' }, // { id: 'cmcnYmd', title: '준공일자' }, { id: 'oprtngStrtYmd', title: '가동개시일자' }, // { id: 'clsgYmd', title: '폐쇄일자' }, @@ -311,7 +311,7 @@ export const SwtrmtFcltCol2 = [ // { id: 'sggNm', title: '시군구명' }, // { id: 'sareaCd', title: '권역코드' }, { id: 'sareaNm', title: '권역명' }, - { id: 'lrgeSareaNm', title: '대권역명' }, + // { id: 'lrgeSareaNm', title: '대권역명' }, { id: 'rvrNm', title: '하천명' }, // { id: 'addr', title: '주소' }, // { id: 'dtlAddr', title: '상세주소' }, @@ -332,7 +332,7 @@ export const SwtrmtFcltCol2 = [ // { id: 'sttyCrtrTn', title: '법정기준총질소(mg/L)' }, // { id: 'sttyCrtrTph', title: '법정기준총인(mg/L)' }, // { id: 'sttyCrtrClbclCnt', title: '법정기준대장균수(군수/100mL)' }, - { id: 'bsnNm', title: '유역명' }, + // { id: 'bsnNm', title: '유역명' }, // { id: 'obsrvnSptCd', title: '관측지점코드' }, ]; @@ -353,9 +353,9 @@ export const SwtrmtPrcsZoneCol2 = [ { id: 'swtrmtZoneNm', title: '하수처리구역명' }, // { id: 'swtrmt_fclt_cd', title: '하수처리시설코드' }, // { id: 'ctpv_cd', title: '시도코드' }, - { id: 'ctpvNm', title: '시도명' }, + { id: 'ctpvNm', title: '시도' }, // { id: 'sgg_cd', title: '시군구코드' }, - { id: 'sggNm', title: '시군구명' }, + { id: 'sggNm', title: '시군구' }, { id: 'swtrmtFcltNm', title: '하수처리시설명' }, ]; From c89c588487632650abb4e7be3c53a08fab4e12ab Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 16:25:09 +0900 Subject: [PATCH 04/13] =?UTF-8?q?fix:=20=EC=8B=9C=EB=8F=84,=20=EC=8B=9C?= =?UTF-8?q?=EA=B5=B0=EA=B5=AC=20=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20->?= =?UTF-8?q?=20=EC=95=8C=EC=97=90=EC=8A=A4=EC=9B=90=20API=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(=EC=9D=B4=ED=9B=84=20Store=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=ED=95=84=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ui/SidoSigunguSelectBox.tsx | 81 +++++++++++++++---- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx index 00f8f1dbb..e32875d42 100644 --- a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx +++ b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx @@ -1,6 +1,7 @@ -import React, { useMemo } from "react"; +import React, { useState, useMemo, useEffect } from "react"; import { SelectBox } from '@common/business_components/ui' import { Label } from '@common/components'; +import { getGeoData } from '@/components/lib/api'; interface Option { id: number; @@ -15,19 +16,19 @@ interface SidoSigunguSelectBoxProps { className?: string; } -const sidoList: { id: number, name: string }[] = [ - { id: 0, name: '전체' }, - { id: 26, name: '부산광역시' }, - { id: 28, name: '인천광역시' }, - { id: 30, name: '대전광역시' }, - { id: 41, name: '경기도' }, - { id: 42, name: '강원도' }, - { id: 44, name: '충청남도' }, - { id: 45, name: '전라북도' }, - { id: 46, name: '전라남도' }, - { id: 47, name: '경상북도' }, - { id: 48, name: '경상남도' }, -]; +// const sidoList: { id: number, name: string }[] = [ +// { id: 0, name: '전체' }, +// { id: 26, name: '부산광역시' }, +// { id: 28, name: '인천광역시' }, +// { id: 30, name: '대전광역시' }, +// { id: 41, name: '경기도' }, +// { id: 42, name: '강원도' }, +// { id: 44, name: '충청남도' }, +// { id: 45, name: '전라북도' }, +// { id: 46, name: '전라남도' }, +// { id: 47, name: '경상북도' }, +// { id: 48, name: '경상남도' }, +// ]; const sigunguMap: Record = { 26: [ { id: 0, name: '전체' }, @@ -134,9 +135,47 @@ export function SidoSigunguSelectBox({ onSigunguChange, className = "", }: SidoSigunguSelectBoxProps) { + + const [ctpvList, setCtpvList] = useState([]); + const [sggList, setSggList] = useState([]); + // 선택된 시도에 따라 시군구 리스트를 가져옴 + const fetchCtpvData = useMemo(() => ( + async () => { + const ctpvData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_ctpv&outputFormat=application%2Fjson'); + const ctpvList: Option[] = ctpvData.features + .map((feature: any) => ({ + id: feature.properties.mctpv_cd.trim(), + name: feature.properties.mctpv_korn_nm + })) + .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬 + setCtpvList(ctpvList); + } + ), []); + + // 선택된 시도에 따라 시군구 리스트를 가져옴 + const fetchSggData = useMemo(() => ( + async () => { + const sggData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_sgg&outputFormat=application%2Fjson'); + const sggList: Option[] = sggData.features + .map((feature: any) => ({ id: feature.properties.sgg_cd, name: feature.properties.sgg_korn_nm })) + .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬 + setSggList(sggList); + } + ), []); + + useEffect(() => { + (async () => { + await fetchCtpvData(); + await fetchSggData(); + onSidoChange(0); + onSigunguChange(0); + })(); + }, []); + const sigunguList = useMemo(() => sigunguMap[sido] || [{ id: 0, name: '전체' }], [sido]); + return (
@@ -144,7 +183,11 @@ export function SidoSigunguSelectBox({ className="w-60 mr-8" selectClass="rounded-lg bg-white" label="" - selectArray={sidoList.map(opt => ({ val: opt.id, text: opt.name }))} + selectArray={ + [{ val: 0, text: '전체' }, + ...ctpvList.map(opt => ({ val: opt.id, text: opt.name })) + ] + } value={sido} onSelectValue={val => onSidoChange(Number(val))} selectContentClass="z-[101]" @@ -154,7 +197,13 @@ export function SidoSigunguSelectBox({ className="w-48" selectClass="w-48 rounded-lg bg-white truncate" label="" - selectArray={sigunguList.map(opt => ({ val: opt.id, text: opt.name }))} + selectArray={ + [{ val: 0, text: '전체' }, + ...sggList + .filter(opt => String(opt.id).slice(0, 2) === String(sido)) + .map(opt => ({ val: opt.id, text: opt.name })) + ] + } value={sigungu} onSelectValue={val => onSigunguChange(Number(val))} selectContentClass="z-[101]" From a05b0e1cfebfedd21475105bc6ff028b36692d09 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 16:33:31 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat,=20remove:=20-=20GeoServer=20API=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?-=20=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20=EC=8B=9C=EB=8F=84,?= =?UTF-8?q?=20=EC=8B=9C=EA=B5=B0=EA=B5=AC=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/components/lib/api/index.ts | 16 ++- .../components/ui/SidoSigunguSelectBox.tsx | 112 ------------------ 2 files changed, 14 insertions(+), 114 deletions(-) diff --git a/apps/sn/app/components/lib/api/index.ts b/apps/sn/app/components/lib/api/index.ts index ab8936329..6574567ad 100644 --- a/apps/sn/app/components/lib/api/index.ts +++ b/apps/sn/app/components/lib/api/index.ts @@ -85,7 +85,7 @@ export const deleteData = async (url: string, data?: object): Promise => { return res; }; -// RSONE DC API 호출 +// DC API 호출 export const getDcData = async (url: string, data?: object): Promise => { const res = await fetch('/dc-service' + url, { method: "GET", @@ -97,7 +97,7 @@ export const getDcData = async (url: string, data?: object): Promise => { throw new Error('Failed to fetch data'); }; -// RSONE DC API 호출 +// CMS API 호출 export const getCmsData = async (url: string, data?: object): Promise => { console.log(url); const res = await fetch('/cms-service' + url, { @@ -110,6 +110,18 @@ export const getCmsData = async (url: string, data?: object): Promise => { throw new Error('Failed to fetch data'); }; +// GeoServer API 호출 +export const getGeoData = async (url: string, data?: object): Promise => { + const res = await fetch('/geoserver' + url, { + method: "GET", + }); + if (res.ok) { + const data = await res.json(); + return data; + } + throw new Error('Failed to fetch data'); +}; + export function getCookie(name: string) { const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); if (match && match[2]) { diff --git a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx index e32875d42..d27da3791 100644 --- a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx +++ b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx @@ -16,118 +16,6 @@ interface SidoSigunguSelectBoxProps { className?: string; } -// const sidoList: { id: number, name: string }[] = [ -// { id: 0, name: '전체' }, -// { id: 26, name: '부산광역시' }, -// { id: 28, name: '인천광역시' }, -// { id: 30, name: '대전광역시' }, -// { id: 41, name: '경기도' }, -// { id: 42, name: '강원도' }, -// { id: 44, name: '충청남도' }, -// { id: 45, name: '전라북도' }, -// { id: 46, name: '전라남도' }, -// { id: 47, name: '경상북도' }, -// { id: 48, name: '경상남도' }, -// ]; -const sigunguMap: Record = { - 26: [ - { id: 0, name: '전체' }, - // ...부산산광역시의 시군구 추가 - ], - 28: [ - { id: 0, name: '전체' }, - // ...인천광역시의 시군구 추가 - ], - 30: [ - { id: 0, name: '전체' }, - // ...대전광역시의 시군구 추가 - ], - 41: [ - { id: 0, name: '전체' }, - { id: 41820, name: '가평군' }, - { id: 41550, name: '안성시' }, - { id: 41830, name: '양평군' }, - { id: 41670, name: '여주시' }, - { id: 41500, name: '이천시' }, - { id: 41430, name: '의왕시' }, - { id: 41150, name: '의정부시' }, - { id: 41480, name: '파주시' }, - { id: 41650, name: '포천시' }, - // ...경기도의 시군구 추가 - ], - 42: [ - { id: 0, name: '전체' }, - { id: 42170, name: '동해시' }, - { id: 42110, name: '춘천시' }, - { id: 42720, name: '홍천군' }, - // ...강원도의 시군구 추가 - ], - 44: [ - { id: 0, name: '전체' }, - { id: 44770, name: '서천군' }, - // ...충청남도의 시군구 추가 - ], - 45: [ - { id: 0, name: '전체' }, - { id: 45130, name: '군산시' }, - { id: 45190, name: '남원시' }, - { id: 45730, name: '무주군' }, - { id: 45800, name: '부안군' }, - { id: 45770, name: '순창군' }, - { id: 45140, name: '익산시' }, - { id: 45750, name: '임실군' }, - { id: 45710, name: '완주군' }, - { id: 45110, name: '전주시' }, - // ...전라북도의 시군구 추가 - ], - 46: [ - { id: 0, name: '전체' }, - { id: 46810, name: "강진군" }, - { id: 46770, name: "고흥군" }, - { id: 46720, name: "곡성군" }, - { id: 46730, name: "구례군" }, - { id: 46230, name: "광양시" }, - { id: 46170, name: "나주시" }, - { id: 46110, name: "목포시" }, - { id: 46840, name: "무안군" }, - { id: 46150, name: "순천시" }, - { id: 46910, name: "신안군" }, - { id: 46130, name: "여수시" }, - { id: 46890, name: "완도군" }, - // ...전라남도의 시군구 추가 - ], - 47: [ - { id: 0, name: '전체' }, - { id: 47130, name: "경주시" }, - { id: 47830, name: "고령군" }, - { id: 47190, name: "구미시" }, - { id: 47720, name: "군위군" }, - { id: 47150, name: "김천시" }, - { id: 47280, name: "문경시" }, - { id: 47920, name: "봉화군" }, - { id: 47250, name: "상주시" }, - { id: 47770, name: "영덕군" }, - { id: 47760, name: "영양군" }, - { id: 47210, name: "영주시" }, - { id: 47900, name: "예천군" }, - { id: 47930, name: "울진군" }, - { id: 47730, name: "의성군" }, - { id: 47750, name: "청송군" }, - { id: 47850, name: "칠곡군" }, - { id: 47110, name: "포항시" }, - // ...경상북도의 시군구 추가 - ], - 48: [ - { id: 0, name: '전체' }, - { id: 48310, name: "거제시" }, - { id: 48250, name: "김해시" }, - { id: 48270, name: "밀양시" }, - { id: 48220, name: "통영시" }, - // ...경상남도의 시군구 추가 - ], - // ...나머지 시도별 시군구 추가 -}; - export function SidoSigunguSelectBox({ sido, sigungu, From 5cc86d81f1aa3675725a8a83885b3cc65912f7f3 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 16:35:11 +0900 Subject: [PATCH 06/13] =?UTF-8?q?refactor:=20featureClickEventPopup.tsx=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(popupComponent=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=EB=A1=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../featureClickEventPopup.tsx | 104 +++--------------- 1 file changed, 14 insertions(+), 90 deletions(-) rename apps/sn/app/(map-layout)/map/{ => components/popupComponent}/featureClickEventPopup.tsx (84%) diff --git a/apps/sn/app/(map-layout)/map/featureClickEventPopup.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx similarity index 84% rename from apps/sn/app/(map-layout)/map/featureClickEventPopup.tsx rename to apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx index e9a4f9e9a..679122d6b 100644 --- a/apps/sn/app/(map-layout)/map/featureClickEventPopup.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx @@ -5,13 +5,13 @@ 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, SwtrmtFcltCol2, SwtrmtPrcsZoneCol, SwtrmtPrcsZoneCol2, untrtSwgRainCol1, untrtSwgRainCol2, MsSwagePplCol, MsSwagePplCol2, ExclnSewagePumpCol, ExclnSewagePumpCol2, DrtwSewagePumpCol, DrtwSewagePumpCol2, MsSwageMhlCol, MsSwageMhlCol2, stofcbrCol, stofcbrCol2, 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 { getLayerContentComponent } from "../common"; +import { SwtrmtFcltCol, SwtrmtFcltCol2, SwtrmtPrcsZoneCol, SwtrmtPrcsZoneCol2, untrtSwgRainCol1, untrtSwgRainCol2, MsSwagePplCol, MsSwagePplCol2, ExclnSewagePumpCol, ExclnSewagePumpCol2, DrtwSewagePumpCol, DrtwSewagePumpCol2, MsSwageMhlCol, MsSwageMhlCol2, stofcbrCol, stofcbrCol2, MS_SWAGE_MHL_CODES, DRTW_SEWAGE_PUMP_USE_CODES } from "../common/table"; +import InfilChart from './chart/infilChart'; +import RdiiChart from './chart/rdiiChart'; +import { useInfilChartModalStore, useRdiiChartModalStore } from "./chartModalStore"; import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue'; -import { codeMapper } from "./components/common/codeMapper"; +import { codeMapper } from "../common/codeMapper"; import { searchUpperPpls } from '@common/business_components/ui/map/Gis'; import LoadingOverlay from '@/components/ui/LoadingBar'; @@ -33,9 +33,10 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, // 🎯 InfilChart 및 RdiiChart 관련 상태 추가 const { setIsOpen: setIsModalInfil } = useInfilChartModalStore(); const { setIsOpen: setIsModalRdii } = useRdiiChartModalStore(); - const [curPage, setCurPage] = useState(1); // 현재 페이지 상태 const [isClicked, setIsClicked] = useState(true); // 클릭 여부 상태 const [isLoading, setIsLoading] = useState(false); // 로딩 상태 + const [chmbrXcnts, setChmbrXcnts] = useState(); // 로딩 상태 + const [chmbrYdnts, setChmbrYdnts] = useState(); // 로딩 상태 // 🎯 관로관리번호 추출 const pplMngNo = featureData?.values_?.fclt_mng_no || ""; @@ -263,18 +264,9 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, data: { ...processedFormattedData } })); - // 강우/측정 정보 데이터 호출 - if (tableData?.chmbr_xcnts && tableData?.chmbr_ydnts) { - fetchRainMeasureData(tableData.chmbr_xcnts, tableData.chmbr_ydnts) - .then(response => { - console.log('additionalResponse', response); - setRainMeasureData(response || []); - }) - .catch(error => { - console.error('추가 데이터 로딩 실패:', error); - setRainMeasureData([]); - }); - } + setChmbrXcnts(data.chmbr_xcnts); + setChmbrYdnts(data.chmbr_ydnts); + break; default: break; @@ -317,76 +309,6 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, fetchData(); }, [featureId, processedData]); - // 🎯 추가 데이터 API 호출 함수 - const fetchRainMeasureData = useCallback(async (chmbrXcnts: string, chmbrYdnts: string) => { - if (!chmbrXcnts || !chmbrYdnts) { - console.warn('추가 데이터 호출 실패: 필수 매개변수 누락', { chmbrXcnts, chmbrYdnts }); - return []; - } - - try { - const queryParams = new URLSearchParams({ - chmbrXcnts: chmbrXcnts, - chmbrYdnts: chmbrYdnts, - pageable: `{}`, - }); - - console.log(`추가 데이터 API 호출 시작: v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`); - - const result = await getData(`v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`); - - console.log('추가 데이터 API 호출 성공:', result); - - // 🎯 result가 페이지네이션 객체인 경우 content 배열 추출 - let dataArray: any[] = []; - if (result && typeof result === 'object' && 'content' in result && Array.isArray(result.content)) { - dataArray = result.content; - } else if (Array.isArray(result)) { - dataArray = result; - } else { - console.warn('예상치 못한 API 응답 형식:', result); - return []; - } - - // 🎯 각 아이템을 전처리하여 반환 - const processedDataArray = dataArray.map((data: any) => { - // 🎯 formatDisplayData로 기본 포맷팅 적용 - const formattedItem = formatDisplayData(data); - - // 🎯 추가 데이터 조합 - return { - ...formattedItem, - flwmtrCombined: `${data.flwmtrMesureTpEtc || '-'} / ${data.flwmtrKnd || '-'}`, - }; - }); - - return processedDataArray; - } catch (error) { - console.error('추가 데이터 로딩 실패:', error); - return []; - } - }, []); - - // 🎯 추가 데이터는 별도 useEffect로 비동기 로딩 - useEffect(() => { - if (layerNm === '중점우수토실' && featureData?.values_) { - const data = featureData.values_; - - if (data?.chmbr_xcnts && data?.chmbr_ydnts) { - // 🎯 추가 데이터를 비동기로 로딩 (UI 블로킹 없음) - fetchRainMeasureData(data.chmbr_xcnts, data.chmbr_ydnts) - .then(response => { - console.log('추가 데이터 로딩 완료:', response); - setRainMeasureData(response || []); - }) - .catch(error => { - console.error('추가 데이터 최종 로딩 실패:', error); - setRainMeasureData([]); - }); - } - } - }, [layerNm, featureData?.values_, fetchRainMeasureData]); - // 저장 시 모달 띄우기 const handleSaveClick = () => { setIsModalOpen(true); // 모달 열기 @@ -555,8 +477,10 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData={fetchData} isMainSsc={isMainSsc} isDrtwSewagePump={isDrtwSewagePump} - rainMeasureData={rainMeasureData} + // rainMeasureData={rainMeasureData} onSaveClick={handleSaveClick} + chmbrXcnts={chmbrXcnts} + chmbrYdnts={chmbrYdnts} /> }
From 340814439a123249f8355dce47219341a59ede98 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 16:44:11 +0900 Subject: [PATCH 07/13] =?UTF-8?q?fix,=20remove:=20-=20featureClickEventPop?= =?UTF-8?q?up.tsx=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95=20-=20?= =?UTF-8?q?=EC=9D=B4=EC=A0=84=20=EC=8B=9C=EB=8F=84,=20=EC=8B=9C=EA=B5=B0?= =?UTF-8?q?=EA=B5=AC=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/page.tsx | 2 +- apps/sn/app/components/ui/SidoSigunguSelectBox.tsx | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/page.tsx b/apps/sn/app/(map-layout)/map/page.tsx index 2dbbcdd1a..b2ed8ecd2 100644 --- a/apps/sn/app/(map-layout)/map/page.tsx +++ b/apps/sn/app/(map-layout)/map/page.tsx @@ -5,7 +5,7 @@ import { getData } from "../../components/lib/api"; import { useCallback, useEffect, useRef, useState } from "react"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; import SearchModal from "./searchModal/searchModal"; -import FeatureClickEventPopup from "./featureClickEventPopup"; +import FeatureClickEventPopup from "./components/popupComponent/featureClickEventPopup"; // 타입 정의 추가 export type LyrStngProps = { diff --git a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx index d27da3791..86e144073 100644 --- a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx +++ b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx @@ -61,8 +61,6 @@ export function SidoSigunguSelectBox({ })(); }, []); - const sigunguList = useMemo(() => sigunguMap[sido] || [{ id: 0, name: '전체' }], [sido]); - return (
From bbfd7fd201af0e564b566f01390152a27e69c9a0 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 17:00:15 +0900 Subject: [PATCH 08/13] =?UTF-8?q?fix:=20=EC=97=B0=EC=9B=94=20=ED=8F=AC?= =?UTF-8?q?=EB=A7=B7=20=EC=88=98=EC=A0=95=20(=EB=85=84=EC=9B=94=EC=9D=BC?= =?UTF-8?q?=20->=20-=EB=A1=9C=20=EA=B5=AC=EB=B6=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/components/lib/utils/date.ts | 8 +++++--- apps/sn/app/components/lib/utils/formatDisplayValue.tsx | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/sn/app/components/lib/utils/date.ts b/apps/sn/app/components/lib/utils/date.ts index a401ad738..30bea45a0 100644 --- a/apps/sn/app/components/lib/utils/date.ts +++ b/apps/sn/app/components/lib/utils/date.ts @@ -103,8 +103,10 @@ export const formatDateString = (dateStr: string): string => { } const year = cleanStr.substring(0, 4); - const month = parseInt(cleanStr.substring(4, 6)); // parseInt로 앞의 0 제거 - const day = parseInt(cleanStr.substring(6, 8)); // parseInt로 앞의 0 제거 + const month = cleanStr.substring(4, 6); // parseInt로 앞의 0 제거 + // const month = parseInt(cleanStr.substring(4, 6)); // parseInt로 앞의 0 제거 + // const day = parseInt(cleanStr.substring(6, 8)); // parseInt로 앞의 0 제거 + const day = cleanStr.substring(6, 8); // parseInt로 앞의 0 제거 - return `${year}년 ${month}월 ${day}일`; + return `${year}-${month}-${day}`; }; \ No newline at end of file diff --git a/apps/sn/app/components/lib/utils/formatDisplayValue.tsx b/apps/sn/app/components/lib/utils/formatDisplayValue.tsx index a5bd847cf..289b05b97 100644 --- a/apps/sn/app/components/lib/utils/formatDisplayValue.tsx +++ b/apps/sn/app/components/lib/utils/formatDisplayValue.tsx @@ -21,7 +21,7 @@ export const formatDisplayData = (data: { [key: string]: any }): { [key: string] if (/^\d{6}$/.test(dateStr)) { const year = dateStr.substring(0, 4); const month = parseInt(dateStr.substring(4, 6)); - formattedData[fieldId] = `${year}년 ${month}월`; + formattedData[fieldId] = `${year}-${month}`; } else { formattedData[fieldId] = String(value); } @@ -45,9 +45,10 @@ export const formatDisplayData = (data: { [key: string]: any }): { [key: string] // 🎯 undefined 체크 후 parseInt 적용 if (year && month && day && hour && minute) { - const formattedMonth = parseInt(month); - const formattedDay = parseInt(day); - formattedData[fieldId] = `${year}년 ${formattedMonth}월 ${formattedDay}일 ${hour}시 ${minute}분 ${second}초`; + // const formattedMonth = parseInt(month); + // const formattedDay = parseInt(day); + // formattedData[fieldId] = `${year}-${formattedMonth}-${formattedDay} ${hour}:${minute}:${second}`; + formattedData[fieldId] = `${year}-${month}-${day} ${hour}:${minute}:${second}`; } else { formattedData[fieldId] = String(value); } From 6c6b5e662cb8c8dd867a8827d554d003137ee4a3 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 17:47:16 +0900 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20=ED=95=98=EC=88=98=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=EC=8B=9C=EC=84=A4=EC=97=90=20=EC=8B=9C=EB=8F=84,=20?= =?UTF-8?q?=EC=8B=9C=EA=B5=B0=EA=B5=AC=20=EA=B2=80=EC=83=89=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(map-layout)/map/searchModal/basicTab.tsx | 10 +++++ .../map/searchModal/searchModal.tsx | 26 ++++++++----- .../map/searchModal/swagePrcsFclt.tsx | 37 ++++++++++++++++--- .../components/ui/SidoSigunguSelectBox.tsx | 22 +++++++++-- 4 files changed, 76 insertions(+), 19 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx index b91271251..57afc22c7 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx @@ -39,7 +39,9 @@ interface BasicTabProps { // setTableCount?: (count: number) => void; setBasicType: (type: string) => void; setCity: (city: number) => void; + setCtpvName: (name: string) => void; setSgg: (sgg: number) => void; + setSggName: (name: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; setStart1: (value: string) => void; setStart2: (value: string) => void; @@ -68,7 +70,9 @@ const BasicTab: React.FC = ({ // setTableCount, setBasicType, setCity, + setCtpvName, setSgg, + setSggName, setYearFilter, setStart1, setStart2, @@ -124,12 +128,18 @@ const BasicTab: React.FC = ({ start2={start2} end1={end1} end2={end2} + city={city} + sgg={sgg} yearFilter={yearFilter} setVar1={setVar1} setStart1={setStart1} setStart2={setStart2} setEnd1={setEnd1} setEnd2={setEnd2} + setCity={setCity} + setCtpvName={setCtpvName} + setSgg={setSgg} + setSggName={setSggName} setYearFilter={setYearFilter} handleSearch={handleSearch} /> diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index afc61252e..b453ba20f 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -63,8 +63,10 @@ const SearchModal: React.FC = ({ const [isResetSelection, setIsResetSelection] = useState(false); const [isResetDetailSelection, setIsResetDetailSelection] = useState(false); const [detailBizId, setDetailBizId] = useState(0); - const [city, setCity] = useState(0); - const [sgg, setSgg] = useState(0); + const [city, setCity] = useState(0); + const [ctpvName, setCtpvName] = useState(''); + const [sgg, setSgg] = useState(0); + const [sggName, setSggName] = useState(''); const [ctpvCd, setCtpvCd] = useState('0'); // 하수정비기본계획 report const [sigungu, setSigungu] = useState('0'); // 하수정비기본계획 report const [gubun, setGubun] = useState(""); // 하수정비기본계획 report @@ -341,13 +343,17 @@ const SearchModal: React.FC = ({ cqlFilters.push(`fclt_cpct BETWEEN ${start1} AND ${end1}`); else if (start1) cqlFilters.push(`fclt_cpct >= ${start1}`); else if (end1) cqlFilters.push(`fclt_cpct <= ${end1}`); - // 처리구역 면적 - if (start2 && end2) - cqlFilters.push(`prcsZoneAreaSum BETWEEN ${start2} AND ${end2}`); - else if (start2) cqlFilters.push(`prcsZoneAreaSum >= ${start2}`); - else if (end2) cqlFilters.push(`prcsZoneAreaSum <= ${end2}`); - // 하수처리시설명 - if (var1) cqlFilters.push(`swtrmt_fclt_nm ILIKE '%${var1}%'`); + + // 시도 + if (ctpvName) cqlFilters.push(`ctpv_nm ILIKE '%${ctpvName}%'`); + if (sggName) cqlFilters.push(`sgg_nm ILIKE '%${sggName}%'`); + // // 처리구역 면적 + // if (start2 && end2) + // cqlFilters.push(`prcsZoneAreaSum BETWEEN ${start2} AND ${end2}`); + // else if (start2) cqlFilters.push(`prcsZoneAreaSum >= ${start2}`); + // else if (end2) cqlFilters.push(`prcsZoneAreaSum <= ${end2}`); + // // 하수처리시설명 + // if (var1) cqlFilters.push(`swtrmt_fclt_nm ILIKE '%${var1}%'`); return cqlFilters; }; // 하수처리구역용 CQL 필터 생성 @@ -575,7 +581,9 @@ const SearchModal: React.FC = ({ handleSearch={handleSearch} setBasicType={setBasicType} setCity={setCity} + setCtpvName={setCtpvName} setSgg={setSgg} + setSggName={setSggName} setYearFilter={setYearFilter} setStart1={setStart1} setStart2={setStart2} diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx index 6f76554d9..85b32c9ef 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx @@ -1,8 +1,10 @@ // 하수처리시설 +import React from 'react'; import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { Button, Input, Label } from '@common/components'; -import React from 'react'; +import { SidoSigunguSelectBox } from '@/components/ui/SidoSigunguSelectBox'; + interface SwagePrcsFcltProps { var1: string; @@ -10,12 +12,18 @@ interface SwagePrcsFcltProps { start2: string; end1: string; end2: string; + city: number; + sgg: number; yearFilter: { start: string; end: string }; setVar1: (value: string) => void; setStart1: (value: string) => void; setStart2: (value: string) => void; setEnd1: (value: string) => void; setEnd2: (value: string) => void; + setCity: (value: number) => void; + setCtpvName: (name: string) => void; + setSgg: (value: number) => void; + setSggName: (name: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; handleSearch: () => void; } @@ -26,20 +34,37 @@ const SwagePrcsFclt: React.FC = ({ start2, end1, end2, + city, + sgg, yearFilter, setVar1, setStart1, setStart2, setEnd1, setEnd2, + setCity, + setCtpvName, + setSgg, + setSggName, setYearFilter, handleSearch, }) => { return (
- {/* 가동개시일자 */}
+ { + setCity(sidoId); + setSgg(0); + }} + onSigunguChange={setSgg} + setCtpvName={setCtpvName} + setSggName={setSggName} + /> + {/* 가동개시일자 */} = ({ }} /> {/* 처리구역 면적 */} - + {/* = ({ handleSearch(); } }} - /> + /> */} {/* 하수처리시설명 */} - + {/* = ({ handleSearch(); } }} - /> + /> */} {/* 조회 버튼 */}
diff --git a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx index 86e144073..96f7841b4 100644 --- a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx +++ b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx @@ -12,7 +12,9 @@ interface SidoSigunguSelectBoxProps { sido: number; sigungu: number; onSidoChange: (id: number) => void; + setCtpvName?: (name: string) => void; onSigunguChange: (id: number) => void; + setSggName?: (name: string) => void; className?: string; } @@ -20,7 +22,9 @@ export function SidoSigunguSelectBox({ sido, sigungu, onSidoChange, + setCtpvName, onSigunguChange, + setSggName, className = "", }: SidoSigunguSelectBoxProps) { @@ -46,8 +50,8 @@ export function SidoSigunguSelectBox({ async () => { const sggData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_sgg&outputFormat=application%2Fjson'); const sggList: Option[] = sggData.features - .map((feature: any) => ({ id: feature.properties.sgg_cd, name: feature.properties.sgg_korn_nm })) - .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬 + .map((feature: any) => ({ id: feature.properties.sgg_cd, name: feature.properties.sgg_korn_nm })) + .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬 setSggList(sggList); } ), []); @@ -58,6 +62,10 @@ export function SidoSigunguSelectBox({ await fetchSggData(); onSidoChange(0); onSigunguChange(0); + if (setCtpvName && setSggName) { + setCtpvName(""); + setSggName(""); + } })(); }, []); @@ -75,7 +83,10 @@ export function SidoSigunguSelectBox({ ] } value={sido} - onSelectValue={val => onSidoChange(Number(val))} + onSelectValue={val => { + onSidoChange(Number(val)); + if (setCtpvName) setCtpvName(ctpvList.find(opt => Number(opt.id) === Number(val))?.name || ""); + }} selectContentClass="z-[101]" /> @@ -91,7 +102,10 @@ export function SidoSigunguSelectBox({ ] } value={sigungu} - onSelectValue={val => onSigunguChange(Number(val))} + onSelectValue={val => { + onSigunguChange(Number(val)) + if (setSggName) setSggName(sggList.find(opt => Number(opt.id) === Number(val))?.name || ""); + }} selectContentClass="z-[101]" />
From 4cfa032be2b61a631dbe902ae71bfdc77a2c79ee Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 20:31:13 +0900 Subject: [PATCH 10/13] =?UTF-8?q?feat:=20=EC=98=A4=EC=88=98=EC=A0=84?= =?UTF-8?q?=ED=99=98=EC=9C=A8=20=EC=B4=88=EA=B9=83=EA=B0=92=200.8=EB=A1=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(with-base-layout)/ii/irsetting/page.tsx | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx index 3adf8c233..99542f5bf 100644 --- a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx @@ -47,7 +47,7 @@ interface ApiSelectOption { } const IrSetting = () => { - const [input1, setInput1] = useState(''); + const [input1, setInput1] = useState('0.8'); // 오수전환율 초기값 const [input2, setInput2] = useState(''); const [select1, setSelect1] = useState('0'); // 환경청코드 const [select2, setSelect2] = useState('0'); // 시도코드 @@ -387,10 +387,7 @@ const IrSetting = () => { accept={".xls, .xlsx, .xlsm, .xltx"} fileIdx={2} /> - + {/* 연월 선택 라이브러리로 수정 필요 */} { startYear={1900} // 시작 연도 설정 /> - + { @@ -434,10 +428,7 @@ const IrSetting = () => { placeholder="예: 0.75" /> - + setInput2(e.target.value)} From b5c7f09bc94b48e6ca193db0719f98b62d2a4190 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 20:55:57 +0900 Subject: [PATCH 11/13] =?UTF-8?q?feat:=20=EC=8B=9C=EB=8F=84,=20=EC=8B=9C?= =?UTF-8?q?=EA=B5=B0=EA=B5=AC=20zustand=20Store=EB=A1=9C=20=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=ED=9B=84=20SearchModal.tsx=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/page.tsx | 7 +++ .../map/searchModal/swagePrcsFclt.tsx | 57 ------------------- .../map/searchModal/swagePrcsZone.tsx | 16 +++--- .../components/ui/SidoSigunguSelectBox.tsx | 40 ++----------- apps/sn/app/store/useStore.ts | 41 +++++++++++++ 5 files changed, 62 insertions(+), 99 deletions(-) create mode 100644 apps/sn/app/store/useStore.ts diff --git a/apps/sn/app/(map-layout)/map/page.tsx b/apps/sn/app/(map-layout)/map/page.tsx index b2ed8ecd2..367bf421e 100644 --- a/apps/sn/app/(map-layout)/map/page.tsx +++ b/apps/sn/app/(map-layout)/map/page.tsx @@ -6,6 +6,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; import SearchModal from "./searchModal/searchModal"; import FeatureClickEventPopup from "./components/popupComponent/featureClickEventPopup"; +import useStore from "../../store/useStore"; // 타입 정의 추가 export type LyrStngProps = { @@ -38,6 +39,12 @@ const Map = () => { const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태 const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터 + const { fetchCtpvData, fetchSggData } = useStore(); + + useEffect(() => { + fetchCtpvData(); + fetchSggData(); + }, [fetchCtpvData, fetchSggData]); const fetchData = async () => { try { diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx index 85b32c9ef..53fd312dc 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx @@ -29,19 +29,13 @@ interface SwagePrcsFcltProps { } const SwagePrcsFclt: React.FC = ({ - var1, start1, - start2, end1, - end2, city, sgg, yearFilter, - setVar1, setStart1, - setStart2, setEnd1, - setEnd2, setCity, setCtpvName, setSgg, @@ -114,57 +108,6 @@ const SwagePrcsFclt: React.FC = ({ } }} /> - {/* 처리구역 면적 */} - {/* - { - // 숫자만 입력 허용 - const val = e.target.value.replace(/[^0-9]/g, ""); - setStart2(val); - }} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); // Enter 키 기본 동작 방지 - handleSearch(); - } - }} - /> - ~ - { - // 숫자만 입력 허용 - const val = e.target.value.replace(/[^0-9]/g, ""); - setEnd2(val); - }} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); // Enter 키 기본 동작 방지 - handleSearch(); - } - }} - /> */} - {/* 하수처리시설명 */} - {/* - { - setVar1(e.target.value); - }} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); // Enter 키 기본 동작 방지 - handleSearch(); - } - }} - /> */} {/* 조회 버튼 */}
diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx index a9065fb35..abeec54b9 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx @@ -40,13 +40,13 @@ const swagePrcsZone: React.FC = ({ }} onSigunguChange={setSgg} /> - + { - setVar1(e.target.value); + setVar2(e.target.value); }} onKeyDown={(e) => { if (e.key === 'Enter') { @@ -55,13 +55,13 @@ const swagePrcsZone: React.FC = ({ } }} /> - + { - setVar2(e.target.value); + setVar1(e.target.value); }} onKeyDown={(e) => { if (e.key === 'Enter') { diff --git a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx index 96f7841b4..a3a138259 100644 --- a/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx +++ b/apps/sn/app/components/ui/SidoSigunguSelectBox.tsx @@ -1,7 +1,7 @@ import React, { useState, useMemo, useEffect } from "react"; import { SelectBox } from '@common/business_components/ui' import { Label } from '@common/components'; -import { getGeoData } from '@/components/lib/api'; +import useStore from '../../store/useStore'; interface Option { id: number; @@ -28,38 +28,10 @@ export function SidoSigunguSelectBox({ className = "", }: SidoSigunguSelectBoxProps) { - const [ctpvList, setCtpvList] = useState([]); - const [sggList, setSggList] = useState([]); - - // 선택된 시도에 따라 시군구 리스트를 가져옴 - const fetchCtpvData = useMemo(() => ( - async () => { - const ctpvData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_ctpv&outputFormat=application%2Fjson'); - const ctpvList: Option[] = ctpvData.features - .map((feature: any) => ({ - id: feature.properties.mctpv_cd.trim(), - name: feature.properties.mctpv_korn_nm - })) - .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬 - setCtpvList(ctpvList); - } - ), []); - - // 선택된 시도에 따라 시군구 리스트를 가져옴 - const fetchSggData = useMemo(() => ( - async () => { - const sggData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_sgg&outputFormat=application%2Fjson'); - const sggList: Option[] = sggData.features - .map((feature: any) => ({ id: feature.properties.sgg_cd, name: feature.properties.sgg_korn_nm })) - .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬 - setSggList(sggList); - } - ), []); + const { ctpv, sgg} = useStore(); useEffect(() => { (async () => { - await fetchCtpvData(); - await fetchSggData(); onSidoChange(0); onSigunguChange(0); if (setCtpvName && setSggName) { @@ -79,13 +51,13 @@ export function SidoSigunguSelectBox({ label="" selectArray={ [{ val: 0, text: '전체' }, - ...ctpvList.map(opt => ({ val: opt.id, text: opt.name })) + ...ctpv.map(opt => ({ val: opt.id, text: opt.name })) ] } value={sido} onSelectValue={val => { onSidoChange(Number(val)); - if (setCtpvName) setCtpvName(ctpvList.find(opt => Number(opt.id) === Number(val))?.name || ""); + if (setCtpvName) setCtpvName(ctpv.find(opt => Number(opt.id) === Number(val))?.name || ""); }} selectContentClass="z-[101]" /> @@ -96,7 +68,7 @@ export function SidoSigunguSelectBox({ label="" selectArray={ [{ val: 0, text: '전체' }, - ...sggList + ...sgg .filter(opt => String(opt.id).slice(0, 2) === String(sido)) .map(opt => ({ val: opt.id, text: opt.name })) ] @@ -104,7 +76,7 @@ export function SidoSigunguSelectBox({ value={sigungu} onSelectValue={val => { onSigunguChange(Number(val)) - if (setSggName) setSggName(sggList.find(opt => Number(opt.id) === Number(val))?.name || ""); + if (setSggName) setSggName(sgg.find(opt => Number(opt.id) === Number(val))?.name || ""); }} selectContentClass="z-[101]" /> diff --git a/apps/sn/app/store/useStore.ts b/apps/sn/app/store/useStore.ts new file mode 100644 index 000000000..518cce66b --- /dev/null +++ b/apps/sn/app/store/useStore.ts @@ -0,0 +1,41 @@ +import { useMemo } from "react"; +import { create } from "zustand"; +import { getGeoData } from "@/components/lib/api"; +import { get } from "http"; + +interface Option { id: number, name: string } + +interface SnStoreState { + ctpv: Option[]; + sgg: Option[]; + fetchCtpvData: () => Promise; + fetchSggData: () => Promise; +} + +const useStore = create((set) => ({ + // Define your store state and actions here + ctpv: [], + sgg: [], + fetchCtpvData: async () => { + const ctpvData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_ctpv&outputFormat=application%2Fjson'); + const ctpvList: Option[] = ctpvData.features + .map((feature: any) => ({ + id: feature.properties.mctpv_cd.trim(), + name: feature.properties.mctpv_korn_nm + })) + .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); + set({ ctpv: ctpvList }); + }, + fetchSggData: async () => { + const sggData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_sgg&outputFormat=application%2Fjson'); + const sggList: Option[] = sggData.features + .map((feature: any) => ({ + id: feature.properties.sgg_cd, + name: feature.properties.sgg_korn_nm + })) + .sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); + set({ sgg: sggList }); + } +})); + +export default useStore; \ No newline at end of file From c23fe686754eac1bfd6b53673589726327c04125 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 21:35:16 +0900 Subject: [PATCH 12/13] =?UTF-8?q?refactor:=20=EC=8B=9C=EB=8F=84,=20?= =?UTF-8?q?=EC=8B=9C=EA=B5=B0=EA=B5=AC=20=ED=98=B8=EC=B6=9C=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/page.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/sn/app/(map-layout)/map/page.tsx b/apps/sn/app/(map-layout)/map/page.tsx index 367bf421e..15c6586eb 100644 --- a/apps/sn/app/(map-layout)/map/page.tsx +++ b/apps/sn/app/(map-layout)/map/page.tsx @@ -41,6 +41,7 @@ const Map = () => { const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터 const { fetchCtpvData, fetchSggData } = useStore(); + // 시도, 시군구 호출 useEffect(() => { fetchCtpvData(); fetchSggData(); From 2e7b06d970ef9235fd890b9983d97c867372519e Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 30 Jul 2025 21:37:40 +0900 Subject: [PATCH 13/13] =?UTF-8?q?feat:=20=EC=A4=91=EC=A0=90=EC=9A=B0?= =?UTF-8?q?=EC=88=98=ED=86=A0=EC=8B=A4=20=ED=8E=98=EC=9D=B4=EC=A7=95=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20(=ED=85=8C=EC=9D=B4=EB=B8=94=20=EB=8F=99?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EC=B6=94=EA=B0=80=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=ED=95=84=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/components/popupComponent/Ssc.tsx | 209 +++++++++++------- 1 file changed, 131 insertions(+), 78 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx index 52fc5523d..4542e56c9 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx @@ -12,20 +12,114 @@ const inputColumn = [ { id: "swtrmtZoneCd", title: "처리구역", type: "input" }, ]; -const Ssc = ({ featureData, isMainSsc, rainMeasureData, onSaveClick }: { +const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: { featureData: any, isMainSsc?: boolean, - rainMeasureData?: any, + chmbrXcnts?: string, + chmbrYdnts?: string, onSaveClick?: () => void }) => { const [isModalOpen, setIsModalOpen] = useState(false); const [isDataLoaded, setIsDataLoaded] = useState(false); const [formData, setFormData] = useState({}); - const [mntrngsData, setMntrngsData] = useState([]); // 수량/수질 측정 정보 + const [rainMeasureData, setRainMeasureData] = useState({}); // 강우, 측정 정보 + const [mntrngsData, setMntrngsData] = useState([]); // 수량/수질측정 정보 + const [totalCount, setTotalCount] = useState(0); + const [totalDetailCount, setTotalDetailCount] = useState(0); const [selectedRowIndex, setSelectedRowIndex] = useState(-1); + const [curPage, setCurPage] = useState(1); + const [curDetailPage, setCurDetailPage] = useState(1); + const [isResetPage, setIsResetPage] = useState(false); + const [isResetDetailPage, setIsResetDetailPage] = useState(false); + const [isResetSelection, setIsResetSelection] = useState(false); + const [curIdx, setCurIdx] = useState(0); - // console.log('featureData data received:', featureData); // 추가 데이터 확인용 - // console.log('rainMeasureData received:', rainMeasureData); // 추가 데이터 확인용 + // 강우, 측정 정보 API 호출 함수 + const fetchRainMeasureData = async (chmbrXcnts: string, chmbrYdnts: string) => { + if (!chmbrXcnts || !chmbrYdnts) { + console.warn('추가 데이터 호출 실패: 필수 매개변수 누락', { chmbrXcnts, chmbrYdnts }); + return []; + } + + try { + const queryParams = new URLSearchParams({ + chmbrXcnts: chmbrXcnts, + chmbrYdnts: chmbrYdnts, + page: `${curPage - 1}`, + size: '3', + }); + + console.log('queryParams', queryParams.toString()); + console.log(`추가 데이터 API 호출 시작: v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`); + + const result = await getData(`v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`); + + console.log('추가 데이터 API 호출 성공:', result); + + const processedDataArray: any[] = result.content.map((data: any) => { + // 🎯 formatDisplayData로 기본 포맷팅 적용 + const formattedItem = formatDisplayData(data); + + // 🎯 추가 데이터 조합 + return { + ...formattedItem, + flwmtrCombined: `${data.flwmtrMesureTpEtc || '-'} / ${data.flwmtrKnd || '-'}`, + }; + }); + setRainMeasureData(processedDataArray); + setTotalCount(result?.totalElements || 0); + } catch (error) { + console.error('추가 데이터 로딩 실패:', error); + return []; + } + }; + + // 수량/수질측정 정보 API 호출 함수 + const fetchMntrngsData = async (adstDstrCd: string, manageNo: string) => { + if (!adstDstrCd || !manageNo) { + console.warn('추가 데이터 호출 실패: 필수 매개변수 누락', { adstDstrCd, manageNo }); + return []; + } + + try { + const queryParams = new URLSearchParams({ + page: `${curDetailPage - 1}`, + size: '3', + }); + + console.log(`SSC 추가 데이터 API 호출 시작: v1/onsemiro/swgRain?${queryParams.toString()}`); + + const result = await getData(`v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs?${queryParams.toString()}`); + + console.log('SSC 추가 데이터 API 호출 성공:', result); + + // 각 아이템 전처리 + const processedDataArray = result.content.map((data: any) => { + // 기본 포맷팅 적용 + const formattedItem = formatDisplayData(data); + return { + ...formattedItem, + }; + }); + + console.log('processedDataArray', processedDataArray); + + setMntrngsData(processedDataArray); + setTotalDetailCount(result?.totalElements || 0); + } catch (error) { + console.error('추가 데이터 로딩 실패:', error); + return []; + } + }; + + + // 🎯 추가 데이터는 별도 useEffect로 비동기 로딩 + useEffect(() => { + // 강우/측정 정보 데이터 호출 + if (isMainSsc && chmbrXcnts && chmbrYdnts) { + fetchRainMeasureData(chmbrXcnts, chmbrYdnts) + } + }, [chmbrXcnts, chmbrYdnts]); const openModal = () => { setIsModalOpen(true); @@ -46,6 +140,19 @@ const Ssc = ({ featureData, isMainSsc, rainMeasureData, onSaveClick }: { } }, [featureData]); + // featureData가 변경될 때 formData 초기화 + useEffect(() => { + // showTable이 true일 때만 fetch (최초 렌더 방지) + setIsResetPage(false); + setIsResetDetailPage(true); + if (chmbrXcnts && chmbrYdnts) fetchRainMeasureData(chmbrXcnts, chmbrYdnts); + }, [curPage]); + + // 페이지 변경 시마다 데이터 fetch + useEffect(() => { + if (chmbrXcnts && chmbrYdnts) fetchMntrngsData(chmbrXcnts, chmbrYdnts); + }, [curDetailPage]); + // 폼 데이터가 변경될 때 호출될 핸들러 const handleFormDataChange = (newFormData: any) => { setFormData(newFormData); @@ -62,91 +169,39 @@ const Ssc = ({ featureData, isMainSsc, rainMeasureData, onSaveClick }: { // 테이블 셀 클릭 핸들러 추가 const handleCellClick = async (index: number | undefined, headId: string) => { if (index !== undefined && rainMeasureData) { - const data = await fetchMntrngsData(rainMeasureData[index].adstDstrCd, rainMeasureData[index].manageNo); - - setMntrngsData(data); + await fetchMntrngsData(rainMeasureData[index].adstDstrCd, rainMeasureData[index].manageNo); setSelectedRowIndex(index); } }; - // 🎯 추가 데이터 API 호출 함수 (독립적으로 실행) - const fetchMntrngsData = useCallback(async (adstDstrCd: string, manageNo: string) => { - if (!adstDstrCd || !manageNo) { - console.warn('추가 데이터 호출 실패: 필수 매개변수 누락', { adstDstrCd, manageNo }); - return []; - } - - try { - const queryParams = new URLSearchParams({ - pageable: `{}`, - }); - - console.log(`SSC 추가 데이터 API 호출 시작: v1/onsemiro/swgRain?${queryParams.toString()}`); - - const result = await getData(`v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs?${queryParams.toString()}`); - - console.log('SSC 추가 데이터 API 호출 성공:', result); - - // 🎯 result가 페이지네이션 객체인 경우 content 배열 추출 - let dataArray: any[] = []; - if (result && typeof result === 'object' && 'content' in result && Array.isArray(result.content)) { - dataArray = result.content; - } else if (Array.isArray(result)) { - dataArray = result; - } else { - console.warn('예상치 못한 API 응답 형식:', result); - return []; - } - - // 🎯 각 아이템을 전처리하여 반환 - const processedDataArray = dataArray.map((data: any) => { - // 🎯 formatDisplayData로 기본 포맷팅 적용 - const formattedItem = formatDisplayData(data); - - // 🎯 추가 데이터 조합 - return { - ...formattedItem, - }; - }); - - console.log('processedDataArray', processedDataArray); - - return processedDataArray; - } catch (error) { - console.error('추가 데이터 로딩 실패:', error); - return []; - } - }, []); - const renderModalBody = () => (
{/* 강우정보 테이블 */} {/* 측정정보 테이블 */} {/* 커스텀 헤더 */} @@ -168,14 +223,12 @@ const Ssc = ({ featureData, isMainSsc, rainMeasureData, onSaveClick }: { {/* 수량/수질측정 정보 테이블 */}
)