Merge remote-tracking branch 'origin/iipbs/sn/ii' into iipbs/sn/dev

This commit is contained in:
swcho
2025-09-01 13:08:25 +09:00
6 changed files with 157 additions and 81 deletions
@@ -12,8 +12,9 @@ import RdiiChart from './chart/rdiiChart';
import { useInfilChartModalStore, useRdiiChartModalStore } from "./chartModalStore"; import { useInfilChartModalStore, useRdiiChartModalStore } from "./chartModalStore";
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue'; import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
import { codeMapper } from "../common/codeMapper"; import { codeMapper } from "../common/codeMapper";
import { searchUpperPpls } from '@common/business_components/ui/map/Gis';
import LoadingOverlay from '@/components/ui/LoadingBar'; import LoadingOverlay from '@/components/ui/LoadingBar';
// import GisApp from "@common/business_components/ui/map/lib/gis.core";
import { searchUpperPpls } from "./smh";
const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => { const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => {
@@ -58,7 +59,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
const getSelectedLayers = () => { const getSelectedLayers = () => {
let result = null; let result = null;
const layers = gisMap.getLayers().getArray(); // gisMap에서 모든 레이어 가져오기 const layers = gisMap.getLayers().getArray(); // gisMap에서 모든 레이어 가져오기
let featureLayer: { get: (key: string) => any }; // 피처가 속한 레이어를 찾기 위한 변수 let featureLayer: any = null; // 피처가 속한 레이어를 찾기 위한 변수
layers.some((layer: any) => { layers.some((layer: any) => {
const source = layer.getSource(); const source = layer.getSource();
// if (source && featureData && featureData.fid) { // if (source && featureData && featureData.fid) {
@@ -121,7 +122,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
setHeadlist2(untrtSwgRainCol2); setHeadlist2(untrtSwgRainCol2);
setLayerSpecificNm(featureData.values_.manage_no); setLayerSpecificNm(featureData.values_.manage_no);
} }
else result = featureLayer.get('lyrNm'); else result = featureLayer ? featureLayer.get('lyrNm') : null;
} }
else { else {
// SearchModal 클릭 이벤트 // SearchModal 클릭 이벤트
@@ -384,6 +385,76 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
// 레이어명에 따라 상세페이지 렌더링 // 레이어명에 따라 상세페이지 렌더링
const ContentComponent = layerNm ? getLayerContentComponent(layerNm) : null; const ContentComponent = layerNm ? getLayerContentComponent(layerNm) : null;
// const searchUpperPpls = async (fcltMngNo: any) => {
// const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
// const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
// method: "GET",
// });
// let data = null;
// if (res.ok) {
// try {
// // 응답이 비어있는지 확인
// const contentLength = res.headers.get("content-length");
// if (contentLength === "0")
// alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
// // 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
// const text = await res.text();
// if (!text || text.trim() === "")
// alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
// // JSON 파싱 시도
// data = JSON.parse(text);
// } catch (error) {
// console.error("JSON parsing error:", error);
// alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
// }
// }
// const select: any = GisApp.Module.select;
// // const gisMap = GisApp.Module.core?.map;
// let foundFeature: any = null;
// data.forEach((item: any) => {
// const pplMngNo = item.ppl_mng_no.trim();
// gisMap
// .getLayers()
// .getArray()
// .filter((e: any) => e.get("lyrTyNm") == "tb_ms_swage_ppl")
// .forEach((layer: any) => {
// const source = layer.getSource?.();
// if (source?.getFeatures) {
// const features = source.getFeatures();
// for (const f of features) {
// if (f.values_.fclt_mng_no.trim() === pplMngNo) {
// foundFeature = f;
// break;
// }
// }
// }
// });
// if (foundFeature) select?.selectMultiFeature?.(foundFeature, true);
// });
// if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
// let geometry = foundFeature?.getGeometry();
// if (geometry) {
// let extent = geometry.getExtent();
// gisMap.getView().fit(extent, {
// duration: 300,
// padding: [50, 50, 50, 50],
// maxZoom: 14,
// constrainResolution: true,
// nearest: true,
// });
// }
// };
return ( return (
<div id="popup" className="absolute top-0 right-0 w-[350px] h-[calc(100vh-5rem)] bg-white border-r border-gray-300 flex flex-col overflow-hidden transition-all duration-300 z-[50]"> <div id="popup" className="absolute top-0 right-0 w-[350px] h-[calc(100vh-5rem)] bg-white border-r border-gray-300 flex flex-col overflow-hidden transition-all duration-300 z-[50]">
<LoadingOverlay isLoading={isLoading} /> <LoadingOverlay isLoading={isLoading} />
@@ -424,7 +495,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
className="px-2 py-1 text-xl text-gray-600 border border-gray-600 rounded hover:bg-gray-700 mr-4" className="px-2 py-1 text-xl text-gray-600 border border-gray-600 rounded hover:bg-gray-700 mr-4"
onClick={() => { onClick={() => {
setIsLoading(true); setIsLoading(true);
searchUpperPpls(layerSpecificNm).finally(() => setIsLoading(false)); searchUpperPpls(gisMap, layerSpecificNm).finally(() => setIsLoading(false));
}} }}
> >
상류관로 보기 상류관로 보기
@@ -1,6 +1,84 @@
// 하수맨홀 // 하수맨홀
import { VerticalTable } from '@/components/ui/verticalTable'; import { VerticalTable } from '@/components/ui/verticalTable';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import GisApp from "@common/business_components/ui/map/lib/gis.core";
// exported helper: 상류관로 검색 및 선택 (FeatureClickEventPopup에서 사용)
export async function searchUpperPpls(gisMap: any, fcltMngNo: any) {
const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
method: "GET",
});
let data: any = null;
if (res.ok) {
try {
// 응답이 비어있는지 확인
const contentLength = res.headers.get("content-length");
if (contentLength === "0") {
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
return;
}
// 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
const text = await res.text();
if (!text || text.trim() === "") {
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
return;
}
// JSON 파싱 시도
data = JSON.parse(text);
} catch (error) {
console.error("JSON parsing error:", error);
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
return;
}
} else {
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
return;
}
const select: any = GisApp.Module.select;
let foundFeature: any = null;
(data || []).forEach((item: any) => {
const pplMngNo = item.ppl_mng_no?.trim?.();
gisMap
.getLayers()
.getArray()
.filter((e: any) => e.get("lyrTyNm") == "tb_ms_swage_ppl")
.forEach((layer: any) => {
const source = layer.getSource?.();
if (source?.getFeatures) {
const features = source.getFeatures();
for (const f of features) {
if (f.values_.fclt_mng_no?.trim?.() === pplMngNo) {
foundFeature = f;
break;
}
}
}
});
if (foundFeature) select?.selectMultiFeature?.(foundFeature, true);
});
if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
const geometry = foundFeature?.getGeometry();
if (geometry) {
const extent = geometry.getExtent();
gisMap.getView().fit(extent, {
duration: 300,
padding: [50, 50, 50, 50],
maxZoom: 14,
constrainResolution: true,
nearest: true,
});
}
}
const inputColumn = [ const inputColumn = [
{ id: "swtrmtZoneNm", title: "처리구역", type: "input" }, { id: "swtrmtZoneNm", title: "처리구역", type: "input" },
@@ -80,12 +80,9 @@ const SearchModal: React.FC<SearchModalProps> = ({
const [end2, setEnd2] = useState(""); const [end2, setEnd2] = useState("");
const [var1, setVar1] = useState(""); const [var1, setVar1] = useState("");
const [var2, setVar2] = useState(""); const [var2, setVar2] = useState("");
const [var3, setVar3] = useState("");
const [var4, setVar4] = useState("");
// 시작, 종료
const [yearFilter, setYearFilter] = useState({ start: "", end: "" }); const [yearFilter, setYearFilter] = useState({ start: "", end: "" });
const { ctpv, sgg, BIZ_TY_CD, BIZ_SE_CD } = useStore(); const { ctpv, sgg, BIZ_TY_CD } = useStore();
// 오늘 날짜 구하기 // 오늘 날짜 구하기
@@ -128,8 +125,6 @@ const SearchModal: React.FC<SearchModalProps> = ({
setEnd2(""); setEnd2("");
setVar1(""); setVar1("");
setVar2(""); setVar2("");
setVar3("");
setVar4("");
setCtpvCd("0"); setCtpvCd("0");
setSggCd("0"); setSggCd("0");
setYearFilter({ setYearFilter({
@@ -165,7 +165,7 @@ export default function LineBarchart({
{chartTitle} {chartTitle}
</div> </div>
) : null} ) : null}
<div className="h-[calc(100%-42px)] flex justify-center"> <div className="h-[calc(100%-42px)] w-[calc(100%-40px)] ">
<ChartContainer config={chartConfig ?? {}} className="h-full w-full"> <ChartContainer config={chartConfig ?? {}} className="h-full w-full">
<ComposedChart <ComposedChart
data={chartData} data={chartData}
@@ -65,7 +65,7 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?:
return ( return (
<div className="w-[180px] rounded bg-white p-2.5 shadow-[0px_2px_10px_rgba(0,0,0,0.2)]"> <div className="w-[180px] rounded bg-white p-2.5 shadow-[0px_2px_10px_rgba(0,0,0,0.2)]">
<p className="text-[12px] font-bold m-3">{label}</p> <p className="text-[12px] font-bold m-3">{label}</p>
{payload.map((item, index) => ( {payload.filter(item => item.value != null && String(item.value) != 'NaN' && item.value != undefined).map((item, index) => (
<div key={index} style={{ marginTop: "10px", display: "flex", alignItems: "center", gap: "8px" }}> <div key={index} style={{ marginTop: "10px", display: "flex", alignItems: "center", gap: "8px" }}>
{/* 색상 박스 추가 (범례 색상과 동일) */} {/* 색상 박스 추가 (범례 색상과 동일) */}
<div style={{ width: "10px", height: "10px", backgroundColor: item.color, borderRadius: "50%" }}></div> <div style={{ width: "10px", height: "10px", backgroundColor: item.color, borderRadius: "50%" }}></div>
@@ -267,6 +267,7 @@ export default function Linechart({
type="linear" type="linear"
strokeWidth={2} strokeWidth={2}
dot={false} dot={false}
connectNulls={true}
name={String(config?.label || "X축")} name={String(config?.label || "X축")}
stroke={config?.color} stroke={config?.color}
/> />
@@ -30,75 +30,6 @@ export const GisContext = createContext({
checkedLayerIds: null, checkedLayerIds: null,
}); });
export const useGisContext = () => useContext(GisContext); export const useGisContext = () => useContext(GisContext);
export const searchUpperPpls = async (fcltMngNo) => {
const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
method: "GET",
});
let data = null;
if (res.ok) {
try {
// 응답이 비어있는지 확인
const contentLength = res.headers.get("content-length");
if (contentLength === "0")
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
// 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
const text = await res.text();
if (!text || text.trim() === "")
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
// JSON 파싱 시도
data = JSON.parse(text);
} catch (error) {
console.error("JSON parsing error:", error);
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
}
}
const select = GisApp.Module.select;
const gisMap = GisApp.Module.core?.map;
let foundFeature = null;
data.forEach((item) => {
const pplMngNo = item.ppl_mng_no.trim();
gisMap
.getLayers()
.getArray()
.filter((e) => e.get("lyrTyNm") == "tb_ms_swage_ppl")
.forEach((layer) => {
const source = layer.getSource?.();
if (source?.getFeatures) {
const features = source.getFeatures();
for (const f of features) {
if (f.values_.fclt_mng_no.trim() === pplMngNo) {
foundFeature = f;
break;
}
}
}
});
if (foundFeature) select.selectMultiFeature(foundFeature, true);
});
if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
let geometry = foundFeature?.getGeometry();
if (geometry) {
let extent = geometry.getExtent();
gisMap.getView().fit(extent, {
duration: 300,
padding: [50, 50, 50, 50],
maxZoom: 14,
constrainResolution: true,
nearest: true,
});
}
};
function Gis({ function Gis({
isOpen, //우측 상세 레이어 팝업 isOpen, //우측 상세 레이어 팝업