From 96bd0185b38f193093ead452149acf0e35ecbacf Mon Sep 17 00:00:00 2001 From: ljpark Date: Mon, 16 Mar 2026 13:33:23 +0900 Subject: [PATCH 1/3] =?UTF-8?q?sn:=20=ED=95=98=EC=88=98=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=EA=B5=AC=EC=97=AD=20=EC=84=A0=ED=83=9D=EC=8B=9C,=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=EC=8B=9C=EC=84=A4=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/components/common/index.ts | 4 +- .../popupComponent/featureClickEventPopup.tsx | 113 +++++++++++++++++- 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/components/common/index.ts b/apps/sn/app/(map-layout)/map/components/common/index.ts index 2581ac0fa..d2aed5956 100644 --- a/apps/sn/app/(map-layout)/map/components/common/index.ts +++ b/apps/sn/app/(map-layout)/map/components/common/index.ts @@ -1,5 +1,5 @@ -import MsSwagePpl from "../popupComponent/MsSwagePpl"; -import sewagePump from "../popupComponent/sewagePump"; +import MsSwagePpl from "../popupComponent/MsSwagePpl"; // 하수관로 +import sewagePump from "../popupComponent/sewagePump"; // 하수펌프 import smh from "../popupComponent/smh"; import Ssc from "../popupComponent/Ssc"; import StormWaterPump from "../popupComponent/stormWaterPump"; diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx index 031c69d8a..8d600ea86 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx @@ -28,6 +28,10 @@ import { VerticalTable } from "@/components/ui/verticalTable"; import { useGisContext } from "@common/business_components/ui/map/Gis"; import { Button } from "@common/components/ui"; import { useEffect, useRef, useState, useMemo } from "react"; +import Style from "ol/style/Style.js"; +import Fill from "ol/style/Fill.js"; +import Stroke from "ol/style/Stroke.js"; +import CircleStyle from "ol/style/Circle.js"; import { getLayerContentComponent } from "../common"; import { SwtrmtFcltCol, SwtrmtFcltCol2, SwtrmtPrcsZoneCol, SwtrmtPrcsZoneCol2, untrtSwgRainCol1, untrtSwgRainCol2, MsSwagePplCol, MsSwagePplCol2, ExclnSewagePumpCol, ExclnSewagePumpCol2, DrtwSewagePumpCol, DrtwSewagePumpCol2, MsSwageMhlCol, MsSwageMhlCol2, stofcbrCol, stofcbrCol2, MS_SWAGE_MHL_CODES, DRTW_SEWAGE_PUMP_USE_CODES } from "../common/table"; import InfilChart from './chart/infilChart'; @@ -38,6 +42,27 @@ import { codeMapper } from "../common/codeMapper"; import LoadingOverlay from '@/components/ui/LoadingBar'; import { searchUpperPpls } from "./smh"; +const linkedFacilityHighlightStyle = new Style({ + image: new CircleStyle({ + radius: 18, + fill: new Fill({ + color: 'rgba(255, 235, 59, 0.35)', + }), + stroke: new Stroke({ + color: 'rgba(255, 193, 7, 0.95)', + width: 4, + }), + }), + fill: new Fill({ + color: 'rgba(255, 235, 59, 0.2)', + }), + stroke: new Stroke({ + color: 'rgba(255, 193, 7, 0.95)', + width: 5, + }), + zIndex: 9999, +}); + const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => { const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; }; @@ -59,6 +84,8 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, const [isLoading, setIsLoading] = useState(false); // 로딩 상태 const [chmbrXcnts, setChmbrXcnts] = useState(''); // 로딩 상태 const [chmbrYdnts, setChmbrYdnts] = useState(''); // 로딩 상태 + const linkedFacilityFeatureRef = useRef(null); + const linkedFacilityOriginalStyleRef = useRef(null); // 🎯 관로관리번호 추출 const pplMngNo = featureData?.values_?.fclt_mng_no || ""; @@ -77,6 +104,70 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, }; }, [featureData?.values_]); + const clearLinkedFacilityHighlight = () => { + if (linkedFacilityFeatureRef.current) { + linkedFacilityFeatureRef.current.setStyle(linkedFacilityOriginalStyleRef.current ?? undefined); + linkedFacilityFeatureRef.current.changed?.(); + } + + linkedFacilityFeatureRef.current = null; + linkedFacilityOriginalStyleRef.current = null; + }; + + // 하수처리구역에 연결된 하수처리시설 피처를 찾아 기존 아이콘 위에 노랑 하이라이트를 덧씌운다. + const highlightLinkedFacility = (facilityCode: string | null | undefined) => { + clearLinkedFacilityHighlight(); + + if (!gisMap || !facilityCode) return; + + const normalizedFacilityCode = String(facilityCode).trim(); + const layers = gisMap.getLayers().getArray(); + + for (const layer of layers) { + const source = layer?.getSource?.(); + if (!source?.getFeatures) continue; + + const features = source.getFeatures(); + const targetFeature = features.find((feature: any) => { + const featureId = feature?.getId?.(); + const isFacilityLayer = typeof featureId === 'string' && featureId.startsWith('tb_il_swage_prcs_fclt.'); + const featureFacilityCode = feature?.get?.('swtrmt_fclt_cd'); + + return isFacilityLayer && String(featureFacilityCode ?? '').trim() === normalizedFacilityCode; + }); + + if (targetFeature) { + const originalFeatureStyle = targetFeature.getStyle?.(); + const featureLayer = targetFeature.getLayer?.(); + const layerStyleFn = featureLayer?.getStyleFunction?.() ?? null; + + linkedFacilityOriginalStyleRef.current = originalFeatureStyle; + linkedFacilityFeatureRef.current = targetFeature; + targetFeature.setStyle((feature: any, resolution: number) => { + let styles: any[] = []; + + if (typeof originalFeatureStyle === 'function') { + const originalStyles = originalFeatureStyle(feature, resolution); + if (Array.isArray(originalStyles)) styles.push(...originalStyles); + else if (originalStyles) styles.push(originalStyles); + } else if (originalFeatureStyle) { + if (Array.isArray(originalFeatureStyle)) styles.push(...originalFeatureStyle); + else styles.push(originalFeatureStyle); + } else if (layerStyleFn) { + const layerStyles = layerStyleFn(feature, resolution); + if (Array.isArray(layerStyles)) styles.push(...layerStyles); + else if (layerStyles) styles.push(layerStyles); + } + + styles.push(linkedFacilityHighlightStyle); + return styles; + }); + targetFeature.changed?.(); + return; + } + } + }; + // 피쳐데이터의 현재 레이어 이름 가져오는 함수 const getSelectedLayers = () => { let result = null; @@ -348,6 +439,26 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, fetchData(); }, [featureId, processedData]); + useEffect(() => { + const layerTypeNm = featureData?.values_ + ? featureData?.id_?.split('.')?.[0] + : featureData?.lyrTypeNm; + + if (layerTypeNm === 'tb_ms_swage_prcs_zone') { + const facilityCode = featureData?.values_?.swtrmt_fclt_cd ?? featureData?.swtrmtFcltCd; + highlightLinkedFacility(facilityCode); + return () => { + clearLinkedFacilityHighlight(); + }; + } + + clearLinkedFacilityHighlight(); + + return () => { + clearLinkedFacilityHighlight(); + }; + }, [featureData, gisMap]); + // 저장 시 모달 띄우기 const handleSaveClick = () => { setIsModalOpen(true); // 모달 열기 @@ -525,4 +636,4 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, ) } -export default FeatureClickEventPopup; \ No newline at end of file +export default FeatureClickEventPopup; From 57afe5dc5ca7c1f2834742c22583a63e1971a6f3 Mon Sep 17 00:00:00 2001 From: ljpark Date: Mon, 16 Mar 2026 17:20:45 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fo:=20=EC=B4=9D=20=EA=B1=B4=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../popupComponent/featureClickEventPopup.tsx | 8 ++++---- apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx | 2 +- .../app/(map-layout)/map/searchModal/searchModal.tsx | 6 +++--- .../common/business_components/src/ui/table/index.tsx | 10 +++++++--- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx index 8d600ea86..11e61b006 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/featureClickEventPopup.tsx @@ -49,16 +49,16 @@ const linkedFacilityHighlightStyle = new Style({ color: 'rgba(255, 235, 59, 0.35)', }), stroke: new Stroke({ - color: 'rgba(255, 193, 7, 0.95)', - width: 4, + color: 'rgba(255, 193, 7, 0.45)', + width: 2, }), }), fill: new Fill({ color: 'rgba(255, 235, 59, 0.2)', }), stroke: new Stroke({ - color: 'rgba(255, 193, 7, 0.95)', - width: 5, + color: 'rgba(255, 193, 7, 0.35)', + width: 2.5, }), zIndex: 9999, }); diff --git a/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx index a90284dde..ad57c0a5f 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx @@ -249,7 +249,7 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg { - return (<>조회 결과 ({tableCount.toLocaleString('ko-KR')})건); + return (<>조회 결과); })() } tableData={tableData} diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index d179652f3..3ce334518 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -130,7 +130,7 @@ const SearchModal: React.FC = () => { { const label = BASIC_TYPES.find((type) => type.val === basicType)?.text - return (<>{label} 조회 결과 ({tableCount.toLocaleString('ko-KR')})건); + return (<>{label} 조회 결과); })() } tableData={tableData} @@ -161,7 +161,7 @@ const SearchModal: React.FC = () => { headName={ (() => { const label = WORK_TYPES.find((type) => type.val === workType)?.text - return (<>{label} 사업 현황 ({tableCount.toLocaleString('ko-KR')})건); + return (<>{label} 사업 현황); })() } tableData={tableData} @@ -188,7 +188,7 @@ const SearchModal: React.FC = () => { headName={ (() => { const label = WORK_TYPES.find((type) => type.val === workType)?.text - return (<>{label} 결과표 ({detailTableCount.toLocaleString('ko-KR')})건); + return (<>{label} 결과표); })() } tableData={detailTableData} diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index d2fd81de6..e5fc933ae 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -16,6 +16,7 @@ export type ChkClass = { chk: boolean; readonly: boolean; }; + type UiTableProps = { headName: React.ReactNode | undefined; tableData: T[]; @@ -123,17 +124,20 @@ export function UiTable>({ }; const leafCols = getLeafCols(headlist); + const totalLabel = typeof total === "number" ? total.toLocaleString("ko-KR") : " "; + const hasTotal = typeof total === "number"; + return ( <> {headName ? ( headButton ? (
-

{headName}

+

{headName} 총 {totalLabel}건

<>{headButton}
) : (
-

{headName}

+

{headName} 총 {totalLabel}건

) ) : ( @@ -286,7 +290,7 @@ export function UiTable>({ )} - {total <= 0 ? ( + {!hasTotal || total <= 0 ? ( <> ) : ( Date: Mon, 16 Mar 2026 18:01:53 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fo:=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20=EB=B0=8F=20=EC=9E=A0=EC=9E=AC=EC=88=98=EC=9A=94?= =?UTF-8?q?=EC=B2=98=20=EC=B4=9D=20=EA=B1=B4=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/pages/(with-layout)/layout.tsx | 1 - apps/wr/app/(with-layout)/matMng/coMng/ldrmntCoSttn/page.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/layout.tsx b/apps/fo/app/pages/(with-layout)/layout.tsx index f77bc244b..e1f6f664e 100644 --- a/apps/fo/app/pages/(with-layout)/layout.tsx +++ b/apps/fo/app/pages/(with-layout)/layout.tsx @@ -21,7 +21,6 @@ export default function RootLayout({ setCurrentMenuInfo(id); getMenuAuth(id.menuCd); router.push(id.urlPath); - console.log(id); }; return ( diff --git a/apps/wr/app/(with-layout)/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/(with-layout)/matMng/coMng/ldrmntCoSttn/page.tsx index 8a6744833..eee7d9f73 100644 --- a/apps/wr/app/(with-layout)/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/(with-layout)/matMng/coMng/ldrmntCoSttn/page.tsx @@ -248,7 +248,7 @@ export default function LdrmntCoSttn() {