159 lines
5.5 KiB
TypeScript
159 lines
5.5 KiB
TypeScript
"use client";
|
|
import { SelectBox, type SelectDataType } from "@common/business_components/ui";
|
|
import { Button } from "@common/components/ui";
|
|
import { useCallback, useEffect, useState } from "react";
|
|
|
|
interface SearchBarProps {
|
|
onFeatureSelect: (feature: any) => void;
|
|
gisMaps: React.RefObject<any>;
|
|
}
|
|
|
|
export function SearchBar({ onFeatureSelect, gisMaps }: SearchBarProps) {
|
|
const [sidoValue, setSidoValue] = useState("0");
|
|
const [sigunValue, setSigunValue] = useState("0");
|
|
const [sidoData, setSidoData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
|
const [sigunData, setSigunData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
|
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
|
const [facilityData, setFacilityData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
|
const [facilityValue, setFacilityValue] = useState("0");
|
|
|
|
const fetchSido = async () => {
|
|
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_ctpv&outputFormat=application/json&propertyName=mctpv_korn_nm,mctpv_cd`;
|
|
const res = await fetch(url);
|
|
const json = await res.json();
|
|
|
|
const list = json.features.map((f: any) => ({
|
|
text: f.properties.mctpv_korn_nm,
|
|
val: f.properties.mctpv_cd,
|
|
}));
|
|
setSidoData([{ text: "선택", val: "0" }, ...list]);
|
|
};
|
|
|
|
const fetchSigun = async () => {
|
|
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_sgg&outputFormat=application/json&propertyName=sgg_cd,sgg_korn_nm`;
|
|
const res = await fetch(url);
|
|
const json = await res.json();
|
|
|
|
const list = json.features.map((f: any) => ({
|
|
text: f.properties.sgg_korn_nm,
|
|
val: f.properties.sgg_cd,
|
|
}));
|
|
setSigunData(list);
|
|
};
|
|
|
|
const fetchFacilitiesBySggNm = async (sggNm: string) => {
|
|
const encodedSggNm = encodeURIComponent(sggNm);
|
|
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_il_swage_prcs_fclt&outputFormat=application/json&cql_filter=sgg_nm='${encodedSggNm}'`;
|
|
const res = await fetch(url);
|
|
const json = await res.json();
|
|
|
|
const list = json.features.map((f: any) => ({
|
|
text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
|
|
val: f.id, // f.properties.swtrmt_fclt_cd 도 가능
|
|
}));
|
|
setFacilityData([{ text: "선택", val: "0" }, ...list]);
|
|
setFacilityValue("0");
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchSido();
|
|
fetchSigun();
|
|
}, []);
|
|
|
|
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" }]);
|
|
} else if (type === "sggCd") {
|
|
setSigunValue(val);
|
|
const sggNm = sigunData.find((item) => item.val === val)?.text || "";
|
|
if (sggNm) fetchFacilitiesBySggNm(sggNm);
|
|
} else if (type === "fcltCd") {
|
|
setFacilityValue(val);
|
|
}
|
|
},
|
|
[initializeSigunData, sigunData]
|
|
);
|
|
|
|
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 (
|
|
<div className="grid grid-cols-4 gap-4">
|
|
<div className="col-span-4">
|
|
<div className="card card-border flex">
|
|
<div className="col-span-10 flex flex-row">
|
|
<SelectBox
|
|
labelClass="w-[40px]"
|
|
className="mr-10 w-[200px]"
|
|
selectClass="rounded-lg bg-white"
|
|
label="시도"
|
|
selectArray={sidoData}
|
|
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
|
|
value={sidoValue}
|
|
/>
|
|
<SelectBox
|
|
labelClass="w-[65px]"
|
|
className="mr-10 w-[200px]"
|
|
selectClass="rounded-lg bg-white"
|
|
label="시군구"
|
|
selectArray={filteredSigunData}
|
|
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
|
|
value={sigunValue}
|
|
/>
|
|
<SelectBox
|
|
labelClass="w-[140px]"
|
|
className="mr-3 w-[250px]"
|
|
selectClass="rounded-lg bg-white"
|
|
label="하수처리시설"
|
|
selectArray={facilityData}
|
|
onSelectValue={(val) => onSelectValue(val.toString(), "fcltCd")}
|
|
value={facilityValue}
|
|
/>
|
|
</div>
|
|
<div className="flex flex-row space-x-2">
|
|
<Button
|
|
color="primary"
|
|
className="mx-2 mt-1 ml-10"
|
|
size={"sm"}
|
|
onClick={handleSearch}
|
|
>
|
|
조회
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|