From 637929ea26c3f87ce942af9dd82953e7b3f9e365 Mon Sep 17 00:00:00 2001 From: yschoi Date: Thu, 31 Jul 2025 13:15:22 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A7=80=EB=8F=84=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dm/app/(popup-layout)/map/popup/page.tsx | 22 ++- apps/fo/app/pages/map/page.tsx | 28 ++- apps/sn/app/(map-layout)/map/page.tsx | 2 + .../(map-layout)/map/searchBar/searchBar.tsx | 83 +++++++++ apps/wr/app/map/mainMap/page.tsx | 11 +- apps/wr/app/map/popup/page.tsx | 11 +- .../business_components/src/ui/map/Gis.js | 176 +++++------------- .../src/ui/map/GisContent.js | 121 ++++++------ .../business_components/src/ui/map/GisTab.js | 84 --------- 9 files changed, 217 insertions(+), 321 deletions(-) create mode 100644 apps/sn/app/(map-layout)/map/searchBar/searchBar.tsx delete mode 100644 packages/common/business_components/src/ui/map/GisTab.js diff --git a/apps/dm/app/(popup-layout)/map/popup/page.tsx b/apps/dm/app/(popup-layout)/map/popup/page.tsx index dc4e404ce..ea71862d8 100644 --- a/apps/dm/app/(popup-layout)/map/popup/page.tsx +++ b/apps/dm/app/(popup-layout)/map/popup/page.tsx @@ -62,10 +62,9 @@ const Map = () => { Object.keys(item).length > 0 && !prev.some((f) => f.pbnstRuseFcltId === item.pbnstRuseFcltId) ); - console.log(newItems) + console.log(newItems); return [...prev, ...newItems]; }); - } catch (error) { console.error("데이터 불러오기 실패:", error); } @@ -232,14 +231,6 @@ const Map = () => { return ( <> - { - if (hasuPk) { - setSelectDataPk(hasuPk); - } - }} - onApply={onApply} - />
{ isSearchModalOpen={isSearchModalOpen} onCheckedLayersChange={onCheckedLayersChange} imgVisble={false} + searchBar={(props: any) => ( + { + if (hasuPk) { + setSelectDataPk(hasuPk); + } + }} + onApply={onApply} + {...props} + /> + )} />
{ getArray: () => Array<{ getSource?: () => { getFeatureById?: (id: string) => FeatureData | null } }> }; + getLayers: () => { + getArray: () => Array<{ + getSource?: () => { getFeatureById?: (id: string) => FeatureData | null }; + }>; + }; getView: () => { fit: (extent: number[], options: object) => void }; } @@ -26,20 +30,20 @@ const Map = () => { const fetchData = async () => { try { - const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map` + const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map`; const reqUrl = `${API_URL}/lyrStngs/FO_NETWORK`; const response = await fetch(reqUrl, { method: "GET", headers: { accept: "application/json", - } + }, }); if (!response.ok) { throw new Error(`HTTP 오류! 상태: ${response.status}`); } - const data = await response.json(); // 여기서 json 파싱 + const data = await response.json(); // 여기서 json 파싱 setTreeData(data); // 데이터 설정 } catch (error) { console.error("데이터 불러오기 실패:", error); @@ -60,7 +64,12 @@ const Map = () => { } // 항상 같은 select 객체 사용 - const select = (GisApp.Module.select as unknown) as { resetSelectedFeature: () => void; selectFeature: (feature: FeatureData, selected: boolean) => void } | undefined; + const select = GisApp.Module.select as unknown as + | { + resetSelectedFeature: () => void; + selectFeature: (feature: FeatureData, selected: boolean) => void; + } + | undefined; if (!select) return; // 1. 기존 선택 초기화 @@ -115,9 +124,12 @@ const Map = () => { }; // onCheckedLayersChange handler - const handleCheckedLayersChange = (checkedIds: string[], checkedNodesData: unknown[]) => { + const handleCheckedLayersChange = ( + checkedIds: string[], + checkedNodesData: unknown[] + ) => { // Handle checked layers change if needed - console.log('Checked layers changed:', checkedIds, checkedNodesData); + console.log("Checked layers changed:", checkedIds, checkedNodesData); }; return ( @@ -137,6 +149,8 @@ const Map = () => { isOpen={isOpen} isSearchModalOpen={isSearchModalOpen} onCheckedLayersChange={handleCheckedLayersChange} + imgVisble={false} + searchBar={undefined} /> ); diff --git a/apps/sn/app/(map-layout)/map/page.tsx b/apps/sn/app/(map-layout)/map/page.tsx index 2dbbcdd1a..40b034199 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 "./featureClickEventPopup"; +import { SearchBar } from "./searchBar/searchBar"; // 타입 정의 추가 export type LyrStngProps = { @@ -130,6 +131,7 @@ const Map = () => { isOpen={isOpen} isSearchModalOpen={isSearchModalOpen} onCheckedLayersChange={undefined} + searchBar={SearchBar} /> ); diff --git a/apps/sn/app/(map-layout)/map/searchBar/searchBar.tsx b/apps/sn/app/(map-layout)/map/searchBar/searchBar.tsx new file mode 100644 index 000000000..b57e66c24 --- /dev/null +++ b/apps/sn/app/(map-layout)/map/searchBar/searchBar.tsx @@ -0,0 +1,83 @@ +"use client"; +import { + SearchDiv, + SearchFormLeft, + SelectBox, + type SelectDataType, +} from "@common/business_components/ui"; +import { useCallback, useEffect, useState } from "react"; + +export function SearchBar() { + const [sidoValue, setSidoValue] = useState(""); + const [sigunValue, setSigunValue] = useState(""); + const [filteredSigunData, setFilteredSigunData] = useState([ + { text: "시도 선택", val: "0" }, + ]); + + const initializeSigunData = useCallback((sidoCd: string) => { + if (sidoCd === "0") { + setSigunValue("0"); + setFilteredSigunData([{ text: "시도 선택", val: "0" }]); + } else { + const newFilteredData = [ + { text: "데이터", val: "0" }, + // ...Common.selectSigunData.filter( + // (item: SelectDataType) => item.val.substring(0, 2) === sidoCd, + // ), + ]; + setSigunValue("0"); + setFilteredSigunData(newFilteredData); + } + }, []); + const onSelectValue = useCallback( + (val: string, type: string) => { + switch (type) { + case "ctpvCd": + initializeSigunData(val); + setSidoValue(val); + break; + case "sggCd": + setSigunValue(val); + } + }, + [initializeSigunData], + ); + + return ( + <> +
+
+
+
+ onSelectValue(val.toString(), "ctpvCd")} + value={sidoValue || /* Common.selectSidoData[0]?.val || */ ""} + /> + onSelectValue(val.toString(), "sggCd")} + value={sigunValue} + /> + onSelectValue(val.toString(), "sggCd")} + value={sigunValue} + /> +
+
+
+
+ + ); +} diff --git a/apps/wr/app/map/mainMap/page.tsx b/apps/wr/app/map/mainMap/page.tsx index 1e9afd74b..1f466f1cd 100644 --- a/apps/wr/app/map/mainMap/page.tsx +++ b/apps/wr/app/map/mainMap/page.tsx @@ -136,16 +136,6 @@ const Map = () => { gisMaps={gisMaps} isMiniMap={false} searchView={undefined} - // searchView={(props: any) => ( - // - // ) - // } detailView={(props: any) => ( { isSearchModalOpen={isSearchModalOpen} onCheckedLayersChange={handleCheckedLayersChange} imgVisble={true} + searchBar={undefined} /> ); diff --git a/apps/wr/app/map/popup/page.tsx b/apps/wr/app/map/popup/page.tsx index 80830aa90..56ec8863b 100644 --- a/apps/wr/app/map/popup/page.tsx +++ b/apps/wr/app/map/popup/page.tsx @@ -123,16 +123,6 @@ const Map = () => { gisMaps={gisMaps} isMiniMap={false} searchView={undefined} - // searchView={(props: any) => ( - // - // ) - // } detailView={(props: any) =>( { isSearchModalOpen={isSearchModalOpen} onCheckedLayersChange={handleCheckedLayersChange} imgVisble={true} + searchBar={undefined} /> ); diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js index f73b428c5..eefb08da6 100644 --- a/packages/common/business_components/src/ui/map/Gis.js +++ b/packages/common/business_components/src/ui/map/Gis.js @@ -98,7 +98,8 @@ function Gis({ detailView: DetailView, onFeatureSelect, setIsSearchModalOpen, - onCheckedLayersChange + onCheckedLayersChange, + searchBar: SearchBar }) { const mapRef = useRef(); const [mapObject, setMapObject] = useState({}); @@ -127,102 +128,7 @@ function Gis({ // Feature Click Event const handleFeatureSelect = useCallback((data) => { - console.log(data); - // gisMap = mapInstanceRef.current; - // gisMap = mapInstanceRef.current; - - // if (!gisMap) { - // console.warn('지도가 초기화되지 않았습니다.'); - // return; - // } - // if (!gisMap) { - // console.warn('지도가 초기화되지 않았습니다.'); - // return; - // } - - // // 항상 같은 select 객체 사용 - // const select = GisApp.Module.select; - // if (!select) return; - // // 항상 같은 select 객체 사용 - // const select = GisApp.Module.select; - // if (!select) return; - - // // 1. 기존 선택 초기화 - // select.resetSelectedFeature(); - - // // 2. data가 OpenLayers Feature 인스턴스인지 확인 - // let foundFeature = null; - // if (data && typeof data.getGeometry === 'function' && typeof data.setStyle === 'function') { - // // 이미 Feature 인스턴스라면 그대로 사용 - // foundFeature = data; - // } else { - // // 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용 - // let featureId = data.fid; - // const layerName = layerNmRef.current - // if (layerName === '하수재이용시설') { - // featureId = data.searchPk; - // } else if (layerName === '빗물이용시설' || layerName == '중수도시설') { - // featureId = data.bdstInfoSn; - // } else if (layerName === '하수처리시설') { - // featureId = data.bscFctCd; - // } else if (layerName === '온배수시설') { - // featureId = data.bdstRuseFcltSn; - // } else if(layerName == '수요처'){ - // featureId = data.dmdInfoId.replaceAll('-','') - // } - // else { - // console.warn('해당 레이어에 대한 featureId 매핑 없음', layerNm); - // featureId = data.fid || data.id || data.ftrIdn; - // } - // // gisMap.getLayers().getArray().forEach(layer => { - // // const source = layer.getSource?.(); - // // if (source?.getFeatureById) { - // // const feature = source.getFeatureById(String(featureId).trim()); - // // if (feature) foundFeature = feature; - // // } - // // }); - // // const [layerType, id] = String(featureId).split('.'); - // gisMap.getLayers().getArray().forEach(layer => { - // const source = layer.getSource?.(); - // if (source?.getFeatures) { - // const allFeatures = source.getFeatures(); - // for (const f of allFeatures) { - // const id = String(f.getId()); - // // console.log('id', id, featureId) - // if (id && id.split('.')[1] === String(featureId)) { - // foundFeature = f; - // break; - // } - // } - // } - // }); - // } - - // // 3. 피처 선택 - // if (foundFeature) { - // let geometry = foundFeature.getGeometry(); - // if (geometry) { - // let extent = geometry.getExtent(); - - // gisMap.getView().fit(extent, { - // duration: 300, - // padding: [50, 50, 50, 50], - // maxZoom: 16, - // constrainResolution: true, - // nearest: true, - // }); - // } - // select.selectFeature(foundFeature, true); - // } else { - // console.warn('OpenLayers Feature를 찾을 수 없습니다:', data); - // } - - // setFeatureData(data); - // setIsOpen(true); - // setIsSearchModalOpen(false); - onFeatureSelect?.(data); // 선택된 피쳐 데이터 콜백 호출 - console.log(data) }, [mapInstanceRef]); // 지도 생성 및 초기화 @@ -347,44 +253,48 @@ function Gis({ <>
-
- { - layerNmRef.current = layerNm - setLayerNm(layerNm); setIsOpen(true); const dummyFeature = { - getProperties: () => ({}), // 최소 구조 - }; - onFeatureSelect(dummyFeature); - }} - imageVisible={imgVisble} - /> - - {/* */} - - {/* DetailView가 존재할 때만 렌더링 isSearchModalOpen이 true면 visible=false로 팝업 숨김 */} - {isOpen && !isSearchModalOpen && ( - ({}) }} - seletectedLayerNm={layerNm} - onClose={closePopup} // 닫기 콜백 전달 - onFeatureSelect={handleFeatureSelect} +
+ { + layerNmRef.current = layerNm + setLayerNm(layerNm); setIsOpen(true); const dummyFeature = { + getProperties: () => ({}), // 최소 구조 + }; + onFeatureSelect(dummyFeature); + }} + imageVisible={imgVisble} /> - )} - {/* SearchView가 존재할 때만 렌더링 */} - {SearchView && ( - - )} - {/* */} - - - + + {/* DetailView가 존재할 때만 렌더링 isSearchModalOpen이 true면 visible=false로 팝업 숨김 */} + {isOpen && !isSearchModalOpen && ( + ({}) }} + seletectedLayerNm={layerNm} + onClose={closePopup} // 닫기 콜백 전달 + onFeatureSelect={handleFeatureSelect} + /> + )} + {/* SearchView가 존재할 때만 렌더링 */} + {SearchView && ( + + )} + {/* 시도/시군구 조회 영역 */} + {SearchBar && ( +
+ +
+ )} + + + +
{isSearch && ( diff --git a/packages/common/business_components/src/ui/map/GisContent.js b/packages/common/business_components/src/ui/map/GisContent.js index d2594ba95..45b44c882 100644 --- a/packages/common/business_components/src/ui/map/GisContent.js +++ b/packages/common/business_components/src/ui/map/GisContent.js @@ -1,74 +1,61 @@ -import { Search } from 'lucide-react'; -import { useCallback, useEffect, useRef, useState } from 'react'; -import { useGisContext } from './Gis'; -import './lib/css/gis.edit.css'; -import GisApp from './lib/gis.core'; +import { Search } from "lucide-react"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { useGisContext } from "./Gis"; +import "./lib/css/gis.edit.css"; +import GisApp from "./lib/gis.core"; -export default function GisContent({ edit = false, onFeatureSelect, isSearch, setIsSearchModalOpen }) { - const { gisMap, gisCore } = useGisContext(); - const [visibleComponents, setVisibleComponents] = useState({}); - const addressResultLayer = useRef(null); - const [playShow, setPlayShow] = useState({ show: false }); +export default function GisContent({ + edit = false, + onFeatureSelect, + isSearch, + setIsSearchModalOpen, +}) { + const { gisMap, gisCore } = useGisContext(); - //셀렉트 버튼 이벤트 - // const clickFeature = useCallback(feature => { - // if (feature) { - // const layer = feature.getLayer(); - // setVisibleComponents(prevState => ({ - // ...prevState, - // })); - // } - // }, []); + //셀렉트 버튼 이벤트 + const selectRslt = useCallback((feature) => { + GisApp.Module.layer.highLightFeature( + [feature], + { + id: GisApp.hlLayerId, + zIndex: 10, + opacity: 1, + selectable: true, + }, + { width: 30 }, + ); + clickFeature(feature); + }, []); - const selectRslt = useCallback(feature => { - GisApp.Module.layer.highLightFeature( - [feature], - { - id: GisApp.hlLayerId, - zIndex: 10, - opacity: 1, - selectable: true, - }, - { width: 30 } - ); - clickFeature(feature); - }, []); + useEffect(() => { + if (gisMap) { + setVisibleComponents((prevState) => ({ + ...prevState, + })); + } + }, [gisMap]); - useEffect(() => { - if (gisMap) { - setVisibleComponents(prevState => ({ - ...prevState, - })); - } - }, [gisMap]); + if (!gisMap) return null; - if (!gisMap) return null; + return ( + <> + + + + + - return ( - <> - {/**/} - {/* - - */} - {/* */} - - {/* 검색 모달 */} - {isSearch && ( -
- -
- )} - - ); + {/* 검색 모달 */} + {isSearch && ( +
+ +
+ )} + + ); } diff --git a/packages/common/business_components/src/ui/map/GisTab.js b/packages/common/business_components/src/ui/map/GisTab.js deleted file mode 100644 index 57d8a48e8..000000000 --- a/packages/common/business_components/src/ui/map/GisTab.js +++ /dev/null @@ -1,84 +0,0 @@ -// import React, { useState } from 'react'; -// import { Tabs, TabsList, TabsTrigger } from '@common/components/ui/tabs'; -// import GisTree from './GisTree'; -// import GisSearch from './GisSearch'; -// import { ChevronLeft, ChevronRight, Search } from 'lucide-react'; -// import SearchModal from '@/map/SearchModal'; - - -// function GisTab({ visible, setVisible, isSearch, isSearchModalOpen, setIsSearchModalOpen, onFeatureSelect }) { -// const [activeTab, setActiveTab] = useState('layers'); - -// return ( -// <> -//
-// -// -// 레이어 -// {/* {isSearch && ( -// -// // -// // -// // -// )} */} -// - -// {/* GisTree는 항상 마운트되며, 탭 상태에 따라 보여주기만 함 */} -//
-// -//
- -// {/* GisSearch도 동일하게 처리 */} -// {/* {isSearch && ( -//
-// -//
-// )} */} - - -// {/* 🔍 검색 모달 */} -// {/* */} -//
- -// {/* 접기 버튼 */} -// -//
- -// {/* 열기 버튼 */} -// {!visible && ( -// -// )} -// -// ); -// } - -// export default React.memo(GisTab);