Merge branch 'iipbs/sn/dev' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/sn/dev

This commit is contained in:
kiminchan
2026-08-31 11:06:24 +09:00
5 changed files with 102 additions and 120 deletions
@@ -523,10 +523,10 @@ export const FldngDpthMapCol = [
{ id: 'fldng_yr', title: '침수년도' },
{ id: 'ctpv_nm', title: '시도명' },
{ id: 'sgg_nm', title: '시군구명' },
{ id: 'fldng_dpth', title: '침수깊이' },
{ id: 'fldng_area', title: '침수면적' },
{ id: 'shape_area', title: '형상면적' },
{ id: 'shape_len', title: '형상길이' },
{ id: 'fldng_dpth', title: '침수깊이(m)' },
{ id: 'fldng_area', title: '침수면적(㎡)' },
// { id: 'shape_area', title: '형상면적(㎡)' },
// { id: 'shape_len', title: '형상길이' },
];
export const FldngWtlvMapExcelCol = {
'fldngYr': '침수년도',
@@ -6,7 +6,7 @@ export const FLOOD_HISTORY_POPUP_KEY = "fldngHstryPopup";
export const FLDNG_HSTRY_ROW_SELECT_MESSAGE = "SN_FLOOD_HISTORY_ROW_SELECT";
export const FLOOD_HISTORY_LAYER_TYPE = "tb_ms_fldng_wtlv_map";
export const FLOOD_HISTORY_PREVIEW_LAYER_TYPE = "tb_sn_flood_trace_mock";
export const FLOOD_HISTORY_LAYER_NAME = "침수흔적수위";
export const FLOOD_HISTORY_LAYER_NAME = "침수흔적위선";
export const FLOOD_HISTORY_AREA_LAYER_ID = "SN_FLOOD_HISTORY_AREA";
export const FLOOD_HISTORY_DEPTH_LAYER_ID = "SN_FLOOD_HISTORY_DEPTH";
export const FLDNG_HSTRY_PAGE_SIZE = 10;
@@ -25,6 +25,7 @@
import { getData, postData } from "@/components/lib/api";
import { VerticalTable } from "@/components/ui/verticalTable";
import { useGisContext } from "@common/business_components/ui/map/Gis";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
import { Button } from "@common/components/ui";
import { useEffect, useRef, useState, useMemo } from "react";
import Style from "ol/style/Style.js";
@@ -64,7 +65,6 @@ import {
isInvalidInstallYmd,
} from "../agedPipe/agedPipeUtils";
import { openWindowPopup } from "@/features/windowPopup/lib/openWindowPopup";
import { WINDOW_POPUP_MESSAGE_TYPE } from "@/features/windowPopup/model/types";
import { useAlertStore } from "@/shared/lib";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import useStore from "@/store/useStore";
@@ -478,7 +478,7 @@ const FeatureClickEventPopup = ({
break;
}
case "tb_ms_fldng_wtlv_map": {
result = "침수흔적수위";
result = "침수흔적위선";
setHeadlist(FldngWtlvMapCol);
setLayerSpecificNm(
normalizeFldngWtlvMapDisplayId(
@@ -488,15 +488,10 @@ const FeatureClickEventPopup = ({
break;
}
case "tb_ms_fldng_dpth_map": {
result = "침수흔적깊이";
result = "침수흔적심선";
setHeadlist(FldngDpthMapCol);
setLayerSpecificNm(
String(
featureData.values_?.data_sn ??
featureData.data_sn ??
featureId ??
"",
),
String(featureId ?? "").replace(/^tb_ms_fldng_dpth_map\./, ""),
);
break;
}
@@ -564,20 +559,18 @@ const FeatureClickEventPopup = ({
break;
}
case "tb_ms_fldng_wtlv_map": {
result = "침수흔적수위";
result = "침수흔적위선";
setHeadlist(FldngWtlvMapCol2);
setLayerSpecificNm(normalizeFldngWtlvMapDisplayId(featureData.fid));
break;
}
case "tb_ms_fldng_dpth_map": {
result = "침수흔적깊이";
result = "침수흔적심선";
setHeadlist(FldngDpthMapCol);
setLayerSpecificNm(
String(
featureData.dataSn ??
featureData.data_sn ??
featureData.fid ??
"",
String(featureData.fid ?? featureId ?? "").replace(
/^tb_ms_fldng_dpth_map\./,
"",
),
);
break;
@@ -634,14 +627,14 @@ const FeatureClickEventPopup = ({
// 🎯 기본 데이터 포맷팅
const normalizedRegionData =
selectedLayerName === "침수흔적수위" ||
selectedLayerName === "침수흔적깊이"
selectedLayerName === "침수흔적위선" ||
selectedLayerName === "침수흔적심선"
? withResolvedRegionNames(data)
: data;
const formattedData = withMngInstName(
formatDisplayData(normalizedRegionData),
);
if (selectedLayerName === "침수흔적수위") {
if (selectedLayerName === "침수흔적위선") {
const fldngBgngDtm = formatFldngWtlvDateTime(
formattedData.bgngYmd ??
formattedData.bgng_ymd ??
@@ -724,7 +717,7 @@ const FeatureClickEventPopup = ({
case "하수처리구역":
setButtonChk(false);
break;
case "침수흔적수위":
case "침수흔적위선":
setButtonChk(false);
break;
case "우수토실":
@@ -854,7 +847,7 @@ const FeatureClickEventPopup = ({
}
}
if (selectedLayerName === "침수흔적수위" && featureId) {
if (selectedLayerName === "침수흔적위선" && featureId) {
const depthLookupKey = normalizeFldngWtlvMapApiFid(featureId);
setFloodDepthRows([]);
setSelectedFloodDepthYear(null);
@@ -893,6 +886,7 @@ const FeatureClickEventPopup = ({
String(row.fldng_yr ?? row.fldngYr ?? row.yr ?? "").trim(),
)
.filter(Boolean);
console.log("depth years:", years);
// 최초에는 연도를 선택하지 않고 목록만 표시한다.
setSelectedFloodDepthYear(null);
}
@@ -1098,12 +1092,89 @@ const FeatureClickEventPopup = ({
</Button>
</div>
<div
className="flex-1 overflow-y-auto overflow-x-hidden"
className="flex flex-1 flex-col overflow-y-auto overflow-x-hidden"
ref={contentRef}
>
<VerticalTable
headName={
layerNm === "하수관로" && tableData?.elapsedYears ? (
layerNm === "침수흔적위선" && floodDepthRows.length > 0 ? (
<div className="flex flex-col items-start gap-2">
<span>기본정보</span>
<div className="flex w-full items-center gap-1">
<button
type="button"
aria-label="이전 연도"
className="shrink-0 px-1 text-lg leading-none text-foreground"
onClick={() =>
floodDepthYearListRef.current?.scrollBy({
left: -120,
behavior: "smooth",
})
}
>
‹
</button>
<div
ref={floodDepthYearListRef}
className="flex min-w-0 flex-1 gap-2 overflow-x-auto whitespace-nowrap"
>
{Array.from(
new Set(
floodDepthRows
.map((row) =>
String(
row.fldng_yr ?? row.fldngYr ?? row.yr ?? "",
).trim(),
)
.filter(Boolean),
),
).map((year) => (
<button
key={year}
type="button"
onClick={async () => {
setSelectedFloodDepthYear(year);
const selectedDepthRow = floodDepthRows.find(
(row) =>
String(
row.fldng_yr ?? row.fldngYr ?? row.yr ?? "",
).trim() === year,
);
const depthFid = String(
selectedDepthRow?.fldng_dpth_map_sn ??
selectedDepthRow?.fid ??
"",
).trim();
if (depthFid) {
const core = GisApp.Module.layer as any;
await core.showSearchResultsFromGeoJSON?.(
"tb_ms_fldng_dpth_map",
`tb_ms_fldng_dpth_map.${depthFid.replace(/^tb_ms_fldng_dpth_map\./, "")}`,
);
}
}}
className={`rounded border px-3 py-1 text-[1.2rem] font-medium leading-5 ${selectedFloodDepthYear === year ? "border-blue-600 bg-white text-blue-700" : "border-border bg-muted text-muted-foreground"}`}
>
{year}년
</button>
))}
</div>
<button
type="button"
aria-label="다음 연도"
className="shrink-0 px-1 text-lg leading-none text-foreground"
onClick={() =>
floodDepthYearListRef.current?.scrollBy({
left: 120,
behavior: "smooth",
})
}
>
›
</button>
</div>
</div>
) : layerNm === "하수관로" && tableData?.elapsedYears ? (
<>
기본정보{" "}
<span className="ml-2 rounded-sm bg-red-50 px-2 py-0.5 text-[1.1rem] font-semibold text-red-700">
@@ -1134,95 +1205,6 @@ const FeatureClickEventPopup = ({
total2={0}
isEditable2={buttonChk}
/>
{layerNm === "침수흔적수위" && floodDepthRows.length > 0 && (
<div className="mx-4 mb-4 rounded-md border border-border bg-background p-3">
<div className="mb-2 flex items-center gap-1">
<button type="button" aria-label="이전 연도" className="shrink-0 px-1 text-blue-600" onClick={() => floodDepthYearListRef.current?.scrollBy({ left: -120, behavior: "smooth" })}>‹</button>
<div ref={floodDepthYearListRef} className="flex min-w-0 flex-1 gap-2 overflow-x-auto whitespace-nowrap">
{Array.from(
new Set(
floodDepthRows
.map((row) => String(row.fldng_yr ?? row.fldngYr ?? row.yr ?? "").trim())
.filter(Boolean),
),
).map((year) => (
<button
key={year}
type="button"
onClick={() => {
setSelectedFloodDepthYear(year);
const selectedDepthRow = floodDepthRows.find(
(row) => String(row.fldng_yr ?? row.fldngYr ?? row.yr ?? "").trim() === year,
);
const depthFid = String(
selectedDepthRow?.fldng_dpth_map_sn ?? selectedDepthRow?.fid ?? "",
).trim();
if (depthFid) {
window.opener?.postMessage(
{
type: WINDOW_POPUP_MESSAGE_TYPE.MAP_SEARCH_SELECT_FEATURE,
payload: {
layerNm: "tb_ms_fldng_dpth_map",
fid: `tb_ms_fldng_dpth_map.${depthFid.replace(/^tb_ms_fldng_dpth_map\./, "")}`,
},
},
window.location.origin,
);
}
}}
className={`rounded-full border px-3 py-1 text-sm ${selectedFloodDepthYear === year ? "border-blue-600 bg-blue-600 text-white" : "border-blue-400 bg-transparent text-blue-600"}`}
>
{year}
</button>
))}
</div>
<button
type="button"
aria-label="다음 연도"
className="shrink-0 px-1 text-blue-600"
onClick={() =>
floodDepthYearListRef.current?.scrollBy({
left: 120,
behavior: "smooth",
})
}
>
›
</button>
</div>
{selectedFloodDepthYear && (
<>
<div className="mb-2 flex items-center justify-between border-b border-border pb-2">
<span className="text-sm font-semibold text-label">침수흔적깊이 정보</span>
<button
type="button"
aria-label="침수흔적깊이 정보 닫기"
className="rounded px-2 text-lg leading-none text-muted-foreground hover:bg-accent"
onClick={() => setSelectedFloodDepthYear(null)}
>
×
</button>
</div>
<div className="max-h-64 overflow-auto">
<table className="w-full border-collapse text-sm">
<tbody>
{Object.entries(
floodDepthRows.find((row) => String(row.fldng_yr ?? row.fldngYr ?? row.yr ?? "").trim() === selectedFloodDepthYear) ?? {},
)
.filter(([key]) => !key.toLowerCase().includes("geom"))
.map(([key, value]) => (
<tr key={key}>
<th className="border border-border bg-secondary px-2 py-1 text-left">{key}</th>
<td className="border border-border px-2 py-1">{String(value ?? "-")}</td>
</tr>
))}
</tbody>
</table>
</div>
</>
)}
</div>
)}
{ContentComponent && (
<ContentComponent
featureData={fetchData}
+1 -1
View File
@@ -1079,7 +1079,7 @@ const getRightPanelFeatureTitle = (data: any) => {
case "tb_ms_fldng_wtlv_map":
return FLOOD_HISTORY_LAYER_NAME;
case "tb_ms_fldng_dpth_map":
return "침수흔적깊이";
return "침수흔적심선";
case "om_dt_untrt_swg_rain":
return "중점우수";
default:
@@ -26,8 +26,8 @@ export const BASIC_TYPES = [
{ val: "tb_ms_swage_ppl", text: "하수관로" },
{ val: "tb_il_swage_prcs_fclt", text: "하수처리시설" },
{ val: "tb_ms_swage_prcs_zone", text: "하수처리구역" },
{ val: "tb_ms_fldng_wtlv_map", text: "침수흔적수위" },
{ val: "tb_ms_fldng_dpth_map", text: "침수흔적깊이" },
{ val: "tb_ms_fldng_wtlv_map", text: "침수흔적위선" },
{ val: "tb_ms_fldng_dpth_map", text: "침수흔적심선" },
{ val: "tb_ms_swage_mhl", text: "하수맨홀" },
{ val: "tb_ms_swage_pmstn", text: "하수펌프장" },
{ val: "tb_ms_stofcbr", text: "우수토실" },