From 721dcbc634fff67e1135f391fb1b137da7adffaf Mon Sep 17 00:00:00 2001 From: leedj312 Date: Wed, 3 Sep 2025 14:34:34 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AC=BC=EC=9E=AC=EC=9D=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=A7=80=EB=8F=84=20=EC=98=A4=EB=B2=84=EB=A0=88=EC=9D=B4=20?= =?UTF-8?q?=ED=8C=9D=EC=97=85=20=EC=88=98=EC=A0=95(=EB=93=9C=EB=9E=98?= =?UTF-8?q?=EA=B7=B8,=20=EC=B6=95=EC=86=8C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/(map-layout)/map/mainMap/page.tsx | 78 +++++-------- apps/wr/app/store/map/rainMap/index.tsx | 2 - apps/wr/components/lib/func/mapUtil.ts | 70 ++++++------ .../components/ui/map/wrOverLay/wrOverLay.tsx | 104 +++++++++++++++--- apps/wr/package.json | 1 + 5 files changed, 152 insertions(+), 103 deletions(-) diff --git a/apps/wr/app/(map-layout)/map/mainMap/page.tsx b/apps/wr/app/(map-layout)/map/mainMap/page.tsx index f31263202..52955d457 100644 --- a/apps/wr/app/(map-layout)/map/mainMap/page.tsx +++ b/apps/wr/app/(map-layout)/map/mainMap/page.tsx @@ -18,7 +18,6 @@ import toast, { Toaster } from "react-hot-toast"; import createOverlayManager from "@common/business_components/ui/map/GisOverlay"; import { createRoot } from "react-dom/client"; import WrOverLay from "@/components/ui/map/wrOverLay/wrOverLay"; -import type { comCodeState } from "@/app/store/common/code"; const Map = () => { @@ -257,60 +256,41 @@ const overlayManagersRef = useRef([]); const overlayActiveRef = useRef(false); const moveEndDebounceRef = useRef(null); -const overlayFormatter = (feature: any, props: any) => { - const propertise = props || {}; +// 반환: Promise +const overlayFormatter = async (feature: any, props: any) => { + const p = props || {}; const featureId = - feature.getId?.() ?? - propertise?.id ?? - propertise?.fid ?? - propertise?.ftrIdn ?? - ''; + feature.getId?.() ?? p?.id ?? p?.fid ?? p?.ftrIdn ?? ''; if (!featureId) return null; - const fcltTableId = featureId.split('.')[0]; - const fcltCd = getFeatureCd(props, fcltTableId); + const tableId = String(featureId).split('.')[0]??''; + const fcltCd = getFeatureCd(props, tableId); + if (!fcltCd) return null; - const div = document.createElement("div"); + let data: any = null; + let title = ''; + + if (tableId === 'tb_il_swage_prcs_fclt') { data = await pbnMapDetaile(fcltCd); title = '하수처리시설'; } + else if (tableId === 'tb_wr_bdst_ruse_fclt') { data = await getRuseMaplListReturn(fcltCd); title = '하수재이용시설'; } + else if (tableId === 'tb_wr_rnwtr_utztn_fclt'){ data = await rainMapDetile(fcltCd); title = '빗물이용시설'; } + else if (tableId === 'tb_wr_rswtr_fclt') { data = await rswtMapDetile(fcltCd); title = '중수도시설'; } + else if (tableId === 'tb_wr_htdfl_fclt') { data = await htdfMapDetile(fcltCd); title = '온배수시설'; } + else if (tableId === 'tb_wr_ruse_fclt_dmd_co'){ data = await coSttnMapDetail(fcltCd); title = '수요처'; } + else if (tableId === 'tb_wr_tmpr_dmd_co') { data = await ldrmntMapDetile(fcltCd); title = '잠재수요처'; } + + const empty = + data == null || + (Array.isArray(data) && data.length === 0) || + (typeof data === 'object' && !Array.isArray(data) && Object.keys(data).length === 0); + + if (empty) return null; + + const div = document.createElement('div'); const root = createRoot(div); - - // 비동기 처리만 따로 - (async () => { - let overLayData; - let title = ''; - - if (fcltTableId === 'tb_il_swage_prcs_fclt') { - overLayData = await pbnMapDetaile( fcltCd); - title = '하수처리시설'; - } else if (fcltTableId === 'tb_wr_bdst_ruse_fclt') { - overLayData = await getRuseMaplListReturn(fcltCd); - title = '하수재이용시설'; - - } else if (fcltTableId === 'tb_wr_rnwtr_utztn_fclt') { - overLayData = await rainMapDetile(fcltCd); - title = '빗물이용시설'; - } else if (fcltTableId === 'tb_wr_rswtr_fclt') { - overLayData = await rswtMapDetile(fcltCd); - title = '중수도시설'; - } else if (fcltTableId === 'tb_wr_htdfl_fclt') { - overLayData = await htdfMapDetile(fcltCd); - title = '온배수시설'; - } else if (fcltTableId === 'tb_wr_ruse_fclt_dmd_co') { - overLayData = await coSttnMapDetail(fcltCd); - title = '수요처'; - } else if (fcltTableId === 'tb_wr_tmpr_dmd_co') { - overLayData = await ldrmntMapDetile(fcltCd); - title = '잠재수요처'; - } - - root.render(} />); - })(); - - // 제거 시 React unmount - (div as any).__dispose = () => root.unmount(); - - return div; // <-- HTMLDivElement 동기 리턴 + (div as any).__dispose = () => { try { root.unmount(); } catch {} }; + root.render(); + return div; // ← 데이터 있을 때만 HTMLElement 반환 }; - const destroyAllManagers = () => { overlayManagersRef.current.forEach(m => { try { m.destroy(); } catch {} }); overlayManagersRef.current = []; diff --git a/apps/wr/app/store/map/rainMap/index.tsx b/apps/wr/app/store/map/rainMap/index.tsx index f80c27cc7..1d23e7991 100644 --- a/apps/wr/app/store/map/rainMap/index.tsx +++ b/apps/wr/app/store/map/rainMap/index.tsx @@ -114,8 +114,6 @@ export const rainMapActionsExport: (set: any) => rainMapActions = ( }, rainMapDetile: async (featureCd: string) => { try { - console.log('featureCd ', featureCd) - const rainDetail = await getFetch(fetchType.WR, `/reuseFc/rainyInfoList/1/3/0/${featureCd}` ) diff --git a/apps/wr/components/lib/func/mapUtil.ts b/apps/wr/components/lib/func/mapUtil.ts index 283b53a75..925961b88 100644 --- a/apps/wr/components/lib/func/mapUtil.ts +++ b/apps/wr/components/lib/func/mapUtil.ts @@ -1,4 +1,4 @@ -import type { comCodeState } from "@/app/store/common/code"; +import { formatCommaNumber, formatPhoneNumber } from "./commom"; const wrLayerList = [ { text: "tb_il_swage_prcs_fclt", val: "bscFctCd" }, @@ -28,7 +28,6 @@ const wrFeaturePK = [ // { text: "잠재수요처", val: "tb_wr_tmpr_dmd_co" }, export const getFeatureCd = (featurePropertise: any, layerNm: string) => { - console.log("featurePropertise ", featurePropertise); const featureCd = layerNm === "tb_wr_bdst_ruse_fclt" ? featurePropertise?.swtrmt_fclt_cd @@ -150,72 +149,73 @@ export function featurePopUpOpen( ); } -export const getOverLayObj = (fclType: string, data: any,code?:Partial) => { +export const getOverLayObj = (fclType: string, data: any,code?:any) => { let newObj = {}; let title = ""; + + if (fclType === "하수재이용시설") { newObj = { - "시설용량(톤/일)": data?.fcltCpct ??"", + "시설용량(톤/일)": formatCommaNumber(data?.fcltCpct) ??'확인불가', "재이용률(%)": (data?.fcltCpct / data?.bscFctCpc)||0, - "장내용수(m³/년)": data?.inUsage ?? "", - "장외용수(m3/년)":data?.outUsage ?? "", - // 수요처: data?.reuseBuilding[0]?.rainyObj.pntfColArea ?? "", + "장내용수(m³/년)": formatCommaNumber(data?.inUsage) ?? '확인불가', + "장외용수(m3/년)":formatCommaNumber(data?.outUsage) ?? '확인불가', + // 수요처: data?.reuseBuilding[0]?.rainyObj.pntfColArea ?? '확인불가', }; - title = data?.bdstNm ?? ""; + title = data?.bdstNm ?? '확인불가'; } else if (fclType === "하수처리시설") { newObj = { - "시설용량(톤/일)": data?.fctCpc ?? "", - 지역구분: data?.efflWqltStndrdNm ?? "", - 재이용여부: data?.rswtrYn ?? "", - "재이용시설 등록여부": data?.ruse ?? "", + "시설용량(톤/일)": formatCommaNumber(data?.fctCpc) ?? '확인불가', + 지역구분: data?.efflWqltStndrdNm ?? '확인불가', + 재이용여부: data?.rswtrYn ?? '확인불가', + "재이용시설 등록여부": data?.ruse ?? '확인불가', }; - title = data?.bscFctNm ?? ""; + title = data?.bscFctNm ?? '확인불가'; } else if (fclType === "빗물이용시설" ) { newObj = { - 건물용도: code?.code?.bdstUsgCd.find((item) => item.val===data?.reuseBuilding[0].bdstUsgCd )?.text ?? "", - 설치완료일: data?.reuseBuilding[0]?.instlCmptnDt ?? "", - 처리시설유무: data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctYn ?? "", - "처리시설용량(m³/일)": - data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctCpct ?? "", - "저류조용량(m³)": data?.reuseBuilding[0]?.rainyObj.pntfColArea ?? "", + 건물용도: code?.bdstUsgCd.find((item) => item.val=== String(data?.reuseBuilding[0].bdstUsgCd) )?.text ?? '확인불가', + 설치완료일: data?.reuseBuilding[0]?.instlCmptnDt ?? '확인불가', + 처리시설유무: data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctYn ?? '확인불가', + "처리시설용량(m³/일)": formatCommaNumber(data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctCpct) ?? '확인불가', + "저류조용량(m³)": formatCommaNumber(data?.reuseBuilding[0]?.rainyObj.pntfColArea) ?? '확인불가', }; - title = data?.bdstNm ?? ""; + title = data?.bdstNm ?? '확인불가'; } else if (fclType === "중수도시설") { newObj = { - 건물용도: code?.code?.bdstUsgCd.find((item) => item.val===data?.reuseBuilding[0].bdstUsgCd )?.text ?? "", - 설치완료일: data?.reuseBuilding[0]?.instlCmptnDt ?? "", - "주요 처리공정": code?.code?.rswtPrscCdMthdCd.find((item) => item.val===data?.reuseBuilding[0]?.rswtrObj.filtrTrtmfctProcs)?.text ?? "", - 원수종류: code?.code?.orgwtKndCd.find((item) => item.val === data?.reuseBuilding[0]?.rswtrObj.orgwtKndCd)?.text ?? "", - //이용용도: isCode.filtrTrtmfctUsgCd data?.reuseBuilding[0]?.rswtrObj.altUswtrKndCd ?? "", + 건물용도: code?.bdstUsgCd.find((item) => item.val===String(data?.reuseBuilding[0].bdstUsgCd) )?.text ?? '확인불가', + 설치완료일: data?.reuseBuilding[0]?.instlCmptnDt ?? '확인불가', + "주요 처리공정": code?.rswtPrscCdMthdCd.find((item) => item.val===data?.reuseBuilding[0]?.rswtrObj.filtrTrtmfctProcs)?.text ?? '확인불가', + 원수종류: code?.orgwtKndCd.find((item) => item.val === data?.reuseBuilding[0]?.rswtrObj.orgwtKndCd)?.text ?? '확인불가', + //이용용도: isCode.filtrTrtmfctUsgCd data?.reuseBuilding[0]?.rswtrObj.altUswtrKndCd ?? '확인불가', }; - title = data?.bdstNm ?? ""; + title = data?.bdstNm ?? '확인불가'; } else if (fclType === "온배수시설") { newObj = { - 미정: "", + 미정: '확인불가', // '설치완료일': data?.reuseBuilding[0]?.instlCmptnDt??'', // '처리시설유무': data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctYn??'', // '처리시설용량(m³/일)': data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctCpct??'', // '저류조용량(m³)': data?.reuseBuilding[0]?.rainyObj.pntfColArea??'', }; - title = data?.bdstNm ?? ""; + title = data?.bdstNm ?? '확인불가'; } else if (fclType === "수요처") { newObj = { '사업자등록번호': data?.dmdInfoId??'', '주소': data?.daddr??'', - '전화번호': data?.telno??'', + '전화번호': formatPhoneNumber(data?.telno)??'', }; - title = data?.dmdCoNm ?? ""; + title = data?.dmdCoNm ?? '확인불가'; } else if (fclType === "잠재수요처") { newObj = { - 공장구분: data?.fctrySe ?? "", - 설립구분: data?.fndnSe ?? "", - 업종명: data?.tpbizNm ?? "", - 생산폼목: data?.prdctnItem ?? "", + 공장구분: data?.fctrySe ?? '확인불가', + 설립구분: data?.fndnSe ?? '확인불가', + 업종명: data?.tpbizNm ?? '확인불가', + 생산폼목: data?.prdctnItem ?? '확인불가', }; - title = data?.dmdCoNm ?? ""; + title = data?.dmdCoNm ?? '확인불가'; } return { title, newObj }; diff --git a/apps/wr/components/ui/map/wrOverLay/wrOverLay.tsx b/apps/wr/components/ui/map/wrOverLay/wrOverLay.tsx index bc8394a9a..225b2ff4c 100644 --- a/apps/wr/components/ui/map/wrOverLay/wrOverLay.tsx +++ b/apps/wr/components/ui/map/wrOverLay/wrOverLay.tsx @@ -1,10 +1,10 @@ "use client"; -import type { comCodeState } from "@/app/store/common/code"; import { getOverLayObj } from "@/components/lib/func/mapUtil"; import { Card } from "@common/business_components/ui/chart/lib/card"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import WrOverLayTable from "./WrOverLayTable/WrOverLayTable"; import WrOverLayRuse from "./WrOverLayRuse/WrOverLayRuse"; +import Draggable from "react-draggable"; export default function WrOverLay({ title, @@ -13,12 +13,18 @@ export default function WrOverLay({ }: { title: string; data: any; - code: Partial; + code: any; }) { const [newOverLayData, setNewOverLayData] = useState>( {} ); const [typeTitle, setTypeTitle] = useState(""); + const [pos, setPos] = useState<{ x: number; y: number }>({ x: 0, y: 0 }); + + const [open, setOpen] = useState(true); + const bubbleLabel = title?.[0] ?? "•"; + + const dragRef = useRef(null); useEffect(() => { if (title !== "하수재이용시설" && data) { @@ -30,21 +36,85 @@ export default function WrOverLay({ return ( <> - - {/* 파란 제목 바 */} - {title !== "하수재이용시설" ? ( -
- {typeTitle + "(" + title + ")"} + {open ? ( + setPos({ x: data.x, y: data.y })} + > +
+ + {/* 헤더: 제목 바 + 우측 정렬 버튼 (절대배치 제거, 타이틀 중앙 정렬 유지) */} +
+
+ {/* 좌측 스페이서: 우측 버튼과 동일한 너비를 차지하도록 동일 버튼을 투명하게 복제 */} +
+
+ + + +
+
+ + {/* 중앙 타이틀 */} +
+ {typeTitle + "(" + title + ")"} +
+ + {/* 우측 실제 버튼 영역 */} +
+ + + +
+
+
+ + {/* 본문 */} + {title === "하수재이용시설" ? ( + + ) : ( + + )} +
- ) : ( - <> - )} - {title === "하수재이용시설" ? ( - - ) : ( - - )} - +
+ ) : ( + + )} ); } diff --git a/apps/wr/package.json b/apps/wr/package.json index 28438b1d8..39f7c2274 100644 --- a/apps/wr/package.json +++ b/apps/wr/package.json @@ -25,6 +25,7 @@ "next": "15.1.7", "ol": "^7.3.0", "ol-ext": "^4.0.11", + "react-draggable": "^4.5.0", "react-hook-form": "^7.54.2", "react-hot-toast": "^2.5.2", "react-i18next": "^15.6.0",