sn: 확률강우량 엑셀다운로드

This commit is contained in:
2026-10-30 13:34:44 +09:00
parent 0336226562
commit 45c8d021cc
2 changed files with 77 additions and 3 deletions
@@ -20,3 +20,30 @@
## 수동 확인 필요
- 실제 로그인 화면에서 팝업 크기·가로 스크롤·강조 색상 및 지도 이동 회귀 확인
## 추가 작업: 확률강우량 팝업 엑셀다운로드 (2026-10-30)
### 변경 내용
- 팝업 헤더 우측(닫기 X 왼쪽)에 `엑셀다운로드` 버튼을 추가했다. 닫기 버튼과 겹치지 않도록 헤더에 `pr-14` 여백을 둔다.
- 공통 유틸 `src/shared/util/download-excel-workbook.ts`의 `downloadExcelWorkbook`을 재사용한다.
- 파일명은 `{시군구명}_확률강우량.xlsx`이며 시트는 두 개다.
- `확률강우량`: 재현기간(년) 행 × `N시간` 열. 셀은 소수 4자리로 자르지 않은 원본 숫자 값이다.
- `확률관측소 면적비율`: 확률관측소코드·관측소명·면적비율(%)과 합계(API `areaRtTotal`).
- 로딩 중·오류·표 데이터 없음 상태에서는 버튼을 비활성화한다.
- API 호출, 응답 구조, 화면 문구와 기존 표 렌더링은 변경하지 않았다.
### 이슈: 팝업 본체가 투명하게 렌더링됨
- 증상: 엑셀다운로드 버튼 추가 후 팝업 본체 배경이 투명해져 뒤쪽 목록 화면이 비쳐 보였다. 새로고침과 애니메이션 완료 후에도 재현됐다.
- 추정 원인: `DialogContent`의 배경이 `bg-[var(--dialog-bg)]`(`--dialog-bg: var(--background)`, `packages/common/assets/src/styles/base.css`)인데, 이 모달에서 해당 변수가 값을 가져오지 못한 것으로 추정한다. 정확한 근본 원인은 확인하지 못했다. 공통 패키지(`@common/components`, `@common/assets`)는 수정 범위 밖이라 변경하지 않았다.
- 조치: `PrbbtRnflDialog.tsx`의 `DialogContent` className에 `bg-background`를 추가해 배경을 직접 지정했다. 사용자가 해결을 확인했다(2026-10-30).
- 참고: 같은 증상이 다른 `DialogContent` 사용 팝업에서 보이면 공통 변수 문제일 수 있으므로 별도 보고 대상이다.
### 수정 파일
- `apps/sn/src/features/fldng-predc-prst/ui/PrbbtRnflDialog.tsx`
### 검증
- 사용자가 실제 화면에서 팝업 배경 정상 표시를 확인했다.
- 타입 체크·빌드·엑셀 파일 내용 열람은 수행하지 않았다.
### 롤백
- 위 파일의 변경(헤더 버튼, `handleExcelDownload`, 두 import, `bg-background`)을 되돌린다.
@@ -2,7 +2,9 @@
import { useLayoutEffect, useMemo, useRef } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@common/components";
import { Button, Dialog, DialogContent, DialogHeader, DialogTitle } from "@common/components";
import { downloadExcelWorkbook } from "@/shared/util/download-excel-workbook";
/** 시군구별 면적가중 확률강우량 한 셀의 API 응답이다. */
export type PrbbtRnflCell = {
@@ -77,6 +79,43 @@ export default function PrbbtRnflDialog({
};
}, [data]);
/** 화면에 표시 중인 확률강우량 표와 관측소 면적비율 표를 두 시트로 내려받는다. */
const handleExcelDownload = async () => {
const stations = data?.stations ?? [];
await downloadExcelWorkbook({
fileName: `${sggName}_확률강우량`,
sheets: [
{
name: "확률강우량",
rows: [
["재현기간(년)", ...durations.map((hour) => `${hour}시간`)],
...frequencies.map((frequencyYear) => [
frequencyYear,
...durations.map(
(durationHour) =>
rainfallByKey.get(`${frequencyYear}:${durationHour}`) ?? null,
),
]),
],
columnWidths: [14, ...durations.map(() => 12)],
},
{
name: "확률관측소 면적비율",
rows: [
["확률관측소코드", "관측소명", "면적비율(%)"],
...stations.map((station) => [
station.prbbtObsvtrCd,
station.prbbtObsvtrNm || "-",
station.areaRt,
]),
["합계", "", data?.areaRtTotal ?? null],
],
columnWidths: [18, 18, 14],
},
],
});
};
/** 표가 표시되면 선택 지속시간 열을 가로 스크롤 영역의 가운데로 맞춘다. */
useLayoutEffect(() => {
if (!open || loading || error || selectedDurationHour == null) return;
@@ -96,11 +135,19 @@ 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"
className="flex max-h-[90vh] w-[94vw] !max-w-[150rem] flex-col gap-4 overflow-hidden bg-background"
aria-describedby={undefined}
>
<DialogHeader>
{/* 우측 상단 닫기(X) 버튼과 겹치지 않도록 pr-14 여백을 둔다. */}
<DialogHeader className="flex-row items-center justify-between pr-14">
<DialogTitle>{sggName} 확률강우량</DialogTitle>
<Button
type="button"
disabled={loading || !!error || !frequencies.length || !durations.length}
onClick={() => void handleExcelDownload()}
>
엑셀다운로드
</Button>
</DialogHeader>
{loading ? (