Merge branch 'iipbs/sn/dev' into iipbs/sn/dev_kic

This commit is contained in:
kiminchan
2026-08-26 14:44:57 +09:00
4 changed files with 45 additions and 11 deletions
+9
View File
@@ -3617,6 +3617,7 @@ const Map = () => {
await select.resetSelectedFeature?.();
const selectedFeatureIds = new Set<string>();
let floodLayerVisible = false;
const selectLoadedGroupFeatures = (source: any) => {
const features = source?.getFeatures?.() ?? [];
features.forEach((feature: any) => {
@@ -3644,6 +3645,7 @@ const Map = () => {
FLOOD_DNGR_MAP_LAYER_TYPE
)
return;
if (layer.getVisible?.() !== false) floodLayerVisible = true;
const source = layer.getSource?.();
if (!source?.getFeatures) return;
selectLoadedGroupFeatures(source);
@@ -3651,6 +3653,13 @@ const Map = () => {
selectLoadedGroupFeatures(source),
);
});
if (!floodLayerVisible) {
event.source?.postMessage?.(
{ type: WINDOW_POPUP_MESSAGE_TYPE.MAP_SEARCH_FLOOD_LAYER_REQUIRED },
event.origin,
);
return;
}
map.getView().fit(extent, {
duration: 300,
padding: [50, 50, 50, 50],
@@ -36,7 +36,7 @@
- 행 선택 시 기존 도시침수지도 group extent API를 호출한다.
- 부모 창에 기존 `MAP_SEARCH_SHOW_FLOOD_GROUP` 메시지를 보내 범위 이동·레이어 표시를 요청한다.
- 도시침수지도에 없는 빈도는 자동 변환하지 않고 화면 안내를 표시한다.
- 도시침수지도 빈도는 30년 이하를 `030`, 100년 초과를 `100`으로 보정하고 그 외 미지원 빈도는 안내한다.
## 검증
@@ -8,7 +8,7 @@ import {
} from "@common/business_components";
import { Button } from "@common/components";
import { getBlobData, getRawJson } from "@/components/lib/api";
import { getBlobData, getData, getRawJson } from "@/components/lib/api";
import { fileDownload } from "@/components/lib/utils/fileDownload";
import LoadingOverlay from "@/components/ui/LoadingBar";
import { windowPopupDefinitions } from "@/features/windowPopup/model/popupDefinitions";
@@ -57,18 +57,26 @@ const PAGE_SIZE = 10;
const MAP_FREQUENCIES = new Set([30, 50, 80, 100]);
const FREQUENCY_OPTIONS = [30, 50, 80, 100] as const;
/** 도시침수지도 DB의 3자리 빈도 코드로 변환한다. 30년 이하는 030, 100년 초과는 100으로 제한한다. */
const toFloodMapFrequencyCode = (value: number) => {
if (!Number.isFinite(value) || value <= 0) return null;
const normalized = value <= 30 ? 30 : value > 100 ? 100 : value;
if (!MAP_FREQUENCIES.has(normalized)) return null;
return String(normalized).padStart(3, "0");
};
const HEADS: UiHeadProps[] = [
{ id: "rowNo", title: "순번", widthPercent: 6 },
{ id: "ctpvNm", title: "시도", widthPercent: 8 },
{ id: "sggNm", title: "시군구", widthPercent: 9 },
{
id: "rainBeginningDateTimeDisplay",
title: "강우시각",
id: "analysisDateTimeDisplay",
title: "분석시각",
widthPercent: 13,
},
{
id: "analysisDateTimeDisplay",
title: "분석시각",
id: "rainBeginningDateTimeDisplay",
title: "강우시각",
widthPercent: 13,
},
{
@@ -208,6 +216,21 @@ export default function FldngPredcPrstPopupContent() {
// 개발 StrictMode에서도 최초 목록 API를 한 번만 호출하기 위한 ref다.
const didInitialLoadRef = useRef(false);
// 부모 지도에서 도시침수지도 레이어가 비활성 상태임을 알려오면 팝업에서 안내한다.
useEffect(() => {
const handleMapMessage = (event: MessageEvent) => {
if (event.origin !== window.location.origin) return;
if (
event.data?.type ===
WINDOW_POPUP_MESSAGE_TYPE.MAP_SEARCH_FLOOD_LAYER_REQUIRED
) {
alert("지도의 좌측 도시침수지도를 선택하여야 지도에 보입니다.");
}
};
window.addEventListener("message", handleMapMessage);
return () => window.removeEventListener("message", handleMapMessage);
}, [alert]);
useEffect(() => {
if (!ctpv.length) void fetchCtpv();
if (!sgg.length) void fetchSgg();
@@ -297,7 +320,8 @@ export default function FldngPredcPrstPopupContent() {
/** 선택 행과 동일한 시군구·빈도의 도시침수지도 범위를 부모 지도에 전달한다. */
const handleRowClick = async (row: TableRow) => {
const frequencyYear = Number(row.exceededFrequencyYear ?? 0);
if (!MAP_FREQUENCIES.has(frequencyYear)) {
const sbmrgFrqExpln = toFloodMapFrequencyCode(frequencyYear);
if (!sbmrgFrqExpln) {
alert(
`${frequencyYear || "해당"}년 빈도 도시침수지도는 제공되지 않습니다. (30·50·80·100년 빈도만 제공)`,
);
@@ -315,12 +339,12 @@ export default function FldngPredcPrstPopupContent() {
setSelectedRowId(buildRowId(row));
setLoading(true);
try {
const sbmrgFrqExpln = `${frequencyYear}년`;
const params = new URLSearchParams({
sggCd: row.sggCd,
sbmrgFrqExpln,
});
const extentData = await getRawJson(
// 백엔드 공통 응답({ data: ... })의 data 영역을 반환하는 API 헬퍼를 사용한다.
const extentData = await getData(
`/sewerage-service/api/v1/fldng/flood-dngr-map/group/extent?${params.toString()}`,
);
const extent = [
@@ -345,7 +369,7 @@ export default function FldngPredcPrstPopupContent() {
alert(
error instanceof Error && error.message.includes("위치 정보")
? error.message
: "도시침수지도 이동에 실패했습니다.",
: "도시침수지도 이동에 실패하였습니다.",
);
} finally {
setLoading(false);
@@ -471,8 +495,8 @@ export default function FldngPredcPrstPopupContent() {
</select>
</label>
{renderDateTimeRange("강우시각", "rainBgngFrom", "rainBgngTo")}
{renderDateTimeRange("분석시각", "analysisFrom", "analysisTo")}
{renderDateTimeRange("강우시각", "rainBgngFrom", "rainBgngTo")}
<label className="flex shrink-0 items-center gap-2">
<span className="shrink-0 whitespace-nowrap text-xl font-medium text-label">
@@ -51,6 +51,7 @@ export const WINDOW_POPUP_MESSAGE_TYPE = {
MAP_SEARCH_SHOW_MULTIPLE: "sn:popup:mapSearchShowMultiple",
MAP_SEARCH_FIT_EXTENT: "sn:popup:mapSearchFitExtent",
MAP_SEARCH_SHOW_FLOOD_GROUP: "sn:popup:mapSearchShowFloodGroup",
MAP_SEARCH_FLOOD_LAYER_REQUIRED: "sn:popup:mapSearchFloodLayerRequired",
GIS_EDIT_SESSION_READY: "sn:popup:gisEditSessionReady",
GIS_EDIT_SESSION_SYNC: "sn:popup:gisEditSessionSync",
GIS_EDIT_SESSION_SHOW_INLINE: "sn:popup:gisEditSessionShowInline",