Merge commit '05b4a4dae547541197c9b9162aab9c3e74ec63bf'

This commit is contained in:
leedj312
2025-09-02 17:46:05 +09:00
10 changed files with 526 additions and 73 deletions
+189 -28
View File
@@ -15,9 +15,14 @@ import {
getWrLayerNm,
} from "@/components/lib/func/mapUtil";
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 = () => {
const { comMap } = useWrStore((state) => state);
const {code, comMap ,rainMapDetile ,rswtMapDetile,getRuseMaplListReturn,pbnMapDetaile,ldrmntMapDetile,htdfMapDetile,coSttnMapDetail} = useWrStore((state) => state);
const { isFeatured } = comMap;
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
const gisMaps = useRef<any | null>(null);
@@ -79,11 +84,10 @@ const Map = () => {
// SearchModal, GisContent 등에서 호출
const onFeatureFocus = (data: any) => {
console.log('data',data)
console.log("data", data);
};
const onFeatureSelect = (data: any ,popUpClick?:boolean) => {
const onFeatureSelect = (data: any, popUpClick?: boolean) => {
const map = gisMaps.current;
if (!map) {
console.warn("지도가 초기화되지 않았습니다.");
@@ -100,21 +104,22 @@ const Map = () => {
// 2. data가 OpenLayers Feature 인스턴스인지 확인
let foundFeature: any = null;
let featureId = data.fid;
if(popUpClick){
if (popUpClick) {
const layerName = getWrLayerNm(data);
const featurePk = getWrFeaturePk(layerName ?? "");
// 재이용시설
if (featurePk) {
const lastPk = layerName==='tb_wr_ruse_fclt_dmd_co'? data[featurePk].replaceAll("-", "") : data[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)
} else {
featureId = getClickFeatureId(data);
}
map
.getLayers()
@@ -143,9 +148,9 @@ const Map = () => {
}
select.selectFeature(foundFeature, true);
} else {
// toast.error('위치정보를 찾을수 없습니다')
// toast.error('위치정보를 찾을수 없습니다')
console.warn("OpenLayers Feature를 찾을 수 없습니다:");
console.log("foundFeature :", foundFeature );
console.log("foundFeature :", foundFeature);
console.warn("featureId : ", featureId);
console.warn("data : ", data);
console.warn(": 끝");
@@ -157,14 +162,21 @@ const Map = () => {
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)
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);
}
};
@@ -178,14 +190,12 @@ const Map = () => {
const bc = new BroadcastChannel("mapDetailPopUp");
bc.onmessage = (event) => {
if (event.data.type === "SELECT_FEATURE") {
onFeatureSelect(event.data.feature,true);
onFeatureSelect(event.data.feature, true);
closePopup();
}
};
}, []);
const renderDetailView = useCallback(
(props: any) => {
const map = gisMaps.current;
@@ -202,11 +212,10 @@ const Map = () => {
isFeature.constructor === Object
)
) {
const layerNm = getSelectedLayers(isFeature,gisMaps);
const safeProps = isFeature.getProperties();
const layerNm = getSelectedLayers(isFeature, gisMaps);
const safeProps = isFeature.getProperties();
const featureCd = getFeatureCd(safeProps, String(layerNm));
if(layerNm)
featurePopUpOpen(layerNm,featureCd,popupDetailRef)
if (layerNm) featurePopUpOpen(layerNm, featureCd, popupDetailRef);
}
} else {
console.log(" data확인 필요");
@@ -239,6 +248,158 @@ const Map = () => {
}
};
const OVERLAY_MIN_ZOOM = 16;
const OVERLAY_COORD_PRECISION = 5;
const OVERLAY_MAX_PER_VIEW = 800;
const overlayManagersRef = useRef<any[]>([]);
const overlayActiveRef = useRef(false);
const moveEndDebounceRef = useRef<number | null>(null);
const overlayFormatter = (feature: any, props: any) => {
const propertise = props || {};
const featureId =
feature.getId?.() ??
propertise?.id ??
propertise?.fid ??
propertise?.ftrIdn ??
'';
if (!featureId) return null;
const fcltTableId = featureId.split('.')[0];
const fcltCd = getFeatureCd(props, fcltTableId);
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(<WrOverLay title={title} data={overLayData} code={code as Partial<comCodeState>} />);
})();
// 제거 시 React unmount
(div as any).__dispose = () => root.unmount();
return div; // <-- HTMLDivElement 동기 리턴
};
const destroyAllManagers = () => {
overlayManagersRef.current.forEach(m => { try { m.destroy(); } catch {} });
overlayManagersRef.current = [];
overlayActiveRef.current = false;
};
const mountOverlayManagers = () => {
const map = gisMaps.current;
if (!map) return;
// 이전 것 정리
destroyAllManagers();
// 체크된 벡터 레이어만 골라 매니저 생성
const checkedSet = new Set(checkedLayers.map(String));
const layers: any[] = map.getLayers().getArray();
const targets = layers.filter((layer: any) => {
const src = layer.getSource?.();
const isVector = src && typeof src.getFeatures === "function";
const id = String(layer.get?.("lyrSn") ?? layer.get?.("id") ?? "");
return isVector && layer.getVisible?.() && checkedSet.has(id);
});
targets.forEach((layer: any) => {
const mgr = createOverlayManager(map, layer, overlayFormatter, {
coordPrecision: OVERLAY_COORD_PRECISION,
maxOverlaysPerViewport: OVERLAY_MAX_PER_VIEW,
});
mgr.mount(); // 리스너 1회 등록
mgr.enable(); // 표시 + 1회 sync
overlayManagersRef.current.push(mgr);
});
overlayActiveRef.current = overlayManagersRef.current.length > 0;
};
useEffect(() => {
const map = gisMaps.current;
if (!map) return;
const z = map.getView()?.getZoom?.() ?? 0;
if (z < OVERLAY_MIN_ZOOM) {
// 저줌에선 그냥 안 보이게만
overlayManagersRef.current.forEach(m => { try { m.disable({ clear:true, delayed:true }); } catch {} });
return;
}
mountOverlayManagers();
return () => { destroyAllManagers(); };
}, [checkedLayers]);
useEffect(() => {
const map = gisMaps.current;
if (!map) return;
const onMoveStart = () => {
// 숨기기만 (리스너/DOM 대량 제거 X)
overlayManagersRef.current.forEach(m => { try { m.disable({ clear:false }); } catch {} });
if (moveEndDebounceRef.current) { clearTimeout(moveEndDebounceRef.current); moveEndDebounceRef.current = null; }
};
const onMoveEnd = () => {
const z = map.getView()?.getZoom?.() ?? 0;
const active = overlayActiveRef.current;
if (moveEndDebounceRef.current) clearTimeout(moveEndDebounceRef.current);
moveEndDebounceRef.current = window.setTimeout(() => {
if (z < OVERLAY_MIN_ZOOM) {
if (active) overlayManagersRef.current.forEach(m => { try { m.disable({ clear:true, delayed:true }); } catch {} });
return;
}
if (!active) {
mountOverlayManagers();
} else {
// 다시 보이고 1회만 동기화
overlayManagersRef.current.forEach(m => { try { m.enable(); m.syncOverlays(); } catch {} });
}
}, 180) as unknown as number;
};
map.on("movestart", onMoveStart);
map.on("moveend", onMoveEnd);
return () => {
map.un("movestart", onMoveStart);
map.un("moveend", onMoveEnd);
if (moveEndDebounceRef.current) { clearTimeout(moveEndDebounceRef.current); moveEndDebounceRef.current = null; }
};
}, [checkedLayers]);
return (
<div className="bg-container">
<Gis
@@ -50,7 +50,7 @@ export default function MapFeaturePopup() {
if (layerNm === "tb_wr_bdst_ruse_fclt") {
setIsDetail(isFeatureCd);
} else if (layerNm === "tb_il_swage_prcs_fclt") {
pbnMapDetaile(isFeatureCd, isFeatureCd).then((res) => {
pbnMapDetaile(isFeatureCd).then((res) => {
setIsDetail(res);
});
} else if (layerNm === "tb_wr_rnwtr_utztn_fclt") {
@@ -211,6 +211,7 @@ export const rswtPrscCdMthdCd = [
},
{ val: "소독(염소, UV 등)", text: "소독(염소, UV 등)" },
{ val: "기타", text: "기타" },
{ val: "확인불가", text: "확인불가" },
];
export const htdPowerMthdCd= [
+4 -5
View File
@@ -77,7 +77,6 @@ type pbnMapActions = {
) => void;
pbnMapDetaile: (
featureCd: string,
data: string
) => Promise<pubHasuType | undefined>;
};
@@ -117,11 +116,11 @@ export const pbnMapActionsExport: (set: any) => pbnMapActions = (set: any) => {
console.log(e);
}
},
pbnMapDetaile: async (featureCd: string, data: string) => {
pbnMapDetaile: async ( featureCd: string) => {
try {
const hasuRes = await postFectch(
`/prcsFclt/ruseInfo/1/20/A/0/0/1/SW/${featureCd}`,
[data],
`/prcsFclt/ruseInfo/1/1/A/0/0/1/SW/`,
[featureCd],
fetchType.COMMON
);
const filteredData = hasuRes.data.map((item: any) => {
@@ -131,7 +130,7 @@ export const pbnMapActionsExport: (set: any) => pbnMapActions = (set: any) => {
ruse: item.ruse === false ? "N" : "Y",
};
});
return filteredData;
return filteredData[0];
} catch (error) {
console.log(error);
throw error; // 호출부에서 catch 가능하도록
+63 -16
View File
@@ -42,8 +42,8 @@ type ruseMapActions = {
fclts: string[],
fcltNm: string
) => void;
ruseMapDetail: (ruseFcltId: string) => Promise<customPbnst | undefined>;
getRuseMaplList: (bscFctCd: string) => void;
getRuseMaplListReturn: (bscFctCd: string) => Promise<customPbnst | undefined>;
};
export type ruseMapType = ruseMapState & ruseMapActions;
@@ -106,21 +106,7 @@ export const ruseMapActionsExport: (set: any) => ruseMapActions = (
console.log(e);
}
},
ruseMapDetail: async (ruseFcltId: string) => {
try {
let ruseDetail = await getFetch("wr", `/reuseFc/pubFc/${ruseFcltId}`);
if (ruseDetail.length >= 0) {
ruseDetail = ruseDetail.find(
(item: customPbnst) => item.pbnstRuseFcltId === ruseFcltId
);
}
// 🔑 스토어 업데이트 대신 리턴
return ruseDetail;
} catch (errorHasu) {
console.log(errorHasu);
throw errorHasu; // 호출부에서 catch 가능하도록
}
},
getRuseMaplList: async (bscFctCd: string) => {
try {
const ruseDetailList = await getFetch(
@@ -204,5 +190,66 @@ export const ruseMapActionsExport: (set: any) => ruseMapActions = (
console.log(e);
}
},
getRuseMaplListReturn: async (bscFctCd: string) => {
try {
const ruseDetailList = await getFetch(
fetchType.WR,
`/reuseFc/pubFc/${bscFctCd}`
);
const year = new Date().getFullYear();
const data = [bscFctCd];
const rusePrfList = await postFectch(
`/reuseFc/pubDetailList/${year}/0/1/10`,
data,
fetchType.WR
);
const dataList = ruseDetailList.map((ruse) => {
const matchRuse = rusePrfList?.data.find(
(prf) => prf.pbnstRuseFcltId === ruse.pbnstRuseFcltId
);
const usage = matchRuse.prfList.reduce(
(acc, cur) => {
acc.inUsage +=
cur.wshwtr +
cur.coolUswtr +
cur.cleanUswtr +
cur.drwtUswtr +
cur.dltnUswtr +
cur.ithlRswtr +
cur.ithlEtcUswtr +
cur.cleanToilUswtr +
cur.resn;
acc.outUsage +=
cur.lndwtr +
cur.hydUswtr +
cur.ugwtChr +
cur.farmUswtr +
cur.rvrKeepUswtr +
cur.indstUswtr;
acc.total = acc.inUsage + acc.outUsage;
return acc;
},
{ total: 0, inUsage: 0, outUsage: 0 }
);
return {
...ruse,
prfList: matchRuse.prfList,
inUsage: usage?.inUsage,
outUsage: usage?.outUsage,
};
});
return dataList
} catch (errorHasu) {
console.log(errorHasu);
throw errorHasu; // 호출부에서 catch 가능하도록
}
}
};
};
@@ -18,8 +18,8 @@ const rswtrObjSchema = z.object({
filtrTrtmfctProcs: z.string({ required_error: validationMessages.required("주요처리공정") }).min(1, { message: validationMessages.required("주요처리공정") }),
filtrTrtmfctUsgCd: z.string().default("").nullish(),
rswtrUsqty: z.number().default(0),
altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(), //안쓰는값
altUswtrKndCd: z.string().default("").nullish(), //안쓰는값
//altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(), //안쓰는값
// altUswtrKndCd: z.string().default("").nullish(), //안쓰는값
altUswtrUtztnQnt: z.number().default(0), //안쓰는값
altUswtrIdntyMthdCd: z.string().default("").nullish(), //안쓰는값
rgtr: z.string().nullish().default(null),
+95 -21
View File
@@ -1,3 +1,5 @@
import type { comCodeState } from "@/app/store/common/code";
const wrLayerList = [
{ text: "tb_il_swage_prcs_fclt", val: "bscFctCd" },
{ text: "tb_wr_bdst_ruse_fclt", val: "pbnstRuseFcltId" },
@@ -26,8 +28,7 @@ const wrFeaturePK = [
// { text: "잠재수요처", val: "tb_wr_tmpr_dmd_co" },
export const getFeatureCd = (featurePropertise: any, layerNm: string) => {
console.log('featurePropertise ', featurePropertise)
console.log("featurePropertise ", featurePropertise);
const featureCd =
layerNm === "tb_wr_bdst_ruse_fclt"
? featurePropertise?.swtrmt_fclt_cd
@@ -39,32 +40,30 @@ export const getFeatureCd = (featurePropertise: any, layerNm: string) => {
].includes(layerNm)
? featurePropertise?.bdst_nm
: layerNm === "tb_il_swage_prcs_fclt"
? featurePropertise?.swtrmt_fclt_nm
: layerNm === "tb_wr_ruse_fclt_dmd_co"?
featurePropertise?.bdst_info_sn
: null;
? featurePropertise?.swtrmt_fclt_cd
: layerNm === "tb_wr_ruse_fclt_dmd_co"
? featurePropertise?.bdst_info_sn
: null;
return featureCd;
};
export const getWrLayerNm = (featurePropertise: any) => {
const result = wrLayerList
.filter(item => item.val in featurePropertise) // 키 존재 여부 체크
.map(item => item.text);
.filter((item) => item.val in featurePropertise) // 키 존재 여부 체크
.map((item) => item.text);
return result[0];
};
export const getWrFeaturePk = (layerName :string) => {
export const getWrFeaturePk = (layerName: string) => {
const result = wrFeaturePK
.filter(item => item.val === layerName) // 키 존재 여부 체크
.map(item => item.text);
.filter((item) => item.val === layerName) // 키 존재 여부 체크
.map((item) => item.text);
return result[0];
};
export const getSelectedLayers = (isFeature: any, gisMaps:any) => {
export const getSelectedLayers = (isFeature: any, gisMaps: any) => {
const map = gisMaps.current;
if (!map) {
console.warn("지도가 초기화되지 않았습니다.");
@@ -97,11 +96,11 @@ export const getSelectedLayers = (isFeature: any, gisMaps:any) => {
return result;
};
export const getClickFeatureId = (data: any) => {
let featureId =''
export const getClickFeatureId = (data: any) => {
let featureId = "";
const layerName = data.layerNm;
if (layerName === "하수재이용시설") {
// 재이용시설
// 재이용시설
featureId = `${layerName}.${data.searchPk}`;
} else if (
//빗물이용시설, 중수도시설
@@ -124,7 +123,11 @@ export const getClickFeatureId = (data: any) => {
return featureId;
};
export function featurePopUpOpen(layerNm:string,featureCd:string,popupDetailRef){
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"
@@ -134,8 +137,8 @@ export function featurePopUpOpen(layerNm:string,featureCd:string,popupDetailRef)
String(layerNm) === "tb_wr_bdst_ruse_fclt"
? Math.floor(window.innerHeight - 100)
: String(layerNm) === "tb_wr_ruse_fclt_dmd_co"
?Math.floor(window.innerHeight - 430)
: Math.floor(window.innerHeight - 300); // 150px 여백 확보; // calc(100% - 70px)
? Math.floor(window.innerHeight - 430)
: Math.floor(window.innerHeight - 300); // 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 `;
@@ -145,4 +148,75 @@ export function featurePopUpOpen(layerNm:string,featureCd:string,popupDetailRef)
"지도 시설 상세정보 팝업",
popupOptions
);
}
}
export const getOverLayObj = (fclType: string, data: any,code?:Partial<comCodeState>) => {
let newObj = {};
let title = "";
if (fclType === "하수재이용시설") {
newObj = {
"시설용량(톤/일)": data?.fcltCpct ??"",
"재이용률(%)": (data?.fcltCpct / data?.bscFctCpc)||0,
"장내용수(m³/년)": data?.inUsage ?? "",
"장외용수(m3/년)":data?.outUsage ?? "",
// 수요처: data?.reuseBuilding[0]?.rainyObj.pntfColArea ?? "",
};
title = data?.bdstNm ?? "";
} else if (fclType === "하수처리시설") {
newObj = {
"시설용량(톤/일)": data?.fctCpc ?? "",
지역구분: data?.efflWqltStndrdNm ?? "",
재이용여부: data?.rswtrYn ?? "",
"재이용시설 등록여부": data?.ruse ?? "",
};
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 ?? "",
};
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 ?? "",
};
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 ?? "";
} else if (fclType === "수요처") {
newObj = {
'사업자등록번호': data?.dmdInfoId??'',
'주소': data?.daddr??'',
'전화번호': data?.telno??'',
};
title = data?.dmdCoNm ?? "";
} else if (fclType === "잠재수요처") {
newObj = {
공장구분: data?.fctrySe ?? "",
설립구분: data?.fndnSe ?? "",
업종명: data?.tpbizNm ?? "",
생산폼목: data?.prdctnItem ?? "",
};
title = data?.dmdCoNm ?? "";
}
return { title, newObj };
};
@@ -0,0 +1,88 @@
"use client";
import { useEffect, useState } from "react";
import WrOverLayTable from "../WrOverLayTable/WrOverLayTable";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@common/components/ui";
import { getOverLayObj } from "@/components/lib/func/mapUtil";
type RuseTabData = {
data: Record<string, string>;
tabData:{
pbnstRuseFcltId: string;
ruseUtztnFcltNm: string;
}
}
export default function WrOverLayRuse({ overLayData }: { overLayData: any }) {
const [fcltTab, setFcltTab] = useState<string>("");
const [ruseData, setRuseData] = useState<RuseTabData[]>([]as RuseTabData[]);
// useEffect(() => {
// const detail = overLayData.find((list) => list.pbnstRuseFcltId === fcltTab);
// if (detail) setIsDetail(detail);
// }, [fcltTab, overLayData]);
useEffect(() => {
if (overLayData && overLayData[0]) {
setFcltTab(overLayData[0].pbnstRuseFcltId);
const newRuseData= overLayData.map((ruse) =>{
const isData = getOverLayObj( '하수재이용시설',ruse);
return {
data: isData.newObj,
tabData:{
pbnstRuseFcltId: ruse.pbnstRuseFcltId,
ruseUtztnFcltNm: ruse.ruseUtztnFcltNm
}
}
})
setRuseData(newRuseData);
}
}, [overLayData]);
if (!(overLayData && overLayData[0])) return;
return (
<>
<div>
<div className="bg-sky-600 text-white text-center font-semibold py-2 text-2xl">
</div>
<Tabs value={fcltTab} onValueChange={setFcltTab}>
<TabsList className="mt-2 mb-2 gap-6 flex flex-wrap">
{ruseData?.map((item, index) => {
return (
<TabsTrigger
key={item.tabData.pbnstRuseFcltId + index}
className="text-center !text-base size-3/12"
value={item.tabData.pbnstRuseFcltId}
>
{item.tabData.ruseUtztnFcltNm}
</TabsTrigger>
);
})}
</TabsList>
{ruseData?.map((item) => (
<TabsContent
key={item.tabData.pbnstRuseFcltId}
className="flex-1 px-4 py-3"
value={item.tabData.pbnstRuseFcltId}
>
<div className="mb-4">
<WrOverLayTable overLayData={item.data} />
</div>
</TabsContent>
))}
</Tabs>
</div>
</>
);
}
@@ -0,0 +1,33 @@
import { Table, TableBody, TableCell, TableRow } from "@common/components/ui";
export default function WrOverLayTable({overLayData}:{overLayData:any,}){
return(
<>
<Table>
<TableBody>
{Object.entries(overLayData).map(([key, value]) => (
<TableRow key={key}>
<TableCell className=" w-1/3 bg-slate-100 text-slate-800 font-medium text-sm align-middle border border-slate-300">
{" "}
{key}{" "}
</TableCell>
<TableCell
className={
"w-1/3 bg-white text-right pr-3 text-sm align-middle border border-slate-300"
}
>
{" "}
{String(value)}{" "}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</>
)
}
@@ -0,0 +1,50 @@
"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 WrOverLayTable from "./WrOverLayTable/WrOverLayTable";
import WrOverLayRuse from "./WrOverLayRuse/WrOverLayRuse";
export default function WrOverLay({
title,
data,
code,
}: {
title: string;
data: any;
code: Partial<comCodeState>;
}) {
const [newOverLayData, setNewOverLayData] = useState<Record<string, string>>(
{}
);
const [typeTitle, setTypeTitle] = useState<string>("");
useEffect(() => {
if (title !== "하수재이용시설" && data) {
const overRayData = getOverLayObj(title, data, code);
setTypeTitle(overRayData?.title ?? "");
setNewOverLayData(overRayData.newObj ?? {});
}
}, [title, data]);
return (
<>
<Card className="w-[320px] p-0 shadow-md rounded-xl overflow-hidden border border-slate-300">
{/* 파란 제목 바 */}
{title !== "하수재이용시설" ? (
<div className="bg-sky-600 text-white text-center font-semibold py-2 text-2xl">
{typeTitle + "(" + title + ")"}
</div>
) : (
<></>
)}
{title === "하수재이용시설" ? (
<WrOverLayRuse overLayData={data ?? []} />
) : (
<WrOverLayTable overLayData={newOverLayData} />
)}
</Card>
</>
);
}