Merge branch 'iipbs/wr/dev'

This commit is contained in:
leedj312
2025-08-11 18:05:04 +09:00
8 changed files with 296 additions and 152 deletions
+2 -2
View File
@@ -312,8 +312,8 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
중권역: item.mdmbsn,
환경청: item.rgnNm,
시설명: item.bscFctNm,
시도: item.sido,
시군구: item.sigungo,
시도: item.sidoNm, // sido ?? 타입에러 나서 수정함
시군구: item.sggNm, //sgg ??
주소: item.daddr,
시설용량: item.fctCpc,
물사용량: item.waterUsage,
+64 -102
View File
@@ -6,7 +6,14 @@ import { mapService } from "../../service";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
import { SearchBar } from "@common/business_components/ui/map/searchBar/searchBar";
import { useWrStore } from "@/app/store";
import { getFeatureCd } from "@/components/lib/func/mapUtil";
import {
featurePopUpOpen,
getClickFeatureId,
getFeatureCd,
getSelectedLayers,
getWrFeaturePk,
getWrLayerNm,
} from "@/components/lib/func/mapUtil";
import toast, { Toaster } from "react-hot-toast";
const Map = () => {
@@ -24,7 +31,7 @@ const Map = () => {
const fetchData = async () => {
try {
const response = await mapService.getLyrStngs('WR_NETWORK');
const response = await mapService.getLyrStngs("WR_NETWORK");
setTreeData(response); // API 응답 저장
} catch (error) {
console.error("데이터 불러오기 실패:", error);
@@ -71,11 +78,11 @@ const Map = () => {
};
// SearchModal, GisContent 등에서 호출
const onFeatureFocus = () => {
console.log("onFeatureFocus");
const onFeatureFocus = (data: any) => {
console.log('data',data)
};
const onFeatureSelect = (data: any) => {
const onFeatureSelect = (data: any ,popUpClick?:boolean) => {
const map = gisMaps.current;
if (!map) {
@@ -93,27 +100,21 @@ const Map = () => {
// 2. data가 OpenLayers Feature 인스턴스인지 확인
let foundFeature: any = null;
let featureId = data.fid;
const layerName = data.layerNm;
if (layerName === "하수재이용시설") {
if(popUpClick){
const layerName = getWrLayerNm(data);
const featurePk = getWrFeaturePk(layerName ?? "");
// 재이용시설
featureId = `${layerName}.${data.searchPk}`;
} else if (
//빗물이용시설, 중수도시설
layerName === "빗물이용시설" ||
layerName == "중수도시설"
) {
featureId = `${layerName}.${data.bdstInfoSn}`;
} else if (layerName === "하수처리시설") {
//하수처리시설
featureId = `${layerName}.${data.bscFctCd}`;
} else if (layerName === "온배수시설") {
//온배수시설
featureId = `${layerName}.${data.bdstRuseFcltSn}`;
} else if (layerName == "수요처") {
//수요처
featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`;
} else {
featureId = `${layerName}.${data.fid || data.id || data.ftrIdn}`;
if (featurePk) {
const lastPk = layerName==='tb_wr_ruse_fclt_dmd_co'? data[featurePk].replaceAll("-", "") : data[featurePk]
featureId = `${layerName}.${lastPk}`;
} else {
console.warn("해당 피처는 선택된 레이어에서 찾을수 없습니다.");
}
}else{
featureId=getClickFeatureId(data)
}
map
.getLayers()
@@ -143,6 +144,10 @@ const Map = () => {
select.selectFeature(foundFeature, true);
} else {
console.warn("OpenLayers Feature를 찾을 수 없습니다:");
console.log("foundFeature :", foundFeature );
console.warn("featureId : ", featureId);
console.warn("data : ", data);
console.warn(": 끝");
}
const currentId = data?.fid || data?.id || data?.ftrIdn;
const lastId = featureData?.fid || featureData?.id || featureData?.ftrIdn;
@@ -150,10 +155,19 @@ const Map = () => {
setFeatureData(data);
setIsOpen(true);
setIsSearchModalOpen(false);
if (popUpClick && foundFeature&&!(
Object.keys(foundFeature?.getProperties()).length === 0 &&
foundFeature.constructor === Object
)){
const layerName = getWrLayerNm(data);
const isColumn = getFeatureCd(foundFeature.getProperties(), String(layerName));
if(layerName&&isColumn)
featurePopUpOpen(layerName,isColumn,popupDetailRef)
}
};
useEffect(() => {
if (isFeatured) {
onFeatureSelect(isFeatured);
}
@@ -163,41 +177,13 @@ const Map = () => {
const bc = new BroadcastChannel("mapDetailPopUp");
bc.onmessage = (event) => {
if (event.data.type === "SELECT_FEATURE") {
onFeatureSelect(event.data.feature);
onFeatureSelect(event.data.feature,true);
closePopup();
}
};
}, []);
const getSelectedLayers = (isFeature: any) => {
const map = gisMaps.current;
if (!map) {
console.warn("지도가 초기화되지 않았습니다.");
return;
}
let result = null;
const layers = map
? map
.getLayers()
.getArray()
.filter((l: any) => l.getVisible())
: []; // gisMap이 null인지 확인 후 레이어 가져오기
let featureLayer: { get: (key: string) => any } = { get: () => null };
layers.forEach((layer: any) => {
const source = layer.getSource();
if (
source &&
source.hasFeature &&
isFeature &&
typeof isFeature.getId === "function" &&
source.hasFeature(isFeature)
) {
featureLayer = layer; // 피처가 속한 레이어 찾기)
}
});
result = featureLayer.get("lyrNm");
return result;
};
const renderDetailView = useCallback(
(props: any) => {
@@ -208,44 +194,21 @@ const Map = () => {
}
const isFeature = props?.featureData;
if( typeof isFeature.getProperties === "function" ){
if (typeof isFeature.getProperties === "function") {
if (
Object.keys(isFeature?.getProperties()).length === 0 &&
isFeature.constructor === Object
!(
Object.keys(isFeature?.getProperties()).length === 0 &&
isFeature.constructor === Object
)
) {
const url = `/mapDetailPopUp?layerNm=${encodeURIComponent(props.seletectedLayerNm)}`;
const width = window.screen.availWidth;
const height = window.screen.availHeight;
const left = 0;
const top = 0;
const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=no`;
popupRef.current = window.open(url, "지도 레이어 팝업", popupOptions);
} else {
const layerNm = getSelectedLayers(isFeature);
const safeProps = isFeature.getProperties();
const featureCd = getFeatureCd(safeProps, String(layerNm));
const url = `/mapFeaturePopup?layerNm=${encodeURIComponent(String(layerNm))}&featureCd=${encodeURIComponent(featureCd)} `;
const width =
String(layerNm) === "하수재이용시설"
? Math.floor(window.innerWidth * 0.8)
: Math.floor(window.innerWidth * 0.4); // 화면 폭의 40%
const height =
String(layerNm) === "하수재이용시설"
? Math.floor(window.innerHeight - 150)
: Math.floor(window.innerHeight - 450); // 150px 여백 확보; // calc(100% - 70px)
const left = (window.screen.availWidth - width) / 2;
const top = (window.screen.availHeight - height) / 2;
const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;
popupDetailRef.current = window.open(
url,
"지도 시설 상세정보 팝업",
popupOptions
);
const layerNm = getSelectedLayers(isFeature,gisMaps);
const safeProps = isFeature.getProperties();
const featureCd = getFeatureCd(safeProps, String(layerNm));
if(layerNm)
featurePopUpOpen(layerNm,featureCd,popupDetailRef)
}
}else{
console.log(' data확인 필요')
} else {
console.log(" data확인 필요");
}
},
[checkedLayers, checkedLayersData, featureData] // 필요 시 의존성 넣기
@@ -259,9 +222,10 @@ const Map = () => {
}
};
const onOpenPopup = (data:any) => {
if(data){
const onOpenPopup = (data: any) => {
if (data) {
setIsOpen(true);
setFeatureData(null);
const url = `/mapDetailPopUp?layerNm=${encodeURIComponent(data)}`;
const width = window.screen.availWidth;
const height = window.screen.availHeight;
@@ -269,12 +233,10 @@ const Map = () => {
const top = 0;
const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=no`;
popupRef.current = window.open(url, "지도 레이어 팝업", popupOptions);
}else{
toast.error('시설 및 수요처가 선택되지 않았습니다.')
} else {
toast.error("시설 및 수요처가 선택되지 않았습니다.");
}
}
};
return (
<div className="bg-container">
@@ -310,12 +272,12 @@ const Map = () => {
/>
}
waterDepth={undefined}
onOpenPopup={(data:any) =>{
onOpenPopup(data)
onOpenPopup={(data: any) => {
onOpenPopup(data);
}}
/>
<Toaster position="top-center" />
</div>
</div>
);
};
@@ -44,6 +44,7 @@ export default function MapDetailPopUp() {
return (
<RswtFacility
rtnFeature={(feature) => {
bc.postMessage({ type: "SELECT_FEATURE", feature });
}}
/>
@@ -1,5 +1,6 @@
"use client";
import { useWrStore } from "@/app/store";
import CoSttnDetailPopup from "@/components/ui/map/detailPopup/coSttnDetailPopup/coSttnDetailPopup";
import { RuseDetailPopup } from "@/components/ui/map/detailPopup/ruseDetailPopup";
import CoDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/coDatailModal";
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
@@ -16,6 +17,7 @@ export default function MapFeaturePopup() {
htdfMapDetile,
pbnMapDetaile,
ldrmntMapDetile,
coSttnMapDetail
} = useWrStore((state) => state);
const { pbnMapHeadList } = pbnMap;
const [isDetail, setIsDetail] = useState<any>(null);
@@ -45,25 +47,30 @@ export default function MapFeaturePopup() {
useEffect(() => {
if (isFeatureCd && layerNm) {
if (layerNm === "하수재이용시설") {
setIsDetail(isFeatureCd);
} else if (layerNm === "하수처리시설") {
if (layerNm === "tb_wr_bdst_ruse_fclt") {
setIsDetail(isFeatureCd);
} else if (layerNm === "tb_il_swage_prcs_fclt") {
pbnMapDetaile(isFeatureCd, isFeatureCd).then((res) => {
setIsDetail(res);
});
} else if (layerNm === "빗물이용시설") {
} else if (layerNm === "tb_wr_rnwtr_utztn_fclt") {
rainMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
} else if (layerNm === "중수도시설") {
} else if (layerNm === "tb_wr_rswtr_fclt") {
rswtMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
} else if (layerNm === "온배수시설") {
} else if (layerNm === "tb_wr_htdfl_fclt") {
htdfMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
} else if (layerNm === "잠재수요처") {
}else if(layerNm ==='tb_wr_ruse_fclt_dmd_co'){
coSttnMapDetail(isFeatureCd).then((res) => {
console.log('tb_wr_ruse_fclt_dmd_co ', res)
setIsDetail(res);
});
} else if (layerNm === "tb_wr_tmpr_dmd_co") {
ldrmntMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
@@ -76,9 +83,9 @@ export default function MapFeaturePopup() {
<>
{isDetail ? (
<div className="fixed inset-0 w-screen h-screen m-0 p-0 bg-white">
{layerNm === "하수재이용시설" ? (
{layerNm === "tb_wr_bdst_ruse_fclt" ? (
<RuseDetailPopup bscFctCd={isDetail} />
) : layerNm === "하수처리시설" ? (
) : layerNm === "tb_il_swage_prcs_fclt" ? (
<div style={{ overflowX: "hidden" }}>
<div className="flex justify-between items-center mb-4">
<Title title="하수처리시설 상세정보" />
@@ -103,21 +110,26 @@ export default function MapFeaturePopup() {
onPageChange={() => {}}
/>
</div>
) : layerNm === "잠재수요처" ? (
) : layerNm === "tb_wr_tmpr_dmd_co" ? (
<CoDetailModal
formObj={isDetail}
readonly={false}
onFormSubmit={async (value) => {
console.log(value)
console.log(value);
}}
isMap={true}
/>
) : (
) :layerNm === "tb_wr_ruse_fclt_dmd_co" ? (
<CoSttnDetailPopup
isDetail={isDetail}
/>
)
: (
<SttnDetailModal
type={
layerNm === "빗물이용시설"
layerNm === "tb_wr_rnwtr_utztn_fclt"
? "RNB"
: layerNm === "중수도시설"
: layerNm === "tb_wr_rswtr_fclt"
? "RST"
: "HTB"
}
+38 -13
View File
@@ -1,11 +1,14 @@
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
import type { CommonTableProps } from "../../common/type/header";
import { coSttHeadListExport, coSttNodeListExport } from "../../matDmd/coSttn/headList";
import { fetchType, getFetchWithCount } from "@/components/lib/api";
import {
coSttHeadListExport,
coSttNodeListExport,
} from "../../matDmd/coSttn/headList";
import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api";
const coSttnMapRes: DemandCompType[] = [];
export const costtnMapSize =20
export const costtnMapSize = 20;
export type coSttnMapState = {
coSttnMap: {
@@ -21,7 +24,13 @@ export type coSttnMapState = {
type coSttnMapActions = {
coSttnMapInit: (pageNo: number, pageCnt: number, con: string) => void;
coSttnMapSearch: (pageNo: number, pageCnt: number, con: string) => void;
coSttnMapTxtSearch: (pageNo: number, pageCnt: number, con: string, txt: string) => void;
coSttnMapTxtSearch: (
pageNo: number,
pageCnt: number,
con: string,
txt: string
) => void;
coSttnMapDetail: (dmdInfoId: string) => Promise<DemandCompType | undefined>;
};
export type coSttnMapType = coSttnMapState & coSttnMapActions;
@@ -37,7 +46,6 @@ export const coSttnMapStateExport: coSttnMapState = {
},
};
export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
set: any
) => {
@@ -60,7 +68,7 @@ export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
};
});
} catch (e) {
console.log(e)
console.log(e);
}
},
coSttnMapSearch: async (pageNo: number, pageCnt: number, con: string) => {
@@ -96,11 +104,17 @@ export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
console.log("error", erTxt);
}
},
coSttnMapTxtSearch: async (pageNo: number, pageCnt: number, con: string, txt: string) => {
coSttnMapTxtSearch: async (
pageNo: number,
pageCnt: number,
con: string,
txt: string
) => {
try {
const coSttnMapRes = await getFetchWithCount(
fetchType.WR,
`/reuseFc/request/${pageNo}/${pageCnt}/${con}/${txt}`)
`/reuseFc/request/${pageNo}/${pageCnt}/${con}/${txt}`
);
set((state: coSttnMapState) => {
return {
...state,
@@ -109,12 +123,23 @@ export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
coSttnMapRes: coSttnMapRes.data,
coSttnMapResCount: coSttnMapRes.count,
isInit: false,
}
}
})
},
};
});
} catch (erTxt) {
console.log("error", erTxt);
}
},
}
}
coSttnMapDetail: async (dmdInfoId: string) => {
try {
const coSttnMapDetail = await getFetch(
fetchType.WR,
`/reuseFc/request/${dmdInfoId}`
);
return coSttnMapDetail;
} catch (erTxt) {
console.log("error", erTxt);
}
},
};
};
+135 -11
View File
@@ -1,18 +1,142 @@
const wrLayerList = [
{ text: "tb_il_swage_prcs_fclt", val: "bscFctCd" },
{ text: "tb_wr_bdst_ruse_fclt", val: "pbnstRuseFcltId" },
{ text: "tb_wr_rnwtr_utztn_fclt", val: "rainyObj" },
{ text: "tb_wr_rswtr_fclt", val: "rswtrObj" },
{ text: "tb_wr_htdfl_fclt", val: "htdflObj" },
{ text: "tb_wr_ruse_fclt_dmd_co", val: "dmdInfoId" },
{ text: "tb_wr_tmpr_dmd_co", val: "fctryMngSn" },
];
const wrFeaturePK = [
{ text: "bscFctCd", val: "tb_il_swage_prcs_fclt" },
{ text: "pbnstRuseFcltId", val: "tb_wr_bdst_ruse_fclt" },
{ text: "bdstInfoSn", val: "tb_wr_rnwtr_utztn_fclt" },
{ text: "bdstInfoSn", val: "tb_wr_rswtr_fclt" },
{ text: "bdstInfoSn", val: "tb_wr_htdfl_fclt" },
{ text: "dmdInfoId", val: "tb_wr_ruse_fclt_dmd_co" },
{ text: "fctryMngSn", val: "tb_wr_tmpr_dmd_co" },
];
// { 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" },
export const getFeatureCd = (featurePropertise:any, layerNm:string) => {
const featureCd =
layerNm === "하수재이용시설"
export const getFeatureCd = (featurePropertise: any, layerNm: string) => {
const featureCd =
layerNm === "tb_wr_bdst_ruse_fclt"
? featurePropertise?.swtrmt_fclt_cd
: ["빗물이용시설", "중수도시설", "온배수시설", "수요처" ,'잠재수요처'].includes(
layerNm
)
: [
"tb_wr_ruse_fclt_dmd_co",
"tb_wr_rswtr_fclt",
"tb_wr_htdfl_fclt",
"tb_wr_rnwtr_utztn_fclt",
"tb_wr_tmpr_dmd_co",
].includes(layerNm)
? featurePropertise?.bdst_nm
: layerNm === "하수처리시설"
: layerNm === "tb_il_swage_prcs_fclt"
? featurePropertise?.swtrmt_fclt_nm
: null;
console.log('featureCd ', featureCd)
return featureCd;
};
return featureCd;
};
export const getWrLayerNm = (featurePropertise: any) => {
const result = wrLayerList
.filter(item => item.val in featurePropertise) // 키 존재 여부 체크
.map(item => item.text);
return result[0];
};
export const getWrFeaturePk = (layerName :string) => {
const result = wrFeaturePK
.filter(item => item.val === layerName) // 키 존재 여부 체크
.map(item => item.text);
return result[0];
};
export const getSelectedLayers = (isFeature: any, gisMaps:any) => {
const map = gisMaps.current;
if (!map) {
console.warn("지도가 초기화되지 않았습니다.");
return;
}
let result = null;
const layers = map
? map
.getLayers()
.getArray()
.filter((l: any) => l.getVisible())
: []; // gisMap이 null인지 확인 후 레이어 가져오기
let featureLayer: { get: (key: string) => any } = { get: () => null };
layers.forEach((layer: any) => {
const source = layer.getSource();
if (
source &&
source.hasFeature &&
isFeature &&
typeof isFeature.getId === "function" &&
source.hasFeature(isFeature)
) {
featureLayer = layer; // 피처가 속한 레이어 찾기)
}
});
result = featureLayer.get("lyrTyNm");
return result;
};
export const getClickFeatureId = (data: any) => {
let featureId =''
const layerName = data.layerNm;
if (layerName === "하수재이용시설") {
// 재이용시설
featureId = `${layerName}.${data.searchPk}`;
} else if (
//빗물이용시설, 중수도시설
layerName === "빗물이용시설" ||
layerName == "중수도시설"
) {
featureId = `${layerName}.${data.bdstInfoSn}`;
} else if (layerName === "하수처리시설") {
//하수처리시설
featureId = `${layerName}.${data.bscFctCd}`;
} else if (layerName === "온배수시설") {
//온배수시설
featureId = `${layerName}.${data.bdstRuseFcltSn}`;
} else if (layerName == "수요처") {
//수요처
featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`;
} else {
featureId = `${layerName}.${data.fid || data.id || data.ftrIdn}`;
}
return featureId;
};
export function featurePopUpOpen(layerNm:string,featureCd:string,popupDetailRef){
const url = `/mapFeaturePopup?layerNm=${encodeURIComponent(String(layerNm))}&featureCd=${encodeURIComponent(featureCd)} `;
const width =
String(layerNm) === "tb_wr_bdst_ruse_fclt"
? Math.floor(window.innerWidth * 0.8)
: Math.floor(window.innerWidth * 0.4); // 화면 폭의 40%
const height =
String(layerNm) === "tb_wr_bdst_ruse_fclt"
? Math.floor(window.innerHeight - 150)
: Math.floor(window.innerHeight - 450); // 150px 여백 확보; // calc(100% - 70px)
const left = (window.screen.availWidth - width) / 2;
const top = (window.screen.availHeight - height) / 2;
const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;
popupDetailRef.current = window.open(
url,
"지도 시설 상세정보 팝업",
popupOptions
);
}
@@ -1,10 +0,0 @@
export default function coSttnDetailPopup(){
return(
<>
</>
)
}
@@ -0,0 +1,30 @@
import { useWrStore } from "@/app/store";
import SdmInsertForm from "@common/business_components/ui/sdmInsertForm";
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
export default function CoSttnDetailPopup({isDetail} :{isDetail:DemandCompType}){
const {
code
} = useWrStore((state) => state);
return(
<div>
<SdmInsertForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
dataList={[]}
rtnValue={(searchText: string, pageCnt: number) => {
console.log(searchText, pageCnt);
}}
rtnInputData={async (data) => {
console.log(data)
}}
bodyClassNm={"w-full mx-auto bg-white rounded-lg shadow-md p-6"}
updateList={isDetail}
readOnly={true}
></SdmInsertForm>
</div>
)
}