sn: 도시침수예방사업 사업명 필수

This commit is contained in:
2026-10-06 13:15:32 +09:00
parent 11d0378060
commit 0c77ed9bba
5 changed files with 29 additions and 24 deletions
@@ -43,5 +43,5 @@
- 선택 지속시간·초과빈도년도의 교차값 한 셀만 색으로 강조하고 헤더는 기존 스타일을 유지한다.
- 팝업 표의 선택 지속시간 열은 로딩 완료 후 표 내부 가로 스크롤 영역 중앙에 자동으로 나타난다.
- 선택 초과빈도년도의 재현기간 행은 년도와 강수량을 굵게 표시한다.
- 분석시각·강우시작시각 열은 고정 폭을 지정하지 않고 말줄임만 해제하여, 전체 시각을 표시하면서 주변 열과 함께 자동으로 너비를 계산한다.
- `pnpm --filter sn run typecheck`, `git diff --check`가 통과했다. 3002 포트 개발 서버 실행 중이므로 build는 실행하지 않았다.
- 현황 목록은 자동 표 레이아웃을 유지하고 `widthPercent` 합계를 100%로 맞춘다. 분석시각·강우시작시각은 각각 13%를 적용해 분까지 표시하며, 최소 표 너비 112rem과 가로 스크롤을 유지한다.
- `pnpm --filter sn run typecheck`, `git diff --check`가 통과했다. 빌드 중 3002 포트 개발 서버가 확인되어 에이전트가 시작한 빌드만 중단했으며, 빌드 완료와 실화면 검증은 미확인이다.
@@ -11,12 +11,12 @@
- 팝업 하단에 확률관측소코드·관측소명·면적비율 및 API 합계를 표시한다.
- 팝업 맨 아래에 `시간은 강우가 지속된 시간입니다` 안내를 표시한다.
- 링크 클릭 이벤트는 기존 행 선택의 지도 이동으로 전파하지 않는다.
- 침수예측현황 목록의 분석시각·강우시작시각은 말줄임을 적용하지 않고, 고정 열 폭 없이 표의 자동 너비 계산과 가로 스크롤로 분까지 표시한다.
- 침수예측현황 목록은 자동 표 레이아웃에서 `widthPercent` 합계 100%를 CSS 너비로 전달한다. 분석시각·강우시작시각은 각각 13%를 적용해 말줄임 없이 분까지 표시하고, 최소 표 너비 112rem과 가로 스크롤을 유지한다.
## 검증
- `pnpm --filter sn run typecheck` 성공
- `git diff --check` 성공
- 개발 서버(3002)가 실행 중이어서 build는 실행하지 않았다.
- 빌드 중 개발 서버(3002)가 확인되어 에이전트가 시작한 빌드만 중단했다. 빌드 완료와 실화면 검증은 미확인이다.
## 수동 확인 필요
- 실제 로그인 화면에서 팝업 크기·가로 스크롤·강조 색상 및 지도 이동 회귀 확인
@@ -93,7 +93,7 @@ const DETAIL_FIELDS = [
] as const;
type BasicKey = (typeof BASIC_FIELDS)[number][0];
/** 저장 전에 반드시 입력해야 하는 항목이다. 시도는 별도 선택이라 region 키로 관리한다. */
const REQUIRED_BASIC_KEYS = new Set<string>(["seqNo", "dsgnYmd"]);
const REQUIRED_BASIC_KEYS = new Set<string>(["seqNo", "dsgnYmd", "bizNm"]);
type FieldErrorKey = BasicKey | "region" | `soa-${string}`;
/** 금액·면적 입력의 DB 자릿수 규칙이다. intDigits 는 정수부, scale 은 소수부 한계다. */
@@ -390,6 +390,7 @@ export function CtyFldngPrvtnBizFormPage({ id }: { id?: string }) {
if (!String(form.ctpvNm ?? "").trim()) nextErrors.region = "시도는 필수입니다.";
if (form.seqNo === null || form.seqNo === undefined || String(form.seqNo) === "")
nextErrors.seqNo = "사업순번은 필수입니다.";
if (!String(form.bizNm ?? "").trim()) nextErrors.bizNm = "사업명은 필수입니다.";
if (!String(form.dsgnYmd ?? "").trim())
nextErrors.dsgnYmd = "지정일은 필수입니다.";
else if (!validDate(form.dsgnYmd))
@@ -478,7 +479,7 @@ export function CtyFldngPrvtnBizFormPage({ id }: { id?: string }) {
key={key}
id={fieldId}
label={label}
required={key === "bizNm" || REQUIRED_BASIC_KEYS.has(key)}
required={REQUIRED_BASIC_KEYS.has(key)}
error={fieldErrors[key]}
span={span}
>
@@ -76,9 +76,9 @@ const toFloodMapFrequencyCode = (value: number) => {
};
const HEADS: UiHeadProps[] = [
{ id: "rowNo", title: "순번", widthPercent: 6 },
{ id: "ctpvNm", title: "시도", widthPercent: 8 },
{ id: "sggNm", title: "시군구", widthPercent: 9 },
{ id: "rowNo", title: "순번", widthPercent: 5 },
{ id: "ctpvNm", title: "시도", widthPercent: 7 },
{ id: "sggNm", title: "시군구", widthPercent: 8 },
{
id: "analysisDateTimeDisplay",
title: "분석시각",
@@ -87,33 +87,33 @@ const HEADS: UiHeadProps[] = [
{
id: "rainBeginningDateTimeDisplay",
title: "강우시작시각",
widthPercent: 16,
widthPercent: 13,
},
{
id: "observedAccumulatedRainfallDisplay",
title: "관측 누적강수량(mm)",
widthPercent: 13,
widthPercent: 11,
align: "right",
},
{
id: "predictionHourDisplay",
title: "예측시간",
widthPercent: 9,
widthPercent: 7,
},
{
id: "predictedAccumulatedRainfallDisplay",
title: "예측 누적강수량(mm)",
widthPercent: 15,
widthPercent: 12,
align: "right",
},
{
id: "exceededFrequencyYearDisplay",
title: "초과 빈도(년)",
widthPercent: 10,
widthPercent: 8,
align: "right",
},
{ id: "floodRiskGrade", title: "침수위험도", widthPercent: 10 },
{ id: "probabilityRainfallDisplay", title: "확률강우량", widthPercent: 10 },
{ id: "floodRiskGrade", title: "침수위험도", widthPercent: 8 },
{ id: "probabilityRainfallDisplay", title: "확률강우량", widthPercent: 8 },
];
/** 날짜·시각의 뒷부분이 잘리지 않도록 전체 표시할 목록 열이다. */
@@ -43,7 +43,8 @@ type MapPopupDataTableProps<T extends Record<string, unknown>> = {
headId: string,
rowIndex: number,
) => ReactNode | undefined;
fullTextHeadIds?: string[]; /** 시각처럼 뒤쪽이 잘리면 의미가 달라지는 열은 고정 너비 없이 말줄임만 해제한다. */
/** 시각처럼 뒤쪽이 잘리면 의미가 달라지는 열의 말줄임을 해제한다. */
fullTextHeadIds?: string[];
sort?: UiTableSort;
onSortChange?: (sort: UiTableSort | undefined) => void;
};
@@ -144,15 +145,18 @@ export default function MapPopupDataTable<T extends Record<string, unknown>>({
head.align === "left" || head.align === "right"
? head.align
: "center",
width: head.widthPercent,
...(fullTextHeadIds?.includes(head.id)
? {
"data-sn-cell-wrap": "",
style: {
whiteSpace: "nowrap",
},
}
? { "data-sn-cell-wrap": "" }
: {}),
style: {
width:
head.widthPercent != null
? `${head.widthPercent}%`
: undefined,
...(fullTextHeadIds?.includes(head.id)
? { whiteSpace: "nowrap" }
: {}),
},
} as ColumnDef<T>["meta"],
})),
[