-
-
-
-
-
- onSelectValue(val.toString(), "ctpvCd")
- }
- value={sidoValue || Common.selectSidoData[0]?.val || ""}
- />
-
- onSelectValue(val.toString(), "sggCd")
- }
- value={sigunValue}
- />
-
-
- {
- let sggOrCity = "";
- if (searchNm) {
- if (sigunValue === "0" || sigunValue === "") {
- sggOrCity = sidoValue;
- } else {
- sggOrCity = sigunValue;
- }
- findRuseFclt(sggOrCity, searchNm);
- }
- }}
- setRtnData={(rtnData: any) => {
- setHasuPk(rtnData);
- }}
- searchList={map.ruseFcltList || []}
- />
-
-
-
-
-
-
-
-
+
+
+ onSelectValue(val.toString(), "ctpvCd")}
+ value={sidoValue || Common.selectSidoData[0]?.val || ""}
+ />
+ onSelectValue(val.toString(), "sggCd")}
+ value={sigunValue}
+ />
+
+ {
+ let sggOrCity = "";
+ if (searchNm) {
+ if (sigunValue === "0" || sigunValue === "") {
+ sggOrCity = sidoValue;
+ } else {
+ sggOrCity = sigunValue;
+ }
+ findRuseFclt(sggOrCity, searchNm);
+ }
+ }}
+ setRtnData={(rtnData: any) => {
+ setHasuPk(rtnData);
+ }}
+ searchList={map.ruseFcltList || []}
+ />
+
- >
+
);
}
diff --git a/apps/dm/public/images/map/layericon/BML_CBAS_PS.png b/apps/dm/public/images/map/layericon/BML_CBAS_PS.png
index 5ff4add3e..0e70939ba 100644
Binary files a/apps/dm/public/images/map/layericon/BML_CBAS_PS.png and b/apps/dm/public/images/map/layericon/BML_CBAS_PS.png differ
diff --git a/apps/dm/public/images/map/layericon/BML_STMS_PS.png b/apps/dm/public/images/map/layericon/BML_STMS_PS.png
index 423f2e8fc..bf4357181 100644
Binary files a/apps/dm/public/images/map/layericon/BML_STMS_PS.png and b/apps/dm/public/images/map/layericon/BML_STMS_PS.png differ
diff --git a/apps/dm/public/images/map/layericon/RDL_ETCT_PS.png b/apps/dm/public/images/map/layericon/RDL_ETCT_PS.png
index 29c0b77b4..e5a83f998 100644
Binary files a/apps/dm/public/images/map/layericon/RDL_ETCT_PS.png and b/apps/dm/public/images/map/layericon/RDL_ETCT_PS.png differ
diff --git a/apps/dm/public/images/map/layericon/RDL_OCUP_PS.png b/apps/dm/public/images/map/layericon/RDL_OCUP_PS.png
index 8a1ac0074..aeae3e266 100644
Binary files a/apps/dm/public/images/map/layericon/RDL_OCUP_PS.png and b/apps/dm/public/images/map/layericon/RDL_OCUP_PS.png differ
diff --git a/apps/dm/public/images/map/layericon/RDL_SEPC_PS.png b/apps/dm/public/images/map/layericon/RDL_SEPC_PS.png
index 087b4e941..b3db8e0a4 100644
Binary files a/apps/dm/public/images/map/layericon/RDL_SEPC_PS.png and b/apps/dm/public/images/map/layericon/RDL_SEPC_PS.png differ
diff --git a/apps/dm/public/images/map/layericon/RDL_STAT_PS.png b/apps/dm/public/images/map/layericon/RDL_STAT_PS.png
index 13d8ea689..9a0b11673 100644
Binary files a/apps/dm/public/images/map/layericon/RDL_STAT_PS.png and b/apps/dm/public/images/map/layericon/RDL_STAT_PS.png differ
diff --git a/apps/dm/public/images/map/layericon/RDL_TSCT_PS.png b/apps/dm/public/images/map/layericon/RDL_TSCT_PS.png
index ffc225159..3776f6c04 100644
Binary files a/apps/dm/public/images/map/layericon/RDL_TSCT_PS.png and b/apps/dm/public/images/map/layericon/RDL_TSCT_PS.png differ
diff --git a/apps/fo/.env.development b/apps/fo/.env.development
index 94488f0cd..44fe06736 100644
--- a/apps/fo/.env.development
+++ b/apps/fo/.env.development
@@ -2,6 +2,7 @@ NEXT_PUBLIC_SITE_ID = FO
NEXT_PUBLIC_PORT = 11300
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
+#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
diff --git a/apps/fo/.env.local b/apps/fo/.env.local
index 76fb868cd..e125bed3d 100644
--- a/apps/fo/.env.local
+++ b/apps/fo/.env.local
@@ -1,7 +1,8 @@
NEXT_PUBLIC_SITE_ID = FO
NEXT_PUBLIC_PORT = 3000
NEXT_PUBLIC_PROXY_HOST = http://localhost:3000
-NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
+NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
+#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
diff --git a/apps/fo/.env.production b/apps/fo/.env.production
index 16675eaec..52534bd8e 100644
--- a/apps/fo/.env.production
+++ b/apps/fo/.env.production
@@ -15,6 +15,7 @@ NEXT_PUBLIC_SITE_ID = FO
NEXT_PUBLIC_PORT = 11300
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
+#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
diff --git a/apps/fo/app/pages/map/page.tsx b/apps/fo/app/pages/map/page.tsx
index 2c27869b0..edd7b70d2 100644
--- a/apps/fo/app/pages/map/page.tsx
+++ b/apps/fo/app/pages/map/page.tsx
@@ -3,6 +3,7 @@
import Gis from "@common/business_components/ui/map/Gis";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
import { useEffect, useRef, useState } from "react";
+import { SearchBar } from "./searchBar/searchBar";
interface FeatureData {
fid?: string;
@@ -123,24 +124,15 @@ const Map = () => {
setIsSearchModalOpen(false);
};
- // onCheckedLayersChange handler
- const handleCheckedLayersChange = (
- checkedIds: string[],
- checkedNodesData: unknown[]
- ) => {
- // Handle checked layers change if needed
- console.log("Checked layers changed:", checkedIds, checkedNodesData);
- };
-
return (
{
setIsSearchModalOpen={setIsSearchModalOpen}
isOpen={isOpen}
isSearchModalOpen={isSearchModalOpen}
- onCheckedLayersChange={handleCheckedLayersChange}
+ onCheckedLayersChange={undefined}
imgVisble={false}
- searchBar={undefined}
+ searchBar={(props:any) => }
/>
);
diff --git a/apps/fo/app/pages/map/searchBar/searchBar.tsx b/apps/fo/app/pages/map/searchBar/searchBar.tsx
new file mode 100644
index 000000000..e9084870a
--- /dev/null
+++ b/apps/fo/app/pages/map/searchBar/searchBar.tsx
@@ -0,0 +1,159 @@
+"use client";
+import { SelectBox, type SelectDataType } from "@common/business_components/ui";
+import { Button } from "@common/components/ui";
+import { useCallback, useEffect, useState } from "react";
+import { GEOSERVER_URL } from "@/src/shared/config/env";
+
+interface SearchBarProps {
+ onFeatureSelect: (feature: any) => void;
+ gisMaps: React.RefObject
;
+}
+
+export function SearchBar({ onFeatureSelect, gisMaps }: 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 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 (
+
+
+
+
+ onSelectValue(val.toString(), "ctpvCd")}
+ value={sidoValue}
+ />
+ onSelectValue(val.toString(), "sggCd")}
+ value={sigunValue}
+ />
+ onSelectValue(val.toString(), "fcltCd")}
+ value={facilityValue}
+ />
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/fo/public/images/map/layericon/BML_CBAS_PS.png b/apps/fo/public/images/map/layericon/BML_CBAS_PS.png
index 5ff4add3e..0e70939ba 100644
Binary files a/apps/fo/public/images/map/layericon/BML_CBAS_PS.png and b/apps/fo/public/images/map/layericon/BML_CBAS_PS.png differ
diff --git a/apps/fo/public/images/map/layericon/BML_STMS_PS.png b/apps/fo/public/images/map/layericon/BML_STMS_PS.png
index 423f2e8fc..bf4357181 100644
Binary files a/apps/fo/public/images/map/layericon/BML_STMS_PS.png and b/apps/fo/public/images/map/layericon/BML_STMS_PS.png differ
diff --git a/apps/fo/public/images/map/layericon/RDL_ETCT_PS.png b/apps/fo/public/images/map/layericon/RDL_ETCT_PS.png
index 29c0b77b4..e5a83f998 100644
Binary files a/apps/fo/public/images/map/layericon/RDL_ETCT_PS.png and b/apps/fo/public/images/map/layericon/RDL_ETCT_PS.png differ
diff --git a/apps/fo/public/images/map/layericon/RDL_OCUP_PS.png b/apps/fo/public/images/map/layericon/RDL_OCUP_PS.png
index 8a1ac0074..aeae3e266 100644
Binary files a/apps/fo/public/images/map/layericon/RDL_OCUP_PS.png and b/apps/fo/public/images/map/layericon/RDL_OCUP_PS.png differ
diff --git a/apps/fo/public/images/map/layericon/RDL_SEPC_PS.png b/apps/fo/public/images/map/layericon/RDL_SEPC_PS.png
index 087b4e941..b3db8e0a4 100644
Binary files a/apps/fo/public/images/map/layericon/RDL_SEPC_PS.png and b/apps/fo/public/images/map/layericon/RDL_SEPC_PS.png differ
diff --git a/apps/fo/public/images/map/layericon/RDL_STAT_PS.png b/apps/fo/public/images/map/layericon/RDL_STAT_PS.png
index 13d8ea689..9a0b11673 100644
Binary files a/apps/fo/public/images/map/layericon/RDL_STAT_PS.png and b/apps/fo/public/images/map/layericon/RDL_STAT_PS.png differ
diff --git a/apps/fo/public/images/map/layericon/RDL_TSCT_PS.png b/apps/fo/public/images/map/layericon/RDL_TSCT_PS.png
index ffc225159..3776f6c04 100644
Binary files a/apps/fo/public/images/map/layericon/RDL_TSCT_PS.png and b/apps/fo/public/images/map/layericon/RDL_TSCT_PS.png differ
diff --git a/apps/fo/src/shared/config/env.ts b/apps/fo/src/shared/config/env.ts
index cc516daf1..8baf1b0f0 100644
--- a/apps/fo/src/shared/config/env.ts
+++ b/apps/fo/src/shared/config/env.ts
@@ -2,8 +2,7 @@ export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "FO";
export const PORT = process.env.NEXT_PUBLIC_PORT || "3000";
export const PROXY_HOST = process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`;
export const SERVER_API_WR_URL = process.env.NEXT_PUBLIC_WR_SERVER_API_URL ||'http://con.mind-one.co.kr:11080/api/v1';
-//export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL||' http://con.mind-one.co.kr:11082/api/v1';
-export const SERVER_API_URL = process.env.NEXT_PUBLIC_CS_SERVER_API_URL||' http://con.mind-one.co.kr:11082/api/v1';
+export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL||' http://con.mind-one.co.kr:11082/api/v1';
export const SERVER_API_CS_URL = process.env.NEXT_PUBLIC_CS_SERVER_API_URL||'http://dev.onasys.co.kr:8000';
export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
export const ACCESS_TOKEN = process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token";
diff --git a/apps/sn/public/images/map/layericon/BML_CBAS_PS copy.png b/apps/sn/public/images/map/layericon/BML_CBAS_PS copy.png
new file mode 100644
index 000000000..0e70939ba
Binary files /dev/null and b/apps/sn/public/images/map/layericon/BML_CBAS_PS copy.png differ
diff --git a/apps/sn/public/images/map/layericon/BML_STMS_PS copy.png b/apps/sn/public/images/map/layericon/BML_STMS_PS copy.png
new file mode 100644
index 000000000..bf4357181
Binary files /dev/null and b/apps/sn/public/images/map/layericon/BML_STMS_PS copy.png differ
diff --git a/apps/sn/public/images/map/layericon/RDL_ETCT_PS copy.png b/apps/sn/public/images/map/layericon/RDL_ETCT_PS copy.png
new file mode 100644
index 000000000..e5a83f998
Binary files /dev/null and b/apps/sn/public/images/map/layericon/RDL_ETCT_PS copy.png differ
diff --git a/apps/sn/public/images/map/layericon/RDL_OCUP_PS copy.png b/apps/sn/public/images/map/layericon/RDL_OCUP_PS copy.png
new file mode 100644
index 000000000..aeae3e266
Binary files /dev/null and b/apps/sn/public/images/map/layericon/RDL_OCUP_PS copy.png differ
diff --git a/apps/sn/public/images/map/layericon/RDL_SEPC_PS copy.png b/apps/sn/public/images/map/layericon/RDL_SEPC_PS copy.png
new file mode 100644
index 000000000..b3db8e0a4
Binary files /dev/null and b/apps/sn/public/images/map/layericon/RDL_SEPC_PS copy.png differ
diff --git a/apps/sn/public/images/map/layericon/RDL_STAT_PS copy.png b/apps/sn/public/images/map/layericon/RDL_STAT_PS copy.png
new file mode 100644
index 000000000..9a0b11673
Binary files /dev/null and b/apps/sn/public/images/map/layericon/RDL_STAT_PS copy.png differ
diff --git a/apps/sn/public/images/map/layericon/RDL_TSCT_PS copy.png b/apps/sn/public/images/map/layericon/RDL_TSCT_PS copy.png
new file mode 100644
index 000000000..3776f6c04
Binary files /dev/null and b/apps/sn/public/images/map/layericon/RDL_TSCT_PS copy.png differ
diff --git a/apps/wr/.env.local b/apps/wr/.env.local
index 2543a96ad..4d00d1cab 100644
--- a/apps/wr/.env.local
+++ b/apps/wr/.env.local
@@ -10,6 +10,8 @@ NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
+NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
diff --git a/apps/wr/app/map/mainMap/page.tsx b/apps/wr/app/map/mainMap/page.tsx
index 8cfb27e2f..420dfdfb0 100644
--- a/apps/wr/app/map/mainMap/page.tsx
+++ b/apps/wr/app/map/mainMap/page.tsx
@@ -5,6 +5,7 @@ import { useEffect, useRef, useState, useCallback } from "react";
import { mapService } from "../service";
import NewWindowPopup from "../newWindowPopup";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
+import { SearchBar } from "../searchBar/searchBar";
const Map = () => {
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
@@ -61,24 +62,28 @@ const Map = () => {
// 2. data가 OpenLayers Feature 인스턴스인지 확인
let foundFeature: any = null;
- console.log(data)
+ console.log(data);
//console.log(data.getId())
let featureId = data.fid;
const layerName = data.layerNm;
-
+
if (layerName === "재이용시설") {
// 재이용시설
featureId = `${layerName}.${data.searchPk}`;
- } else if ( //빗물이용시설, 중수도시설
+ } else if (
+ //빗물이용시설, 중수도시설
layerName === "빗물이용시설" ||
layerName == "tb_wr_rswtr_fclt"
) {
featureId = `${layerName}.${data.bdstInfoSn}`;
- } else if (layerName === "tb_il_swage_prcs_fclt") { //하수처리시설
+ } else if (layerName === "tb_il_swage_prcs_fclt") {
+ //하수처리시설
featureId = `${layerName}.${data.bscFctCd}`;
- } else if (layerName === "tb_wr_htdfl_fclt") { //온배수시설
+ } else if (layerName === "tb_wr_htdfl_fclt") {
+ //온배수시설
featureId = `${layerName}.${data.bdstRuseFcltSn}`;
- } else if (layerName == "tb_wr_ruse_fclt_dmd_co") { //수요처
+ } else if (layerName == "tb_wr_ruse_fclt_dmd_co") {
+ //수요처
featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`;
} else {
console.warn("해당 레이어에 대한 featureId 매핑 없음", layerName);
@@ -120,17 +125,6 @@ const Map = () => {
setIsSearchModalOpen(false);
};
- // MapSearchBar 래퍼 컴포넌트
- // const CustomMapSearchBar = (props: any) => {
- // return (
- //
- // );
- // };
-
return (
{
isSearchModalOpen={isSearchModalOpen}
onCheckedLayersChange={handleCheckedLayersChange}
imgVisble={true}
- searchBar={undefined}
+ searchBar={(props: any) => {
+ const facilityTypes = [
+ { text: "하수처리시설", val: "tb_il_swage_prcs_fclt" },
+ { text: "하수재이용시설", val: "tb_wr_bdst_ruse_fclt" },
+ { text: "빗물이용시설", val: "tb_wr_rnwtr_utztn_fclt" },
+ { text: "중수도시설", val: "tb_wr_rswtr_fclt" },
+ { text: "온배수시설", val: "tb_wr_htdfl_fclt" },
+ { text: "수요처", val: "tb_wr_ruse_fclt_dmd_co" },
+ { text: "잠재수요처", val: "tb_wr_tmpr_dmd_co" },
+ ];
+ return (
+
+ );
+ }}
/>
);
diff --git a/apps/wr/app/map/searchBar/searchBar.tsx b/apps/wr/app/map/searchBar/searchBar.tsx
new file mode 100644
index 000000000..7502daf94
--- /dev/null
+++ b/apps/wr/app/map/searchBar/searchBar.tsx
@@ -0,0 +1,299 @@
+"use client";
+import { SelectBox, type SelectDataType } from "@common/business_components/ui";
+import { Button } from "@common/components/ui";
+import { useCallback, useEffect, useState } from "react";
+import { SERVER_API_WR_URL } from "@/src/shared/config";
+
+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/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx
index e45a0a0f2..813b4e23f 100644
--- a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx
+++ b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx
@@ -17,35 +17,45 @@ import {
UiModal,
UiTable,
type SelectDataType,
+ type SheetParameter,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
-import { Button } from "@common/components/ui";
+import { Button, Label } from "@common/components/ui";
import { useEffect, useState } from "react";
-import { Toaster } from "react-hot-toast";
+import toast, { Toaster } from "react-hot-toast";
+import { useTranslation } from "react-i18next";
export default function RuseCaseMng() {
- const { code, ruseCaseMng, selectRuseCaseMng } = useWrStore((state) => state);
- const { ruseCaseMngList, status, count } = ruseCaseMng;
+ const { code, ruseCaseMng, selectRuseCaseMng, ruseCaseMngInit } = useWrStore((state) => state);
+ const { ruseCaseMngList, status, count, excelList } = ruseCaseMng;
const [selectSgg, setSelectSgg] = useState([]);
const [objSearch, setObjSearch] = useState({ sgg: "", city: "" });
-
+
const [sidoCd, setSidoCd] = useState("");
const [sigunguCd, setSigunguCd] = useState("");
- const [selectUtz, setSelectUtz] = useState(["조경용수"]);
+ // const [selectUtz, setSelectUtz] = useState(["조경용수"]);
+ const [selectUtz, setSelectUtz] = useState("");
const [name, setName] = useState("");
+ const [resetPage, isResetPage] = useState(false);
+ const { t } = useTranslation('base');
// 물재이용사례 조회
- const searchRuseCaseMng = async (pageNo: number, pageSize: number) => {
+ const searchRuseCaseMng = async (isExcel: boolean, pageNo: number, pageSize: number) => {
await selectRuseCaseMng(
+ isExcel,
pageNo,
pageSize,
- sidoCd ?? "",
- sigunguCd ?? "",
- selectUtz[0] ?? "",
+ sidoCd ?? "",
+ sigunguCd ?? "",
+ selectUtz ?? "",
name ?? ""
);
}
+ useEffect(() => {
+ ruseCaseMngInit();
+ }, [])
+
// 시도 선택
const getSelCity = (val: string | number) => {
const cityValue = String(val);
@@ -69,91 +79,97 @@ export default function RuseCaseMng() {
isModal: boolean;
}>({ isModal: false });
- // 다운로드
- const download = () => {
- searchRuseCaseMng(1, 10000);;
-
+
+ useEffect(() => {
+
+ if (excelList !== undefined && excelList.length === 0) {
+ toast.error(t('excelDownErrMsg'));
+ return;
+ }
fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => {
- if (!response.ok) {
- throw Error(response.statusText);
- }
- // 받은 파일 바인너리 처리
- const blobRet = await response.arrayBuffer();
-
- const excelData1 = ruseCaseMngList.map((item) => {
- return [
- item.ruseBizNm,
- item.bizBgngDate,
- item.bizEndDate,
- item.splyFcltKnd,
- item.splyFcltNm,
- item.splyFcltCpct,
- item.dmdFcltNm,
- item.dmdFcltAddr,
- item.ruseFcltCpct,
- item.ruseFcltPplLen,
- item.ruseFcltUsg,
- item.ruseFcltSplyCpct,
- item.ruseFcltPrcsMsrc,
- item.grnteWqUsg,
- item.grnteWqGrssClfg,
- item.grnteWqCombResdch,
- item.grnteWqTrbt,
- item.grnteWqBod,
- item.grnteWqSmll,
- item.grnteWqCrmty,
- item.grnteWqTn,
- item.grnteWqTp,
- item.grnteWqPh,
- item.grnteWqClIonQnt,
- item.grnteWqCndctStat,
- item.grnteWqRmrk,
- item.reqBizGrssCst,
- item.reqBizReuseFcltCst,
- item.reqBizPplCst,
- item.reqBizArchCst,
- item.reqBizMchnCst,
- item.reqBizMtrngCst,
- item.reqBizGisCst,
- item.reqBizCctvCst,
- item.reqBizCmcnCst,
- item.reqBizWstCst,
- item.reqBizDesignCst,
- item.reqBizSpvsCst,
- item.reqBizSbsdCst,
- item.reqBizEtc,
- item.prcmPlanGrssCst,
- item.prcmPlanNlep,
- item.prcmPlanLcep,
- item.prcmPlanBrdnCst,
- item.prcmPlanEcqrRt,
- item.clclnGrssCst,
- item.clclnNlep,
- item.clclnLcep,
- item.clclnBrdnCst,
- item.clclnEcqrRt,
- ];
- });
-
- const sheetParameter = [
- {
- data: excelData1,
- headerNum: 2,
- headerRange: 'A1:AX1',
- sheetName: '물재이용사례',
- startCol: 'A'
+ if (!response.ok) {
+ throw Error(response.statusText);
+ }
+ // 받은 파일 바인너리 처리
+ const blobRet = await response.arrayBuffer();
+ if(excelList){
+ const excelData1 = excelList.map((item) => {
+ return [
+ item.ruseBizNm,
+ item.bizBgngDate,
+ item.bizEndDate,
+ item.splyFcltKnd,
+ item.splyFcltNm,
+ item.splyFcltCpct,
+ item.dmdFcltNm,
+ item.dmdFcltAddr,
+ item.ruseFcltCpct,
+ item.ruseFcltPplLen,
+ item.ruseFcltUsg,
+ item.ruseFcltSplyCpct,
+ item.ruseFcltPrcsMsrc,
+ item.grnteWqUsg,
+ item.grnteWqGrssClfg,
+ item.grnteWqCombResdch,
+ item.grnteWqTrbt,
+ item.grnteWqBod,
+ item.grnteWqSmll,
+ item.grnteWqCrmty,
+ item.grnteWqTn,
+ item.grnteWqTp,
+ item.grnteWqPh,
+ item.grnteWqClIonQnt,
+ item.grnteWqCndctStat,
+ item.grnteWqRmrk,
+ item.reqBizGrssCst,
+ item.reqBizReuseFcltCst,
+ item.reqBizPplCst,
+ item.reqBizArchCst,
+ item.reqBizMchnCst,
+ item.reqBizMtrngCst,
+ item.reqBizGisCst,
+ item.reqBizCctvCst,
+ item.reqBizCmcnCst,
+ item.reqBizWstCst,
+ item.reqBizDesignCst,
+ item.reqBizSpvsCst,
+ item.reqBizSbsdCst,
+ item.reqBizEtc,
+ item.prcmPlanGrssCst,
+ item.prcmPlanNlep,
+ item.prcmPlanLcep,
+ item.prcmPlanBrdnCst,
+ item.prcmPlanEcqrRt,
+ item.clclnGrssCst,
+ item.clclnNlep,
+ item.clclnLcep,
+ item.clclnBrdnCst,
+ item.clclnEcqrRt,
+ ];
+ });
+
+ const sheetParameter: SheetParameter[] = [
+ {
+ data: excelData1,
+ headerNum: 2,
+ headerRange: 'A1:AX1',
+ sheetName: '물재이용사례',
+ startCol: 'A'
+ }
+ ];
+ // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
+ await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter);
}
- ];
- // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
- await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter);
});
- }
+
+
+ }, [excelList])
// 양식받기
const sampleDownLoad = () => {
excelDownload(
[[]],
- "물재이용사례 관리",
+ "물재이용사례 관리 등록양식",
"sample_ruseCaseMng.xlsx",
"A1:AX1",
2
@@ -161,7 +177,7 @@ export default function RuseCaseMng() {
}
useEffect(() => {
- if(status === 200){
+ if (status === 200) {
setIsExcelOpen({ isModal: false });
}
}, [status]);
@@ -174,7 +190,7 @@ export default function RuseCaseMng() {
-
+
{
- if (val) setSelectUtz([String(val)]);
+ if (val) setSelectUtz(String(val));
}}
+ value={selectUtz || ruseUtzType[0]?.val}
/>
+
{
setName(e);
@@ -211,13 +231,29 @@ export default function RuseCaseMng() {
-
@@ -254,9 +292,9 @@ export default function RuseCaseMng() {
{
- setIsExcelOpen({ isModal: !isExcelOpen.isModal })
+ setIsExcelOpen({ isModal: !isExcelOpen.isModal })
}}
- bodyClass={"w-[40vw] max-w-none"}
+ bodyClass={"w-[35vw] max-w-none"}
body={}
/>
>
diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx
index 8c3a232e7..bc71fbf81 100644
--- a/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx
+++ b/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx
@@ -1,7 +1,6 @@
import type { SelectDataType } from "@common/business_components/ui";
import type { TableUpperProps } from "../../common/type/header";
-//★☆★☆ 여기서부터 수정하기 ★☆★☆
export const ruseCaseHeadListExport: TableUpperProps[] = [
{
id: "ruseBizNm",
@@ -358,6 +357,7 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [
];
export const ruseUtzType: SelectDataType[] = [
+ { text: "전체", val: "0" },
{ text: "조경용수", val: "조경용수" },
{ text: "청소화장실용수", val: "청소화장실용수" },
{ text: "세척살수용수", val: "세척살수용수" },
diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx
index 5ae2e67b4..160e1f7f3 100644
--- a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx
+++ b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx
@@ -4,90 +4,93 @@ import type { TableUpperProps } from "../../common/type/header";
import { ruseCaseHeadListExport } from "./headList";
export type ruseCaseState = {
ruseCaseMng: {
- ruseHeadList:TableUpperProps[];
- ruseCaseMngList:ruseCaseMngExcelProps[];
+ ruseHeadList: TableUpperProps[];
+ ruseCaseMngList: ruseCaseMngExcelProps[];
status: number;
count: number;
+ excelList?: ruseCaseMngExcelProps[];
};
};
export interface ruseCaseMngExcelProps {
- ruseBizNm: string,
- bizBgngDate: string,
- bizEndDate: string,
- splyFcltKnd: string,
- splyFcltNm: string,
- splyFcltCpct: number | 0 |'',
- dmdFcltNm: string,
- dmdFcltAddr: string,
- ruseFcltCpct: number | 0 |'',
- ruseFcltPplLen: string,
- ruseFcltUsg: string,
- ruseFcltSplyCpct: number | 0 |'',
- ruseFcltPrcsMsrc: string,
- grnteWqUsg: string,
- grnteWqGrssClfg: number | 0 |'',
- grnteWqCombResdch: number | 0 |'',
- grnteWqTrbt: string,
- grnteWqBod: string,
- grnteWqSmll: string,
- grnteWqCrmty: string,
- grnteWqTn: string,
- grnteWqTp: string,
- grnteWqPh: string,
- grnteWqClIonQnt: string,
- grnteWqCndctStat: string,
- grnteWqRmrk: string,
- reqBizReuseFcltCst: number | 0 |'',
- reqBizPplCst: number | 0 |'',
- reqBizArchCst: number | 0 |'',
- reqBizMchnCst: number | 0 |'',
- reqBizMtrngCst: number | 0 |'',
- reqBizGisCst: number | 0 |'',
- reqBizCctvCst: number | 0 |'',
- reqBizCmcnCst: number | 0 |'',
- reqBizWstCst: number | 0 |'',
- reqBizDesignCst: number | 0 |'',
- reqBizSpvsCst: number | 0 |'',
- reqBizSbsdCst: number | 0 |'',
- reqBizEtc: string,
- reqBizGrssCst: number | 0 |'',
- prcmPlanNlep: number | 0 |'',
- prcmPlanLcep: number | 0 |'',
- prcmPlanBrdnCst: number | 0 |'',
- prcmPlanEcqrRt: number | 0 |'',
- prcmPlanGrssCst: number | 0 |'',
- clclnNlep: number | 0 |'',
- clclnLcep: number | 0 |'',
- clclnBrdnCst: number | 0 |'',
- clclnEcqrRt: number | 0 |'',
- clclnGrssCst: number | 0 |'',
+ ruseBizNm: string,
+ bizBgngDate: string,
+ bizEndDate: string,
+ splyFcltKnd: string,
+ splyFcltNm: string,
+ splyFcltCpct: number | 0 | '',
+ dmdFcltNm: string,
+ dmdFcltAddr: string,
+ ruseFcltCpct: number | 0 | '',
+ ruseFcltPplLen: string,
+ ruseFcltUsg: string,
+ ruseFcltSplyCpct: number | 0 | '',
+ ruseFcltPrcsMsrc: string,
+ grnteWqUsg: string,
+ grnteWqGrssClfg: number | 0 | '',
+ grnteWqCombResdch: number | 0 | '',
+ grnteWqTrbt: string,
+ grnteWqBod: string,
+ grnteWqSmll: string,
+ grnteWqCrmty: string,
+ grnteWqTn: string,
+ grnteWqTp: string,
+ grnteWqPh: string,
+ grnteWqClIonQnt: string,
+ grnteWqCndctStat: string,
+ grnteWqRmrk: string,
+ reqBizReuseFcltCst: number | 0 | '',
+ reqBizPplCst: number | 0 | '',
+ reqBizArchCst: number | 0 | '',
+ reqBizMchnCst: number | 0 | '',
+ reqBizMtrngCst: number | 0 | '',
+ reqBizGisCst: number | 0 | '',
+ reqBizCctvCst: number | 0 | '',
+ reqBizCmcnCst: number | 0 | '',
+ reqBizWstCst: number | 0 | '',
+ reqBizDesignCst: number | 0 | '',
+ reqBizSpvsCst: number | 0 | '',
+ reqBizSbsdCst: number | 0 | '',
+ reqBizEtc: string,
+ reqBizGrssCst: number | 0 | '',
+ prcmPlanNlep: number | 0 | '',
+ prcmPlanLcep: number | 0 | '',
+ prcmPlanBrdnCst: number | 0 | '',
+ prcmPlanEcqrRt: number | 0 | '',
+ prcmPlanGrssCst: number | 0 | '',
+ clclnNlep: number | 0 | '',
+ clclnLcep: number | 0 | '',
+ clclnBrdnCst: number | 0 | '',
+ clclnEcqrRt: number | 0 | '',
+ clclnGrssCst: number | 0 | '',
}
type ruseCaseActions = {
- selectRuseCaseMng: (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => Promise;
+ ruseCaseMngInit: () => void;
+ selectRuseCaseMng: (isExcel: boolean, pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => Promise;
insertRuseCaseMng: (data: any) => Promise;
};
-export const fetchSearchRuseCaseMng = async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
- const tailUrl = '/'+pageNo+'/'+pageSize+ ((sigunguCd !== '전체' && sigunguCd !=='') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd? `/${usageCd}` : '/0') + (name? `/${name}` : '');
- const resp = await getFetchWithCount(fetchType.WR,`/reuseFc/pubFcRuseCase${tailUrl}`);
- return {data:resp.data, count:resp.count};
+export const fetchSearchRuseCaseMng = async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => {
+ const tailUrl = '/' + pageNo + '/' + pageSize + ((sigunguCd !== '전체' && sigunguCd !== '') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd ? `/${usageCd}` : '/0') + (name ? `/${name}` : '');
+ const resp = await getFetchWithCount(fetchType.WR, `/reuseFc/pubFcRuseCase${tailUrl}`);
+ return { data: resp.data, count: resp.count };
};
export const fetchInsertRuseCaseMng = async (data: any) => {
const response = await postFectch('/reuseFc/pubFcRuseCase', data, fetchType.WR);
- return {data:response.data, status:response.status};
+ return { data: response.data, status: response.status };
};
export type ruseCaseType = ruseCaseState & ruseCaseActions;
export const ruseCaseStateExport: ruseCaseState = {
ruseCaseMng: {
- ruseHeadList:ruseCaseHeadListExport,
- ruseCaseMngList:[],
+ ruseHeadList: ruseCaseHeadListExport,
+ ruseCaseMngList: [],
status: 0,
count: 0,
+ excelList: undefined,
},
};
@@ -95,8 +98,8 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
set: any
) => {
return {
- selectRuseCaseMng: async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
- const res = await fetchSearchRuseCaseMng(pageNo, pageSize, sidoCd, sigunguCd, usageCd, name);
+ ruseCaseMngInit: async () => {
+ const res = await getFetchWithCount(fetchType.WR, `/reuseFc/pubFcRuseCase/1/10/0/0`);
set((state: ruseCaseState) => ({
ruseCaseMng: {
...state.ruseCaseMng,
@@ -105,12 +108,35 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
},
}));
},
+ selectRuseCaseMng: async (isExcel: boolean, pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => {
+ const res = await fetchSearchRuseCaseMng(pageNo, pageSize, sidoCd, sigunguCd, usageCd, name);
+ if (isExcel) {
+ set((state: ruseCaseState) => {
+ return {
+ ...state,
+ ruseCaseMng: {
+ ...state.ruseCaseMng,
+ count: res.count,
+ excelList: res.data
+ },
+ };
+ });
+ } else {
+ set((state: ruseCaseState) => ({
+ ruseCaseMng: {
+ ...state.ruseCaseMng,
+ ruseCaseMngList: res.data,
+ count: res.count,
+ },
+ }));
+ }
+ },
insertRuseCaseMng: async (data: any) => {
const response = await fetchInsertRuseCaseMng(data);
- if(response.status === 200){
+ if (response.status === 200) {
toast.success("물재이용사례 등록이 완료되었습니다. ");
- }else{
+ } else {
toast.error("물재이용사례 등록에 실패하였습니다. ");
}
set((state: ruseCaseState) => ({
diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx
index 6d6ef18a6..a484f87c2 100644
--- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx
+++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx
@@ -6,6 +6,7 @@ import {
isInvalidNumber,
parseRawValue,
} from "@/components/lib/func/excelFunc";
+import toast from "react-hot-toast";
export const useTypes = [
"조경용수",
"청소화장실용수",
@@ -16,6 +17,18 @@ export const useTypes = [
"기타",
];
+
+export const chkMngType =[
+ '위탁',
+ '자체'
+]
+export const chkSpwtPositnType = [
+ '유량계',
+ '수위계',
+ '펌프적산전력계',
+ '기타'
+]
+
export type Buildingtype = {
bdstInfoSn: number;
ctpvCd: 1;
@@ -143,43 +156,56 @@ export const excelToRainChkData = (excelData: any, year: string) => {
})
.filter((el: any) => el !== undefined);
+console.log("rainChkgdData", rainChkgdData);
if (rainChkgdData.length > 0) {
rainChkgdData.forEach((rain: any) => {
const defaultMessage = `[시설명: ${rain.bdstNm}, 점검일: ${rain.chckYmd}, 이용용도: ${rain.guideDetails[0]?.utztnUsgCd}] 항목에서 `;
if (rain.chckYmd && isInvalidDate(rain.chckYmd)) {
issues.push(
- defaultMessage + `점검일: 날짜 형식 아님 (${rain.chckYmd})`
+ defaultMessage + `점검일: 날짜 형식 아님 입력값 : (${rain.chckYmd})`
);
}
if (rain.anlOperCst.length > 2 && isInvalidNumber(rain.anlOperCst)) {
issues.push(
defaultMessage +
- ` 연간운영비(원/년): 숫자 형식 아님 (${rain.anlOperCst})`
+ ` 연간운영비(원/년): 숫자 형식 아님 /입력값:${rain.anlOperCst}`
);
}
+ if (rain.oilqMeasMthd.length > 1 && !chkMngType.includes(rain.oilqMeasMthd)) {
+ issues.push(
+ defaultMessage + `유량측정방법: 위탁 혹은 자체 만 허용) /입력값:${rain.oilqMeasMthd}`
+ );
+ }
+ if (rain.spwtPositn.length > 1 && !chkSpwtPositnType.includes(rain.spwtPositn)) {
+ issues.push(
+ defaultMessage + `측정위치: 유량계, 수위계, 펌프적산전력계, 기타 중 하나만 허용) /입력값:${rain.spwtPositn}`
+ );
+ }
+
+
rain.rainyDetails?.forEach((key) => {
if (key.ph?.length > 1 && isInvalidNumber(key.ph)) {
- issues.push(defaultMessage + `PH: 숫자 형식 아님 (${key.ph})`);
+ issues.push(defaultMessage + `PH: 숫자 형식 아님 /입력값:${key.ph}`);
}
if (key.trbt?.length > 1 && isInvalidNumber(key.trbt)) {
- issues.push(defaultMessage + `탁도: 숫자 형식 아님 (${key.trbt})`);
+ issues.push(defaultMessage + `탁도: 숫자 형식 아님 /입력값:${key.trbt}`);
}
if (key.grssClfg?.length > 1 && isInvalidNumber(key.grssClfg)) {
issues.push(
- defaultMessage + `총대장균군수: 숫자 형식 아님 (${key.grssClfg})`
+ defaultMessage + `총대장균군수: 숫자 형식 아님 /입력값:${key.grssClfg}`
);
}
if (key.levyAmt?.length > 1 && isInvalidNumber(key.levyAmt)) {
issues.push(
defaultMessage +
- `과태료부과금액(천원): 숫자 형식 아님 (${key.levyAmt})`
+ `과태료부과금액(천원): 숫자 형식 아님 /입력값:${key.levyAmt}`
);
}
if (key.vltnDt?.length > 2 && isInvalidDate(key.vltnDt)) {
issues.push(
defaultMessage +
- `과태료 부과일(위반일): 날짜 형식 아님 (${key.vltnDt})`
+ `과태료 부과일(위반일): 날짜 형식 아님 /입력값:${key.vltnDt}`
);
}
});
@@ -188,17 +214,19 @@ export const excelToRainChkData = (excelData: any, year: string) => {
if (isInvalidNumber(guide.splyUswtrUtztnQnt)) {
issues.push(
defaultMessage +
- `대체_${mm}: 숫자 형식 아님 (${guide.splyUswtrUtztnQnt})`
+ `대체_${mm}: 숫자 형식 아님 /입력값:${guide.splyUswtrUtztnQnt}`
);
}
if (isInvalidNumber(guide.ruseFcltUtztnQnt)) {
issues.push(
defaultMessage +
- `빗물_${mm}: 숫자 형식 아님 (${guide.ruseFcltUtztnQnt})`
+ `빗물_${mm}: 숫자 형식 아님 /입력값:${guide.ruseFcltUtztnQnt}`
);
}
});
});
+ }else{
+ toast.error("데이터가 없습니다. 점검 데이터를 확인해주세요.");
}
if (issues.length > 0) {
diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx
index 262b1cb30..aa550dcd1 100644
--- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx
+++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx
@@ -1,5 +1,10 @@
import type { SelectDataType } from "@common/business_components/ui";
-import { useTypes, type Buildingtype } from "../rainChkgdn/excel";
+import {
+ chkMngType,
+ chkSpwtPositnType,
+ useTypes,
+ type Buildingtype,
+} from "../rainChkgdn/excel";
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type { rswtChkZodType } from ".";
import {
@@ -171,14 +176,14 @@ export const excelToRswtGuideData = (
.filter((el: any) => el !== undefined);
if (rswtChkgdData.length > 0) {
- rswtExcelDataCheck(rswtChkgdData,issues)
+ rswtExcelDataCheck(rswtChkgdData, issues);
}
if (issues.length > 0) {
return { data: [], issues };
}
- return { data:rswtChkgdData, issues: [] };
+ return { data: rswtChkgdData, issues: [] };
};
export const excelToRswtPolution = (excelData: any, issues: string[]) => {
@@ -248,25 +253,25 @@ export const excelToRswtPolution = (excelData: any, issues: string[]) => {
})
.filter((el: any) => el !== undefined);
if (rswtChkgdData.length > 0) {
- rswtExcelDataCheck(rswtChkgdData,issues)
+ rswtExcelDataCheck(rswtChkgdData, issues);
}
if (issues.length > 0) {
return { data: [], issues };
}
- return { data:rswtChkgdData, issues: [] };
+ return { data: rswtChkgdData, issues: [] };
};
-
-const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
+const rswtExcelDataCheck = (
+ rswtChkgdData: rswtChkZodType[],
+ issues: string[]
+) => {
rswtChkgdData.forEach((rswt: any) => {
const defaultMessage = `*중수도 수질 [NO: ${rswt.bdstRuseFcltSn}, 점검일: ${rswt.chckYmd}, 이용용도: ${rswt.utztnUsgCd}] 항목에서 `;
if (rswt.chckYmd && isInvalidDate(rswt.chckYmd)) {
- issues.push(
- defaultMessage + `점검일: 날짜 형식 아님 (${rswt.chckYmd})`
- );
+ issues.push(defaultMessage + `점검일: 날짜 형식 아님 (${rswt.chckYmd})`);
}
if (rswt.anlOperCst.length > 2 && isInvalidNumber(rswt.anlOperCst)) {
issues.push(
@@ -279,6 +284,25 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
defaultMessage + ` 처리용량(m³): 숫자 형식 아님 (${rswt.prcsCpct})`
);
}
+ if (
+ rswt.oilqMeasMthd.length > 1 &&
+ !chkMngType.includes(rswt.oilqMeasMthd)
+ ) {
+ issues.push(
+ defaultMessage +
+ `유량측정방법: 위탁 혹은 자체 만 허용) /입력값:${rswt.oilqMeasMthd}`
+ );
+ }
+ if (
+ rswt.spwtPositn.length > 1 &&
+ !chkSpwtPositnType.includes(rswt.spwtPositn)
+ ) {
+ issues.push(
+ defaultMessage +
+ `측정위치: 유량계, 수위계, 펌프적산전력계, 기타 중 하나만 허용) /입력값:${rswt.spwtPositn}`
+ );
+ }
+
if (rswt?.rswtrPollutions && rswt?.rswtrPollutions.length > 0) {
rswt.rswtrPollutions.forEach((pol) => {
if (isInvalidNumber(pol.grssClfgUswtr)) {
@@ -301,8 +325,7 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
}
if (isInvalidNumber(pol.bod)) {
issues.push(
- defaultMessage +
- `${pol.node}분기_BOD: 숫자 형식 아님 (${pol.bod})`
+ defaultMessage + `${pol.node}분기_BOD: 숫자 형식 아님 (${pol.bod})`
);
}
if (isInvalidNumber(pol.smll)) {
@@ -319,8 +342,7 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
}
if (isInvalidNumber(pol.tph)) {
issues.push(
- defaultMessage +
- `${pol.node}분기_T-P: 숫자 형식 아님 (${pol.tph})`
+ defaultMessage + `${pol.node}분기_T-P: 숫자 형식 아님 (${pol.tph})`
);
}
if (isInvalidNumber(pol.tn)) {
@@ -358,7 +380,5 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
}
});
}
- })
-
-
-}
\ No newline at end of file
+ });
+};
diff --git a/apps/wr/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal.tsx b/apps/wr/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal.tsx
index 57424996e..a809c88f6 100644
--- a/apps/wr/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal.tsx
+++ b/apps/wr/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal.tsx
@@ -1,14 +1,14 @@
+import { useWrStore } from "@/app/store";
import { coRegExcel } from "@/app/store/matDmd/coSttn/headList";
-import type { ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/index";
import { reUseCaseNames } from "@/app/store/matDmd/ruseCaseMng/excel";
-import { filePicked, FileUpload, FormUi, Title } from "@common/business_components/ui";
-import { Form, FormField } from "@common/business_components/ui/form";
-import { Button } from "@common/components/ui";
+import type { ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/index";
+import { filePicked, Title } from "@common/business_components/ui";
+import { Form } from "@common/business_components/ui/form";
+import { Button, Input } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useState } from "react";
import { useForm } from "react-hook-form";
import type { z } from "zod";
-import { useWrStore } from "@/app/store";
export default function RuseCaseMngExcel() {
const { insertRuseCaseMng } = useWrStore((state) => state);
@@ -79,6 +79,7 @@ export default function RuseCaseMngExcel() {
};
Object.keys(reUseCaseNames).forEach((key: string) => {
+ console.log("reUseCaseNames", reUseCaseNames)
if (item && reUseCaseNames[key] !== undefined) {
const mappedKey = reUseCaseNames[key];
if (mappedKey && object.hasOwnProperty(mappedKey)) {
@@ -146,23 +147,16 @@ export default function RuseCaseMngExcel() {
diff --git a/apps/wr/middleware.ts b/apps/wr/middleware.ts
index 61f41d634..1a90a5591 100644
--- a/apps/wr/middleware.ts
+++ b/apps/wr/middleware.ts
@@ -8,6 +8,7 @@ const serverApiUrl = CS_URL;
const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || "";
const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || "";
const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
+const REUSE_API_URL = process.env.NEXT_PUBLIC_WR_SERVER_API_URL || "";
export function middleware(req: NextRequest) {
const pathname = req.nextUrl.pathname;
@@ -135,6 +136,15 @@ export function middleware(req: NextRequest) {
return NextResponse.rewrite(new URL(newUrl));
}
+ if (pathname.startsWith("/reuse-service")) {
+ const queryParams = searchParams.toString();
+ const newUrl = `${REUSE_API_URL}${pathname.replace("/reuse-service", "")}${
+ queryParams ? `?${queryParams}` : ""
+ }`;
+ console.log(`[Middleware] Rewriting from '/reuse-service' path to: ${newUrl}`);
+ return NextResponse.rewrite(new URL(newUrl));
+ }
+
return NextResponse.next();
}
@@ -146,6 +156,7 @@ export const config = {
"/attach-service/:path*",
"/geoserver/:path*",
"/sewerage-service/:path*",
+ "/reuse-service/:path*",
"/"
],
};
diff --git a/apps/wr/public/images/map/layericon/BML_CBAS_PS.png b/apps/wr/public/images/map/layericon/BML_CBAS_PS.png
index 5ff4add3e..0e70939ba 100644
Binary files a/apps/wr/public/images/map/layericon/BML_CBAS_PS.png and b/apps/wr/public/images/map/layericon/BML_CBAS_PS.png differ
diff --git a/apps/wr/public/images/map/layericon/BML_STMS_PS.png b/apps/wr/public/images/map/layericon/BML_STMS_PS.png
index 423f2e8fc..bf4357181 100644
Binary files a/apps/wr/public/images/map/layericon/BML_STMS_PS.png and b/apps/wr/public/images/map/layericon/BML_STMS_PS.png differ
diff --git a/apps/wr/public/images/map/layericon/RDL_ETCT_PS.png b/apps/wr/public/images/map/layericon/RDL_ETCT_PS.png
index 29c0b77b4..e5a83f998 100644
Binary files a/apps/wr/public/images/map/layericon/RDL_ETCT_PS.png and b/apps/wr/public/images/map/layericon/RDL_ETCT_PS.png differ
diff --git a/apps/wr/public/images/map/layericon/RDL_OCUP_PS.png b/apps/wr/public/images/map/layericon/RDL_OCUP_PS.png
index 8a1ac0074..aeae3e266 100644
Binary files a/apps/wr/public/images/map/layericon/RDL_OCUP_PS.png and b/apps/wr/public/images/map/layericon/RDL_OCUP_PS.png differ
diff --git a/apps/wr/public/images/map/layericon/RDL_SEPC_PS.png b/apps/wr/public/images/map/layericon/RDL_SEPC_PS.png
index 087b4e941..b3db8e0a4 100644
Binary files a/apps/wr/public/images/map/layericon/RDL_SEPC_PS.png and b/apps/wr/public/images/map/layericon/RDL_SEPC_PS.png differ
diff --git a/apps/wr/public/images/map/layericon/RDL_STAT_PS.png b/apps/wr/public/images/map/layericon/RDL_STAT_PS.png
index 13d8ea689..9a0b11673 100644
Binary files a/apps/wr/public/images/map/layericon/RDL_STAT_PS.png and b/apps/wr/public/images/map/layericon/RDL_STAT_PS.png differ
diff --git a/apps/wr/public/images/map/layericon/RDL_TSCT_PS.png b/apps/wr/public/images/map/layericon/RDL_TSCT_PS.png
index ffc225159..3776f6c04 100644
Binary files a/apps/wr/public/images/map/layericon/RDL_TSCT_PS.png and b/apps/wr/public/images/map/layericon/RDL_TSCT_PS.png differ
diff --git a/apps/wr/public/sample_ruseCaseMng.xlsx b/apps/wr/public/sample_ruseCaseMng.xlsx
index 96027d557..3676b4f71 100644
Binary files a/apps/wr/public/sample_ruseCaseMng.xlsx and b/apps/wr/public/sample_ruseCaseMng.xlsx differ
diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js
index 89b7e982b..92a64ed44 100644
--- a/packages/common/business_components/src/ui/map/Gis.js
+++ b/packages/common/business_components/src/ui/map/Gis.js
@@ -1,323 +1,357 @@
-import { Search } from 'lucide-react';
-import OlMap from 'ol/Map';
-import View from 'ol/View';
-import { defaults as defaultControls, OverviewMap } from 'ol/control';
-import { defaults } from 'ol/interaction';
-import * as olProj from 'ol/proj';
-import { register } from 'ol/proj/proj4';
-import proj4 from 'proj4';
-import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
-import GisMapToggle from './GisMapToggle';
-import GisSelect from './GisSelect';
-import GisToolBar from './GisToolBar';
-import GisTree from './GisTree';
-import './lib/css/gis.common.css';
-import GisApp from './lib/gis.core';
+import { Search } from "lucide-react";
+import OlMap from "ol/Map";
+import View from "ol/View";
+import { defaults as defaultControls, OverviewMap } from "ol/control";
+import { defaults } from "ol/interaction";
+import * as olProj from "ol/proj";
+import { register } from "ol/proj/proj4";
+import proj4 from "proj4";
+import React, {
+ createContext,
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from "react";
+import GisMapToggle from "./GisMapToggle";
+import GisSelect from "./GisSelect";
+import GisToolBar from "./GisToolBar";
+import GisTree from "./GisTree";
+import "./lib/css/gis.common.css";
+import GisApp from "./lib/gis.core";
-export const GisContext = createContext({ gisCore: null, gisMap: null, treeData: null, checkedLayerIds: null });
+export const GisContext = createContext({
+ gisCore: null,
+ gisMap: null,
+ treeData: null,
+ checkedLayerIds: null,
+});
export const useGisContext = () => useContext(GisContext);
export const searchUpperPpls = async (fcltMngNo) => {
- const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || '';
+ const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
+ const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
+ method: "GET",
+ });
- const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
- method: "GET",
- });
+ let data = null;
+ if (res.ok) {
+ try {
+ // 응답이 비어있는지 확인
+ const contentLength = res.headers.get("content-length");
+ if (contentLength === "0")
+ alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
- let data = null;
- if (res.ok) {
- try {
- // 응답이 비어있는지 확인
- const contentLength = res.headers.get('content-length');
- if (contentLength === '0') alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
+ // 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
+ const text = await res.text();
+ if (!text || text.trim() === "")
+ alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
- // 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
- const text = await res.text();
- if (!text || text.trim() === '') alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
+ // JSON 파싱 시도
+ data = JSON.parse(text);
+ } catch (error) {
+ console.error("JSON parsing error:", error);
+ alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
+ }
+ }
- // JSON 파싱 시도
- data = JSON.parse(text);
- } catch (error) {
- console.error('JSON parsing error:', error);
- alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
- }
- }
+ const select = GisApp.Module.select;
+ const gisMap = GisApp.Module.core?.map;
+ let foundFeature = null;
- const select = GisApp.Module.select;
+ data.forEach((item) => {
+ const pplMngNo = item.ppl_mng_no.trim();
- const gisMap = GisApp.Module.core?.map;
+ gisMap
+ .getLayers()
+ .getArray()
+ .filter((e) => e.get("lyrTyNm") == "tb_ms_swage_ppl")
+ .forEach((layer) => {
+ const source = layer.getSource?.();
+ if (source?.getFeatures) {
+ const features = source.getFeatures();
+ for (const f of features) {
+ if (f.values_.fclt_mng_no.trim() === pplMngNo) {
+ foundFeature = f;
+ break;
+ }
+ }
+ }
+ });
- let foundFeature = null;
+ if (foundFeature) select.selectMultiFeature(foundFeature, true);
+ });
- data.forEach(item => {
- const pplMngNo = item.ppl_mng_no.trim();
+ if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
- gisMap.getLayers().getArray().filter(e => e.get("lyrTyNm") == 'tb_ms_swage_ppl').forEach(layer => {
- const source = layer.getSource?.();
- if (source?.getFeatures) {
- const features = source.getFeatures();
- for (const f of features) {
- if (f.values_.fclt_mng_no.trim() === pplMngNo) {
- foundFeature = f;
- break;
- }
- }
- }
- });
+ let geometry = foundFeature?.getGeometry();
+ if (geometry) {
+ let extent = geometry.getExtent();
- if (foundFeature) select.selectMultiFeature(foundFeature, true);
- });
-
- if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
-
- let geometry = foundFeature?.getGeometry();
- if (geometry) {
- let extent = geometry.getExtent();
-
- gisMap.getView().fit(extent, {
- duration: 300,
- padding: [50, 50, 50, 50],
- maxZoom: 14,
- constrainResolution: true,
- nearest: true,
- });
- }
+ gisMap.getView().fit(extent, {
+ duration: 300,
+ padding: [50, 50, 50, 50],
+ maxZoom: 14,
+ constrainResolution: true,
+ nearest: true,
+ });
+ }
};
function Gis({
- isOpen, //우측 상세 레이어 팝업
- gisMaps,
- isSearchModalOpen,
- treeData = [],
- isSearch = false,
- isMiniMap = false,
- setIsOpen,
- setFeatureData,
- featureData,
- imgVisble = false,
- searchView: SearchView,
- detailView: DetailView,
- onFeatureSelect,
- setIsSearchModalOpen,
- onCheckedLayersChange,
- searchBar: SearchBar,
- waterDepth: WaterDepth,
+ isOpen, //우측 상세 레이어 팝업
+ gisMaps,
+ isSearchModalOpen,
+ treeData = [],
+ isSearch = false,
+ isMiniMap = false,
+ setIsOpen,
+ setFeatureData,
+ featureData,
+ imgVisble = false,
+ searchView: SearchView,
+ detailView: DetailView,
+ onFeatureSelect,
+ setIsSearchModalOpen,
+ onCheckedLayersChange,
+ searchBar: SearchBar,
+ waterDepth: WaterDepth,,
+ height:height="h-[calc(100vh-10rem)]",
}) {
- const mapRef = useRef();
- const [mapObject, setMapObject] = useState({});
- const [tabVisible, setTabVisible] = useState(true);
- const [layerNm, setLayerNm] = useState('')
- // const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
- // const [featureData, setFeatureData] = useState(null) // 선택된 피쳐 데이터
- // const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
- const gisCore = useMemo(() => new GisApp.core({ targetId: mapRef.current }), []);
- const mapInstanceRef = useRef(null);
- const checkedLayerIds = useRef([]);
- const layerNmRef = useRef('')
+ const mapRef = useRef();
+ const [mapObject, setMapObject] = useState({});
+ const [tabVisible, setTabVisible] = useState(true);
+ const [layerNm, setLayerNm] = useState("");
+ // const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
+ // const [featureData, setFeatureData] = useState(null) // 선택된 피쳐 데이터
+ // const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
+ const gisCore = useMemo(
+ () => new GisApp.core({ targetId: mapRef.current }),
+ [],
+ );
+ const mapInstanceRef = useRef(null);
+ const checkedLayerIds = useRef([]);
+ const layerNmRef = useRef("");
- // 팝업 데이터를 저장할 상태와 오버레이 참조를 저장할 ref 추가
- // const [facilityInfoPopupData, setFacilityInfoPopupData] = useState([]);
- // const facilityOverlaysRef = useRef([]);
- // 체크된 레이어 상태 관리
- const [checkedLayers, setCheckedLayers] = useState([]);
- const [checkedLayersData, setCheckedLayersData] = useState([]);
+ // 팝업 데이터를 저장할 상태와 오버레이 참조를 저장할 ref 추가
+ // const [facilityInfoPopupData, setFacilityInfoPopupData] = useState([]);
+ // const facilityOverlaysRef = useRef([]);
+ // 체크된 레이어 상태 관리
+ const [checkedLayers, setCheckedLayers] = useState([]);
+ const [checkedLayersData, setCheckedLayersData] = useState([]);
- let gisMap = null;
- const closePopup = () => {
- setIsOpen(false); // 팝업 닫기
- setFeatureData(null)
- };
+ let gisMap = null;
+ const closePopup = () => {
+ setIsOpen(false); // 팝업 닫기
+ setFeatureData(null);
+ };
- // Feature Click Event
- const handleFeatureSelect = useCallback((data) => {
- onFeatureSelect?.(data); // 선택된 피쳐 데이터 콜백 호출
- }, [mapInstanceRef]);
+ // Feature Click Event
+ const handleFeatureSelect = useCallback(
+ (data) => {
+ onFeatureSelect?.(data); // 선택된 피쳐 데이터 콜백 호출
+ },
+ [mapInstanceRef],
+ );
- // 지도 생성 및 초기화
- useEffect(() => {
- if (!mapRef.current) return;
- if (mapInstanceRef.current) return; // 이미 생성된 맵이 있다면 중단
+ // 지도 생성 및 초기화
+ useEffect(() => {
+ if (!mapRef.current) return;
+ if (mapInstanceRef.current) return; // 이미 생성된 맵이 있다면 중단
- // EPSG:5179 등록
- proj4.defs([
- [
- 'EPSG:5179',
- '+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs',
- ],
- ]);
- register(proj4);
+ // EPSG:5179 등록
+ proj4.defs([
+ [
+ "EPSG:5179",
+ "+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs",
+ ],
+ ]);
+ register(proj4);
- // OpenLayers 지도 객체 생성
- const map = new OlMap({
- layers: [gisCore.baseLayers['base'], gisCore.baseLayers['satellite']],
- renderer: 'webgl',
- target: mapRef.current,
- interactions: defaults({ doubleClickZoom: false }),
- controls: defaultControls({
- zoom: false,
- rotate: false,
- attributionOptions: {
- collapsible: false,
- },
- }).extend([]),
- view: new View({
- projection: GisApp.TO_PROJ,
- zoom: gisCore.defaults.zoom,
- center: olProj.transform(
- [127.4875, 37.4916],
- GisApp.FROM_PROJ,
- GisApp.TO_PROJ
- ),
- minZoom: gisCore.defaults.minZoom,
- maxZoom: gisCore.defaults.maxZoom,
- }),
- });
+ // OpenLayers 지도 객체 생성
+ const map = new OlMap({
+ layers: [gisCore.baseLayers["base"], gisCore.baseLayers["satellite"]],
+ renderer: "webgl",
+ target: mapRef.current,
+ interactions: defaults({ doubleClickZoom: false }),
+ controls: defaultControls({
+ zoom: false,
+ rotate: false,
+ attributionOptions: {
+ collapsible: false,
+ },
+ }).extend([]),
+ view: new View({
+ projection: GisApp.TO_PROJ,
+ zoom: gisCore.defaults.zoom,
+ center: olProj.transform(
+ [127.4875, 37.4916],
+ GisApp.FROM_PROJ,
+ GisApp.TO_PROJ,
+ ),
+ minZoom: gisCore.defaults.minZoom,
+ maxZoom: gisCore.defaults.maxZoom,
+ }),
+ });
- gisMaps.current = map
+ gisMaps.current = map;
- // 미니맵 추가
- if (isMiniMap) {
- const overviewMap = new OverviewMap({
- layers: [GisApp.Module.core.baseMiniMapLayers['base']],
- view: new View({
- projection: GisApp.TO_PROJ,
- minZoom: 9,
- }),
- collapsed: false,
- collapseLabel: '\u00BB',
- label: '\u00AB',
- });
- map.addControl(overviewMap);
- }
+ // 미니맵 추가
+ if (isMiniMap) {
+ const overviewMap = new OverviewMap({
+ layers: [GisApp.Module.core.baseMiniMapLayers["base"]],
+ view: new View({
+ projection: GisApp.TO_PROJ,
+ minZoom: 9,
+ }),
+ collapsed: false,
+ collapseLabel: "\u00BB",
+ label: "\u00AB",
+ });
+ map.addControl(overviewMap);
+ }
- // 스케일 컨트롤 및 베이스 레이어 설정
- gisCore.__proto__.map = map;
- gisCore.scaleControl();
- gisCore.changeBaseLayer('base');
- setMapObject({ map: map });
- mapInstanceRef.current = map; // 생성 완료 플래그 설정
+ // 스케일 컨트롤 및 베이스 레이어 설정
+ gisCore.__proto__.map = map;
+ gisCore.scaleControl();
+ gisCore.changeBaseLayer("base");
+ setMapObject({ map: map });
+ mapInstanceRef.current = map; // 생성 완료 플래그 설정
+ }, []);
- }, []);
+ // treeData 변경 시 레이어 코드 생성
+ useEffect(() => {
+ if (!treeData || treeData.length === 0) return;
- // treeData 변경 시 레이어 코드 생성
- useEffect(() => {
- if (!treeData || treeData.length === 0) return;
+ // 기존 오버레이 및 레이어 모두 삭제
+ gisCore.deleteAllOverlay();
+ gisCore.deleteAllLayer();
- // 기존 오버레이 및 레이어 모두 삭제
- gisCore.deleteAllOverlay();
- gisCore.deleteAllLayer();
+ // 트리 데이터를 레이어 코드 객체로 변환
+ const layerCode = gisCore.convertLayerInfosToLayerCode(treeData, "lyrSn");
+ GisApp.layerCode = layerCode; // 전역 레이어 코드 설정
- // 트리 데이터를 레이어 코드 객체로 변환
- const layerCode = gisCore.convertLayerInfosToLayerCode(treeData, 'lyrSn');
- GisApp.layerCode = layerCode; // 전역 레이어 코드 설정
+ //setTreeData(data);
+ // 편집 가능한 레이어 목록 생성
+ //const layerItems = getLayerItems(layerCode);
+ //setEditLayerItems(prev => [...layerItems])
+ }, [treeData]);
- //setTreeData(data);
- // 편집 가능한 레이어 목록 생성
- //const layerItems = getLayerItems(layerCode);
- //setEditLayerItems(prev => [...layerItems])
- }, [treeData]);
+ const getLayerItems = (layerCode) => {
+ const layerItems = Object.entries(layerCode)
+ .filter(([key, obj], idx) => obj?.updtPsblYn === "Y")
+ .map(([key, obj]) => ({
+ ...obj,
+ name: obj.lyrNm,
+ label: obj.lyrNm,
+ value: obj.lyrSn + "",
+ }))
+ .sort((a, b) => {
+ if (a.sortOrdr > b.sortOrdr) return 1;
+ if (a.sortOrdr < b.sortOrdr) return -1;
+ return 0;
+ });
+ return layerItems;
+ };
- const getLayerItems = (layerCode) => {
- const layerItems = Object.entries(layerCode)
- .filter(([key, obj], idx) => obj?.updtPsblYn === 'Y')
- .map(([key, obj]) => ({
- ...obj,
- name: obj.lyrNm,
- label: obj.lyrNm,
- value: obj.lyrSn + '',
- }))
- .sort((a, b) => {
- if (a.sortOrdr > b.sortOrdr) return 1;
- if (a.sortOrdr < b.sortOrdr) return -1;
- return 0;
- });
- return layerItems;
- };
+ if (mapObject.map) {
+ try {
+ gisMap = mapObject.map;
+ } catch (e) {
+ console.error("오류 발생:", e); // 시큐어코딩 관련 수정 : 오류 정보를 로그로 출력
+ }
+ }
- if (mapObject.map) {
- try {
- gisMap = mapObject.map;
- } catch (e) {
- console.error('오류 발생:', e); // 시큐어코딩 관련 수정 : 오류 정보를 로그로 출력
- }
- }
+ // 체크된 레이어 정보를 처리하는 함수
+ const handleCheckedLayersChange = useCallback(
+ (checkedIds, checkedNodesData) => {
+ setTimeout(() => {
+ setCheckedLayers(checkedIds);
+ setCheckedLayersData(checkedNodesData);
+ onCheckedLayersChange?.(checkedIds, checkedNodesData);
+ }, 1000);
+ },
+ [onCheckedLayersChange],
+ );
- // 체크된 레이어 정보를 처리하는 함수
- const handleCheckedLayersChange = useCallback((checkedIds, checkedNodesData) => {
- setTimeout(() => {
- setCheckedLayers(checkedIds);
- setCheckedLayersData(checkedNodesData);
- onCheckedLayersChange?.(checkedIds, checkedNodesData);
- }, 1000);
- }, [onCheckedLayersChange]);
+ return (
+ <>
+
+
+
+
{
+ layerNmRef.current = layerNm;
+ setLayerNm(layerNm);
+ setIsOpen(true);
+ const dummyFeature = {
+ getProperties: () => ({}), // 최소 구조
+ };
+ onFeatureSelect(dummyFeature);
+ }}
+ imageVisible={imgVisble}
+ />
- return (
- <>
-
-
-
-
{
- 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}
- />
- )}
- {/* SearchView가 존재할 때만 렌더링 */}
- {SearchView && (
-
- )}
- {/* 시도/시군구 조회 영역 */}
- {SearchBar && (
-
-
-
- )}
-
-
-
+ {/* DetailView가 존재할 때만 렌더링 isSearchModalOpen이 true면 visible=false로 팝업 숨김 */}
+ {isOpen && !isSearchModalOpen && (
+ ({}) }}
+ seletectedLayerNm={layerNm}
+ onClose={closePopup} // 닫기 콜백 전달
+ onFeatureSelect={handleFeatureSelect}
+ />
+ )}
+ {/* SearchView가 존재할 때만 렌더링 */}
+ {SearchView && (
+
+ )}
+ {/* 시도/시군구 조회 영역 */}
+ {SearchBar && (
+
+
+
+ )}
+
+
+
{typeof WaterDepth === "function" && setIsOpen(false)} />}
-
-
+
+
- {isSearch && (
-
- setIsSearchModalOpen(true)}
- className="overflow-hidden w-[40px] h-[40px] bg-white
- border border-[#9aa7b8]
- rounded
- shadow-[0_0_5px_#999]
- flex items-center justify-center
- p-0
- "
- >
-
-
-
- )}
-
- >
- );
+ {isSearch && (
+
+ setIsSearchModalOpen(true)}
+ className="flex h-[40px] w-[40px] items-center justify-center overflow-hidden rounded border border-[#9aa7b8] bg-white p-0 shadow-[0_0_5px_#999]"
+ >
+
+
+
+ )}
+
+ >
+ );
}
export default React.memo(Gis);
diff --git a/packages/common/business_components/src/ui/map/GisTree.js b/packages/common/business_components/src/ui/map/GisTree.js
index 335b1b119..47e86d4dc 100644
--- a/packages/common/business_components/src/ui/map/GisTree.js
+++ b/packages/common/business_components/src/ui/map/GisTree.js
@@ -196,7 +196,7 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes
return (
<>