sn : 침수예측 관측소중심으로 로직 변경
This commit is contained in:
@@ -3,6 +3,10 @@ import { downloadExcelWithKoreanHeaders } from "@/shared/lib/download-excel";
|
||||
export type FloodPredictionExcelRow = {
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
/** `/prst` 조회 때 시군구-관측소 매핑에서 붙인 관측소명이다. 기존 로직 행이나 매핑에 없는 조합은 null이다. */
|
||||
obsrvnBrnchNm: string | null;
|
||||
/** 시군구 면적 중 관측소 영역의 비율(%)이다. 기존 로직 행이나 매핑에 없는 조합은 null이다. */
|
||||
areaRt: number | null;
|
||||
analysisDateTime: string;
|
||||
rainBeginningDateTime: string;
|
||||
observedAccumulatedRainfall: number | null;
|
||||
@@ -12,10 +16,13 @@ export type FloodPredictionExcelRow = {
|
||||
floodRiskGrade: string;
|
||||
};
|
||||
|
||||
/** Excel 행 객체 키를 한글 헤더로 바꾸는 매핑이다. 실제 열 순서는 행 객체의 키 순서를 따르므로 같은 순서로 둔다. */
|
||||
const HEADERS: Record<string, string> = {
|
||||
rowNo: "순번",
|
||||
ctpvNm: "시도",
|
||||
sggNm: "시군구",
|
||||
obsrvnBrnchNm: "관측소",
|
||||
areaRt: "면적비율(%)",
|
||||
analysisDateTime: "분석시각",
|
||||
rainBeginningDateTime: "강우시작시각",
|
||||
observedAccumulatedRainfall: "관측 누적강수량(mm)",
|
||||
@@ -39,12 +46,20 @@ export const downloadFloodPredictionStatusExcel = async (
|
||||
rowNo: index + 1,
|
||||
ctpvNm: row.ctpvNm || "-",
|
||||
sggNm: row.sggNm || "-",
|
||||
// 관측소·면적비율은 시군구 뒤에 두고, 기존 로직 행이나 매핑에 없는 조합은 `-`로 내보낸다.
|
||||
obsrvnBrnchNm: row.obsrvnBrnchNm || "-",
|
||||
// 면적비율은 목록과 같이 소수 둘째 자리까지 반올림한 숫자로 내보낸다.
|
||||
areaRt:
|
||||
row.areaRt == null || !Number.isFinite(Number(row.areaRt))
|
||||
? "-"
|
||||
: Number(Number(row.areaRt).toFixed(2)),
|
||||
analysisDateTime: formatDateTime(row.analysisDateTime),
|
||||
rainBeginningDateTime: formatDateTime(row.rainBeginningDateTime),
|
||||
observedAccumulatedRainfall:
|
||||
row.observedAccumulatedRainfall == null
|
||||
? "-"
|
||||
: Number(row.observedAccumulatedRainfall.toFixed(1)),
|
||||
// 관측소 기준 행의 예측시간 0(대표값이 분석시각)도 목록과 같이 `0시간 후`로 내보낸다.
|
||||
predictionHour:
|
||||
row.predictionHour == null ? "-" : `${row.predictionHour}시간 후`,
|
||||
predictedAccumulatedRainfall:
|
||||
@@ -60,7 +75,8 @@ export const downloadFloodPredictionStatusExcel = async (
|
||||
data: excelRows as unknown as JSON[],
|
||||
fileName: "침수예측현황.xlsx",
|
||||
sheetNameArray: ["침수예측현황"],
|
||||
headerRange: "A1:J1",
|
||||
// 순번~침수위험도 12개 열(관측소·면적비율 포함)의 헤더 행 범위다.
|
||||
headerRange: "A1:L1",
|
||||
headerMapping: HEADERS,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,7 +6,10 @@ import { Button, Dialog, DialogContent, DialogHeader, DialogTitle } from "@commo
|
||||
|
||||
import { downloadExcelWorkbook } from "@/shared/util/download-excel-workbook";
|
||||
|
||||
/** 시군구별 면적가중 확률강우량 한 셀의 API 응답이다. */
|
||||
/**
|
||||
* 시군구별 면적가중 확률강우량 한 셀의 API 응답이다.
|
||||
* 관측소 기준표 응답에서는 최근접 확률관측소 1곳의 값을 면적가중 없이 그대로 담는다.
|
||||
*/
|
||||
export type PrbbtRnflCell = {
|
||||
frequencyYear: number;
|
||||
durationHour: number;
|
||||
@@ -20,18 +23,37 @@ export type PrbbtRnflStation = {
|
||||
areaRt: number;
|
||||
};
|
||||
|
||||
/** 확률강우량 표와 그 계산에 사용한 관측소 비율을 함께 받는다. */
|
||||
/**
|
||||
* 확률강우량 표와 그 계산에 사용한 관측소 비율을 함께 받는다.
|
||||
* 시군구 기준표(`/prst/prbbt-rnfl?sggCd=`)는 `sggCd`를, 관측소 기준표(`/prst/prbbt-rnfl/obsvtr?obsrvnBrnchCd=`)는
|
||||
* `sggCd` 대신 `obsrvnBrnchCd`·`obsrvnBrnchNm`을 담으므로 두 응답을 모두 받도록 식별 필드는 선택값으로 둔다.
|
||||
*/
|
||||
export type PrbbtRnflResponse = {
|
||||
sggCd: string;
|
||||
/** 시군구 기준표 응답의 시군구코드다. 관측소 기준표 응답에는 없다. */
|
||||
sggCd?: string;
|
||||
/** 관측소 기준표 응답의 관측지점코드다. 시군구 기준표 응답에는 없다. */
|
||||
obsrvnBrnchCd?: string;
|
||||
/** 관측소 기준표 응답의 관측소명이다. 시군구 기준표 응답에는 없다. */
|
||||
obsrvnBrnchNm?: string;
|
||||
rainfall: PrbbtRnflCell[];
|
||||
/** 시군구 기준은 면적가중에 쓴 확률관측소 전부, 관측소 기준은 최근접 확률관측소 1곳(비율 100)이다. */
|
||||
stations: PrbbtRnflStation[];
|
||||
areaRtTotal: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* 기준표를 연 목록 행의 분석 기준이다.
|
||||
* `sgg`는 기존 시군구 면적가중 행, `obsvtr`는 관측지점코드가 있는 관측소 기준(새 로직) 행이다.
|
||||
*/
|
||||
export type PrbbtRnflTargetKind = "sgg" | "obsvtr";
|
||||
|
||||
type PrbbtRnflDialogProps = {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
sggName: string;
|
||||
/** 상단 제목·표 제목·Excel 파일명에 쓰는 대상 이름이다. 시군구 기준은 시군구명, 관측소 기준은 관측소명이다. */
|
||||
targetName: string;
|
||||
/** 대상 이름이 시군구인지 관측소인지 구분해 아래 표 제목과 안내 문구를 고른다. */
|
||||
targetKind: PrbbtRnflTargetKind;
|
||||
selectedDurationHour: number | null;
|
||||
selectedFrequencyYear: number | null;
|
||||
data: PrbbtRnflResponse | null;
|
||||
@@ -45,11 +67,27 @@ const formatRainfall = (value: number) =>
|
||||
const formatAreaRatio = (value: number) =>
|
||||
Number.isFinite(Number(value)) ? Number(value).toFixed(3) : "-";
|
||||
|
||||
/**
|
||||
* 아래 확률관측소 표의 제목(Excel 두 번째 시트명 겸용)이다.
|
||||
* 관측소 기준은 면적가중 없이 최근접 확률관측소 1곳을 쓰므로 `적용 확률관측소`로 보인다.
|
||||
*/
|
||||
const STATION_TABLE_TITLE: Record<PrbbtRnflTargetKind, string> = {
|
||||
sgg: "확률관측소 면적비율",
|
||||
obsvtr: "적용 확률관측소",
|
||||
};
|
||||
|
||||
/** 기준자료가 없을 때 보이는 안내 문구다. 관측소 기준은 시군구 대신 관측소로 안내한다. */
|
||||
const EMPTY_MESSAGE: Record<PrbbtRnflTargetKind, string> = {
|
||||
sgg: "해당 시군구의 확률강우량 기준자료가 없습니다.",
|
||||
obsvtr: "해당 관측소의 확률강우량 기준자료가 없습니다.",
|
||||
};
|
||||
|
||||
/** 재현기간을 행, 강우지속시간을 열로 구성하고 선택한 두 기준이 교차하는 값만 색으로 강조한다. */
|
||||
export default function PrbbtRnflDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
sggName,
|
||||
targetName,
|
||||
targetKind,
|
||||
selectedDurationHour,
|
||||
selectedFrequencyYear,
|
||||
data,
|
||||
@@ -60,6 +98,8 @@ export default function PrbbtRnflDialog({
|
||||
const tableScrollRef = useRef<HTMLDivElement>(null);
|
||||
/** 목록에서 클릭한 지속시간에 대응하는 표 헤더이다. */
|
||||
const selectedDurationHeaderRef = useRef<HTMLTableCellElement>(null);
|
||||
/** 행 종류에 따른 아래 표 제목이다. 시군구 기준 행은 기존 제목을 그대로 쓴다. */
|
||||
const stationTableTitle = STATION_TABLE_TITLE[targetKind];
|
||||
|
||||
const { frequencies, durations, rainfallByKey } = useMemo(() => {
|
||||
const rainfall = data?.rainfall ?? [];
|
||||
@@ -79,11 +119,14 @@ export default function PrbbtRnflDialog({
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
/** 화면에 표시 중인 확률강우량 표와 관측소 면적비율 표를 두 시트로 내려받는다. */
|
||||
/**
|
||||
* 화면에 표시 중인 확률강우량 표와 관측소 면적비율 표를 두 시트로 내려받는다.
|
||||
* 파일명은 대상 이름(시군구명 또는 관측소명)을, 두 번째 시트명은 아래 표 제목을 따른다.
|
||||
*/
|
||||
const handleExcelDownload = async () => {
|
||||
const stations = data?.stations ?? [];
|
||||
await downloadExcelWorkbook({
|
||||
fileName: `${sggName}_확률강우량`,
|
||||
fileName: `${targetName}_확률강우량`,
|
||||
sheets: [
|
||||
{
|
||||
name: "확률강우량",
|
||||
@@ -100,7 +143,7 @@ export default function PrbbtRnflDialog({
|
||||
columnWidths: [14, ...durations.map(() => 12)],
|
||||
},
|
||||
{
|
||||
name: "확률관측소 면적비율",
|
||||
name: stationTableTitle,
|
||||
rows: [
|
||||
["확률관측소코드", "관측소명", "면적비율(%)"],
|
||||
...stations.map((station) => [
|
||||
@@ -135,12 +178,12 @@ export default function PrbbtRnflDialog({
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent
|
||||
className="flex max-h-[90vh] w-[94vw] !max-w-[150rem] flex-col gap-4 overflow-hidden bg-background"
|
||||
className="flex max-h-[90vh] w-[94vw] !max-w-[150rem] flex-col gap-4 overflow-hidden"
|
||||
aria-describedby={undefined}
|
||||
>
|
||||
{/* 우측 상단 닫기(X) 버튼과 겹치지 않도록 pr-14 여백을 둔다. */}
|
||||
<DialogHeader className="flex-row items-center justify-between pr-14">
|
||||
<DialogTitle>{sggName} 확률강우량</DialogTitle>
|
||||
<DialogTitle>{targetName} 확률강우량</DialogTitle>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={loading || !!error || !frequencies.length || !durations.length}
|
||||
@@ -160,14 +203,14 @@ export default function PrbbtRnflDialog({
|
||||
</p>
|
||||
) : !frequencies.length || !durations.length ? (
|
||||
<p className="py-8 text-center text-xl" role="status">
|
||||
해당 시군구의 확률강우량 기준자료가 없습니다.
|
||||
{EMPTY_MESSAGE[targetKind]}
|
||||
</p>
|
||||
) : (
|
||||
<>
|
||||
<div ref={tableScrollRef} className="min-h-0 overflow-auto rounded-md border border-border">
|
||||
<table className="w-max min-w-full border-collapse text-right text-lg">
|
||||
<caption className="sr-only">
|
||||
{sggName} 재현기간 및 강우지속시간별 확률강우량(mm)
|
||||
{targetName} 재현기간 및 강우지속시간별 확률강우량(mm)
|
||||
</caption>
|
||||
<thead className="sticky top-0 z-10 bg-muted text-foreground">
|
||||
<tr>
|
||||
@@ -229,7 +272,7 @@ export default function PrbbtRnflDialog({
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 space-y-2">
|
||||
<h3 className="text-xl font-semibold">확률관측소 면적비율</h3>
|
||||
<h3 className="text-xl font-semibold">{stationTableTitle}</h3>
|
||||
<div className="max-h-[16rem] overflow-auto rounded-md border border-border">
|
||||
<table className="w-full border-collapse text-lg">
|
||||
<thead className="bg-muted text-foreground">
|
||||
|
||||
@@ -31,9 +31,16 @@ type ApiRow = {
|
||||
ctpvCd: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
/** 관측소 기준(새 로직) 분석 행의 관측지점코드다. 기존 시군구 면적가중 행은 null이다. */
|
||||
obsrvnBrnchCd: string | null;
|
||||
/** `/prst` 조회 때 시군구-관측소 매핑에서 붙인 관측소명이다. 기존 로직 행이나 매핑에 없는 조합은 null이다. */
|
||||
obsrvnBrnchNm: string | null;
|
||||
/** 시군구 면적 중 관측소 영역의 비율(%)이다. 기존 로직 행이나 매핑에 없는 조합은 null이다. */
|
||||
areaRt: number | null;
|
||||
rainBeginningDateTime: string;
|
||||
analysisDateTime: string;
|
||||
observedAccumulatedRainfall: number | null;
|
||||
/** 분석시각 기준 대표 예측시간이다. 관측소 기준 행의 0은 대표값이 분석시각(관측 누적)이라는 뜻이다. */
|
||||
predictionHour: number | null;
|
||||
predcRainHr: number | null;
|
||||
predictedAccumulatedRainfall: number | null;
|
||||
@@ -46,6 +53,10 @@ type TableRow = ApiRow &
|
||||
rowNo: number;
|
||||
analysisDateTimeDisplay: string;
|
||||
rainBeginningDateTimeDisplay: string;
|
||||
/** 관측소 열 표시값이다. 관측소명이 없으면 `-`이다. */
|
||||
obsrvnBrnchNmDisplay: string;
|
||||
/** 면적비율(%) 열 표시값이다. 소수 둘째 자리까지, 값이 없으면 `-`이다. */
|
||||
areaRtDisplay: string;
|
||||
observedAccumulatedRainfallDisplay: string;
|
||||
predictionHourDisplay: string;
|
||||
predictedAccumulatedRainfallDisplay: string;
|
||||
@@ -76,47 +87,61 @@ const toFloodMapFrequencyCode = (value: number) => {
|
||||
return String(normalized).padStart(3, "0");
|
||||
};
|
||||
|
||||
/**
|
||||
* 침수예측현황 목록 열 정의다.
|
||||
* 시군구 뒤에 관측소 기준 분석의 관측소·면적비율 열을 두고, 13개 열의 widthPercent 합은 100으로 맞춘다.
|
||||
*/
|
||||
const HEADS: UiHeadProps[] = [
|
||||
{ id: "rowNo", title: "순번", widthPercent: 5 },
|
||||
{ id: "rowNo", title: "순번", widthPercent: 4 },
|
||||
{ id: "ctpvNm", title: "시도", widthPercent: 7 },
|
||||
{ id: "sggNm", title: "시군구", widthPercent: 8 },
|
||||
{ id: "obsrvnBrnchNmDisplay", title: "관측소", widthPercent: 7 },
|
||||
{
|
||||
id: "areaRtDisplay",
|
||||
title: "면적비율(%)",
|
||||
widthPercent: 6,
|
||||
align: "right",
|
||||
},
|
||||
{
|
||||
id: "analysisDateTimeDisplay",
|
||||
title: "분석시각",
|
||||
widthPercent: 13,
|
||||
widthPercent: 11,
|
||||
},
|
||||
{
|
||||
id: "rainBeginningDateTimeDisplay",
|
||||
title: "강우시작시각",
|
||||
widthPercent: 13,
|
||||
widthPercent: 11,
|
||||
},
|
||||
{
|
||||
id: "observedAccumulatedRainfallDisplay",
|
||||
title: "관측 누적강수량(mm)",
|
||||
widthPercent: 11,
|
||||
widthPercent: 9,
|
||||
align: "right",
|
||||
},
|
||||
{
|
||||
id: "predictionHourDisplay",
|
||||
title: "예측시간",
|
||||
widthPercent: 7,
|
||||
widthPercent: 6,
|
||||
},
|
||||
{
|
||||
id: "predictedAccumulatedRainfallDisplay",
|
||||
title: "예측 누적강수량(mm)",
|
||||
widthPercent: 12,
|
||||
widthPercent: 9,
|
||||
align: "right",
|
||||
},
|
||||
{
|
||||
id: "exceededFrequencyYearDisplay",
|
||||
title: "초과 빈도(년)",
|
||||
widthPercent: 8,
|
||||
widthPercent: 7,
|
||||
align: "right",
|
||||
},
|
||||
{ id: "floodRiskGrade", title: "침수위험도", widthPercent: 8 },
|
||||
{ id: "floodRiskGrade", title: "침수위험도", widthPercent: 7 },
|
||||
{ id: "probabilityRainfallDisplay", title: "확률강우량", widthPercent: 8 },
|
||||
];
|
||||
|
||||
/** 관측소·면적비율 열이 더해진 목록의 최소 표 너비다. 기본 팝업 너비(1280px)에서는 가로 스크롤 없이 보이도록 잡는다. */
|
||||
const LIST_MIN_TABLE_WIDTH = "118rem";
|
||||
|
||||
/** 날짜·시각의 뒷부분이 잘리지 않도록 전체 표시할 목록 열이다. */
|
||||
const FULL_TEXT_TIME_HEAD_IDS = [
|
||||
"analysisDateTimeDisplay",
|
||||
@@ -157,6 +182,34 @@ const predictionHourText = (value: number | null) => {
|
||||
return hour > 0 ? `${hour}시간 후` : "-";
|
||||
};
|
||||
|
||||
/** 관측지점코드가 있으면 관측소 기준(새 로직) 분석 행이다. 기준표 API·표시 문구를 고를 때 쓴다. */
|
||||
const isObsvtrRow = (row: Pick<ApiRow, "obsrvnBrnchCd">) =>
|
||||
Boolean(row.obsrvnBrnchCd);
|
||||
|
||||
/**
|
||||
* 목록 예측시간 열의 표시문구를 정한다.
|
||||
* 관측소 기준 행의 예측시간 0은 대표값이 분석시각(관측 누적)이라는 뜻이므로 `0시간 후`로 보인다.
|
||||
* 그 밖의 행은 기존 `predictionHourText` 규칙(0 이하 `-`)을 그대로 따른다.
|
||||
*/
|
||||
const predictionHourDisplayText = (
|
||||
row: Pick<ApiRow, "predictionHour" | "obsrvnBrnchCd">,
|
||||
) =>
|
||||
isObsvtrRow(row) && row.predictionHour === 0
|
||||
? "0시간 후"
|
||||
: predictionHourText(row.predictionHour);
|
||||
|
||||
/**
|
||||
* 확률강우량 기준표 버튼 aria-label과 모달 제목에 쓸 대상 이름이다.
|
||||
* 관측소 기준 행은 관측소명(목록 → 기준표 응답 → 관측지점코드 순으로 대체), 기존 행은 시군구명을 쓴다.
|
||||
*/
|
||||
const probabilityTargetName = (
|
||||
row: Pick<ApiRow, "obsrvnBrnchCd" | "obsrvnBrnchNm" | "sggNm">,
|
||||
responseStationName?: string,
|
||||
) =>
|
||||
isObsvtrRow(row)
|
||||
? row.obsrvnBrnchNm || responseStationName || row.obsrvnBrnchCd || ""
|
||||
: row.sggNm;
|
||||
|
||||
/** 분석 결과의 대표 누적강우시간을 확률강우량 기준표 링크 문구로 표시한다. */
|
||||
const probabilityDurationText = (value: number | null) => {
|
||||
const hour = Number(value);
|
||||
@@ -291,11 +344,14 @@ export default function FldngPredcPrstPopupContent() {
|
||||
rainBeginningDateTimeDisplay: displayDate(
|
||||
item.rainBeginningDateTime,
|
||||
),
|
||||
// 기존 로직 행(관측지점코드 null)이나 매핑에 없는 조합은 관측소·면적비율을 `-`로 보인다.
|
||||
obsrvnBrnchNmDisplay: item.obsrvnBrnchNm || "-",
|
||||
areaRtDisplay: formatNumber(item.areaRt, 2),
|
||||
observedAccumulatedRainfallDisplay: formatNumber(
|
||||
item.observedAccumulatedRainfall,
|
||||
1,
|
||||
),
|
||||
predictionHourDisplay: predictionHourText(item.predictionHour),
|
||||
predictionHourDisplay: predictionHourDisplayText(item),
|
||||
predictedAccumulatedRainfallDisplay: formatNumber(
|
||||
item.predictedAccumulatedRainfall,
|
||||
1,
|
||||
@@ -417,9 +473,19 @@ export default function FldngPredcPrstPopupContent() {
|
||||
}
|
||||
};
|
||||
|
||||
/** 선택 시군구의 확률강우량과 관측소 비율을 조회한다. 지도 행 클릭은 버튼에서 차단한다. */
|
||||
/**
|
||||
* 선택 행의 확률강우량과 관측소 비율을 조회한다. 지도 행 클릭은 버튼에서 차단한다.
|
||||
* 관측지점코드가 있는 관측소 기준 행은 판정에 쓴 최근접 확률관측소 기준표(`/prst/prbbt-rnfl/obsvtr`)를,
|
||||
* 기존 시군구 기준 행은 지금처럼 시군구 면적가중 기준표(`/prst/prbbt-rnfl`)를 부른다.
|
||||
*/
|
||||
const handleProbabilityClick = async (row: TableRow) => {
|
||||
if (!row.sggCd || !Number.isInteger(Number(row.predcRainHr)) || Number(row.predcRainHr) <= 0) {
|
||||
// 관측소 기준 행이면 조회에 쓸 관측지점코드, 기존 행이면 null이다.
|
||||
const obsrvnBrnchCd = row.obsrvnBrnchCd || null;
|
||||
if (
|
||||
(!obsrvnBrnchCd && !row.sggCd) ||
|
||||
!Number.isInteger(Number(row.predcRainHr)) ||
|
||||
Number(row.predcRainHr) <= 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const requestId = ++probabilityRequestIdRef.current;
|
||||
@@ -428,16 +494,22 @@ export default function FldngPredcPrstPopupContent() {
|
||||
setProbabilityError(null);
|
||||
setProbabilityLoading(true);
|
||||
try {
|
||||
const params = new URLSearchParams({ sggCd: row.sggCd });
|
||||
const response = await getRawJson(
|
||||
`/sewerage-service/api/v1/fldng/predc/prst/prbbt-rnfl?${params.toString()}`,
|
||||
);
|
||||
// 행 종류에 맞는 기준표 API 주소다. 기존 시군구 기준 행은 이전과 같은 sggCd 쿼리를 쓴다.
|
||||
const requestUrl = obsrvnBrnchCd
|
||||
? `/sewerage-service/api/v1/fldng/predc/prst/prbbt-rnfl/obsvtr?${new URLSearchParams({ obsrvnBrnchCd }).toString()}`
|
||||
: `/sewerage-service/api/v1/fldng/predc/prst/prbbt-rnfl?${new URLSearchParams({ sggCd: row.sggCd }).toString()}`;
|
||||
const response = await getRawJson(requestUrl);
|
||||
if (requestId !== probabilityRequestIdRef.current) return;
|
||||
const payload: PrbbtRnflResponse = response?.data ?? response;
|
||||
setProbabilityData(payload);
|
||||
} catch (error) {
|
||||
if (requestId !== probabilityRequestIdRef.current) return;
|
||||
console.error("시군구 확률강우량 조회 중 오류:", error);
|
||||
console.error(
|
||||
obsrvnBrnchCd
|
||||
? "관측소 확률강우량 조회 중 오류:"
|
||||
: "시군구 확률강우량 조회 중 오류:",
|
||||
error,
|
||||
);
|
||||
setProbabilityError("확률강우량 기준표를 조회하지 못했습니다.");
|
||||
} finally {
|
||||
if (requestId === probabilityRequestIdRef.current) {
|
||||
@@ -479,6 +551,7 @@ export default function FldngPredcPrstPopupContent() {
|
||||
getItems: (response) => response.content,
|
||||
getTotal: (response) => response.totalElements,
|
||||
});
|
||||
// API 원본 행을 그대로 넘겨 관측지점코드·관측소명·면적비율도 Excel 헬퍼에서 함께 쓴다.
|
||||
await downloadFloodPredictionStatusExcel(result.items);
|
||||
} catch (error) {
|
||||
console.error("침수예측현황 Excel 다운로드 중 오류:", error);
|
||||
@@ -659,7 +732,7 @@ export default function FldngPredcPrstPopupContent() {
|
||||
<button
|
||||
type="button"
|
||||
className="font-medium text-primary underline underline-offset-2 hover:opacity-75 focus-visible:rounded-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
|
||||
aria-label={`${row.sggNm} ${row.probabilityRainfallDisplay} 확률강우량 기준표 보기`}
|
||||
aria-label={`${probabilityTargetName(row)} ${row.probabilityRainfallDisplay} 확률강우량 기준표 보기`}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
void handleProbabilityClick(row);
|
||||
@@ -671,7 +744,7 @@ export default function FldngPredcPrstPopupContent() {
|
||||
) : undefined
|
||||
}
|
||||
scrollMode="horizontal"
|
||||
minTableWidth="112rem"
|
||||
minTableWidth={LIST_MIN_TABLE_WIDTH}
|
||||
fullTextHeadIds={FULL_TEXT_TIME_HEAD_IDS}
|
||||
fillAvailableHeight={rows.length === 0}
|
||||
emptyMessage="조회 조건에 해당하는 침수예측현황이 없습니다."
|
||||
@@ -706,7 +779,17 @@ export default function FldngPredcPrstPopupContent() {
|
||||
<PrbbtRnflDialog
|
||||
open={probabilityRow !== null}
|
||||
onOpenChange={handleProbabilityOpenChange}
|
||||
sggName={probabilityRow?.sggNm ?? ""}
|
||||
targetName={
|
||||
probabilityRow
|
||||
? probabilityTargetName(
|
||||
probabilityRow,
|
||||
probabilityData?.obsrvnBrnchNm,
|
||||
)
|
||||
: ""
|
||||
}
|
||||
targetKind={
|
||||
probabilityRow && isObsvtrRow(probabilityRow) ? "obsvtr" : "sgg"
|
||||
}
|
||||
selectedDurationHour={probabilityRow?.predcRainHr ?? null}
|
||||
selectedFrequencyYear={probabilityRow?.exceededFrequencyYear ?? null}
|
||||
data={probabilityData}
|
||||
|
||||
Reference in New Issue
Block a user