"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]" />
); }