From be43fd38a7c91dcafdf2a04a8525ffa8f9f987af Mon Sep 17 00:00:00 2001 From: yschoi Date: Sun, 10 Aug 2025 21:32:21 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AC=BC=EC=9E=AC=EC=9D=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=A7=80=EB=8F=84=EB=B3=B4=EA=B8=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/(map-layout)/map/mainMap/page.tsx | 9 +- apps/wr/app/(map-layout)/map/popup/page.tsx | 153 -------- apps/wr/app/layout.tsx | 16 +- apps/wr/app/map/searchBar/SearchInputText.tsx | 122 ------ apps/wr/app/map/searchBar/comboSearchBar.tsx | 298 --------------- apps/wr/app/map/searchBar/procSearchBar.tsx | 298 --------------- apps/wr/app/map/searchBar/searchBar.tsx | 351 ------------------ apps/wr/app/store/store.tsx | 2 +- apps/wr/middleware.ts | 13 +- .../src/ui/map/searchBar/searchBar.tsx | 34 +- 10 files changed, 41 insertions(+), 1255 deletions(-) delete mode 100644 apps/wr/app/(map-layout)/map/popup/page.tsx delete mode 100644 apps/wr/app/map/searchBar/SearchInputText.tsx delete mode 100644 apps/wr/app/map/searchBar/comboSearchBar.tsx delete mode 100644 apps/wr/app/map/searchBar/procSearchBar.tsx delete mode 100644 apps/wr/app/map/searchBar/searchBar.tsx diff --git a/apps/wr/app/(map-layout)/map/mainMap/page.tsx b/apps/wr/app/(map-layout)/map/mainMap/page.tsx index 7451ae4b5..4130fff63 100644 --- a/apps/wr/app/(map-layout)/map/mainMap/page.tsx +++ b/apps/wr/app/(map-layout)/map/mainMap/page.tsx @@ -56,13 +56,11 @@ const Map = () => { const messageHandler = (event: MessageEvent) => { if (event.data.type === "POPUP_CLOSED") { if (event.data.target === "detail") { - console.log("디테일 팝업 닫힘 감지됨"); setFeatureData(null); setIsOpen(false); setIsSearchModalOpen(true); popupDetailRef.current = null; } else { - console.log("기타 팝업 닫힘 감지됨"); popupRef.current = null; } } @@ -74,10 +72,8 @@ const Map = () => { }, []); useEffect(() => { - console.log("isFeatured ", isFeatured); if (isFeatured) { - console.log("isFeatured ", isFeatured); onFeatureSelect(isFeatured); } }, [isFeatured]); @@ -93,7 +89,7 @@ const Map = () => { // SearchModal, GisContent 등에서 호출 const onFeatureFocus = (data: any) => { - console.log(data); + console.log("onFeatureFocus"); }; const onFeatureSelect = (data: any) => { @@ -114,7 +110,6 @@ const Map = () => { let foundFeature: any = null; let featureId = data.fid; const layerName = data.layerNm; - console.log("선택된 레이어 이름:", data, layerName); if (layerName === "하수재이용시설") { // 재이용시설 featureId = `${layerName}.${data.searchPk}`; @@ -134,7 +129,6 @@ const Map = () => { //수요처 featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`; } else { - console.warn("해당 레이어에 대한 featureId 매핑 없음", layerName); featureId = `${layerName}.${data.fid || data.id || data.ftrIdn}`; } map @@ -214,7 +208,6 @@ const Map = () => { const isFeature = props?.featureData; - console.log('isFeature 1', isFeature) if( typeof isFeature.getProperties === "function" ){ if ( diff --git a/apps/wr/app/(map-layout)/map/popup/page.tsx b/apps/wr/app/(map-layout)/map/popup/page.tsx deleted file mode 100644 index ca7a07b43..000000000 --- a/apps/wr/app/(map-layout)/map/popup/page.tsx +++ /dev/null @@ -1,153 +0,0 @@ -// "use client"; - -// import Gis from "@common/business_components/ui/map/Gis"; -// import { useEffect, useRef, useState, useCallback } from "react"; -// import { mapService } from "../service"; -// import NewWindowPopup from "../components/newWindowPopup"; -// import GisApp from "@common/business_components/ui/map/lib/gis.core"; - -// const Map = () => { -// const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 -// const gisMaps = useRef(null); -// const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 -// const [isSearchModalOpen, setIsSearchModalOpen] = useState(true); // SearchModal 열림 상태 -// const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터 -// const [checkedLayers, setCheckedLayers] = useState([]); -// const [checkedLayersData, setCheckedLayersData] = useState([]); - -// const fetchData = async () => { -// try { -// const response = await mapService.getLyrStngs(); -// setTreeData(response); // API 응답 저장 -// } catch (error) { -// console.error("데이터 불러오기 실패:", error); -// } -// }; - -// // 팝업 닫기 핸들러를 useCallback으로 메모이제이션 -// const handlePopupClose = useCallback(() => { -// setIsOpen(false); -// setFeatureData(null); -// }, []); - -// // 컴포넌트 마운트 시 1회 실행 -// useEffect(() => { -// fetchData(); -// }, []); - -// // 체크된 레이어 정보를 받는 핸들러 -// const handleCheckedLayersChange = (checkedIds: string[], checkedNodesData: any[]) => { -// setCheckedLayers(checkedIds); -// setCheckedLayersData(checkedNodesData); -// }; - -// // SearchModal, GisContent 등에서 호출 -// const onFeatureSelect = (data: any) => { -// const map = gisMaps.current; -// if (!map) { -// console.warn("지도가 초기화되지 않았습니다."); -// return; -// } - -// // 항상 같은 select 객체 사용 -// const select = GisApp.Module.select as any; -// if (!select) return; - -// // 1. 기존 선택 초기화 -// select.resetSelectedFeature(); - -// // 2. data가 OpenLayers Feature 인스턴스인지 확인 -// let foundFeature: any = null; -// if ( -// data && -// typeof data.getGeometry === "function" && -// typeof data.setStyle === "function" -// ) { -// // 이미 Feature 인스턴스라면 그대로 사용 -// foundFeature = data; -// } else { -// // 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용 -// const featureId = data.fid || data.ftrIdn || data.id; -// map -// .getLayers() -// .getArray() -// .forEach((layer: any) => { -// const source = layer.getSource?.(); -// if (source?.getFeatureById) { -// const feature = source.getFeatureById(String(featureId).trim()); -// if (feature) foundFeature = feature; -// } -// }); -// } - -// // 3. 피처 선택 -// if (foundFeature) { -// const geometry = foundFeature.getGeometry(); -// if (geometry) { -// const extent = geometry.getExtent(); - -// map.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); -// }; - -// // MapSearchBar 래퍼 컴포넌트 -// // const CustomMapSearchBar = (props: any) => { -// // return ( -// // -// // ); -// // }; - -// return ( -//
-// -// // -// { - -// console.log('p' ,props) -// } -// } -// onFeatureSelect={onFeatureSelect} -// setIsOpen={setIsOpen} -// setFeatureData={setFeatureData} -// featureData={featureData} -// setIsSearchModalOpen={setIsSearchModalOpen} -// isOpen={isOpen} -// isSearchModalOpen={isSearchModalOpen} -// onCheckedLayersChange={handleCheckedLayersChange} -// imgVisble={true} -// searchBar={undefined} -// /> -//
-// ); -// }; - -// export default Map; diff --git a/apps/wr/app/layout.tsx b/apps/wr/app/layout.tsx index fe4c3aff0..953c1d7ab 100644 --- a/apps/wr/app/layout.tsx +++ b/apps/wr/app/layout.tsx @@ -4,6 +4,8 @@ import i18next from "i18next"; import { I18nextProvider } from "react-i18next"; import koBase from "../public/locales/ko/message.json"; import { StoreProvider } from "./store"; +import { LoginApi } from "@/src/entities/auth"; +import { useEffect, useMemo } from "react"; export default function RootLayout({ children, @@ -20,13 +22,21 @@ export default function RootLayout({ }, }); + useEffect(() => { + // 렌더 중이 아니라 클라이언트에서만 실행 + 에러 캐치 + void LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" }) + .catch((e) => { + console.error("Auto login failed:", e); + }); + }, []); + return ( - - {children} - + + {children} + diff --git a/apps/wr/app/map/searchBar/SearchInputText.tsx b/apps/wr/app/map/searchBar/SearchInputText.tsx deleted file mode 100644 index 97ba51fb7..000000000 --- a/apps/wr/app/map/searchBar/SearchInputText.tsx +++ /dev/null @@ -1,122 +0,0 @@ -// SearchInputText.tsx -"use client"; -import { Input } from "@common/components/ui"; -import { useEffect, useRef, useState } from "react"; - -interface SearchInputTextProps { - initValue?: string; - setValue: (val: string) => void; - setRtnData: (val: { fnm: string; fid: string }) => void; - searchList: { fnm: string; fid: string }[]; - onEnter?: () => void; - className?: string; -} - -export default function SearchInputText({ - initValue, - setValue, - setRtnData, - searchList, - onEnter, - className, -}: SearchInputTextProps) { - const [showResults, setShowResults] = useState(false); - const [text, setText] = useState(initValue ?? ""); - const [highlightIndex, setHighlightIndex] = useState(-1); - const wrapperRef = useRef(null); - - useEffect(() => { - setText(initValue ?? ""); - }, [initValue]); - - useEffect(() => { - if (searchList.length > 0) { - setShowResults(true); - } else { - setShowResults(false); - } - setHighlightIndex(-1); - }, [searchList]); - - useEffect(() => { - function handleClickOutside(event: MouseEvent) { - if ( - wrapperRef.current && - !(wrapperRef.current as any).contains(event.target) - ) { - setShowResults(false); - } - } - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [wrapperRef]); - - const handleChange = (e: React.ChangeEvent) => { - setText(e.target.value); - setValue(e.target.value); - setHighlightIndex(-1); - }; - - const handleSelect = (item: { fnm: string; fid: string }) => { - setText(item.fnm); - setValue(item.fnm); - setRtnData(item); - setShowResults(false); - }; - - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { - if (highlightIndex >= 0 && highlightIndex < searchList.length) { - const selected = searchList[highlightIndex]; - if (selected) handleSelect(selected); - } else if (onEnter) { - onEnter(); - } - } else if (e.key === "ArrowDown") { - e.preventDefault(); - setHighlightIndex((prev) => - prev < searchList.length - 1 ? prev + 1 : prev - ); - } else if (e.key === "ArrowUp") { - e.preventDefault(); - setHighlightIndex((prev) => (prev > 0 ? prev - 1 : -1)); - } - }; - - return ( -
- - {showResults && ( -
- {searchList.length > 0 ? ( - searchList.map((item, index) => ( -
handleSelect(item)} - > - {item.fnm} -
- )) - ) : ( -
- 검색 결과가 없습니다. -
- )} -
- )} -
- ); -} diff --git a/apps/wr/app/map/searchBar/comboSearchBar.tsx b/apps/wr/app/map/searchBar/comboSearchBar.tsx deleted file mode 100644 index 15736d710..000000000 --- a/apps/wr/app/map/searchBar/comboSearchBar.tsx +++ /dev/null @@ -1,298 +0,0 @@ -"use client"; -import { SelectBox, type SelectDataType } from "@common/business_components/ui"; -import { Button } from "@common/components/ui"; -import { useCallback, useEffect, useState } from "react"; - -const geoserverUrl = - "/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&outputFormat=application/json"; - -const FACILITY_TYPE_URL_MAP: Record = { - tb_il_swage_prcs_fclt: geoserverUrl, //하수처리시설 - tb_wr_bdst_ruse_fclt: - "/reuse-service/reuseFc/pubDetailList/{year}/{sggCd}/1/1000", //재이용시설 post - tb_wr_rnwtr_utztn_fclt: "/reuse-service/reuseFc/rainyInfoList/1/1000/{sggCd}", //빗물이용시설 get - tb_wr_rswtr_fclt: "/reuse-service/reuseFc/waterreuseFc/1/1000/{sggCd}", //중수도시설 get - tb_wr_htdfl_fclt: "/reuse-service/drain/facilityList/1/1000/{sggCd}", //온배수시설 get - tb_wr_ruse_fclt_dmd_co: "/reuse-service/reuseFc/request/1/1000/{sggCd}", //수요처 get - tb_wr_tmpr_dmd_co: - "/reuse-service/reuseFc/request/temp/1/1000/{sidoNm} {sggNm}", //잠재수요처 get -}; - -interface SearchBarProps { - onFeatureSelect: (feature: any) => void; - gisMaps: React.RefObject; - facilityTypes: { text: string; val: string }[]; -} - -export function SearchBar({ - onFeatureSelect, - gisMaps, - facilityTypes, -}: SearchBarProps) { - const [sidoValue, setSidoValue] = useState("0"); - const [sigunValue, setSigunValue] = useState("0"); - const [sidoData, setSidoData] = useState([ - { text: "선택", val: "0" }, - ]); - const [sigunData, setSigunData] = useState([ - { text: "선택", val: "0" }, - ]); - const [filteredSigunData, setFilteredSigunData] = useState([ - { text: "선택", val: "0" }, - ]); - - const [facilityData, setFacilityData] = useState([ - { text: "선택", val: "0" }, - ]); - const [facilityValue, setFacilityValue] = useState("0"); - - const [facilityType, setFacilityType] = useState( - facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0" - ); - - //시도, 시군구 조회 - const fetchSido = async () => { - const url = `/cms-service/api/v1/code/cache/ADSTDSTRCD/Y`; - const res = await fetch(url); - const json = await res.json(); - const sidoList = json - .filter( - (item: any) => - typeof item.lwpoCd === "string" && item.lwpoCd.length === 2 - ) - .map((feature: any) => ({ - val: feature.lwpoCd, - text: feature.lwpoCdNm, - })); - setSidoData([{ text: "선택", val: "0" }, ...sidoList]); - - const sigunList = json - .filter( - (item: any) => - typeof item.lwpoCd === "string" && item.lwpoCd.length !== 2 - ) - .map((feature: any) => ({ - val: feature.lwpoCd, - text: feature.lwpoCdNm, - })); - setSigunData(sigunList); - }; - - //시설명 콤보박스 조회 - const fetchFacilitiesBySggNm = async ( - sggCd: string, - sggNm: string, - sidoNm: string, - currentFacilityType?: string - ) => { - const type = currentFacilityType ?? facilityType; - if (!type || type === "0") return; - - const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type]; - if (!baseUrlTemplate) return; - - const year = new Date().getFullYear().toString(); - let url = baseUrlTemplate - .replace("{year}", year) - .replace("{sggCd}", sggCd) - .replace("{sidoNm}", encodeURIComponent(sidoNm)) - .replace("{sggNm}", encodeURIComponent(sggNm)); - - let list: SelectDataType[] = []; - - if ( - type === "tb_il_swage_prcs_fclt" //하수처리시설 - ) { - const cqlFilter = `ctpv_nm='${encodeURIComponent(sidoNm)}' AND sgg_nm='${encodeURIComponent(sggNm)}'`; - url = `${url}&typeName=hasudo:${type}&cql_filter=${cqlFilter}`; - const res = await fetch(url); - const json = await res.json(); - list = json.features.map((f: any) => ({ - text: f.properties.swtrmt_fclt_nm ?? "(이름없음)", - val: f.id, - })); - } else if ( - type === "tb_wr_bdst_ruse_fclt" // 재이용시설 - ) { - //재용에서 참조하는 하수처리시설 목록 - const paramsRes = await fetch("/reuse-service/reuseFc/pubFc"); - const paramsJson = await paramsRes.json(); - const params = paramsJson.data; - - const res = await fetch(url, { - method: "POST", - headers: { - accept: "application/json", - "Content-Type": "application/json", - }, - body: JSON.stringify(params), - }); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.ruseUtztnFcltNm ?? "(이름없음)", - val: item.pbnstRuseFcltId, - })); - } else if ( - type === "tb_wr_ruse_fclt_dmd_co" //수요처 - ) { - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.dmdCoNm ?? "(이름없음)", - val: item.dmdInfoId, - })); - } else if ( - type === "tb_wr_tmpr_dmd_co" //잠재수요처 - ) { - // GET 방식 - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.dmdCoNm ?? "(이름없음)", - val: item.fctryMngSn, - })); - } else { - // GET 방식 - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.bdstNm ?? "(이름없음)", - val: item.bdstInfoSn, - })); - } - - setFacilityData([{ text: "선택", val: "0" }, ...list]); - setFacilityValue("0"); - }; - - //시도, 시군구 초기 데이터 조회 - useEffect(() => { - fetchSido(); - }, []); - - //시군구 데이터 초기화 - const initializeSigunData = useCallback( - (sidoCd: string) => { - if (sidoCd === "0") { - setFilteredSigunData([{ text: "선택", val: "0" }]); - setSigunValue("0"); - return; - } - const prefix = sidoCd.substring(0, 2); - const filtered = sigunData.filter((item) => item.val.startsWith(prefix)); - setFilteredSigunData([{ text: "선택", val: "0" }, ...filtered]); - setSigunValue("0"); - }, - [sigunData] - ); - - //콤보박스 선택시 연관 콤보박스 처리 - const onSelectValue = useCallback( - (val: string, type: string) => { - if (type === "ctpvCd") { - setSidoValue(val); - initializeSigunData(val); - setFacilityData([{ text: "선택", val: "0" }]); - setFacilityValue("0"); - } else if (type === "sggCd") { - setSigunValue(val); - const sidoNm = - sidoData.find((item) => item.val === sidoValue)?.text || ""; - const sggNm = sigunData.find((item) => item.val === val)?.text || ""; - const sggCd = sigunData.find((item) => item.val === val)?.val || ""; - if (sggNm && sidoNm) - fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, facilityType); - } else if (type === "facilityType") { - setFacilityType(val); - setFacilityValue("0"); - setFacilityData([{ text: "선택", val: "0" }]); - const sidoNm = - sidoData.find((item) => item.val === sidoValue)?.text || ""; - const sggNm = - sigunData.find((item) => item.val === sigunValue)?.text || ""; - const sggCd = - sigunData.find((item) => item.val === sigunValue)?.val || ""; - if (sggNm && sidoNm) fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, val); - } else if (type === "fcltCd") { - setFacilityValue(val); - } - }, - [initializeSigunData, sigunData, sigunValue, sidoData, sidoValue] - ); - - //조회 버튼 클릭 - const handleSearch = () => { - if (!gisMaps.current || facilityValue === "0") return; - const layers = gisMaps.current.getLayers().getArray(); - for (const layer of layers) { - const source = layer.getSource?.(); - const feature = source?.getFeatureById?.(facilityValue); - if (feature) { - onFeatureSelect(feature); - return; - } - } - alert("해당 처리시설을 지도에서 찾을 수 없습니다."); - }; - - return ( -
-
-
-
- {facilityTypes.length > 1 && ( - - onSelectValue(val.toString(), "facilityType") - } - value={facilityType} - /> - )} - onSelectValue(val.toString(), "ctpvCd")} - value={sidoValue} - /> - onSelectValue(val.toString(), "sggCd")} - value={sigunValue} - /> - onSelectValue(val.toString(), "fcltCd")} - value={facilityValue} - /> -
-
- -
-
-
-
- ); -} diff --git a/apps/wr/app/map/searchBar/procSearchBar.tsx b/apps/wr/app/map/searchBar/procSearchBar.tsx deleted file mode 100644 index 15736d710..000000000 --- a/apps/wr/app/map/searchBar/procSearchBar.tsx +++ /dev/null @@ -1,298 +0,0 @@ -"use client"; -import { SelectBox, type SelectDataType } from "@common/business_components/ui"; -import { Button } from "@common/components/ui"; -import { useCallback, useEffect, useState } from "react"; - -const geoserverUrl = - "/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&outputFormat=application/json"; - -const FACILITY_TYPE_URL_MAP: Record = { - tb_il_swage_prcs_fclt: geoserverUrl, //하수처리시설 - tb_wr_bdst_ruse_fclt: - "/reuse-service/reuseFc/pubDetailList/{year}/{sggCd}/1/1000", //재이용시설 post - tb_wr_rnwtr_utztn_fclt: "/reuse-service/reuseFc/rainyInfoList/1/1000/{sggCd}", //빗물이용시설 get - tb_wr_rswtr_fclt: "/reuse-service/reuseFc/waterreuseFc/1/1000/{sggCd}", //중수도시설 get - tb_wr_htdfl_fclt: "/reuse-service/drain/facilityList/1/1000/{sggCd}", //온배수시설 get - tb_wr_ruse_fclt_dmd_co: "/reuse-service/reuseFc/request/1/1000/{sggCd}", //수요처 get - tb_wr_tmpr_dmd_co: - "/reuse-service/reuseFc/request/temp/1/1000/{sidoNm} {sggNm}", //잠재수요처 get -}; - -interface SearchBarProps { - onFeatureSelect: (feature: any) => void; - gisMaps: React.RefObject; - facilityTypes: { text: string; val: string }[]; -} - -export function SearchBar({ - onFeatureSelect, - gisMaps, - facilityTypes, -}: SearchBarProps) { - const [sidoValue, setSidoValue] = useState("0"); - const [sigunValue, setSigunValue] = useState("0"); - const [sidoData, setSidoData] = useState([ - { text: "선택", val: "0" }, - ]); - const [sigunData, setSigunData] = useState([ - { text: "선택", val: "0" }, - ]); - const [filteredSigunData, setFilteredSigunData] = useState([ - { text: "선택", val: "0" }, - ]); - - const [facilityData, setFacilityData] = useState([ - { text: "선택", val: "0" }, - ]); - const [facilityValue, setFacilityValue] = useState("0"); - - const [facilityType, setFacilityType] = useState( - facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0" - ); - - //시도, 시군구 조회 - const fetchSido = async () => { - const url = `/cms-service/api/v1/code/cache/ADSTDSTRCD/Y`; - const res = await fetch(url); - const json = await res.json(); - const sidoList = json - .filter( - (item: any) => - typeof item.lwpoCd === "string" && item.lwpoCd.length === 2 - ) - .map((feature: any) => ({ - val: feature.lwpoCd, - text: feature.lwpoCdNm, - })); - setSidoData([{ text: "선택", val: "0" }, ...sidoList]); - - const sigunList = json - .filter( - (item: any) => - typeof item.lwpoCd === "string" && item.lwpoCd.length !== 2 - ) - .map((feature: any) => ({ - val: feature.lwpoCd, - text: feature.lwpoCdNm, - })); - setSigunData(sigunList); - }; - - //시설명 콤보박스 조회 - const fetchFacilitiesBySggNm = async ( - sggCd: string, - sggNm: string, - sidoNm: string, - currentFacilityType?: string - ) => { - const type = currentFacilityType ?? facilityType; - if (!type || type === "0") return; - - const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type]; - if (!baseUrlTemplate) return; - - const year = new Date().getFullYear().toString(); - let url = baseUrlTemplate - .replace("{year}", year) - .replace("{sggCd}", sggCd) - .replace("{sidoNm}", encodeURIComponent(sidoNm)) - .replace("{sggNm}", encodeURIComponent(sggNm)); - - let list: SelectDataType[] = []; - - if ( - type === "tb_il_swage_prcs_fclt" //하수처리시설 - ) { - const cqlFilter = `ctpv_nm='${encodeURIComponent(sidoNm)}' AND sgg_nm='${encodeURIComponent(sggNm)}'`; - url = `${url}&typeName=hasudo:${type}&cql_filter=${cqlFilter}`; - const res = await fetch(url); - const json = await res.json(); - list = json.features.map((f: any) => ({ - text: f.properties.swtrmt_fclt_nm ?? "(이름없음)", - val: f.id, - })); - } else if ( - type === "tb_wr_bdst_ruse_fclt" // 재이용시설 - ) { - //재용에서 참조하는 하수처리시설 목록 - const paramsRes = await fetch("/reuse-service/reuseFc/pubFc"); - const paramsJson = await paramsRes.json(); - const params = paramsJson.data; - - const res = await fetch(url, { - method: "POST", - headers: { - accept: "application/json", - "Content-Type": "application/json", - }, - body: JSON.stringify(params), - }); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.ruseUtztnFcltNm ?? "(이름없음)", - val: item.pbnstRuseFcltId, - })); - } else if ( - type === "tb_wr_ruse_fclt_dmd_co" //수요처 - ) { - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.dmdCoNm ?? "(이름없음)", - val: item.dmdInfoId, - })); - } else if ( - type === "tb_wr_tmpr_dmd_co" //잠재수요처 - ) { - // GET 방식 - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.dmdCoNm ?? "(이름없음)", - val: item.fctryMngSn, - })); - } else { - // GET 방식 - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.bdstNm ?? "(이름없음)", - val: item.bdstInfoSn, - })); - } - - setFacilityData([{ text: "선택", val: "0" }, ...list]); - setFacilityValue("0"); - }; - - //시도, 시군구 초기 데이터 조회 - useEffect(() => { - fetchSido(); - }, []); - - //시군구 데이터 초기화 - const initializeSigunData = useCallback( - (sidoCd: string) => { - if (sidoCd === "0") { - setFilteredSigunData([{ text: "선택", val: "0" }]); - setSigunValue("0"); - return; - } - const prefix = sidoCd.substring(0, 2); - const filtered = sigunData.filter((item) => item.val.startsWith(prefix)); - setFilteredSigunData([{ text: "선택", val: "0" }, ...filtered]); - setSigunValue("0"); - }, - [sigunData] - ); - - //콤보박스 선택시 연관 콤보박스 처리 - const onSelectValue = useCallback( - (val: string, type: string) => { - if (type === "ctpvCd") { - setSidoValue(val); - initializeSigunData(val); - setFacilityData([{ text: "선택", val: "0" }]); - setFacilityValue("0"); - } else if (type === "sggCd") { - setSigunValue(val); - const sidoNm = - sidoData.find((item) => item.val === sidoValue)?.text || ""; - const sggNm = sigunData.find((item) => item.val === val)?.text || ""; - const sggCd = sigunData.find((item) => item.val === val)?.val || ""; - if (sggNm && sidoNm) - fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, facilityType); - } else if (type === "facilityType") { - setFacilityType(val); - setFacilityValue("0"); - setFacilityData([{ text: "선택", val: "0" }]); - const sidoNm = - sidoData.find((item) => item.val === sidoValue)?.text || ""; - const sggNm = - sigunData.find((item) => item.val === sigunValue)?.text || ""; - const sggCd = - sigunData.find((item) => item.val === sigunValue)?.val || ""; - if (sggNm && sidoNm) fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, val); - } else if (type === "fcltCd") { - setFacilityValue(val); - } - }, - [initializeSigunData, sigunData, sigunValue, sidoData, sidoValue] - ); - - //조회 버튼 클릭 - const handleSearch = () => { - if (!gisMaps.current || facilityValue === "0") return; - const layers = gisMaps.current.getLayers().getArray(); - for (const layer of layers) { - const source = layer.getSource?.(); - const feature = source?.getFeatureById?.(facilityValue); - if (feature) { - onFeatureSelect(feature); - return; - } - } - alert("해당 처리시설을 지도에서 찾을 수 없습니다."); - }; - - return ( -
-
-
-
- {facilityTypes.length > 1 && ( - - onSelectValue(val.toString(), "facilityType") - } - value={facilityType} - /> - )} - onSelectValue(val.toString(), "ctpvCd")} - value={sidoValue} - /> - onSelectValue(val.toString(), "sggCd")} - value={sigunValue} - /> - onSelectValue(val.toString(), "fcltCd")} - value={facilityValue} - /> -
-
- -
-
-
-
- ); -} diff --git a/apps/wr/app/map/searchBar/searchBar.tsx b/apps/wr/app/map/searchBar/searchBar.tsx deleted file mode 100644 index ab3dacb0e..000000000 --- a/apps/wr/app/map/searchBar/searchBar.tsx +++ /dev/null @@ -1,351 +0,0 @@ -"use client"; -import { SelectBox, type SelectDataType } from "@common/business_components/ui"; -import { Button } from "@common/components/ui"; -import { useCallback, useEffect, useState } from "react"; -import SearchInputText from "./SearchInputText"; - -const FACILITY_TYPE_URL_MAP: Record = { - tb_il_swage_prcs_fclt: - "/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_il_swage_prcs_fclt&outputFormat=application/json&propertyName=swtrmt_fclt_cd,swtrmt_fclt_nm&cql_filter=", - tb_wr_bdst_ruse_fclt: - "/reuse-service/reuseFc/pubDetailList/{year}/{sggCd}/1/1000/", - tb_wr_rnwtr_utztn_fclt: - "/reuse-service/reuseFc/rainyInfoList/1/1000/{sggCd}/{fcltyNm}", - tb_wr_rswtr_fclt: - "/reuse-service/reuseFc/waterreuseFc/1/1000/{sggCd}/{fcltyNm}", - tb_wr_htdfl_fclt: - "/reuse-service/drain/facilityList/1/1000/{sggCd}/{fcltyNm}", - tb_wr_ruse_fclt_dmd_co: - "/reuse-service/reuseFc/request/1/1000/{sggCd}/{fcltyNm}", - tb_wr_tmpr_dmd_co: - "/reuse-service/reuseFc/request/temp/1/1000/{sidoNm} {sggNm}/{fcltyNm}", -}; - -interface SearchBarProps { - gisMaps: React.RefObject; - facilityTypes: { text: string; val: string }[]; - onFeatureFocus: any; -} - -export function SearchBar({ - gisMaps, - facilityTypes, - onFeatureFocus, -}: SearchBarProps) { - console.log('gisMaps ', gisMaps) - console.log('onFeatureFocus ', onFeatureFocus) - - const [sidoValue, setSidoValue] = useState("0"); - const [sigunValue, setSigunValue] = useState("0"); - const [facilityType, setFacilityType] = useState( - facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0" - ); - const [fcltyNm, setFcltyNm] = useState(""); - const [searchList, setSearchList] = useState<{ fnm: string; fid: string }[]>( - [] - ); - - const [sidoData, setSidoData] = useState([ - { text: "시도", val: "0" }, - ]); - const [sigunData, setSigunData] = useState([ - { text: "시군구", val: "0" }, - ]); - const [filteredSigunData, setFilteredSigunData] = useState([ - { text: "시군구", val: "0" }, - ]); - - const fetchSido = async () => { - const res = await fetch("/cms-service/api/v1/code/cache/ADSTDSTRCD/Y"); - const json = await res.json(); - const sidoList = json - .filter((item: any) => item.lwpoCd?.length === 2) - .map((item: any) => ({ val: item.lwpoCd, text: item.lwpoCdNm })); - const sigunList = json - .filter((item: any) => item.lwpoCd?.length > 2) - .map((item: any) => ({ val: item.lwpoCd, text: item.lwpoCdNm })); - setSidoData([{ text: "시도", val: "0" }, ...sidoList]); - setSigunData(sigunList); - }; - - const initializeSigunData = useCallback( - (sidoCd: string) => { - if (sidoCd === "0") { - setFilteredSigunData([{ text: "시도", val: "0" }]); - setSigunValue("0"); - return; - } - const prefix = sidoCd.substring(0, 2); - const filtered = sigunData.filter((item) => item.val.startsWith(prefix)); - setFilteredSigunData([{ text: "시군구", val: "0" }, ...filtered]); - setSigunValue("0"); - }, - [sigunData] - ); - - useEffect(() => { - fetchSido(); - }, []); - - const onSelectValue = useCallback( - (val: string, type: string) => { - if (type === "ctpvCd") { - setSidoValue(val); - initializeSigunData(val); - setSearchList([]); - setFcltyNm(""); - } else if (type === "sggCd") { - setSigunValue(val); - setSearchList([]); - setFcltyNm(""); - } else if (type === "facilityType") { - setFacilityType(val); - setSearchList([]); - setFcltyNm(""); - } - }, - [initializeSigunData] - ); - - const handleSearch = async () => { - if (!fcltyNm) return alert("시설명을 입력하세요."); - - const sidoNm = sidoData.find((item) => item.val === sidoValue)?.text || ""; - const sggNm = sigunData.find((item) => item.val === sigunValue)?.text || ""; - - const type = facilityType; - const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type]; - if (!baseUrlTemplate) return; - - let url = baseUrlTemplate; - const year = new Date().getFullYear().toString(); - url = url - .replace("{year}", year) - .replace("{sggCd}", sigunValue) - .replace("{sidoNm}", encodeURIComponent(sidoNm)) - .replace("{sggNm}", encodeURIComponent(sggNm)) - .replace("{fcltyNm}", encodeURIComponent(fcltyNm)); - - let list: SelectDataType[] = []; - - if (type === "tb_il_swage_prcs_fclt") { - const cqlFilter = `ctpv_nm='${sidoNm}' and sgg_nm='${sggNm}' and swtrmt_fclt_nm like '%${fcltyNm}%'`; - url += encodeURIComponent(cqlFilter); - const res = await fetch(url); - const json = await res.json(); - list = json.features.map((f: any) => ({ - text: f.properties.swtrmt_fclt_nm ?? "(이름없음)", - val: f.id, - })); - } else if ( - type === "tb_wr_bdst_ruse_fclt" // 재이용시설 - ) { - //재이용에서 참조하는 하수처리시설 목록 - const procRes = await fetch("/reuse-service/reuseFc/pubFc"); - const procJson = await procRes.json(); - const procData = procJson.data; - const procResult = procData - .filter((code: string) => code.slice(0, 5) === sigunValue) - .map((code: string) => { - return code; - }); - - //처리시설명으로 처리시설코드 조회 - let procUrl2 = - "/operation-service/prcsFclt/ruseInfo/1/1000/A/{sggCd}/0/1/SW/{fcltyNm}"; - procUrl2 = procUrl2 - .replace("{sggCd}", sigunValue) - .replace("{fcltyNm}", encodeURIComponent(fcltyNm)); - const procRes2 = await fetch(procUrl2, { - method: "POST", - headers: { - accept: "application/json", - "Content-Type": "application/json", - }, - body: JSON.stringify(procResult), - }); - const procJson2 = await procRes2.json(); - const procResult2 = (procJson2.data || []).map((item: any) => item.fid); - - //최종 처리시설코드로 재이용시설조회 - const res = await fetch(url, { - method: "POST", - headers: { - accept: "application/json", - "Content-Type": "application/json", - }, - body: JSON.stringify(procResult2), - }); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.ruseUtztnFcltNm ?? "(이름없음)", - val: item.pbnstRuseFcltId, - })); - } else if ( - type === "tb_wr_ruse_fclt_dmd_co" //수요처 - ) { - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.dmdCoNm ?? "(이름없음)", - val: item.dmdInfoId, - })); - } else if ( - type === "tb_wr_tmpr_dmd_co" //잠재수요처 - ) { - // GET 방식 - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.dmdCoNm ?? "(이름없음)", - val: item.fctryMngSn, - })); - } else { - // GET 방식 - const res = await fetch(url); - const json = await res.json(); - list = (json.data || []).map((item: any) => ({ - text: item.bdstNm ?? "(이름없음)", - val: item.bdstInfoSn, - })); - } - - if (list.length === 0) { - alert("검색 결과가 없습니다."); - setSearchList([]); - setFcltyNm(""); - return; - } - - const newList = list.map((item: any) => { - const code = item.val; - const name = item.text; - return { fnm: name, fid: code }; - }); - setSearchList(newList); - }; - - const moveFocus = (feature: any) => { - console.log('feature ' ,feature) - - // console.log('searchbar:moveFocus') - // const map = gisMaps.current; - // if (!map) { - // console.warn("지도가 초기화되지 않았습니다."); - // return; - // } - - // // 항상 같은 select 객체 사용 - // const select = GisApp.Module.select as any; - // if (!select) return; - - // // 1. 기존 선택 초기화 - // select.resetSelectedFeature(); - - // // 2. data가 OpenLayers Feature 인스턴스인지 확인 - // let foundFeature: any = null; - // let featureId = data.fid; - // const layerName = data.layerNm; - // map - // .getLayers() - // .getArray() - // .forEach((layer: any) => { - // const source = layer.getSource?.(); - // if (source?.getFeatureById) { - // const feature = source.getFeatureById(String(featureId).trim()); - // if (feature) foundFeature = feature; - // } - // }); - - // // 3. 피처 선택 - // if (foundFeature) { - // const geometry = foundFeature.getGeometry(); - // if (geometry) { - // const extent = geometry.getExtent(); - - // map.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); - // } - }; - - return ( -
-
-
-
- {facilityTypes.length > 1 && ( - - onSelectValue(val.toString(), "facilityType") - } - value={facilityType} - /> - )} - onSelectValue(val.toString(), "ctpvCd")} - value={sidoValue} - /> - onSelectValue(val.toString(), "sggCd")} - value={sigunValue} - /> - { - setFcltyNm(val); - }} - setRtnData={(selected: { fnm: string; fid: string }) => { - // 선택된 항목이 있을 경우 onFeatureSelect 실행 - const type = facilityType; - moveFocus({ - layerNm: type, - ...selected, - }); - }} - searchList={searchList} - onEnter={handleSearch} - className="mr-5 w-[150px]" - /> -
-
- -
-
-
-
- ); -} diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx index c7dcf1ca8..bbff85bcb 100644 --- a/apps/wr/app/store/store.tsx +++ b/apps/wr/app/store/store.tsx @@ -342,7 +342,7 @@ export const StoreZus = ( getMiddleRegionCd(set); getUnitWaterShedCd(set); getEnvPartCd(set); - LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" }); + // LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" }); return { ...initState, ...comFcltSearchAction(set), diff --git a/apps/wr/middleware.ts b/apps/wr/middleware.ts index c5c7f8c01..e47a2a8f5 100644 --- a/apps/wr/middleware.ts +++ b/apps/wr/middleware.ts @@ -16,15 +16,6 @@ export function middleware(req: NextRequest) { console.log(`[Middleware] Request URL: ${req.url}`); const searchParams = req.nextUrl.searchParams; - // if (pathname.startsWith("/server")) { - // const queryParams = searchParams.toString(); - // const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${ - // queryParams ? `?${queryParams}` : "" - // }`; - // console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`); - // return NextResponse.rewrite(new URL(newUrl)); - // } - if (pathname.startsWith("/server")) { const decodedParams = Array.from(searchParams.entries()) .map(([key, value]) => `${key}=${decodeURIComponent(value)}`) @@ -46,7 +37,6 @@ export function middleware(req: NextRequest) { const Authorization = req.cookies.get(CLAIM_NAME)?.value; const newUrl = `${serverApiUrl}${pathname}`; - console.log("Authorization cms-service ", Authorization); if (Authorization) requestHeaders.set(CLAIM_NAME, Authorization); //if (userId) requestHeaders.set(AUTH_USER_ID, userId); @@ -90,7 +80,6 @@ export function middleware(req: NextRequest) { if (pathname.startsWith("/geoserver")) { let queryParams = searchParams.toString(); const typename = searchParams.get("TYPENAME"); - console.log("typename ", typename); const startYmd = searchParams.get("START_YMD") ?? null; const endYmd = searchParams.get("END_YMD") ?? null; @@ -129,7 +118,7 @@ export function middleware(req: NextRequest) { newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`; } - console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); + //console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); return NextResponse.rewrite(new URL(newUrl)); } diff --git a/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx b/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx index e750ab1a7..3f5fc1820 100644 --- a/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx +++ b/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx @@ -69,7 +69,7 @@ export const SearchBar = ({ const initializeSigunData = useCallback( (sidoCd: string) => { if (sidoCd === "0") { - setFilteredSigunData([{ text: "시도", val: "0" }]); + setFilteredSigunData([{ text: "시군구", val: "0" }]); setSigunValue("0"); return; } @@ -110,7 +110,6 @@ export const SearchBar = ({ const sidoNm = sidoData.find((item) => item.val === sidoValue)?.text || ""; const sggNm = sigunData.find((item) => item.val === sigunValue)?.text || ""; - const type = facilityType; const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type]; if (!baseUrlTemplate) return; @@ -149,8 +148,7 @@ export const SearchBar = ({ }); //처리시설명으로 처리시설코드 조회 - let procUrl2 = - "/operation-service/prcsFclt/ruseInfo/1/1000/A/{sggCd}/0/1/SW/{fcltyNm}"; + let procUrl2 = "/operation-service/prcsFclt/ruseInfo/1/1000/A/{sggCd}/0/1/SW/{fcltyNm}"; procUrl2 = procUrl2 .replace("{sggCd}", sigunValue) .replace("{fcltyNm}", encodeURIComponent(fcltyNm)); @@ -163,7 +161,7 @@ export const SearchBar = ({ body: JSON.stringify(procResult), }); const procJson2 = await procRes2.json(); - const procResult2 = (procJson2.data || []).map((item: any) => item.fid); + const procResult2 = (procJson2.data || []).map((item: any) => item.bscFctCd); //최종 처리시설코드로 재이용시설조회 const res = await fetch(url, { @@ -179,6 +177,7 @@ export const SearchBar = ({ text: item.ruseUtztnFcltNm ?? "(이름없음)", val: item.pbnstRuseFcltId, })); + } else if ( type === "tb_wr_ruse_fclt_dmd_co" //수요처 ) { @@ -225,6 +224,23 @@ export const SearchBar = ({ //해당 시설물로 이동 const handleFeatureFocus = (data: any) => { + + let featureId = data.fid; + const layerNm = data.layerNm; + + if (!isNaN(Number(featureId))) { + // 숫자면 문자열로 변환 + featureId = String(featureId); + } + + if (layerNm === "tb_wr_bdst_ruse_fclt") { + featureId = featureId.slice(0, 11); + } + + if (!featureId.includes(".")) { + featureId = layerNm + "." + featureId; + } + const map = gisMaps.current; if (!map) { console.warn("지도가 초기화되지 않았습니다."); @@ -237,7 +253,7 @@ export const SearchBar = ({ //select.resetSelectedFeature(); // 2. data가 OpenLayers Feature 인스턴스인지 확인 let foundFeature: any = null; - let featureId = data.fid; + map .getLayers() .getArray() @@ -285,7 +301,7 @@ export const SearchBar = ({ { text: "시설 구분", val: "0" }, ...facilityTypes, ]} - onSelectValue={(val:any) => + onSelectValue={(val: any) => onSelectValue(val.toString(), "facilityType") } value={facilityType} @@ -297,7 +313,7 @@ export const SearchBar = ({ selectClass="rounded-lg bg-white" label="" selectArray={sidoData} - onSelectValue={(val:any) => onSelectValue(val.toString(), "ctpvCd")} + onSelectValue={(val: any) => onSelectValue(val.toString(), "ctpvCd")} value={sidoValue} /> onSelectValue(val.toString(), "sggCd")} + onSelectValue={(val: any) => onSelectValue(val.toString(), "sggCd")} value={sigunValue} />