diff --git a/apps/wr/app/(map-layout)/map/mainMap/page.tsx b/apps/wr/app/(map-layout)/map/mainMap/page.tsx
index 331e487bd..7451ae4b5 100644
--- a/apps/wr/app/(map-layout)/map/mainMap/page.tsx
+++ b/apps/wr/app/(map-layout)/map/mainMap/page.tsx
@@ -24,7 +24,7 @@ const Map = () => {
const fetchData = async () => {
try {
- const response = await mapService.getLyrStngs();
+ const response = await mapService.getLyrStngs('WR_NETWORK');
setTreeData(response); // API 응답 저장
} catch (error) {
console.error("데이터 불러오기 실패:", error);
diff --git a/apps/wr/app/(map-layout)/service/map.ts b/apps/wr/app/(map-layout)/service/map.ts
index 5002afef7..79ba7fe9e 100644
--- a/apps/wr/app/(map-layout)/service/map.ts
+++ b/apps/wr/app/(map-layout)/service/map.ts
@@ -30,8 +30,8 @@ export type LyrStngProps = {
export const mapService = {
//레이어 설정 조회
- getLyrStngs: async () => {
- const response = await fetch(`${API_URL}/lyrStngs/WR_NETWORK`, {
+ getLyrStngs: async (lyrGrp : string) => {
+ const response = await fetch(`${API_URL}/lyrStngs/${lyrGrp}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
diff --git a/apps/wr/app/(popUp-layout)/mapDrgtPopUp/drgtLegend.tsx b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/drgtLegend.tsx
new file mode 100644
index 000000000..9c558851c
--- /dev/null
+++ b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/drgtLegend.tsx
@@ -0,0 +1,70 @@
+"use client";
+
+import React from "react";
+import { Label } from "@common/components/ui/label";
+
+export const DRGT_LAYER_TYPES: string[] = [
+ // 수정 필요
+ 'drought1',
+ 'drought2',
+ 'drought3',
+ 'drought4',
+ 'drought5',
+ 'drought6',
+];
+// 지정된 순서에 따른 lyr_sn 배열
+export const EXPRS_ORDERED_LAYERS: string[] = [
+ // 수정 필요
+ '106', // 침수위험지도(tb_ms_sbmrg_dngr_map) - 30년 빈도
+ '107', // 침수위험지도(tb_ms_sbmrg_dngr_map) - 50년 빈도
+ '108', // 침수위험지도(tb_ms_sbmrg_dngr_map) - 80년 빈도
+ '109', // 침수위험지도(tb_ms_sbmrg_dngr_map) - 100년 빈도
+ '110', // 도시침수지도(tb_ms_flood_dngr_map) - 30년 빈도
+ '111', // 도시침수지도(tb_ms_flood_dngr_map) - 50년 빈도
+];
+
+export function DrgtLegend() {
+
+
+ return (
+ <>
+
+
+
+
+
+
+
가 뭄 정 보
+
+
+ {/* 관심 - 1회 미만 */}
+ {/* 관심 - 1회 이상 */}
+
+ {/* 주의 - 1회 미만 */}
+ {/* 주의 - 1회 이상 */}
+
+ {/* 관심+주의 - 1회 미만 */}
+ {/* 관심+주의 - 1회 이상 */}
+
+
+
+
+ >
+ );
+}
+
+function LegendItem({ color, label }: { color: string; label: string }) {
+ return (
+
+
+ {label}
+
+ );
+}
\ No newline at end of file
diff --git a/apps/wr/app/(popUp-layout)/mapDrgtPopUp/median.ts b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/median.ts
new file mode 100644
index 000000000..ab63e7c91
--- /dev/null
+++ b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/median.ts
@@ -0,0 +1,24 @@
+import { boundingExtent, getCenter } from 'ol/extent';
+import Feature from 'ol/Feature';
+import Geometry from 'ol/geom/Geometry';
+
+export function medianCoordinate2D(feature: Feature) {
+ // Feature를 입력 받아 중심 좌표를 계산하는 함수
+ if (!feature) {
+ console.warn("유효한 피처가 없습니다.");
+ return;
+ }
+
+ console.log(feature)
+
+ const geometry = feature.getGeometry();
+ if (!geometry) {
+ console.warn("피처에 geometry가 없습니다.");
+ return;
+ }
+
+ const extent = geometry.getExtent();
+ const center = getCenter(extent);
+ const centerExtent = boundingExtent([center]);
+ return centerExtent;
+}
\ No newline at end of file
diff --git a/apps/wr/app/(popUp-layout)/mapDrgtPopUp/page.tsx b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/page.tsx
new file mode 100644
index 000000000..a2c843351
--- /dev/null
+++ b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/page.tsx
@@ -0,0 +1,88 @@
+"use client";
+
+import Gis from "@common/business_components/ui/map/Gis";
+import { useEffect, useRef, useState, useCallback } from "react";
+import { useSearchParams } from "next/navigation";
+import { mapService } from "../../(map-layout)/service";
+import { DrgtLegend, DRGT_LAYER_TYPES, EXPRS_ORDERED_LAYERS } from "./drgtLegend";
+import { SearchBar } from "./searchBar";
+
+
+export default function MapDrgtPopUp() {
+ const searchParams = useSearchParams();
+ const ctpvCd = searchParams.get('ctpvCd') || '';
+ const sggCd = searchParams.get('sggCd') || '';
+ const fromDate = searchParams.get('fromDate') || '';
+ const toDate = searchParams.get('toDate') || '';
+
+ const gisMaps = useRef(null);
+ const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
+ const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
+ const [showDrgtLegend, setShowDrgtLegend] = useState(false); // DrgtLegend 표시 여부
+ const [isPlaying, setIsPlaying] = useState(false);
+
+ // 컴포넌트 마운트 시 1회 실행
+ useEffect(() => {
+ fetchData();
+ }, []);
+
+ function fetchData() {
+ (async () => {
+ try {
+ const response = await mapService.getLyrStngs('WR_DROUGHT');
+ setTreeData(response); // API 응답 저장
+ console.log("Drought layers fetched:", response);
+ } catch (error) {
+ console.error("데이터 불러오기 실패:", error);
+ }
+ })();
+ }
+
+ // WaterDepth 표시 여부를 결정하는 함수
+ const handleDrgtLegndVisibility = useCallback((checkedIds: string[], checkedNodesData: any[]) => {
+ const drgtLegndLayers = checkedNodesData.filter(node =>
+ DRGT_LAYER_TYPES.includes(node.data?.lyrTyNm)
+ );
+
+ const hasDrgtLegndLayer = drgtLegndLayers.length > 0;
+ setShowDrgtLegend(hasDrgtLegndLayer);
+ }, []);
+
+ // 체크된 레이어 변경 처리 함수
+ const handleCheckedLayersChange = useCallback((checkedIds: string[], checkedNodesData: any[]) => {
+ handleDrgtLegndVisibility(checkedIds, checkedNodesData);
+ }, [handleDrgtLegndVisibility]);
+
+
+
+ return (
+
+ }
+ waterDepth={showDrgtLegend ? DrgtLegend : undefined}
+ isPlaying={isPlaying}
+ setIsPlaying={setIsPlaying as any}
+ targetLayerTypes={DRGT_LAYER_TYPES as any}
+ orderedLayers={EXPRS_ORDERED_LAYERS as any}
+ checkInterval={2500}
+ height={`h-[100vh]`}
+ droughtDates={{ startYmd: fromDate, endYmd: toDate }}
+ />
+
+ );
+}
diff --git a/apps/wr/app/(popUp-layout)/mapDrgtPopUp/searchBar.tsx b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/searchBar.tsx
new file mode 100644
index 000000000..21a98d696
--- /dev/null
+++ b/apps/wr/app/(popUp-layout)/mapDrgtPopUp/searchBar.tsx
@@ -0,0 +1,173 @@
+"use client";
+
+import React, { useState, useEffect } from "react";
+import { SelectBox } from '@common/business_components/ui'
+import { Label, Button } from '@common/components';
+import { type SelectDataType } from "@common/business_components/ui";
+import GisApp from "@common/business_components/ui/map/lib/gis.core";
+import GeoJSON from "ol/format/GeoJSON";
+import Feature from "ol/Feature";
+import Geometry from "ol/geom/Geometry";
+import { medianCoordinate2D } from "./median";
+
+interface CtpvSggPrcsFcltSelectBoxProps {
+ gisMaps: React.RefObject;
+ ctpvCode: string;
+ sggCode: string;
+ fromDate: string;
+ toDate: string;
+}
+
+const DEFAULT_OPTION: SelectDataType = { val: '0', text: '전체' };
+
+export function SearchBar({ gisMaps, ctpvCode, sggCode }: CtpvSggPrcsFcltSelectBoxProps) {
+ const [ctpvCd, setCtpvCd] = useState(ctpvCode);
+ const [sggCd, setSggCd] = useState(sggCode);
+ const [ctpv, setCtpv] = useState([]);
+ const [sgg, setSgg] = useState([]);
+
+ useEffect(() => {
+ (async () => {
+ await fetchSido();
+ await fetchSigungu();
+ setCtpvCd(ctpvCode);
+ setSggCd(sggCode);
+ })();
+ }, []);
+
+ function onViewMapClick() {
+ if (sggCd && sggCd !== '0') {
+ fetchSggData();
+ return;
+ }
+ if (ctpvCd && ctpvCd !== '0') fetchCtpvData();
+ }
+
+ async function fetchCtpvData() {
+ try {
+ const ctpvData = await fetch(`/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_ctpv&outputFormat=application%2Fjson&cql_filter=mctpv_cd=%27${ctpvCd.trim()}%27&srsName=EPSG:5179`)
+ .then(res => res.json());
+ console.log('시도 데이터', ctpvData.features[0]);
+
+ const format = new GeoJSON();
+ const feature: Feature = format.readFeature(ctpvData.features[0], {
+ dataProjection: "EPSG:5179", // GeoJSON 좌표계
+ featureProjection: GisApp.TO_PROJ // 지도 좌표계
+ });
+
+ console.log('feature', feature);
+
+ const extent = medianCoordinate2D(feature);
+ console.log('GisApp.TO_PROJ', GisApp.TO_PROJ);
+ console.log('extent', extent)
+
+ handleFeatureFocus(extent);
+ }
+ catch (error) {
+ console.error("시도 data fetching Error:", error);
+ }
+ }
+
+ async function fetchSggData() {
+ try {
+ const sggData = await fetch(`/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_sgg&outputFormat=application%2Fjson&cql_filter=sgg_cd=%27${sggCd}%27&srsName=EPSG:5179`)
+ .then(res => res.json());
+ console.log('시군구 데이터', sggData.features[0]);
+
+
+ const format = new GeoJSON();
+ const feature: Feature = format.readFeature(sggData.features[0], {
+ dataProjection: "EPSG:5179", // GeoJSON 좌표계
+ featureProjection: GisApp.TO_PROJ // 지도 좌표계
+ });
+
+ const extent = medianCoordinate2D(feature);
+
+ handleFeatureFocus(extent);
+ }
+ catch (error) {
+ console.error("시군구 data fetching Error:", error);
+ }
+ }
+
+ function handleFeatureFocus(extent: any) {
+ console.log('ctpv', ctpv);
+ console.log('sgg', sgg);
+ const map = gisMaps.current;
+ if (!map) {
+ console.warn("지도가 초기화되지 않았습니다.");
+ return;
+ }
+
+ map.getView().fit(extent, {
+ duration: 300,
+ padding: [50, 50, 50, 50],
+ maxZoom: 11
+ });
+ };
+
+ 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).then(res => res.json());
+
+ const list = res.features.map((f: any) => ({
+ text: f.properties.mctpv_korn_nm,
+ val: f.properties.mctpv_cd,
+ }));
+
+ console.log('시도 데이터', list);
+ setCtpv(list);
+ };
+
+ const fetchSigungu = 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).then(res => res.json());
+
+ const list = res.features.map((f: any) => ({
+ text: f.properties.sgg_korn_nm,
+ val: f.properties.sgg_cd,
+ }));
+
+ console.log('시군구 데이터', list);
+ setSgg(list);
+ };
+
+
+
+ return (
+
+
+
+ {
+ setCtpvCd(String(val));
+ setSggCd(String(0));
+ }}
+ selectContentClass="z-[101]"
+ />
+
+ String(opt.val).slice(0, 2) === String(ctpvCd).trim())
+ ]
+ }
+ value={sggCd}
+ onSelectValue={val => { setSggCd(String(val)) }}
+ selectContentClass="z-[101]"
+ />
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/apps/wr/app/(with-layout)/matMng/coMng/drgtSttn/page.tsx b/apps/wr/app/(with-layout)/matMng/coMng/drgtSttn/page.tsx
index be7210f3f..f6881688a 100644
--- a/apps/wr/app/(with-layout)/matMng/coMng/drgtSttn/page.tsx
+++ b/apps/wr/app/(with-layout)/matMng/coMng/drgtSttn/page.tsx
@@ -9,7 +9,7 @@ import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/b
import { ContentsDiv, DateMonthPicker, downloadExcel, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiModal, UiTable, type SelectDataType } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Label, ScrollArea } from "@common/components/ui";
-import { useEffect, useState } from "react";
+import { useEffect, useState, useRef } from "react";
import { toast, Toaster } from "react-hot-toast";
export default function DrgtSttn() {
@@ -26,6 +26,7 @@ export default function DrgtSttn() {
isOpen: boolean;
data: customDrgt[] | undefined;
}>({ data: undefined, isOpen: false });
+ const popupRef = useRef(null);
const cellClick = (index: number) => {
if (fromDate && toDate && drgtRes[index]) {
@@ -121,6 +122,19 @@ export default function DrgtSttn() {
setToDate(formatted);
}
}, [fromDate, toDate])
+
+ function onViewMapClick() {
+ const params = new URLSearchParams({
+ ctpvCd: String(objSearch.city),
+ sggCd: String(objSearch.sgg),
+ fromDate: fromDate || '',
+ toDate: toDate || ''
+ });
+ const popupOptions = `width=${window.screen.availWidth},height=${window.screen.availHeight},left=0,top=0,resizable=yes,scrollbars=yes`;
+ popupRef.current = window.open(`/mapDrgtPopUp?${params.toString()}`, "가뭄 지도 보기 팝업", popupOptions);
+ }
+
+
return (
<>
@@ -136,7 +150,7 @@ export default function DrgtSttn() {
selectClass={""}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
- value={objSearch?.city ||code.cityCd[0]?.val ||""}
+ value={objSearch?.city || code.cityCd[0]?.val || ""}
/>
@@ -156,7 +170,7 @@ export default function DrgtSttn() {
onChange: (date: string | undefined) => {
const year = date ? date.slice(0, 4) : '';
let month = date?.slice(4);
- if (month&&month?.length < 2) {
+ if (month && month?.length < 2) {
month = month?.padStart(2, "0");
}
const formatted = `${year}${month}`;
@@ -172,7 +186,7 @@ export default function DrgtSttn() {
onChange: (date: string | undefined) => {
const year = date ? date.slice(0, 4) : '';
let month = date?.slice(4);
- if (month&&month.length < 2) {
+ if (month && month.length < 2) {
month = month?.padStart(2, "0");
}
const formatted = `${year}${month}`;
@@ -211,7 +225,7 @@ export default function DrgtSttn() {
sggText = sidoText;
}
- const searchArr:string[] = [];
+ const searchArr: string[] = [];
if (sidoText) searchArr.push(sidoText);
if (Array.isArray(sggText)) {
searchArr.push(...sggText);
@@ -234,7 +248,7 @@ export default function DrgtSttn() {
diff --git a/apps/wr/middleware.ts b/apps/wr/middleware.ts
index d068f6aa5..c5c7f8c01 100644
--- a/apps/wr/middleware.ts
+++ b/apps/wr/middleware.ts
@@ -91,6 +91,8 @@ export function middleware(req: NextRequest) {
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;
let newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`;
@@ -116,10 +118,13 @@ export function middleware(req: NextRequest) {
typename == "hasudo:tb_wr_rswtr_fclt" || //중수도시설
typename == "hasudo:tb_wr_htdfl_fclt" || //온배수시설
typename == "hasudo:tb_wr_ruse_fclt_dmd_co" || //수요처
- typename == "hasudo:tb_wr_tmpr_dmd_co" //잠재수요처
+ typename == "hasudo:tb_wr_tmpr_dmd_co" || //잠재수요처
+ typename?.startsWith("hasudo:drought") //가뭄 지도
) {
const url = req.nextUrl.clone();
url.searchParams.set("TYPENAME", typename.replace("hasudo:", ""));
+ if (startYmd) url.searchParams.set("startYmd", startYmd);
+ if (endYmd) url.searchParams.set("endYmd", endYmd);
queryParams = url.searchParams.toString();
newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
}