This commit is contained in:
+2
-2
@@ -12,8 +12,8 @@ NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
SEWERAGE_API_URL = http://localhost:8883
|
||||
# SEWERAGE_API_URL = http://con.mind-one.co.kr:11083
|
||||
# SEWERAGE_API_URL = http://localhost:8883
|
||||
SEWERAGE_API_URL = http://con.mind-one.co.kr:11083
|
||||
DC_URL = https://apigateway.apps.rsonesoft.com
|
||||
# NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = /auth/login
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useAlertStore } from "@/shared/lib";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { getData } from "@/components/lib/api";
|
||||
import { appendApiSearchParams } from "@/shared/util/util";
|
||||
import { CtpvSggPrcsFcltSelectBox } from "@/components/ui/ctpvSggPrcsFcltSelectBox";
|
||||
import { formatDisplayData } from "@/components/lib/utils/formatDisplayValue";
|
||||
import useStore from "@/store/useStore";
|
||||
@@ -132,16 +133,13 @@ export default function InftwtResultPopupPage() {
|
||||
: "inftwtAnlsSn,desc",
|
||||
);
|
||||
|
||||
if (nextFilters.aplcnYmFrom)
|
||||
queryParams.set("aplcnYmFrom", nextFilters.aplcnYmFrom);
|
||||
if (nextFilters.aplcnYmTo)
|
||||
queryParams.set("aplcnYmTo", nextFilters.aplcnYmTo);
|
||||
if (nextFilters.ctpvCd !== "0")
|
||||
queryParams.set("ctpvCd", nextFilters.ctpvCd);
|
||||
if (nextFilters.sggCd !== "0")
|
||||
queryParams.set("sggCd", nextFilters.sggCd);
|
||||
if (nextFilters.swtrmtFcltNm.trim())
|
||||
queryParams.set("swtrmtFcltNm", nextFilters.swtrmtFcltNm.trim());
|
||||
appendApiSearchParams(queryParams, {
|
||||
aplcnYmFrom: nextFilters.aplcnYmFrom,
|
||||
aplcnYmTo: nextFilters.aplcnYmTo,
|
||||
ctpvCd: nextFilters.ctpvCd,
|
||||
sggCd: nextFilters.sggCd,
|
||||
swtrmtFcltNm: nextFilters.swtrmtFcltNm,
|
||||
});
|
||||
|
||||
const response = await getData(`v1/inftwtAnls?${queryParams.toString()}`);
|
||||
const content = Array.isArray(response?.content) ? response.content : [];
|
||||
|
||||
+11
-13
@@ -6,6 +6,7 @@ import { Button, Input } from "@common/components";
|
||||
import { StandardPopupLayout } from "@common/business_components";
|
||||
import { downloadExcelWithKoreanHeaders } from "@/shared/lib/download-excel";
|
||||
import { getData } from "@/components/lib/api";
|
||||
import { appendApiSearchParams } from "@/shared/util/util";
|
||||
import LoadingOverlay from "@/components/ui/LoadingBar";
|
||||
import useStore from "@/store/useStore";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
@@ -131,19 +132,16 @@ export default function PipeAnalysisDetailPopupPage() {
|
||||
size: String(size),
|
||||
});
|
||||
|
||||
if (nextFilters.ctpvCd !== "0") params.set("ctpvCd", nextFilters.ctpvCd);
|
||||
if (nextFilters.sggCd !== "0") params.set("sggCd", nextFilters.sggCd);
|
||||
if (nextFilters.swtrmtZoneNm !== "0")
|
||||
params.set("swtrmtZoneNm", nextFilters.swtrmtZoneNm);
|
||||
if (baseElapsedYearBucket)
|
||||
params.set("elapsedYearBucket", baseElapsedYearBucket);
|
||||
if (nextFilters.materialCode !== "0")
|
||||
params.set("materialCode", nextFilters.materialCode);
|
||||
if (nextFilters.useCd !== "0") params.set("useCd", nextFilters.useCd);
|
||||
if (nextFilters.diameterFrom)
|
||||
params.set("diameterFrom", nextFilters.diameterFrom);
|
||||
if (nextFilters.diameterTo)
|
||||
params.set("diameterTo", nextFilters.diameterTo);
|
||||
appendApiSearchParams(params, {
|
||||
ctpvCd: nextFilters.ctpvCd,
|
||||
sggCd: nextFilters.sggCd,
|
||||
swtrmtZoneNm: nextFilters.swtrmtZoneNm,
|
||||
elapsedYearBucket: baseElapsedYearBucket,
|
||||
materialCode: nextFilters.materialCode,
|
||||
useCd: nextFilters.useCd,
|
||||
diameterFrom: nextFilters.diameterFrom,
|
||||
diameterTo: nextFilters.diameterTo,
|
||||
});
|
||||
if (scope.regionCode) params.set("scopeRegionCode", scope.regionCode);
|
||||
|
||||
const response = await getData(
|
||||
|
||||
@@ -14,6 +14,7 @@ import { StandardPopupLayout } from "@common/business_components";
|
||||
import UiPageNations from "@common/business_components/ui/table/uiPageNations";
|
||||
import { downloadExcelWithKoreanHeaders } from "@/shared/lib/download-excel";
|
||||
import { getData } from "@/components/lib/api";
|
||||
import { appendApiSearchParams } from "@/shared/util/util";
|
||||
import LoadingOverlay from "@/components/ui/LoadingBar";
|
||||
import useStore from "@/store/useStore";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
@@ -144,10 +145,11 @@ export default function PipeAnalysisPopupPage() {
|
||||
analysisType: nextFilters.analysisType,
|
||||
});
|
||||
|
||||
if (nextFilters.ctpvCd !== "0") params.set("ctpvCd", nextFilters.ctpvCd);
|
||||
if (nextFilters.sggCd !== "0") params.set("sggCd", nextFilters.sggCd);
|
||||
if (nextFilters.swtrmtZoneNm !== "0")
|
||||
params.set("swtrmtZoneNm", nextFilters.swtrmtZoneNm);
|
||||
appendApiSearchParams(params, {
|
||||
ctpvCd: nextFilters.ctpvCd,
|
||||
sggCd: nextFilters.sggCd,
|
||||
swtrmtZoneNm: nextFilters.swtrmtZoneNm,
|
||||
});
|
||||
if (nextFilters.scopeRegionCode)
|
||||
params.set("scopeRegionCode", nextFilters.scopeRegionCode);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { getData } from "@/components/lib/api";
|
||||
import { appendApiSearchParams } from "@/shared/util/util";
|
||||
import { downloadExcelWithKoreanHeaders } from "@/shared/lib/download-excel";
|
||||
import { fetchAllPages } from "@/shared/lib/fetch-all-pages";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
@@ -134,16 +135,13 @@ export default function RdiiResultPopupPage() {
|
||||
: "rainInfwtAnlsSn,desc",
|
||||
);
|
||||
|
||||
if (nextFilters.aplcnYmFrom)
|
||||
queryParams.set("aplcnYmFrom", nextFilters.aplcnYmFrom);
|
||||
if (nextFilters.aplcnYmTo)
|
||||
queryParams.set("aplcnYmTo", nextFilters.aplcnYmTo);
|
||||
if (nextFilters.ctpvCd !== "0")
|
||||
queryParams.set("ctpvCd", nextFilters.ctpvCd);
|
||||
if (nextFilters.sggCd !== "0")
|
||||
queryParams.set("sggCd", nextFilters.sggCd);
|
||||
if (nextFilters.swtrmtFcltNm.trim())
|
||||
queryParams.set("swtrmtFcltNm", nextFilters.swtrmtFcltNm.trim());
|
||||
appendApiSearchParams(queryParams, {
|
||||
aplcnYmFrom: nextFilters.aplcnYmFrom,
|
||||
aplcnYmTo: nextFilters.aplcnYmTo,
|
||||
ctpvCd: nextFilters.ctpvCd,
|
||||
sggCd: nextFilters.sggCd,
|
||||
swtrmtFcltNm: nextFilters.swtrmtFcltNm,
|
||||
});
|
||||
|
||||
const response = await getData(`v1/rdiiAnls?${queryParams.toString()}`);
|
||||
const content = Array.isArray(response?.content) ? response.content : [];
|
||||
|
||||
@@ -69,3 +69,11 @@
|
||||
- 2026-08-18 목록 강수량을 소수점 한 자리로, 헤더를 `초과빈도년도`로 변경하고 값의 `년` 접미사를 제거했다.
|
||||
- 기존 `.next` 산출물을 재생성한 뒤 `pnpm --filter sn run build`를 최종 통과했다.
|
||||
- TypeScript 정적검사는 저장소 기존 `ignoreDeprecations` 설정과 실행 중 산출물 잠금 때문에 완료하지 못했고, Next 빌드는 최적화 단계 장기 대기 후 중단했다.
|
||||
|
||||
## Excel 프론트 생성 전환 결과 (2026-09-03)
|
||||
|
||||
- 현재 적용 검색조건으로 `/api/v1/fldng/predc/prst`를 500건 단위 전체 페이지 조회한다.
|
||||
- 공통 `fetchAllPages`로 `totalElements`와 실제 수집 건수 일치를 검증한다.
|
||||
- `fldng-predc-prst-excel.ts`가 화면 열 순서의 단일 시트 `침수예측현황.xlsx`를 브라우저에서 생성한다.
|
||||
- 서버 `/prst/excel` Blob 호출과 `getBlobData`, `fileDownload` 사용을 제거했다.
|
||||
- 독립 TypeScript `--noEmit` 검증을 통과했다.
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
type PaginationState,
|
||||
} from "@tanstack/react-table";
|
||||
|
||||
import { formatDate } from "../../common/util";
|
||||
import { appendApiSearchParams, formatDate } from "@/shared/util/util";
|
||||
import {
|
||||
getAllCtyFldngPrvtnBusinesses,
|
||||
getCtyFldngPrvtnBusinesses,
|
||||
@@ -454,9 +454,7 @@ export function CtyFldngPrvtnBizListPage() {
|
||||
? `${nextSort.key},${nextSort.direction}`
|
||||
: "ctyFldngPrvtnBizSn,desc",
|
||||
});
|
||||
Object.entries(condition).forEach(([k, v]) => {
|
||||
if (v.trim()) query.set(k, v.trim());
|
||||
});
|
||||
appendApiSearchParams(query, condition);
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await getCtyFldngPrvtnBusinesses(query);
|
||||
@@ -529,9 +527,7 @@ export function CtyFldngPrvtnBizListPage() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const query = new URLSearchParams();
|
||||
Object.entries(applied).forEach(([k, v]) => {
|
||||
if (v.trim()) query.set(k, v.trim());
|
||||
});
|
||||
appendApiSearchParams(query, applied);
|
||||
await downloadCtyFldngPrvtnExcel(
|
||||
await getAllCtyFldngPrvtnBusinesses(
|
||||
query,
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { downloadExcelWithKoreanHeaders } from "@/shared/lib/download-excel";
|
||||
|
||||
export type FloodPredictionExcelRow = {
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
analysisDateTime: string;
|
||||
rainBeginningDateTime: string;
|
||||
observedAccumulatedRainfall: number | null;
|
||||
predictionHour: number | null;
|
||||
predictedAccumulatedRainfall: number | null;
|
||||
exceededFrequencyYear: number | null;
|
||||
floodRiskGrade: string;
|
||||
};
|
||||
|
||||
const HEADERS: Record<string, string> = {
|
||||
rowNo: "순번",
|
||||
ctpvNm: "시도",
|
||||
sggNm: "시군구",
|
||||
analysisDateTime: "분석시각",
|
||||
rainBeginningDateTime: "강우 시작시각",
|
||||
observedAccumulatedRainfall: "관측 누적강수량(mm)",
|
||||
predictionHour: "예측시간",
|
||||
predictedAccumulatedRainfall: "예측 누적강수량(mm)",
|
||||
exceededFrequencyYear: "초과빈도(년)",
|
||||
floodRiskGrade: "침수위험도",
|
||||
};
|
||||
|
||||
/** yyyyMMddHHmm 형식의 API 시각을 Excel 표시 문자열로 변환한다. */
|
||||
const formatDateTime = (value: string) =>
|
||||
/^\d{12}$/.test(value)
|
||||
? `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)} ${value.slice(8, 10)}:${value.slice(10, 12)}`
|
||||
: value || "-";
|
||||
|
||||
/** 적용 조회조건의 전체 침수예측현황을 브라우저에서 한 시트 XLSX로 생성한다. */
|
||||
export const downloadFloodPredictionStatusExcel = async (
|
||||
rows: FloodPredictionExcelRow[],
|
||||
) => {
|
||||
const excelRows = rows.map((row, index) => ({
|
||||
rowNo: index + 1,
|
||||
ctpvNm: row.ctpvNm || "-",
|
||||
sggNm: row.sggNm || "-",
|
||||
analysisDateTime: formatDateTime(row.analysisDateTime),
|
||||
rainBeginningDateTime: formatDateTime(row.rainBeginningDateTime),
|
||||
observedAccumulatedRainfall:
|
||||
row.observedAccumulatedRainfall == null
|
||||
? "-"
|
||||
: Number(row.observedAccumulatedRainfall.toFixed(1)),
|
||||
predictionHour:
|
||||
row.predictionHour == null ? "-" : `${row.predictionHour}시간 후`,
|
||||
predictedAccumulatedRainfall:
|
||||
row.predictedAccumulatedRainfall == null
|
||||
? "-"
|
||||
: Number(row.predictedAccumulatedRainfall.toFixed(1)),
|
||||
exceededFrequencyYear:
|
||||
row.exceededFrequencyYear == null ? "-" : row.exceededFrequencyYear,
|
||||
floodRiskGrade: row.floodRiskGrade || "-",
|
||||
}));
|
||||
|
||||
await downloadExcelWithKoreanHeaders({
|
||||
data: excelRows as unknown as JSON[],
|
||||
fileName: "침수예측현황.xlsx",
|
||||
sheetNameArray: ["침수예측현황"],
|
||||
headerRange: "A1:J1",
|
||||
headerMapping: HEADERS,
|
||||
});
|
||||
};
|
||||
@@ -8,8 +8,8 @@ import {
|
||||
} from "@common/business_components";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { getBlobData, getData, getRawJson } from "@/components/lib/api";
|
||||
import { fileDownload } from "@/components/lib/utils/fileDownload";
|
||||
import { getData, getRawJson } from "@/components/lib/api";
|
||||
import { appendApiSearchParams } from "@/shared/util/util";
|
||||
import LoadingOverlay from "@/components/ui/LoadingBar";
|
||||
import { windowPopupDefinitions } from "@/features/windowPopup/model/popupDefinitions";
|
||||
import { WINDOW_POPUP_MESSAGE_TYPE } from "@/features/windowPopup/model/types";
|
||||
@@ -18,6 +18,8 @@ import PopupSearchPanel from "@/features/windowPopup/ui/PopupSearchPanel";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import useStore from "@/store/useStore";
|
||||
import { createPredictionAnalysisTimeRange } from "../model/analysisTimeRange";
|
||||
import { fetchAllPages } from "@/shared/lib/fetch-all-pages";
|
||||
import { downloadFloodPredictionStatusExcel } from "../lib/fldng-predc-prst-excel";
|
||||
|
||||
type ApiRow = {
|
||||
sggCd: string;
|
||||
@@ -55,6 +57,7 @@ type Filters = {
|
||||
};
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
const EXCEL_DOWNLOAD_PAGE_SIZE = 500;
|
||||
const MAP_FREQUENCIES = new Set([30, 50, 80, 100]);
|
||||
const FREQUENCY_OPTIONS = [30, 50, 80, 100] as const;
|
||||
|
||||
@@ -118,7 +121,7 @@ const buildInitialFilters = (): Filters => {
|
||||
rainBgngTo: "",
|
||||
analysisFrom: toDateTimeLocal(range.analysisFrom),
|
||||
analysisTo: toDateTimeLocal(range.analysisTo),
|
||||
frequencyYear: "",
|
||||
frequencyYear: "0",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -141,21 +144,21 @@ const formatNumber = (value: number | null, digits: number) =>
|
||||
: Number(value).toFixed(digits);
|
||||
|
||||
/** 화면 조회조건을 목록·Excel API 쿼리로 변환한다. */
|
||||
const buildQuery = (filters: Filters, page?: number) => {
|
||||
const buildQuery = (filters: Filters, page?: number, size = PAGE_SIZE) => {
|
||||
const params = new URLSearchParams();
|
||||
if (page !== undefined) {
|
||||
params.set("page", String(page - 1));
|
||||
params.set("size", String(PAGE_SIZE));
|
||||
params.set("size", String(size));
|
||||
}
|
||||
if (filters.ctpvCd !== "0") params.set("ctpvCd", filters.ctpvCd.slice(0, 2));
|
||||
if (filters.sggCd !== "0") params.set("sggCd", filters.sggCd.slice(0, 5));
|
||||
(
|
||||
["rainBgngFrom", "rainBgngTo", "analysisFrom", "analysisTo"] as const
|
||||
).forEach((key) => {
|
||||
const value = apiDate(filters[key]);
|
||||
if (value) params.set(key, value);
|
||||
appendApiSearchParams(params, {
|
||||
ctpvCd: filters.ctpvCd === "0" ? "0" : filters.ctpvCd.slice(0, 2),
|
||||
sggCd: filters.sggCd === "0" ? "0" : filters.sggCd.slice(0, 5),
|
||||
rainBgngFrom: apiDate(filters.rainBgngFrom),
|
||||
rainBgngTo: apiDate(filters.rainBgngTo),
|
||||
analysisFrom: apiDate(filters.analysisFrom),
|
||||
analysisTo: apiDate(filters.analysisTo),
|
||||
frequencyYear: filters.frequencyYear,
|
||||
});
|
||||
if (filters.frequencyYear) params.set("frequencyYear", filters.frequencyYear);
|
||||
return params.toString();
|
||||
};
|
||||
|
||||
@@ -176,7 +179,7 @@ const validateFilters = (filters: Filters) => {
|
||||
return "분석시각의 시작은 종료보다 늦을 수 없습니다.";
|
||||
}
|
||||
if (
|
||||
filters.frequencyYear &&
|
||||
filters.frequencyYear != "0" &&
|
||||
!FREQUENCY_OPTIONS.includes(
|
||||
Number(filters.frequencyYear) as 30 | 50 | 80 | 100,
|
||||
)
|
||||
@@ -389,10 +392,25 @@ export default function FldngPredcPrstPopupContent() {
|
||||
}
|
||||
setLoading(true);
|
||||
try {
|
||||
const blob = await getBlobData(
|
||||
`/sewerage-service/api/v1/fldng/predc/prst/excel?${buildQuery(appliedFilters)}`,
|
||||
);
|
||||
fileDownload(blob, "침수예측현황.xlsx");
|
||||
const result = await fetchAllPages<
|
||||
{ content: ApiRow[]; totalElements: number },
|
||||
ApiRow
|
||||
>({
|
||||
batchSize: EXCEL_DOWNLOAD_PAGE_SIZE,
|
||||
fetchPage: async (pageIndex, size) => {
|
||||
const response = await getRawJson(
|
||||
`/sewerage-service/api/v1/fldng/predc/prst?${buildQuery(appliedFilters, pageIndex + 1, size)}`,
|
||||
);
|
||||
const payload = response?.data ?? response;
|
||||
return {
|
||||
content: Array.isArray(payload?.content) ? payload.content : [],
|
||||
totalElements: Number(payload?.totalElements ?? 0),
|
||||
};
|
||||
},
|
||||
getItems: (response) => response.content,
|
||||
getTotal: (response) => response.totalElements,
|
||||
});
|
||||
await downloadFloodPredictionStatusExcel(result.items);
|
||||
} catch (error) {
|
||||
console.error("침수예측현황 Excel 다운로드 중 오류:", error);
|
||||
alert("침수예측현황 Excel 다운로드에 실패했습니다.");
|
||||
@@ -519,7 +537,7 @@ export default function FldngPredcPrstPopupContent() {
|
||||
}))
|
||||
}
|
||||
>
|
||||
<option value="">전체</option>
|
||||
<option value="0">전체</option>
|
||||
{FREQUENCY_OPTIONS.map((frequency) => (
|
||||
<option key={frequency} value={String(frequency)}>
|
||||
{frequency}년
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as XLSX from "xlsx";
|
||||
import XlsxPopulate from "xlsx-populate/browser/xlsx-populate";
|
||||
|
||||
import { formatDate } from "../../common/util";
|
||||
import { formatDate } from "@/shared/util/util";
|
||||
import type { ObsltPplBusiness, ObsltPplBusinessSaveRequest } from "../model/obslt-ppl-types";
|
||||
|
||||
type BusinessType = ObsltPplBusinessSaveRequest["bizSe"];
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
Textarea,
|
||||
} from "@common/components";
|
||||
|
||||
import { formatDate } from "../../common/util";
|
||||
import { formatDate } from "@/shared/util/util";
|
||||
import {
|
||||
createObsltPplBusiness,
|
||||
deleteObsltPplBusiness,
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
getObsltPplBusinesses,
|
||||
uploadObsltPplExcel,
|
||||
} from "../api/obslt-ppl-api";
|
||||
import { formatDate } from "../../common/util";
|
||||
import { appendApiSearchParams, formatDate } from "@/shared/util/util";
|
||||
import {
|
||||
downloadObsltPplExcel,
|
||||
parseObsltPplExcel,
|
||||
@@ -322,9 +322,7 @@ export function ObsltPplListPage() {
|
||||
? `${nextSort.key},${nextSort.direction}`
|
||||
: "obsltSwagePplBizSn,desc",
|
||||
});
|
||||
Object.entries(targetSearch).forEach(([key, value]) => {
|
||||
if (value.trim()) params.set(key, value.trim());
|
||||
});
|
||||
appendApiSearchParams(params, targetSearch);
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
@@ -423,9 +421,7 @@ export function ObsltPplListPage() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
Object.entries(appliedSearch).forEach(([key, value]) => {
|
||||
if (value.trim()) params.set(key, value.trim());
|
||||
});
|
||||
appendApiSearchParams(params, appliedSearch);
|
||||
const exportRows = await getAllObsltPplBusinesses(
|
||||
params,
|
||||
sort ? `${sort.key},${sort.direction}` : undefined,
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
import moment from "moment";
|
||||
|
||||
/** 빈 값과 화면의 전체 선택값 `0`을 제외하고 API 검색 파라미터를 추가한다. */
|
||||
export const appendApiSearchParams = (
|
||||
params: URLSearchParams,
|
||||
search: Readonly<Record<string, string>>,
|
||||
) => {
|
||||
Object.entries(search).forEach(([key, value]) => {
|
||||
const normalized = value.trim();
|
||||
if (!normalized || normalized === "0") return;
|
||||
params.set(key, normalized);
|
||||
});
|
||||
};
|
||||
|
||||
/** 8자리 또는 구분자가 섞인 날짜 문자열을 YYYY-MM-DD 형식으로 정규화한다. */
|
||||
export const formatDate = (value?: string | null) => {
|
||||
if (!value) return "";
|
||||
@@ -955,7 +955,7 @@ const DataGrid = ({
|
||||
try {
|
||||
gv.commit?.();
|
||||
} catch {
|
||||
/* ignore */
|
||||
console.error('commit error');
|
||||
}
|
||||
const ds = gv.getDataSource();
|
||||
if (!ds) return rowDataRef.current.map((r) => ({ ...r }));
|
||||
@@ -1954,7 +1954,7 @@ useEffect(() => {
|
||||
}
|
||||
| undefined;
|
||||
if (!gv?.getDataSource) return [];
|
||||
try { gv.commit?.(); } catch { /* ignore */ }
|
||||
try { gv.commit?.(); } catch { console.error('commit error'); }
|
||||
const ds = gv.getDataSource();
|
||||
if (!ds) return [];
|
||||
const cnt = ds.getRowCount();
|
||||
@@ -2022,7 +2022,7 @@ useEffect(() => {
|
||||
column.footer.styleName = styleName;
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
console.error('총계 스타일 재적용/초기화 error');
|
||||
}
|
||||
});
|
||||
gridView.refresh?.();
|
||||
|
||||
@@ -236,12 +236,13 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
const sggOptions = sggList?.data ?? [];
|
||||
const isDoSelected = isDoSido(selectedSido);
|
||||
const firstConcreteSggOption = firstConcreteSgg(sggOptions);
|
||||
// 도: 빈 값일 때만 첫 시군구로 보이게. ALL은 사용자가 고른 전체 유지
|
||||
const gugunSelectValue =
|
||||
isDoSelected && isAllGugunValue(values.gugun)
|
||||
isDoSelected && !values.gugun
|
||||
? (firstConcreteSggOption?.gugun ?? undefined)
|
||||
: values.gugun || undefined;
|
||||
|
||||
// 도: 전체(ALL/"")가 아니라 그 다음 시군구. 그 외: 전체
|
||||
// 도: 초기/시도 변경(빈 값)만 첫 시군구. 전체(ALL)는 유지. 그 외: 전체
|
||||
useEffect(() => {
|
||||
if (!mergedProps.gugun) return;
|
||||
if (props.defaultRegionAll) return;
|
||||
@@ -263,7 +264,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
if (!firstConcreteSggOption) return;
|
||||
|
||||
setValues((prev) => {
|
||||
if (!isAllGugunValue(prev.gugun)) return prev;
|
||||
if (prev.gugun) return prev;
|
||||
return {
|
||||
...prev,
|
||||
gugun: firstConcreteSggOption.gugun,
|
||||
|
||||
@@ -104,7 +104,7 @@ function safeGridViewRefresh(gv: { refresh?: () => void } | null | undefined) {
|
||||
try {
|
||||
gv.refresh();
|
||||
} catch {
|
||||
/* noop */
|
||||
console.error('refresh error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ function setRowCheckByItemIndex(
|
||||
try {
|
||||
gv?.checkItem?.(itemIndex, checked, false);
|
||||
} catch {
|
||||
/* RealGrid 체크 API 미지원 등 */
|
||||
console.error('RealGrid 체크 API error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ function uncheckGridRow(gridRef: MutableRefObject<RealGridReact | null>, itemInd
|
||||
try {
|
||||
(gridRef.current?.gridView as GridViewWithCheckApi | undefined)?.checkItem?.(itemIndex, false, false);
|
||||
} catch {
|
||||
/* ignore */
|
||||
console.error('RealGrid 체크 API error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,7 @@ import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import type {
|
||||
SeweragePipeInputFactInstallStatusSaveRequest,
|
||||
SeweragePipeInputFactInstallStatusSubmitRequest,
|
||||
SeweragePipeInputManholeStatusItem,
|
||||
SeweragePipeInputManholeStatusSaveRequest,
|
||||
SeweragePipeInputManholeStatusSaveYearlyStatItem,
|
||||
SeweragePipeInputManholeStatusSubmitRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSaveRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSubmitRequest,
|
||||
@@ -221,11 +219,6 @@ const applyPipeTypeStatusEditableColumns = (
|
||||
});
|
||||
};
|
||||
|
||||
const getManholeLastDataYear = () => {
|
||||
const lastDataYear = new Date().getFullYear() - 1;
|
||||
return Math.max(2014, lastDataYear);
|
||||
};
|
||||
|
||||
/** 2-3 관종별: verificationResult.prlgWhol → 총계 계(pipeByPrstWhol) */
|
||||
function remapPipeTypePrlgWholVerification(
|
||||
result?: SeweragePipeInputVerificationResult | null,
|
||||
@@ -280,43 +273,6 @@ function normalizePipeTypeStatusRow(
|
||||
};
|
||||
}
|
||||
|
||||
/** 맨홀 신 응답(yearlyStats) -> 그리드 yy{14..25}* 필드로 정규화 */
|
||||
function normalizeManholeStatusRow(
|
||||
row: SeweragePipeInputManholeStatusItem,
|
||||
ctpvNm: string,
|
||||
): Record<string, string | number | SeweragePipeInputVerificationResult | undefined> {
|
||||
const maxYy = getManholeLastDataYear() % 100;
|
||||
const { yearlyStats, ...rest } = row;
|
||||
const yearFields: Record<string, number> = {};
|
||||
for (let yy = 14; yy <= maxYy; yy++) {
|
||||
yearFields[`yy${yy}WholMnhlCnt`] = 0;
|
||||
yearFields[`yy${yy}Step1MnhlCnt`] = 0;
|
||||
yearFields[`yy${yy}Step2MnhlCnt`] = 0;
|
||||
yearFields[`yy${yy}Step3MnhlCnt`] = 0;
|
||||
yearFields[`yy${yy}Step4MnhlCnt`] = 0;
|
||||
yearFields[`yy${yy}Step5MnhlCnt`] = 0;
|
||||
}
|
||||
|
||||
for (const y of yearlyStats ?? []) {
|
||||
const year = Number(y.manhYr);
|
||||
if (!Number.isFinite(year)) continue;
|
||||
const yy = year % 100;
|
||||
if (yy < 14 || yy > maxYy) continue;
|
||||
yearFields[`yy${yy}WholMnhlCnt`] = Number(y.wholMnhlCnt ?? 0);
|
||||
yearFields[`yy${yy}Step1MnhlCnt`] = Number(y.step1MnhlCnt ?? 0);
|
||||
yearFields[`yy${yy}Step2MnhlCnt`] = Number(y.step2MnhlCnt ?? 0);
|
||||
yearFields[`yy${yy}Step3MnhlCnt`] = Number(y.step3MnhlCnt ?? 0);
|
||||
yearFields[`yy${yy}Step4MnhlCnt`] = Number(y.step4MnhlCnt ?? 0);
|
||||
yearFields[`yy${yy}Step5MnhlCnt`] = Number(y.step5MnhlCnt ?? 0);
|
||||
}
|
||||
|
||||
return {
|
||||
ctpvNm,
|
||||
...rest,
|
||||
...yearFields,
|
||||
};
|
||||
}
|
||||
|
||||
/** ST00020006(연결)은 행이 좌·우 그리드 키에만 있음 */
|
||||
type GridRowWithVerification = Record<string, string | number> & {
|
||||
verificationResult?: SeweragePipeInputVerificationResult;
|
||||
@@ -884,9 +840,10 @@ const SewagePipeInp = () => {
|
||||
const response = await statisticsInputSewPipeApiService.getManholeStatus(searchParam);
|
||||
if (response.status === 'success') {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const convertedData = filterFetched(response.data.manholeStatusList).map((d) =>
|
||||
normalizeManholeStatusRow(d, commonInfo.ctpvNm),
|
||||
);
|
||||
const convertedData = filterFetched(response.data.manholeStatusList).map((d) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}));
|
||||
applyRowMap((m) => m.set('ST00020005', toGridRows(convertedData)));
|
||||
setTabStatusInfoMap((prev) => new Map(prev).set(tabKey, response.data.statusInfo));
|
||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||
@@ -1434,36 +1391,17 @@ const SewagePipeInp = () => {
|
||||
const decimalPlaces = format.match(/\.(\d+)/)?.[1]?.length ?? 0;
|
||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||
};
|
||||
const minYy = 14;
|
||||
const maxYy = getManholeLastDataYear() % 100;
|
||||
const submitList = currentData.map((d) => {
|
||||
const yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[] = [];
|
||||
for (let yy = minYy; yy <= maxYy; yy++) {
|
||||
const year = 2000 + yy;
|
||||
const wholKey = `yy${yy}WholMnhlCnt`;
|
||||
const step1Key = `yy${yy}Step1MnhlCnt`;
|
||||
const step2Key = `yy${yy}Step2MnhlCnt`;
|
||||
const step3Key = `yy${yy}Step3MnhlCnt`;
|
||||
const step4Key = `yy${yy}Step4MnhlCnt`;
|
||||
const step5Key = `yy${yy}Step5MnhlCnt`;
|
||||
yearlyStats.push({
|
||||
manhYr: String(year),
|
||||
wholMnhlCnt: formatNumber(d[wholKey] as string | number | undefined, wholKey),
|
||||
step1MnhlCnt: formatNumber(d[step1Key] as string | number | undefined, step1Key),
|
||||
step2MnhlCnt: formatNumber(d[step2Key] as string | number | undefined, step2Key),
|
||||
step3MnhlCnt: formatNumber(d[step3Key] as string | number | undefined, step3Key),
|
||||
step4MnhlCnt: formatNumber(d[step4Key] as string | number | undefined, step4Key),
|
||||
step5MnhlCnt: formatNumber(d[step5Key] as string | number | undefined, step5Key),
|
||||
});
|
||||
}
|
||||
return {
|
||||
emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd),
|
||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
||||
yearlyStats,
|
||||
rmrk: nullableTrimmedString(d.rmrk),
|
||||
};
|
||||
});
|
||||
const submitList = currentData.map((d) => ({
|
||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
||||
emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd),
|
||||
frlvlMnhlCnt: formatNumber(d.frlvlMnhlCnt, "frlvlMnhlCnt"),
|
||||
sclvlMnhlCnt: formatNumber(d.sclvlMnhlCnt, "sclvlMnhlCnt"),
|
||||
thlvlMnhlCnt: formatNumber(d.thlvlMnhlCnt, "thlvlMnhlCnt"),
|
||||
folvlMnhlCnt: formatNumber(d.folvlMnhlCnt, "folvlMnhlCnt"),
|
||||
filvlMnhlCnt: formatNumber(d.filvlMnhlCnt, "filvlMnhlCnt"),
|
||||
rmrk: nullableTrimmedString(d.rmrk),
|
||||
}));
|
||||
const requestData: SeweragePipeInputManholeStatusSubmitRequest = {
|
||||
...submitBase,
|
||||
submitList,
|
||||
@@ -1989,37 +1927,17 @@ const SewagePipeInp = () => {
|
||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||
};
|
||||
|
||||
const minYy = 14;
|
||||
const maxYy = getManholeLastDataYear() % 100;
|
||||
|
||||
const saveList = currentData.map((d) => {
|
||||
const yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[] = [];
|
||||
for (let yy = minYy; yy <= maxYy; yy++) {
|
||||
const year = 2000 + yy;
|
||||
const wholKey = `yy${yy}WholMnhlCnt`;
|
||||
const step1Key = `yy${yy}Step1MnhlCnt`;
|
||||
const step2Key = `yy${yy}Step2MnhlCnt`;
|
||||
const step3Key = `yy${yy}Step3MnhlCnt`;
|
||||
const step4Key = `yy${yy}Step4MnhlCnt`;
|
||||
const step5Key = `yy${yy}Step5MnhlCnt`;
|
||||
yearlyStats.push({
|
||||
manhYr: String(year),
|
||||
wholMnhlCnt: formatNumber(d[wholKey] as string | number | undefined, wholKey),
|
||||
step1MnhlCnt: formatNumber(d[step1Key] as string | number | undefined, step1Key),
|
||||
step2MnhlCnt: formatNumber(d[step2Key] as string | number | undefined, step2Key),
|
||||
step3MnhlCnt: formatNumber(d[step3Key] as string | number | undefined, step3Key),
|
||||
step4MnhlCnt: formatNumber(d[step4Key] as string | number | undefined, step4Key),
|
||||
step5MnhlCnt: formatNumber(d[step5Key] as string | number | undefined, step5Key),
|
||||
});
|
||||
}
|
||||
return {
|
||||
emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd),
|
||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
||||
yearlyStats,
|
||||
rmrk: nullableTrimmedString(d.rmrk),
|
||||
};
|
||||
});
|
||||
const saveList = currentData.map((d) => ({
|
||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
||||
emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd),
|
||||
frlvlMnhlCnt: formatNumber(d.frlvlMnhlCnt, "frlvlMnhlCnt"),
|
||||
sclvlMnhlCnt: formatNumber(d.sclvlMnhlCnt, "sclvlMnhlCnt"),
|
||||
thlvlMnhlCnt: formatNumber(d.thlvlMnhlCnt, "thlvlMnhlCnt"),
|
||||
folvlMnhlCnt: formatNumber(d.folvlMnhlCnt, "folvlMnhlCnt"),
|
||||
filvlMnhlCnt: formatNumber(d.filvlMnhlCnt, "filvlMnhlCnt"),
|
||||
rmrk: nullableTrimmedString(d.rmrk),
|
||||
}));
|
||||
|
||||
const userInfo = await getUserInfo();
|
||||
const param: SeweragePipeInputManholeStatusSaveRequest = {
|
||||
|
||||
@@ -103,7 +103,7 @@ export function ReviewOpinionDialog({
|
||||
resetForm();
|
||||
onOpenChange(false);
|
||||
} catch {
|
||||
/* 저장 실패 시 부모에서 alert 후 throw — 다이얼로그는 유지 */
|
||||
console.error('검토 의견 저장 error');
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import type {
|
||||
ColumnLayoutItem,
|
||||
} from "@/components/type/DataGrid.type";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { getST00020003RvwConfig, getST00020005RvwConfig,SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn";
|
||||
import { getST00020003RvwConfig,SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||
|
||||
@@ -151,11 +151,9 @@ const SewagePipeRvw = () => {
|
||||
() => {
|
||||
const statsYr = lastSearchValues?.year ?? new Date().getFullYear();
|
||||
const st00020003Config = getST00020003RvwConfig(statsYr);
|
||||
const st00020005Config = getST00020005RvwConfig(statsYr);
|
||||
return SewagePipeColumnInfoListRvw.map((tab) => {
|
||||
const source =
|
||||
tab.tabKey === "ST00020003" ? st00020003Config
|
||||
: tab.tabKey === "ST00020005" ? st00020005Config
|
||||
: tab;
|
||||
return {
|
||||
...source,
|
||||
|
||||
@@ -11,7 +11,7 @@ import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { getST00020003Config, getST00020005Config,SewagePipeColumnInfoListTot } from "@/components/util/column/total/SewagePipeTotColumn";
|
||||
import { getST00020003Config, SewagePipeColumnInfoListTot } from "@/components/util/column/total/SewagePipeTotColumn";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
|
||||
const firstTabKey = SewagePipeColumnInfoListTot[0]?.tabKey ?? "ST00020001";
|
||||
@@ -205,12 +205,10 @@ const SewagePipeTot = () => {
|
||||
{columnInfo.map((info) => {
|
||||
const tabKey = info.tabKey;
|
||||
|
||||
// ★ [동적 처리] ST00020003·ST00020005는 함수를 통해 컬럼 정보를 실시간으로 생성
|
||||
// ★ [동적 처리] ST00020003은 함수를 통해 컬럼 정보를 실시간으로 생성
|
||||
const currentYear = lastSearchedValuesRef.current?.year || new Date().getFullYear();
|
||||
const finalTabConfig =
|
||||
tabKey === "ST00020003" ? getST00020003Config(currentYear) :
|
||||
tabKey === "ST00020005" ? getST00020005Config(currentYear) :
|
||||
info;
|
||||
tabKey === "ST00020003" ? getST00020003Config(currentYear) : info;
|
||||
|
||||
if (!finalTabConfig.columns || !finalTabConfig.columnLayout) {
|
||||
return null;
|
||||
|
||||
@@ -9,7 +9,12 @@ import { useAlertStore } from "@/shared/lib";
|
||||
import { NoData } from "@/shared/ui/no-data";
|
||||
import { CodeSelectWithAll } from "@/entities/code";
|
||||
import { generalverificationApiService } from "@/entities/statistics/api/general-verification-service";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import type { GeneralverificationList } from "@/entities/statistics/model/general-verification-interface";
|
||||
import {
|
||||
getInputPeriodVerificationManageBlockedMessage,
|
||||
isInputPeriodCurrent,
|
||||
} from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||
import {
|
||||
Button,
|
||||
DataTable,
|
||||
@@ -47,6 +52,10 @@ const GeneralVerificationManagement = () => {
|
||||
const [isExporting, setIsExporting] = useState<boolean>(false);
|
||||
const [selectedVrfcRow, setSelectedVrfcRow] = useState<number | null>(null);
|
||||
const [showRegistForm, setShowRegistForm] = useState<boolean>(false);
|
||||
const [inputPeriodBlocked, setInputPeriodBlocked] = useState(false);
|
||||
const [inputPeriodBlockedMessage, setInputPeriodBlockedMessage] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
|
||||
@@ -91,8 +100,18 @@ const GeneralVerificationManagement = () => {
|
||||
};
|
||||
|
||||
const columns = useMemo(
|
||||
() => getGeneralVerificationColumns(() => handleSearch()),
|
||||
[searchValues.statsCd, searchValues.vrfcClsfCd, searchValues.useYn],
|
||||
() =>
|
||||
getGeneralVerificationColumns(() => handleSearch(), {
|
||||
mutationBlocked: inputPeriodBlocked,
|
||||
blockedMessage: inputPeriodBlockedMessage,
|
||||
}),
|
||||
[
|
||||
searchValues.statsCd,
|
||||
searchValues.vrfcClsfCd,
|
||||
searchValues.useYn,
|
||||
inputPeriodBlocked,
|
||||
inputPeriodBlockedMessage,
|
||||
],
|
||||
);
|
||||
|
||||
const table = useReactTable({
|
||||
@@ -162,6 +181,24 @@ const GeneralVerificationManagement = () => {
|
||||
|
||||
useEffect(() => {
|
||||
void handleSearch();
|
||||
void (async () => {
|
||||
try {
|
||||
const statsYr = String(new Date().getFullYear() - 1);
|
||||
const response =
|
||||
await statisticsInputSewSupplyRateApi.checkInputPeriod(statsYr);
|
||||
if (response.status !== "success") return;
|
||||
const blocked = isInputPeriodCurrent(response.data);
|
||||
setInputPeriodBlocked(blocked);
|
||||
setInputPeriodBlockedMessage(
|
||||
blocked
|
||||
? getInputPeriodVerificationManageBlockedMessage(response.data)
|
||||
: null,
|
||||
);
|
||||
} catch {
|
||||
setInputPeriodBlocked(false);
|
||||
setInputPeriodBlockedMessage(null);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@@ -263,13 +300,25 @@ const GeneralVerificationManagement = () => {
|
||||
<i className="diveicon di-file-excel" />
|
||||
<span>내보내기</span>
|
||||
</Button>
|
||||
<RegistDialog
|
||||
open={showRegistForm}
|
||||
onOpenChange={setShowRegistForm}
|
||||
onSuccess={() => void handleSearch()}
|
||||
>
|
||||
<Button>등록</Button>
|
||||
</RegistDialog>
|
||||
{inputPeriodBlocked ? (
|
||||
<span
|
||||
title={
|
||||
inputPeriodBlockedMessage ?? undefined
|
||||
}
|
||||
>
|
||||
<Button disabled type="button">
|
||||
등록
|
||||
</Button>
|
||||
</span>
|
||||
) : (
|
||||
<RegistDialog
|
||||
open={showRegistForm}
|
||||
onOpenChange={setShowRegistForm}
|
||||
onSuccess={() => void handleSearch()}
|
||||
>
|
||||
<Button>등록</Button>
|
||||
</RegistDialog>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !mx-2 !my-4 h-full overflow-auto !p-0">
|
||||
@@ -294,7 +343,11 @@ const GeneralVerificationManagement = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<DetailComponent selectedVrfcRow={selectedVrfcRow} />
|
||||
<DetailComponent
|
||||
selectedVrfcRow={selectedVrfcRow}
|
||||
mutationBlocked={inputPeriodBlocked}
|
||||
blockedMessage={inputPeriodBlockedMessage}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
+76
-2
@@ -391,9 +391,15 @@ const buildRuleBlocksFromFormulas = (
|
||||
|
||||
interface DetailComponentProps {
|
||||
selectedVrfcRow: number | null;
|
||||
mutationBlocked?: boolean;
|
||||
blockedMessage?: string | null;
|
||||
}
|
||||
|
||||
const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
const DetailComponent = ({
|
||||
selectedVrfcRow,
|
||||
mutationBlocked = false,
|
||||
blockedMessage = null,
|
||||
}: DetailComponentProps) => {
|
||||
const [detailInfo, setDetailInfo] = useState<VerifyDetailData | null>(null);
|
||||
/** 수식 / 조건·논리 연산자를 순서대로 담는 UI 블록 (서로 강제 교차하지 않음) */
|
||||
const [ruleBlocks, setRuleBlocks] = useState<RuleBlock[]>([
|
||||
@@ -487,6 +493,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
};
|
||||
|
||||
const handleSaveClick = async () => {
|
||||
if (mutationBlocked) {
|
||||
alert(
|
||||
blockedMessage ??
|
||||
"입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
const trgtStatsCd = detailInfo?.commonInfo.trgtStatsCd;
|
||||
if (!trgtStatsCd) {
|
||||
alert("대상 통계항목(trgtStatsCd) 정보가 없습니다.");
|
||||
@@ -623,6 +636,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
formula?: VerifyDetailResponseDto | null,
|
||||
blockId?: string,
|
||||
) => {
|
||||
if (mutationBlocked) {
|
||||
alert(
|
||||
blockedMessage ??
|
||||
"입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
setSelectedFormula(formula ?? null);
|
||||
setSelectedFormulaBlockId(blockId ?? null);
|
||||
setShowFomulaDialog(true);
|
||||
@@ -671,6 +691,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
};
|
||||
|
||||
const handleResetClick = async () => {
|
||||
if (mutationBlocked) {
|
||||
alert(
|
||||
blockedMessage ??
|
||||
"입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
const currentSignature = JSON.stringify(
|
||||
normalizeFormulaListForCompare(formulaList, groupByFlags),
|
||||
);
|
||||
@@ -689,6 +716,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
};
|
||||
|
||||
const handleAddClause = () => {
|
||||
if (mutationBlocked) {
|
||||
alert(
|
||||
blockedMessage ??
|
||||
"입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
setRuleBlocks((prev) => [
|
||||
...prev,
|
||||
{
|
||||
@@ -702,6 +736,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
|
||||
/** 항상 목록 맨 뒤(마지막 수식 뒤 포함)에 조건·논리 연산자 Select 추가 */
|
||||
const handleAddConnector = () => {
|
||||
if (mutationBlocked) {
|
||||
alert(
|
||||
blockedMessage ??
|
||||
"입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (connectorOperators.length === 0) {
|
||||
alert("조건·논리 연산자 목록을 불러오지 못했습니다.");
|
||||
return;
|
||||
@@ -720,6 +761,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
};
|
||||
|
||||
const handleRemoveBlock = (blockId: string) => {
|
||||
if (mutationBlocked) {
|
||||
alert(
|
||||
blockedMessage ??
|
||||
"입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
setRuleBlocks((prev) => {
|
||||
const next = prev.filter((b) => b.id !== blockId);
|
||||
if (next.some((b) => b.kind === "formula")) return next;
|
||||
@@ -831,6 +879,7 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
<div className="h-px flex-1 bg-[#e2e5ea]" />
|
||||
<Select
|
||||
value={block.value}
|
||||
disabled={mutationBlocked}
|
||||
onValueChange={(v) => {
|
||||
setRuleBlocks(
|
||||
(prev) => {
|
||||
@@ -907,6 +956,7 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
size="icon"
|
||||
color="red"
|
||||
className="size-[3.2rem] shrink-0 rounded-full"
|
||||
disabled={mutationBlocked}
|
||||
onClick={() =>
|
||||
handleRemoveBlock(
|
||||
block.id,
|
||||
@@ -933,6 +983,7 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
blockIndex,
|
||||
)}
|
||||
groupBy={block.groupBy}
|
||||
disabled={mutationBlocked}
|
||||
onGroupByChange={(
|
||||
checked,
|
||||
) => {
|
||||
@@ -1045,6 +1096,12 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
<Button
|
||||
type="button"
|
||||
className="h-[3.6rem] gap-1.5 px-4"
|
||||
disabled={mutationBlocked}
|
||||
title={
|
||||
mutationBlocked
|
||||
? (blockedMessage ?? undefined)
|
||||
: undefined
|
||||
}
|
||||
onClick={handleAddClause}
|
||||
>
|
||||
<i className="ri-play-list-add-fill text-[16px]" />
|
||||
@@ -1054,6 +1111,12 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
type="button"
|
||||
color="gray"
|
||||
className="h-[3.6rem] gap-1.5 px-4"
|
||||
disabled={mutationBlocked}
|
||||
title={
|
||||
mutationBlocked
|
||||
? (blockedMessage ?? undefined)
|
||||
: undefined
|
||||
}
|
||||
onClick={handleAddConnector}
|
||||
>
|
||||
<i className="ri-git-commit-line text-[16px]" />
|
||||
@@ -1083,13 +1146,24 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
<Button
|
||||
type="button"
|
||||
color="red"
|
||||
title="리셋"
|
||||
title={
|
||||
mutationBlocked
|
||||
? (blockedMessage ?? "리셋")
|
||||
: "리셋"
|
||||
}
|
||||
disabled={mutationBlocked}
|
||||
onClick={handleResetClick}
|
||||
>
|
||||
<i className="diveicon di-arrow-reset" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={mutationBlocked}
|
||||
title={
|
||||
mutationBlocked
|
||||
? (blockedMessage ?? undefined)
|
||||
: undefined
|
||||
}
|
||||
onClick={handleSaveClick}
|
||||
>
|
||||
등록
|
||||
|
||||
+11
-2
@@ -19,6 +19,7 @@ interface FormulaComponentsProps {
|
||||
index?: number,
|
||||
) => void;
|
||||
vrfcClsfCd?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const zoneClassName: Record<ClauseZone, string> = {
|
||||
@@ -45,6 +46,7 @@ const FormulaComponents = ({
|
||||
onOperatorChange,
|
||||
handleFomulaDialog,
|
||||
vrfcClsfCd,
|
||||
disabled = false,
|
||||
}: FormulaComponentsProps) => {
|
||||
const cmprOpert = data?.cmprOpert;
|
||||
const displayFormula = data
|
||||
@@ -60,6 +62,7 @@ const FormulaComponents = ({
|
||||
size="icon"
|
||||
className="formulaDeleteBtn size-[2.6rem] shrink-0 rounded-full !bg-[#f24e5b] hover:!bg-[#d63c48]"
|
||||
color="red"
|
||||
disabled={disabled}
|
||||
onClick={onDelete}
|
||||
>
|
||||
<i className="ri-subtract-fill text-[16px]" />
|
||||
@@ -70,21 +73,27 @@ const FormulaComponents = ({
|
||||
id={`formulaInput-${index ?? 0}`}
|
||||
value={displayFormula}
|
||||
title={displayFormula}
|
||||
onClick={() => handleFomulaDialog?.(true, data, index)}
|
||||
onClick={() => {
|
||||
if (disabled) return;
|
||||
handleFomulaDialog?.(true, data, index);
|
||||
}}
|
||||
readOnly
|
||||
disabled={disabled}
|
||||
/>
|
||||
<div className="w-[200px] shrink-0 [&_button]:!h-[3.6rem] [&_button]:!w-[200px] [&_button]:min-w-[200px] [&_button]:max-w-[200px]">
|
||||
<OperatorsComponents
|
||||
cmprOpert={cmprOpert}
|
||||
onValueChange={onOperatorChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
{vrfcClsfCd !== "TOTAL" &&
|
||||
<label className="flex w-[96px] shrink-0 items-center justify-end gap-1.5 text-[#4b5563] cursor-pointer">
|
||||
<label className={`flex w-[96px] shrink-0 items-center justify-end gap-1.5 text-[#4b5563] ${disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"}`}>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="cursor-pointer accent-[#3a6df0]"
|
||||
checked={groupBy}
|
||||
disabled={disabled}
|
||||
onChange={(e) => onGroupByChange?.(e.target.checked)}
|
||||
/>
|
||||
group by
|
||||
|
||||
+4
-1
@@ -26,13 +26,15 @@ interface OperatorsComponentsProps {
|
||||
onValueChange?: (value: string) => void;
|
||||
placeholder?: string;
|
||||
opertSeCd?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const OperatorsComponents = ({
|
||||
cmprOpert,
|
||||
onValueChange,
|
||||
placeholder = "연산자 없음",
|
||||
opertSeCd = "opertSeCd=CMPR"
|
||||
opertSeCd = "opertSeCd=CMPR",
|
||||
disabled = false,
|
||||
}: OperatorsComponentsProps) => {
|
||||
const [operators, setOperators] = useState<OperatorItem[]>([]);
|
||||
const [localValue, setLocalValue] = useState<string>(cmprOpert ?? "");
|
||||
@@ -75,6 +77,7 @@ const OperatorsComponents = ({
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
onValueChange={(v) => {
|
||||
setLocalValue(v);
|
||||
onValueChange?.(v);
|
||||
|
||||
+32
-8
@@ -50,6 +50,9 @@ interface RegistDialogProps {
|
||||
vrfcSn?: number;
|
||||
/** 수정/등록 성공 시 부모에서 목록 재조회 등 실행 */
|
||||
onSuccess?: () => void;
|
||||
/** 입력기간이면 수정 불가(삭제는 가능) */
|
||||
mutationBlocked?: boolean;
|
||||
blockedMessage?: string | null;
|
||||
}
|
||||
|
||||
const RegistDialog = memo(
|
||||
@@ -59,10 +62,13 @@ const RegistDialog = memo(
|
||||
onOpenChange,
|
||||
vrfcSn,
|
||||
onSuccess,
|
||||
mutationBlocked = false,
|
||||
blockedMessage = null,
|
||||
...props
|
||||
}: RegistDialogProps) => {
|
||||
|
||||
const isVrfcSn = vrfcSn != null;
|
||||
const editBlocked = mutationBlocked && isVrfcSn;
|
||||
const [checkVrfcNm, setCheckVrfcNm] = useState<boolean>(false);
|
||||
const { confirm } = useConfirm();
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
@@ -219,6 +225,13 @@ const RegistDialog = memo(
|
||||
}, [vrfcNm, open, isVrfcSn]);
|
||||
|
||||
const onSubmit = async (data: GeneralVerificationMasterSubmitFormData) => {
|
||||
if (mutationBlocked) {
|
||||
alert(
|
||||
blockedMessage ??
|
||||
"입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
const currentVrfcNm = (data.vrfcNm ?? '').trim();
|
||||
const originalVrfcNm = originalVrfcNmRef.current;
|
||||
|
||||
@@ -321,7 +334,7 @@ const RegistDialog = memo(
|
||||
onValueChange={field.onChange}
|
||||
placeholder="전체"
|
||||
className="w-[16rem]"
|
||||
disabled={isVrfcSn}
|
||||
disabled={isVrfcSn || editBlocked}
|
||||
/>
|
||||
</FormControl>
|
||||
{form.formState.errors.trgtStatsCd && (
|
||||
@@ -348,7 +361,7 @@ const RegistDialog = memo(
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="검증명을 입력해주세요"
|
||||
disabled={(trgtStatsCd ?? '') === ''}
|
||||
disabled={editBlocked || (trgtStatsCd ?? '') === ''}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -380,6 +393,7 @@ const RegistDialog = memo(
|
||||
<Select
|
||||
value={field.value ?? ""}
|
||||
onValueChange={field.onChange}
|
||||
disabled={editBlocked}
|
||||
>
|
||||
<SelectTrigger className="w-[10rem]">
|
||||
<SelectValue placeholder="선택" />
|
||||
@@ -416,6 +430,7 @@ const RegistDialog = memo(
|
||||
placeholder="소수점자리수를 입력해주세요"
|
||||
type="number"
|
||||
min={0}
|
||||
disabled={editBlocked}
|
||||
/>
|
||||
</FormControl>
|
||||
<p className="text-gray-500 text-base !mt-0">
|
||||
@@ -443,7 +458,7 @@ const RegistDialog = memo(
|
||||
<Select
|
||||
value={field.value ?? ""}
|
||||
onValueChange={field.onChange}
|
||||
disabled={Number(dcptDigtCnt ?? 0) === 0}
|
||||
disabled={editBlocked || Number(dcptDigtCnt ?? 0) === 0}
|
||||
>
|
||||
<SelectTrigger className="w-[10rem]">
|
||||
<SelectValue placeholder="선택" />
|
||||
@@ -484,13 +499,14 @@ const RegistDialog = memo(
|
||||
{...field}
|
||||
name="useYn"
|
||||
onValueChange={field.onChange}
|
||||
disabled={editBlocked}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<RadioGroupItem value="Y" id="useY" disabled={editBlocked} />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<RadioGroupItem value="N" id="useN" disabled={editBlocked} />
|
||||
<Label htmlFor="useN">사용안함</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
@@ -599,9 +615,17 @@ const RegistDialog = memo(
|
||||
삭제
|
||||
</Button>
|
||||
}
|
||||
<Button size="lg" type="submit">
|
||||
{vrfcSn != null ? '수정' : '등록'}
|
||||
</Button>
|
||||
{editBlocked ? (
|
||||
<span title={blockedMessage ?? undefined}>
|
||||
<Button size="lg" type="submit" disabled>
|
||||
수정
|
||||
</Button>
|
||||
</span>
|
||||
) : (
|
||||
<Button size="lg" type="submit">
|
||||
{vrfcSn != null ? '수정' : '등록'}
|
||||
</Button>
|
||||
)}
|
||||
<DialogClose asChild>
|
||||
<Button size="lg" color="white">
|
||||
취소
|
||||
|
||||
@@ -5,130 +5,18 @@ import { footerInt } from "@/components/util/grid/footerSummary";
|
||||
|
||||
// 하수도 통계 관리 > 02.하수관로 > tab 5. 맨홀 현황
|
||||
// SeweragePipeInputManholeStatusItem + commonInfo.ctpvNm (그리드 행에 병합)
|
||||
// API: yy14=2015년 이전(2014년 데이터) … yy{(현재연도-1)%100} (필드 접두 yy + 연도 끝자리)
|
||||
|
||||
const MANHOLE_START_YEAR = 2014;
|
||||
const MANHOLE_LAST_DATA_YEAR = Math.max(MANHOLE_START_YEAR, new Date().getFullYear() - 1);
|
||||
const MANHOLE_YY_MIN = MANHOLE_START_YEAR % 100;
|
||||
const MANHOLE_YY_MAX = MANHOLE_LAST_DATA_YEAR % 100;
|
||||
const calendarYearFromYy = (yy: number) => 2000 + yy;
|
||||
|
||||
/** yy14(2014) 구간은 헤더에 「2015년 이전」 표기 (합계·검토 컬럼과 동일) */
|
||||
const manholeYearHeaderText = (yy: number): string => {
|
||||
const y = calendarYearFromYy(yy);
|
||||
return y === MANHOLE_START_YEAR ? "2015년 이전" : `${y}년`;
|
||||
};
|
||||
|
||||
const intCol = (name: string, headerText: string): ColumnConfig => ({
|
||||
const intCol = (name: string, headerText: string, editable = true): ColumnConfig => ({
|
||||
name,
|
||||
fieldName: name,
|
||||
header: { text: headerText },
|
||||
footer: footerInt,
|
||||
// editable: false,
|
||||
editable,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: "#,##0",
|
||||
...(editable ? {} : { styleName: "rg-cell-total" }),
|
||||
});
|
||||
|
||||
const yearlySumFields = (suffix: "WholMnhlCnt" | "Step1MnhlCnt" | "Step2MnhlCnt" | "Step3MnhlCnt" | "Step4MnhlCnt" | "Step5MnhlCnt") =>
|
||||
Array.from({ length: MANHOLE_YY_MAX - MANHOLE_YY_MIN + 1 }, (_, i) => `yy${MANHOLE_YY_MIN + i}${suffix}`);
|
||||
|
||||
function totalBlockColumns(): ColumnConfig[] {
|
||||
return [
|
||||
{
|
||||
...intCol("totalWholMnhlCnt", "계"),
|
||||
styleName: "rg-cell-total",
|
||||
editable: false,
|
||||
computed: { fields: yearlySumFields("WholMnhlCnt"), type: "sum" as const },
|
||||
},
|
||||
{
|
||||
...intCol("totalStep1MnhlCnt", "주철"),
|
||||
styleName: "rg-cell-total",
|
||||
editable: false,
|
||||
computed: { fields: yearlySumFields("Step1MnhlCnt"), type: "sum" as const },
|
||||
},
|
||||
{
|
||||
...intCol("totalStep2MnhlCnt", "주철(조화)"),
|
||||
styleName: "rg-cell-total",
|
||||
editable: false,
|
||||
computed: { fields: yearlySumFields("Step2MnhlCnt"), type: "sum" as const },
|
||||
},
|
||||
{
|
||||
...intCol("totalStep3MnhlCnt", "콘크리트"),
|
||||
styleName: "rg-cell-total",
|
||||
editable: false,
|
||||
computed: { fields: yearlySumFields("Step3MnhlCnt"), type: "sum" as const },
|
||||
},
|
||||
{
|
||||
...intCol("totalStep4MnhlCnt", "기타"),
|
||||
styleName: "rg-cell-total",
|
||||
editable: false,
|
||||
computed: { fields: yearlySumFields("Step4MnhlCnt"), type: "sum" as const },
|
||||
},
|
||||
{
|
||||
...intCol("totalStep5MnhlCnt", "추락방지시설설치맨홀(개)"),
|
||||
styleName: "rg-cell-total",
|
||||
editable: false,
|
||||
computed: { fields: yearlySumFields("Step5MnhlCnt"), type: "sum" as const },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function yyBlockColumns(yy: number): ColumnConfig[] {
|
||||
const p = `yy${yy}`;
|
||||
return [
|
||||
{
|
||||
...intCol(`${p}WholMnhlCnt`, "계"),
|
||||
styleName: "rg-cell-total",
|
||||
editable: false,
|
||||
computed: {
|
||||
fields: [
|
||||
`${p}Step1MnhlCnt`,
|
||||
`${p}Step2MnhlCnt`,
|
||||
`${p}Step3MnhlCnt`,
|
||||
`${p}Step4MnhlCnt`,
|
||||
`${p}Step5MnhlCnt`,
|
||||
],
|
||||
type: "sum" as const,
|
||||
},
|
||||
},
|
||||
intCol(`${p}Step1MnhlCnt`, "주철"),
|
||||
intCol(`${p}Step2MnhlCnt`, "주철(조화)"),
|
||||
intCol(`${p}Step3MnhlCnt`, "콘크리트"),
|
||||
intCol(`${p}Step4MnhlCnt`, "기타"),
|
||||
intCol(`${p}Step5MnhlCnt`, "추락방지시설설치맨홀(개)"),
|
||||
];
|
||||
}
|
||||
|
||||
function yyYearLayout(yy: number): ColumnLayoutItem {
|
||||
const y = calendarYearFromYy(yy);
|
||||
const p = `yy${yy}`;
|
||||
return {
|
||||
name: `year${y}`,
|
||||
hideChildHeaders: false,
|
||||
header: { text: manholeYearHeaderText(yy) },
|
||||
items: [
|
||||
{
|
||||
name: `year${y}Material`,
|
||||
hideChildHeaders: false,
|
||||
header: { text: "맨홀뚜껑 재질(개)" },
|
||||
items: [
|
||||
`${p}WholMnhlCnt`,
|
||||
`${p}Step1MnhlCnt`,
|
||||
`${p}Step2MnhlCnt`,
|
||||
`${p}Step3MnhlCnt`,
|
||||
`${p}Step4MnhlCnt`,
|
||||
],
|
||||
},
|
||||
`${p}Step5MnhlCnt`,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const yearLayoutItems: ColumnLayoutItem[] = [];
|
||||
for (let yy = MANHOLE_YY_MIN; yy <= MANHOLE_YY_MAX; yy++) {
|
||||
yearLayoutItems.push(yyYearLayout(yy));
|
||||
}
|
||||
|
||||
export const ManholeStatusInpColumn = {
|
||||
columns: [
|
||||
{
|
||||
@@ -160,12 +48,19 @@ export const ManholeStatusInpColumn = {
|
||||
editable: false,
|
||||
styleName: "rg-cell-readonly",
|
||||
footer: { text: "합계" },
|
||||
// editable: false,
|
||||
},
|
||||
...totalBlockColumns(),
|
||||
...Array.from({ length: MANHOLE_YY_MAX - MANHOLE_YY_MIN + 1 }, (_, i) =>
|
||||
yyBlockColumns(MANHOLE_YY_MIN + i)
|
||||
).flat(),
|
||||
{
|
||||
...intCol("wholMnhlCnt", "계", false),
|
||||
computed: {
|
||||
fields: ["frlvlMnhlCnt", "sclvlMnhlCnt", "thlvlMnhlCnt", "folvlMnhlCnt"],
|
||||
type: "sum" as const,
|
||||
},
|
||||
},
|
||||
intCol("frlvlMnhlCnt", "주철"),
|
||||
intCol("sclvlMnhlCnt", "주철(조화)"),
|
||||
intCol("thlvlMnhlCnt", "콘크리트"),
|
||||
intCol("folvlMnhlCnt", "기타"),
|
||||
intCol("filvlMnhlCnt", "추락방지시설설치맨홀(개)"),
|
||||
{ name: "rmrk", fieldName: "rmrk", header: { text: "비고" } },
|
||||
{
|
||||
name: "admdstCd",
|
||||
@@ -194,31 +89,17 @@ export const ManholeStatusInpColumn = {
|
||||
"admdstNm",
|
||||
"emphsMngSeNm",
|
||||
{
|
||||
name: "yearlyTotal",
|
||||
name: "mtrlGroup",
|
||||
hideChildHeaders: false,
|
||||
header: { text: "연도별총계" },
|
||||
items: [
|
||||
{
|
||||
name: "yearlyTotalMaterial",
|
||||
hideChildHeaders: false,
|
||||
header: { text: "맨홀뚜껑 재질(개)" },
|
||||
items: [
|
||||
"totalWholMnhlCnt",
|
||||
"totalStep1MnhlCnt",
|
||||
"totalStep2MnhlCnt",
|
||||
"totalStep3MnhlCnt",
|
||||
"totalStep4MnhlCnt",
|
||||
],
|
||||
},
|
||||
"totalStep5MnhlCnt",
|
||||
],
|
||||
header: { text: "맨홀뚜껑 재질(개)" },
|
||||
items: ["wholMnhlCnt", "frlvlMnhlCnt", "sclvlMnhlCnt", "thlvlMnhlCnt", "folvlMnhlCnt"],
|
||||
},
|
||||
...yearLayoutItems,
|
||||
"filvlMnhlCnt",
|
||||
"rmrk",
|
||||
"admdstCd",
|
||||
"emphsMngSeCd",
|
||||
] as ColumnLayoutItem[],
|
||||
rowStartNum: 3,
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 2,
|
||||
tabKey: "ST00020005",
|
||||
tabLabel: "맨홀 현황",
|
||||
|
||||
@@ -11,6 +11,7 @@ import RegistDialog from "@/components/statistics/verification/generalVerificati
|
||||
|
||||
export const getGeneralVerificationColumns = (
|
||||
onUpdateSuccess?: () => void,
|
||||
options?: { mutationBlocked?: boolean; blockedMessage?: string | null },
|
||||
): ColumnDef<GeneralverificationList>[] => [
|
||||
{
|
||||
id: "no",
|
||||
@@ -53,6 +54,8 @@ export const getGeneralVerificationColumns = (
|
||||
<GeneralVerificationCopyButton
|
||||
row={row.original}
|
||||
onSuccess={onUpdateSuccess}
|
||||
mutationBlocked={options?.mutationBlocked}
|
||||
blockedMessage={options?.blockedMessage}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
@@ -65,6 +68,8 @@ export const getGeneralVerificationColumns = (
|
||||
<GeneralVerificationManageButton
|
||||
vrfcSn={row.original.vrfcSn}
|
||||
onSuccess={onUpdateSuccess}
|
||||
mutationBlocked={options?.mutationBlocked}
|
||||
blockedMessage={options?.blockedMessage}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
@@ -74,9 +79,13 @@ export const getGeneralVerificationColumns = (
|
||||
const GeneralVerificationManageButton = ({
|
||||
vrfcSn,
|
||||
onSuccess,
|
||||
mutationBlocked,
|
||||
blockedMessage,
|
||||
}: {
|
||||
vrfcSn: number;
|
||||
onSuccess?: () => void;
|
||||
mutationBlocked?: boolean;
|
||||
blockedMessage?: string | null;
|
||||
}) => {
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
return (
|
||||
@@ -85,6 +94,8 @@ const GeneralVerificationManageButton = ({
|
||||
onOpenChange={setDialogOpen}
|
||||
vrfcSn={vrfcSn}
|
||||
onSuccess={onSuccess}
|
||||
mutationBlocked={mutationBlocked}
|
||||
blockedMessage={blockedMessage}
|
||||
>
|
||||
<Button size="sm">관리</Button>
|
||||
</RegistDialog>
|
||||
@@ -94,11 +105,24 @@ const GeneralVerificationManageButton = ({
|
||||
const GeneralVerificationCopyButton = ({
|
||||
row,
|
||||
onSuccess,
|
||||
mutationBlocked,
|
||||
blockedMessage,
|
||||
}: {
|
||||
row: GeneralverificationList;
|
||||
onSuccess?: () => void;
|
||||
mutationBlocked?: boolean;
|
||||
blockedMessage?: string | null;
|
||||
}) => {
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
if (mutationBlocked) {
|
||||
return (
|
||||
<span title={blockedMessage ?? undefined}>
|
||||
<Button size="sm" color="white" disabled type="button">
|
||||
복사
|
||||
</Button>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<CopyDialog
|
||||
open={dialogOpen}
|
||||
|
||||
@@ -434,18 +434,16 @@ const rawList = [
|
||||
]
|
||||
},
|
||||
|
||||
// ST00020005 맨홀 현황은 연도 범위가 동적이므로 rawList에 포함하지 않고
|
||||
// getST00020005RvwConfig() 로 런타임에 생성합니다.
|
||||
{
|
||||
tabKey: "ST00020005_PLACEHOLDER",
|
||||
tabLabel: "맨홀 현황",
|
||||
rowStartNum: 3,
|
||||
tabKey: 'ST00020005',
|
||||
tabLabel: '맨홀 현황',
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 3,
|
||||
columns: [
|
||||
{
|
||||
name: "ctpvNm",
|
||||
fieldName: "ctpvNm",
|
||||
header: { text: "시도" },
|
||||
name: 'ctpvNm',
|
||||
fieldName: 'ctpvNm',
|
||||
header: { text: '시도' },
|
||||
mergeCells: true,
|
||||
sortdisable: true,
|
||||
footer: [
|
||||
@@ -455,11 +453,11 @@ const rawList = [
|
||||
const dataSource = grid.getDataSource();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < dataSource.getRowCount(); i++) {
|
||||
const val = dataSource.getValue(i, "displayYear");
|
||||
const val = dataSource.getValue(i, 'displayYear');
|
||||
if (val) uniqueValues.add(String(val));
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + "합계" : "합계";
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -468,18 +466,18 @@ const rawList = [
|
||||
const dataSource = grid.getDataSource();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < dataSource.getRowCount(); i++) {
|
||||
const val = dataSource.getValue(i, "displayYear");
|
||||
const val = dataSource.getValue(i, 'displayYear');
|
||||
if (val) uniqueValues.add(String(val));
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + "합계" : "합계";
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, mergeCells: true, sortdisable: true },
|
||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역명" }, mergeCells: true, sortdisable: true },
|
||||
{ name: "emphsMngSeNm", fieldName: "emphsMngSeNm", header: { text: "집중강우\n중점관리\n구역구분" }, mergeCells: true },
|
||||
{ name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
|
||||
{ name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
|
||||
{ name: 'emphsMngSeNm', fieldName: 'emphsMngSeNm', header: { text: '집중강우\n중점관리\n구역구분' }, mergeCells: true },
|
||||
{
|
||||
name: 'displayYear',
|
||||
fieldName: 'displayYear',
|
||||
@@ -514,233 +512,38 @@ const rawList = [
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{ name: "totalWholMnhlCnt", fieldName: "totalWholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totalStep1MnhlCnt", fieldName: "totalStep1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totalStep2MnhlCnt", fieldName: "totalStep2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totalStep3MnhlCnt", fieldName: "totalStep3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totalStep4MnhlCnt", fieldName: "totalStep4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totalStep5MnhlCnt", fieldName: "totalStep5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2015년 이전 (yy14) ──────────────────────────────────
|
||||
{ name: "yy14WholMnhlCnt", fieldName: "yy14WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step1MnhlCnt", fieldName: "yy14Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step2MnhlCnt", fieldName: "yy14Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step3MnhlCnt", fieldName: "yy14Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step4MnhlCnt", fieldName: "yy14Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step5MnhlCnt", fieldName: "yy14Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2015년 (yy15) ───────────────────────────────────────
|
||||
{ name: "yy15WholMnhlCnt", fieldName: "yy15WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step1MnhlCnt", fieldName: "yy15Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step2MnhlCnt", fieldName: "yy15Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step3MnhlCnt", fieldName: "yy15Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step4MnhlCnt", fieldName: "yy15Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step5MnhlCnt", fieldName: "yy15Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2016년 (yy16) ───────────────────────────────────────
|
||||
{ name: "yy16WholMnhlCnt", fieldName: "yy16WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step1MnhlCnt", fieldName: "yy16Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step2MnhlCnt", fieldName: "yy16Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step3MnhlCnt", fieldName: "yy16Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step4MnhlCnt", fieldName: "yy16Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step5MnhlCnt", fieldName: "yy16Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2017년 (yy17) ───────────────────────────────────────
|
||||
{ name: "yy17WholMnhlCnt", fieldName: "yy17WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step1MnhlCnt", fieldName: "yy17Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step2MnhlCnt", fieldName: "yy17Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step3MnhlCnt", fieldName: "yy17Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step4MnhlCnt", fieldName: "yy17Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step5MnhlCnt", fieldName: "yy17Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2018년 (yy18) ───────────────────────────────────────
|
||||
{ name: "yy18WholMnhlCnt", fieldName: "yy18WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step1MnhlCnt", fieldName: "yy18Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step2MnhlCnt", fieldName: "yy18Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step3MnhlCnt", fieldName: "yy18Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step4MnhlCnt", fieldName: "yy18Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step5MnhlCnt", fieldName: "yy18Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2019년 (yy19) ───────────────────────────────────────
|
||||
{ name: "yy19WholMnhlCnt", fieldName: "yy19WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step1MnhlCnt", fieldName: "yy19Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step2MnhlCnt", fieldName: "yy19Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step3MnhlCnt", fieldName: "yy19Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step4MnhlCnt", fieldName: "yy19Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step5MnhlCnt", fieldName: "yy19Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2020년 (yy20) ───────────────────────────────────────
|
||||
{ name: "yy20WholMnhlCnt", fieldName: "yy20WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step1MnhlCnt", fieldName: "yy20Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step2MnhlCnt", fieldName: "yy20Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step3MnhlCnt", fieldName: "yy20Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step4MnhlCnt", fieldName: "yy20Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step5MnhlCnt", fieldName: "yy20Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2021년 (yy21) ───────────────────────────────────────
|
||||
{ name: "yy21WholMnhlCnt", fieldName: "yy21WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step1MnhlCnt", fieldName: "yy21Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step2MnhlCnt", fieldName: "yy21Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step3MnhlCnt", fieldName: "yy21Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step4MnhlCnt", fieldName: "yy21Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step5MnhlCnt", fieldName: "yy21Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2022년 (yy22) ───────────────────────────────────────
|
||||
{ name: "yy22WholMnhlCnt", fieldName: "yy22WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step1MnhlCnt", fieldName: "yy22Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step2MnhlCnt", fieldName: "yy22Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step3MnhlCnt", fieldName: "yy22Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step4MnhlCnt", fieldName: "yy22Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step5MnhlCnt", fieldName: "yy22Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2023년 (yy23) ───────────────────────────────────────
|
||||
{ name: "yy23WholMnhlCnt", fieldName: "yy23WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step1MnhlCnt", fieldName: "yy23Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step2MnhlCnt", fieldName: "yy23Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step3MnhlCnt", fieldName: "yy23Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step4MnhlCnt", fieldName: "yy23Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step5MnhlCnt", fieldName: "yy23Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2024년 (yy24) ───────────────────────────────────────
|
||||
{ name: "yy24WholMnhlCnt", fieldName: "yy24WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step1MnhlCnt", fieldName: "yy24Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step2MnhlCnt", fieldName: "yy24Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step3MnhlCnt", fieldName: "yy24Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step4MnhlCnt", fieldName: "yy24Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step5MnhlCnt", fieldName: "yy24Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2025년 (yy25) ───────────────────────────────────────
|
||||
{ name: "yy25WholMnhlCnt", fieldName: "yy25WholMnhlCnt", header: { text: "계" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step1MnhlCnt", fieldName: "yy25Step1MnhlCnt", header: { text: "주철" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step2MnhlCnt", fieldName: "yy25Step2MnhlCnt", header: { text: "주철(조화)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step3MnhlCnt", fieldName: "yy25Step3MnhlCnt", header: { text: "콘크리트" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step4MnhlCnt", fieldName: "yy25Step4MnhlCnt", header: { text: "기타" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step5MnhlCnt", fieldName: "yy25Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
{ name: "rmrk", fieldName: "rmrk", header: { text: "비고" }, editable: false },
|
||||
{ name: 'wholMnhlCnt', fieldName: 'wholMnhlCnt', header: { text: '계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'frlvlMnhlCnt', fieldName: 'frlvlMnhlCnt', header: { text: '주철' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sclvlMnhlCnt', fieldName: 'sclvlMnhlCnt', header: { text: '주철(조화)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'thlvlMnhlCnt', fieldName: 'thlvlMnhlCnt', header: { text: '콘크리트' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'folvlMnhlCnt', fieldName: 'folvlMnhlCnt', header: { text: '기타' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'filvlMnhlCnt', fieldName: 'filvlMnhlCnt', header: { text: '추락방지시설\n설치맨홀(개)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
|
||||
],
|
||||
columnLayout: [
|
||||
{
|
||||
name: "addrGroup",
|
||||
header: { text: "행정구역" },
|
||||
name: 'addrGroup',
|
||||
header: { text: '행정구역' },
|
||||
items: [
|
||||
{ column: "ctpvNm", footerUserSpans: [{ colspan: 5 }, { colspan: 5 }] },
|
||||
"sggNm",
|
||||
"admdstNm",
|
||||
{ column: 'ctpvNm', footerUserSpans: [{ colspan: 5 }, { colspan: 5 }] },
|
||||
'sggNm',
|
||||
'admdstNm',
|
||||
],
|
||||
},
|
||||
"emphsMngSeNm",
|
||||
"displayYear",
|
||||
'emphsMngSeNm',
|
||||
'displayYear',
|
||||
{
|
||||
name: "totGroup",
|
||||
header: { text: "총계" },
|
||||
items: [
|
||||
{ name: "totMtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["totalWholMnhlCnt", "totalStep1MnhlCnt", "totalStep2MnhlCnt", "totalStep3MnhlCnt", "totalStep4MnhlCnt"] },
|
||||
"totalStep5MnhlCnt",
|
||||
],
|
||||
name: 'mtrlGroup',
|
||||
header: { text: '맨홀뚜껑 재질(개)' },
|
||||
items: ['wholMnhlCnt', 'frlvlMnhlCnt', 'sclvlMnhlCnt', 'thlvlMnhlCnt', 'folvlMnhlCnt'],
|
||||
},
|
||||
{
|
||||
name: "yy14Group",
|
||||
header: { text: "2015년 이전" }, // ← _14Y
|
||||
items: [
|
||||
{ name: "yy14MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy14WholMnhlCnt", "yy14Step1MnhlCnt", "yy14Step2MnhlCnt", "yy14Step3MnhlCnt", "yy14Step4MnhlCnt"] },
|
||||
"yy14Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy15Group",
|
||||
header: { text: "2015년" }, // ← _15Y
|
||||
items: [
|
||||
{ name: "yy15MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy15WholMnhlCnt", "yy15Step1MnhlCnt", "yy15Step2MnhlCnt", "yy15Step3MnhlCnt", "yy15Step4MnhlCnt"] },
|
||||
"yy15Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy16Group",
|
||||
header: { text: "2016년" }, // ← _16Y
|
||||
items: [
|
||||
{ name: "yy16MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy16WholMnhlCnt", "yy16Step1MnhlCnt", "yy16Step2MnhlCnt", "yy16Step3MnhlCnt", "yy16Step4MnhlCnt"] },
|
||||
"yy16Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy17Group",
|
||||
header: { text: "2017년" },
|
||||
items: [
|
||||
{ name: "yy17MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy17WholMnhlCnt", "yy17Step1MnhlCnt", "yy17Step2MnhlCnt", "yy17Step3MnhlCnt", "yy17Step4MnhlCnt"] },
|
||||
"yy17Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy18Group",
|
||||
header: { text: "2018년" },
|
||||
items: [
|
||||
{ name: "yy18MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy18WholMnhlCnt", "yy18Step1MnhlCnt", "yy18Step2MnhlCnt", "yy18Step3MnhlCnt", "yy18Step4MnhlCnt"] },
|
||||
"yy18Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy19Group",
|
||||
header: { text: "2019년" },
|
||||
items: [
|
||||
{ name: "yy19MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy19WholMnhlCnt", "yy19Step1MnhlCnt", "yy19Step2MnhlCnt", "yy19Step3MnhlCnt", "yy19Step4MnhlCnt"] },
|
||||
"yy19Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy20Group",
|
||||
header: { text: "2020년" },
|
||||
items: [
|
||||
{ name: "yy20MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy20WholMnhlCnt", "yy20Step1MnhlCnt", "yy20Step2MnhlCnt", "yy20Step3MnhlCnt", "yy20Step4MnhlCnt"] },
|
||||
"yy20Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy21Group",
|
||||
header: { text: "2021년" },
|
||||
items: [
|
||||
{ name: "yy21MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy21WholMnhlCnt", "yy21Step1MnhlCnt", "yy21Step2MnhlCnt", "yy21Step3MnhlCnt", "yy21Step4MnhlCnt"] },
|
||||
"yy21Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy22Group",
|
||||
header: { text: "2022년" },
|
||||
items: [
|
||||
{ name: "yy22MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy22WholMnhlCnt", "yy22Step1MnhlCnt", "yy22Step2MnhlCnt", "yy22Step3MnhlCnt", "yy22Step4MnhlCnt"] },
|
||||
"yy22Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy23Group",
|
||||
header: { text: "2023년" },
|
||||
items: [
|
||||
{ name: "yy23MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy23WholMnhlCnt", "yy23Step1MnhlCnt", "yy23Step2MnhlCnt", "yy23Step3MnhlCnt", "yy23Step4MnhlCnt"] },
|
||||
"yy23Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy24Group",
|
||||
header: { text: "2024년" },
|
||||
items: [
|
||||
{ name: "yy24MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy24WholMnhlCnt", "yy24Step1MnhlCnt", "yy24Step2MnhlCnt", "yy24Step3MnhlCnt", "yy24Step4MnhlCnt"] },
|
||||
"yy24Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy25Group",
|
||||
header: { text: "2025년" },
|
||||
items: [
|
||||
{ name: "yy25MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy25WholMnhlCnt", "yy25Step1MnhlCnt", "yy25Step2MnhlCnt", "yy25Step3MnhlCnt", "yy25Step4MnhlCnt"] },
|
||||
"yy25Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
"rmrk",
|
||||
],
|
||||
'filvlMnhlCnt',
|
||||
'rmrk',
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
/** ST00020003 관종별 현황 — 검토 화면용 동적 컬럼 생성
|
||||
* 필드명: prlg_whol_{year}, lyng_prlg_{year}, dmltn_prlg_{year}
|
||||
* (total의 getST00020003Config와 동일 필드, oldPipeRt 제외)
|
||||
@@ -813,100 +616,8 @@ export const getST00020003RvwConfig = (statsYr: string | number) => {
|
||||
};
|
||||
};
|
||||
|
||||
/** ST00020005 맨홀 현황 — 검토 화면용 동적 컬럼 생성
|
||||
* 필드명: wholMnhlCnt{year}, step1~5MnhlCnt{year}
|
||||
* (total의 getST00020005Config와 동일 필드)
|
||||
*/
|
||||
export const getST00020005RvwConfig = (statsYr: string | number) => {
|
||||
const firstYear = 2014;
|
||||
const lastYear = Number(statsYr) || dayjs().year();
|
||||
const yearRange = Array.from({ length: lastYear - firstYear + 1 }, (_, i) => firstYear + i);
|
||||
|
||||
const makeFooterValueCallback = (divisionIndex: number) => ({
|
||||
valueCallback: (grid: GridView) => {
|
||||
const dataSource = grid.getDataSource();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < dataSource.getRowCount(); i++) {
|
||||
const val = dataSource.getValue(i, 'displayYear');
|
||||
if (val) uniqueValues.add(String(val));
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
return divisionValues.length > divisionIndex
|
||||
? divisionValues[divisionIndex] + '합계'
|
||||
: '합계';
|
||||
},
|
||||
});
|
||||
|
||||
const mnhlYearCols = (year: number) => [
|
||||
{ name: `wholMnhlCnt${year}`, fieldName: `wholMnhlCnt${year}`, header: { text: '계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: `step1MnhlCnt${year}`, fieldName: `step1MnhlCnt${year}`, header: { text: '주철' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: `step2MnhlCnt${year}`, fieldName: `step2MnhlCnt${year}`, header: { text: '주철(조화)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: `step3MnhlCnt${year}`, fieldName: `step3MnhlCnt${year}`, header: { text: '콘크리트' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: `step4MnhlCnt${year}`, fieldName: `step4MnhlCnt${year}`, header: { text: '기타' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: `step5MnhlCnt${year}`, fieldName: `step5MnhlCnt${year}`, header: { text: '추락방지시설\n설치맨홀(개)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
];
|
||||
|
||||
const mnhlYearLayout = (year: number) => ({
|
||||
name: `yr${year}Group`,
|
||||
header: { text: year === firstYear ? '2015년 이전' : `${year}년` },
|
||||
items: [
|
||||
{
|
||||
name: `yr${year}MtrlGroup`,
|
||||
header: { text: '맨홀뚜껑 재질(개)' },
|
||||
items: [`wholMnhlCnt${year}`, `step1MnhlCnt${year}`, `step2MnhlCnt${year}`, `step3MnhlCnt${year}`, `step4MnhlCnt${year}`],
|
||||
},
|
||||
`step5MnhlCnt${year}`,
|
||||
],
|
||||
});
|
||||
|
||||
return {
|
||||
tabKey: 'ST00020005',
|
||||
tabLabel: '맨홀 현황',
|
||||
rowStartNum: 3,
|
||||
fixedColumns: 3,
|
||||
columns: [
|
||||
{ name: 'ctpvNm', fieldName: 'ctpvNm', header: { text: '시도' }, editable: false, styleName: 'rg-cell-readonly', mergeCells: true, sortdisable: true, footer: [makeFooterValueCallback(0), makeFooterValueCallback(1)] },
|
||||
{ name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, editable: false, styleName: 'rg-cell-readonly', mergeCells: true, sortdisable: true },
|
||||
{ name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, editable: false, styleName: 'rg-cell-readonly', mergeCells: true, sortdisable: true },
|
||||
{ name: 'emphsMngSeNm', fieldName: 'emphsMngSeNm', header: { text: '집중강우\n중점관리\n구역구분' }, editable: false, styleName: 'rg-cell-readonly', mergeCells: true },
|
||||
{ name: 'displayYear', fieldName: 'displayYear', header: { text: '구분' }, editable: false, styleName: 'rg-cell-readonly', sortdisable: true, footer: [makeFooterValueCallback(0), makeFooterValueCallback(1)] },
|
||||
{ name: 'totWholMnhlCnt', fieldName: 'totWholMnhlCnt', header: { text: '계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'totStep1MnhlCnt', fieldName: 'totStep1MnhlCnt', header: { text: '주철' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'totStep2MnhlCnt', fieldName: 'totStep2MnhlCnt', header: { text: '주철(조화)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'totStep3MnhlCnt', fieldName: 'totStep3MnhlCnt', header: { text: '콘크리트' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'totStep4MnhlCnt', fieldName: 'totStep4MnhlCnt', header: { text: '기타' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'totStep5MnhlCnt', fieldName: 'totStep5MnhlCnt', header: { text: '추락방지시설\n설치맨홀(개)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0', editable: false, styleName: 'rg-cell-readonly' },
|
||||
...yearRange.flatMap(mnhlYearCols),
|
||||
{ name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
],
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'addrGroup',
|
||||
header: { text: '행정구역' },
|
||||
items: [
|
||||
{ column: 'ctpvNm', footerUserSpans: [{ colspan: 5 }, { colspan: 5 }] },
|
||||
'sggNm',
|
||||
'admdstNm',
|
||||
],
|
||||
},
|
||||
'emphsMngSeNm',
|
||||
'displayYear',
|
||||
{
|
||||
name: 'totGroup',
|
||||
header: { text: '연도별총계' },
|
||||
items: [
|
||||
{ name: 'totMtrlGroup', header: { text: '맨홀뚜껑 재질(개)' }, items: ['totWholMnhlCnt', 'totStep1MnhlCnt', 'totStep2MnhlCnt', 'totStep3MnhlCnt', 'totStep4MnhlCnt'] },
|
||||
'totStep5MnhlCnt',
|
||||
],
|
||||
},
|
||||
...yearRange.map(mnhlYearLayout),
|
||||
'rmrk',
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
export const SewagePipeColumnInfoListRvw = rawList
|
||||
.filter((tab) => tab.tabKey !== 'ST00020003_PLACEHOLDER' && tab.tabKey !== 'ST00020005_PLACEHOLDER')
|
||||
.filter((tab) => tab.tabKey !== 'ST00020003_PLACEHOLDER')
|
||||
.map((tab) => ({
|
||||
...tab,
|
||||
columns: tab.columns.map((col) => ({
|
||||
@@ -925,15 +636,5 @@ const st00020003RvwPlaceholder = {
|
||||
columnLayout: [] as ReturnType<typeof getST00020003RvwConfig>['columnLayout'],
|
||||
};
|
||||
|
||||
const st00020005RvwPlaceholder = {
|
||||
tabKey: 'ST00020005',
|
||||
tabLabel: '맨홀 현황',
|
||||
rowStartNum: 3,
|
||||
fixedColumns: 3,
|
||||
columns: [] as ReturnType<typeof getST00020005RvwConfig>['columns'],
|
||||
columnLayout: [] as ReturnType<typeof getST00020005RvwConfig>['columnLayout'],
|
||||
};
|
||||
|
||||
// ST00020003: index 2, ST00020005: 끝에 추가
|
||||
// ST00020003: index 2
|
||||
SewagePipeColumnInfoListRvw.splice(2, 0, st00020003RvwPlaceholder);
|
||||
SewagePipeColumnInfoListRvw.push(st00020005RvwPlaceholder);
|
||||
@@ -700,232 +700,34 @@ const rawSewagePipeTotList = [
|
||||
],
|
||||
},
|
||||
|
||||
// ST00020005 맨홀 현황은 연도 범위가 동적이므로 rawSewagePipeTotList에 포함하지 않고
|
||||
// getST00020005Config() 로 런타임에 생성합니다.
|
||||
{
|
||||
tabKey: "ST00020005_PLACEHOLDER",
|
||||
tabLabel: "맨홀 현황",
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 2,
|
||||
columns: [
|
||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, editable: false },
|
||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역명" }, editable: false },
|
||||
{ name: "emphsMngSeNm", fieldName: "emphsMngSeNm", header: { text: "집중강우\n중점관리\n구역구분" }, editable: false },
|
||||
|
||||
{ name: "totWholMnhlCnt", fieldName: "totWholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep1MnhlCnt", fieldName: "totStep1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep2MnhlCnt", fieldName: "totStep2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep3MnhlCnt", fieldName: "totStep3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep4MnhlCnt", fieldName: "totStep4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep5MnhlCnt", fieldName: "totStep5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2015년 이전 (yy14) ──────────────────────────────────
|
||||
{ name: "yy14WholMnhlCnt", fieldName: "yy14WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step1MnhlCnt", fieldName: "yy14Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step2MnhlCnt", fieldName: "yy14Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step3MnhlCnt", fieldName: "yy14Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step4MnhlCnt", fieldName: "yy14Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step5MnhlCnt", fieldName: "yy14Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2015년 (yy15) ───────────────────────────────────────
|
||||
{ name: "yy15WholMnhlCnt", fieldName: "yy15WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step1MnhlCnt", fieldName: "yy15Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step2MnhlCnt", fieldName: "yy15Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step3MnhlCnt", fieldName: "yy15Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step4MnhlCnt", fieldName: "yy15Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step5MnhlCnt", fieldName: "yy15Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2016년 (yy16) ───────────────────────────────────────
|
||||
{ name: "yy16WholMnhlCnt", fieldName: "yy16WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step1MnhlCnt", fieldName: "yy16Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step2MnhlCnt", fieldName: "yy16Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step3MnhlCnt", fieldName: "yy16Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step4MnhlCnt", fieldName: "yy16Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step5MnhlCnt", fieldName: "yy16Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2017년 (yy17) ───────────────────────────────────────
|
||||
{ name: "yy17WholMnhlCnt", fieldName: "yy17WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step1MnhlCnt", fieldName: "yy17Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step2MnhlCnt", fieldName: "yy17Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step3MnhlCnt", fieldName: "yy17Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step4MnhlCnt", fieldName: "yy17Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step5MnhlCnt", fieldName: "yy17Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2018년 (yy18) ───────────────────────────────────────
|
||||
{ name: "yy18WholMnhlCnt", fieldName: "yy18WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step1MnhlCnt", fieldName: "yy18Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step2MnhlCnt", fieldName: "yy18Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step3MnhlCnt", fieldName: "yy18Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step4MnhlCnt", fieldName: "yy18Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step5MnhlCnt", fieldName: "yy18Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2019년 (yy19) ───────────────────────────────────────
|
||||
{ name: "yy19WholMnhlCnt", fieldName: "yy19WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step1MnhlCnt", fieldName: "yy19Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step2MnhlCnt", fieldName: "yy19Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step3MnhlCnt", fieldName: "yy19Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step4MnhlCnt", fieldName: "yy19Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step5MnhlCnt", fieldName: "yy19Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2020년 (yy20) ───────────────────────────────────────
|
||||
{ name: "yy20WholMnhlCnt", fieldName: "yy20WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step1MnhlCnt", fieldName: "yy20Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step2MnhlCnt", fieldName: "yy20Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step3MnhlCnt", fieldName: "yy20Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step4MnhlCnt", fieldName: "yy20Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step5MnhlCnt", fieldName: "yy20Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2021년 (yy21) ───────────────────────────────────────
|
||||
{ name: "yy21WholMnhlCnt", fieldName: "yy21WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step1MnhlCnt", fieldName: "yy21Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step2MnhlCnt", fieldName: "yy21Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step3MnhlCnt", fieldName: "yy21Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step4MnhlCnt", fieldName: "yy21Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step5MnhlCnt", fieldName: "yy21Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2022년 (yy22) ───────────────────────────────────────
|
||||
{ name: "yy22WholMnhlCnt", fieldName: "yy22WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step1MnhlCnt", fieldName: "yy22Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step2MnhlCnt", fieldName: "yy22Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step3MnhlCnt", fieldName: "yy22Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step4MnhlCnt", fieldName: "yy22Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step5MnhlCnt", fieldName: "yy22Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2023년 (yy23) ───────────────────────────────────────
|
||||
{ name: "yy23WholMnhlCnt", fieldName: "yy23WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step1MnhlCnt", fieldName: "yy23Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step2MnhlCnt", fieldName: "yy23Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step3MnhlCnt", fieldName: "yy23Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step4MnhlCnt", fieldName: "yy23Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step5MnhlCnt", fieldName: "yy23Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2024년 (yy24) ───────────────────────────────────────
|
||||
{ name: "yy24WholMnhlCnt", fieldName: "yy24WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step1MnhlCnt", fieldName: "yy24Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step2MnhlCnt", fieldName: "yy24Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step3MnhlCnt", fieldName: "yy24Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step4MnhlCnt", fieldName: "yy24Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step5MnhlCnt", fieldName: "yy24Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2025년 (yy25) ───────────────────────────────────────
|
||||
{ name: "yy25WholMnhlCnt", fieldName: "yy25WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step1MnhlCnt", fieldName: "yy25Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step2MnhlCnt", fieldName: "yy25Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step3MnhlCnt", fieldName: "yy25Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step4MnhlCnt", fieldName: "yy25Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step5MnhlCnt", fieldName: "yy25Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
],
|
||||
columnLayout: [
|
||||
{ name: "addrGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm"] },
|
||||
"emphsMngSeNm",
|
||||
{
|
||||
name: "totGroup",
|
||||
header: { text: "연도별총계" },
|
||||
items: [
|
||||
{ name: "totMtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["totWholMnhlCnt", "totStep1MnhlCnt", "totStep2MnhlCnt", "totStep3MnhlCnt", "totStep4MnhlCnt"] },
|
||||
"totStep5MnhlCnt",
|
||||
tabKey: "ST00020005",
|
||||
tabLabel: "맨홀 현황",
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 2,
|
||||
columns: [
|
||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, editable: false },
|
||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역명" }, editable: false },
|
||||
{ name: "emphsMngSeNm", fieldName: "emphsMngSeNm", header: { text: "집중강우\n중점관리\n구역구분" }, editable: false },
|
||||
{ name: "wholMnhlCnt", fieldName: "wholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "frlvlMnhlCnt", fieldName: "frlvlMnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "sclvlMnhlCnt", fieldName: "sclvlMnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "thlvlMnhlCnt", fieldName: "thlvlMnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "folvlMnhlCnt", fieldName: "folvlMnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "filvlMnhlCnt", fieldName: "filvlMnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
],
|
||||
columnLayout: [
|
||||
{ name: "addrGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm", "admdstNm"] },
|
||||
"emphsMngSeNm",
|
||||
{
|
||||
name: "mtrlGroup",
|
||||
header: { text: "맨홀뚜껑 재질(개)" },
|
||||
items: ["wholMnhlCnt", "frlvlMnhlCnt", "sclvlMnhlCnt", "thlvlMnhlCnt", "folvlMnhlCnt"],
|
||||
},
|
||||
"filvlMnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy14Group",
|
||||
header: { text: "2015년 이전" }, // ← _14Y
|
||||
items: [
|
||||
{ name: "yy14MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy14WholMnhlCnt", "yy14Step1MnhlCnt", "yy14Step2MnhlCnt", "yy14Step3MnhlCnt", "yy14Step4MnhlCnt"] },
|
||||
"yy14Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy15Group",
|
||||
header: { text: "2015년" }, // ← _15Y
|
||||
items: [
|
||||
{ name: "yy15MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy15WholMnhlCnt", "yy15Step1MnhlCnt", "yy15Step2MnhlCnt", "yy15Step3MnhlCnt", "yy15Step4MnhlCnt"] },
|
||||
"yy15Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy16Group",
|
||||
header: { text: "2016년" }, // ← _16Y
|
||||
items: [
|
||||
{ name: "yy16MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy16WholMnhlCnt", "yy16Step1MnhlCnt", "yy16Step2MnhlCnt", "yy16Step3MnhlCnt", "yy16Step4MnhlCnt"] },
|
||||
"yy16Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy17Group",
|
||||
header: { text: "2017년" },
|
||||
items: [
|
||||
{ name: "yy17MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy17WholMnhlCnt", "yy17Step1MnhlCnt", "yy17Step2MnhlCnt", "yy17Step3MnhlCnt", "yy17Step4MnhlCnt"] },
|
||||
"yy17Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy18Group",
|
||||
header: { text: "2018년" },
|
||||
items: [
|
||||
{ name: "yy18MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy18WholMnhlCnt", "yy18Step1MnhlCnt", "yy18Step2MnhlCnt", "yy18Step3MnhlCnt", "yy18Step4MnhlCnt"] },
|
||||
"yy18Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy19Group",
|
||||
header: { text: "2019년" },
|
||||
items: [
|
||||
{ name: "yy19MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy19WholMnhlCnt", "yy19Step1MnhlCnt", "yy19Step2MnhlCnt", "yy19Step3MnhlCnt", "yy19Step4MnhlCnt"] },
|
||||
"yy19Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy20Group",
|
||||
header: { text: "2020년" },
|
||||
items: [
|
||||
{ name: "yy20MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy20WholMnhlCnt", "yy20Step1MnhlCnt", "yy20Step2MnhlCnt", "yy20Step3MnhlCnt", "yy20Step4MnhlCnt"] },
|
||||
"yy20Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy21Group",
|
||||
header: { text: "2021년" },
|
||||
items: [
|
||||
{ name: "yy21MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy21WholMnhlCnt", "yy21Step1MnhlCnt", "yy21Step2MnhlCnt", "yy21Step3MnhlCnt", "yy21Step4MnhlCnt"] },
|
||||
"yy21Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy22Group",
|
||||
header: { text: "2022년" },
|
||||
items: [
|
||||
{ name: "yy22MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy22WholMnhlCnt", "yy22Step1MnhlCnt", "yy22Step2MnhlCnt", "yy22Step3MnhlCnt", "yy22Step4MnhlCnt"] },
|
||||
"yy22Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy23Group",
|
||||
header: { text: "2023년" },
|
||||
items: [
|
||||
{ name: "yy23MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy23WholMnhlCnt", "yy23Step1MnhlCnt", "yy23Step2MnhlCnt", "yy23Step3MnhlCnt", "yy23Step4MnhlCnt"] },
|
||||
"yy23Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy24Group",
|
||||
header: { text: "2024년" },
|
||||
items: [
|
||||
{ name: "yy24MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy24WholMnhlCnt", "yy24Step1MnhlCnt", "yy24Step2MnhlCnt", "yy24Step3MnhlCnt", "yy24Step4MnhlCnt"] },
|
||||
"yy24Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy25Group",
|
||||
header: { text: "2025년" },
|
||||
items: [
|
||||
{ name: "yy25MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy25WholMnhlCnt", "yy25Step1MnhlCnt", "yy25Step2MnhlCnt", "yy25Step3MnhlCnt", "yy25Step4MnhlCnt"] },
|
||||
"yy25Step5MnhlCnt",
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
// 2. 동적 컬럼(ST00020003) 생성 함수
|
||||
@@ -987,79 +789,7 @@ export const getST00020003Config = (statsYr: string | number) => {
|
||||
};
|
||||
};
|
||||
|
||||
/** ST00020005 — 맨홀 현황 동적 컬럼 생성
|
||||
* 응답 필드: wholMnhlCnt{year}, step1~5MnhlCnt{year}
|
||||
* firstYear: 데이터 시작 연도(기본 2014), lastYear: 조회 연도(statsYr)
|
||||
*/
|
||||
export const getST00020005Config = (statsYr: string | number) => {
|
||||
const firstYear = 2014;
|
||||
const lastYear = Number(statsYr) || new Date().getFullYear();
|
||||
|
||||
const mnhlYearCols = (year: number) => [
|
||||
{ name: `wholMnhlCnt${year}`, fieldName: `wholMnhlCnt${year}`, header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: `step1MnhlCnt${year}`, fieldName: `step1MnhlCnt${year}`, header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: `step2MnhlCnt${year}`, fieldName: `step2MnhlCnt${year}`, header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: `step3MnhlCnt${year}`, fieldName: `step3MnhlCnt${year}`, header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: `step4MnhlCnt${year}`, fieldName: `step4MnhlCnt${year}`, header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: `step5MnhlCnt${year}`, fieldName: `step5MnhlCnt${year}`, header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
];
|
||||
|
||||
const mnhlYearLayout = (year: number) => ({
|
||||
name: `yr${year}Group`,
|
||||
header: { text: year === firstYear ? `${firstYear}년 이전` : `${year}년` },
|
||||
items: [
|
||||
{
|
||||
name: `yr${year}MtrlGroup`,
|
||||
header: { text: "맨홀뚜껑 재질(개)" },
|
||||
items: [
|
||||
`wholMnhlCnt${year}`,
|
||||
`step1MnhlCnt${year}`,
|
||||
`step2MnhlCnt${year}`,
|
||||
`step3MnhlCnt${year}`,
|
||||
`step4MnhlCnt${year}`,
|
||||
],
|
||||
},
|
||||
`step5MnhlCnt${year}`,
|
||||
],
|
||||
});
|
||||
|
||||
const yearRange = Array.from({ length: lastYear - firstYear + 1 }, (_, i) => firstYear + i);
|
||||
|
||||
return {
|
||||
tabKey: "ST00020005",
|
||||
tabLabel: "맨홀 현황",
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 2,
|
||||
columns: [
|
||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, editable: false },
|
||||
{ name: "emphsMngSeNm", fieldName: "emphsMngSeNm", header: { text: "집중강우\n중점관리\n구역구분" }, editable: false },
|
||||
{ name: "totWholMnhlCnt", fieldName: "totWholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep1MnhlCnt", fieldName: "totStep1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep2MnhlCnt", fieldName: "totStep2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep3MnhlCnt", fieldName: "totStep3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep4MnhlCnt", fieldName: "totStep4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep5MnhlCnt", fieldName: "totStep5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
...yearRange.flatMap(mnhlYearCols),
|
||||
],
|
||||
columnLayout: [
|
||||
{ name: "addrGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm"] },
|
||||
"emphsMngSeNm",
|
||||
{
|
||||
name: "totGroup",
|
||||
header: { text: "연도별총계" },
|
||||
items: [
|
||||
{ name: "totMtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["totWholMnhlCnt", "totStep1MnhlCnt", "totStep2MnhlCnt", "totStep3MnhlCnt", "totStep4MnhlCnt"] },
|
||||
"totStep5MnhlCnt",
|
||||
],
|
||||
},
|
||||
...yearRange.map(mnhlYearLayout),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
export const SewagePipeColumnInfoListTot: ColumnInfoList[] = rawSewagePipeTotList
|
||||
.filter((tab) => tab.tabKey !== "ST00020005_PLACEHOLDER")
|
||||
.map((tab) => ({ ...tab, columns: tab.columns.map((col) => ({ ...col, editable: false as const })) }));
|
||||
|
||||
const st00020003PlaceholderTab: ColumnInfoList = {
|
||||
@@ -1071,14 +801,4 @@ const st00020003PlaceholderTab: ColumnInfoList = {
|
||||
columnLayout: [],
|
||||
};
|
||||
|
||||
const st00020005PlaceholderTab: ColumnInfoList = {
|
||||
tabKey: "ST00020005",
|
||||
tabLabel: "맨홀 현황",
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 2,
|
||||
columns: [],
|
||||
columnLayout: [],
|
||||
};
|
||||
|
||||
SewagePipeColumnInfoListTot.splice(2, 0, st00020003PlaceholderTab);
|
||||
SewagePipeColumnInfoListTot.push(st00020005PlaceholderTab);
|
||||
SewagePipeColumnInfoListTot.splice(2, 0, st00020003PlaceholderTab);
|
||||
+13
-44
@@ -412,43 +412,19 @@ export interface SeweragePipeInputPipeDiameterStatusSubmitRequest extends Sewera
|
||||
submitList: SeweragePipeInputPipeDiameterStatusSaveItem[];
|
||||
}
|
||||
|
||||
/** 맨홀 현황 — 연도별 통계 항목 */
|
||||
export interface SeweragePipeInputManholeYearlyStatItem {
|
||||
manhYr: string;
|
||||
wholMnhlCnt: number;
|
||||
step1MnhlCnt: number;
|
||||
step2MnhlCnt: number;
|
||||
step3MnhlCnt: number;
|
||||
step4MnhlCnt: number;
|
||||
step5MnhlCnt: number;
|
||||
}
|
||||
|
||||
type SeweragePipeInputManholeLegacyYy = 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25;
|
||||
type SeweragePipeInputManholeLegacySuffix =
|
||||
| "WholMnhlCnt"
|
||||
| "Step1MnhlCnt"
|
||||
| "Step2MnhlCnt"
|
||||
| "Step3MnhlCnt"
|
||||
| "Step4MnhlCnt"
|
||||
| "Step5MnhlCnt";
|
||||
type SeweragePipeInputManholeLegacyYearField =
|
||||
`yy${SeweragePipeInputManholeLegacyYy}${SeweragePipeInputManholeLegacySuffix}`;
|
||||
|
||||
/** 맨홀 현황 — 목록 항목 */
|
||||
export interface SeweragePipeInputManholeStatusItem
|
||||
extends Partial<Record<SeweragePipeInputManholeLegacyYearField, number>> {
|
||||
export interface SeweragePipeInputManholeStatusItem {
|
||||
sggNm: string;
|
||||
admdstCd: string;
|
||||
admdstNm: string;
|
||||
emphsMngSeCd: string;
|
||||
emphsMngSeNm: string;
|
||||
totalWholMnhlCnt: number;
|
||||
totalStep1MnhlCnt: number;
|
||||
totalStep2MnhlCnt: number;
|
||||
totalStep3MnhlCnt: number;
|
||||
totalStep4MnhlCnt: number;
|
||||
totalStep5MnhlCnt: number;
|
||||
yearlyStats?: SeweragePipeInputManholeYearlyStatItem[];
|
||||
wholMnhlCnt: number;
|
||||
frlvlMnhlCnt: number;
|
||||
sclvlMnhlCnt: number;
|
||||
thlvlMnhlCnt: number;
|
||||
folvlMnhlCnt: number;
|
||||
filvlMnhlCnt: number;
|
||||
rmrk: string;
|
||||
verificationResult?: SeweragePipeInputVerificationResult;
|
||||
}
|
||||
@@ -467,23 +443,16 @@ export interface SeweragePipeInputManholeResponse {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
/** 맨홀 현황 저장 — yearlyStats 항목 */
|
||||
export interface SeweragePipeInputManholeStatusSaveYearlyStatItem {
|
||||
manhYr: string;
|
||||
wholMnhlCnt: number;
|
||||
step1MnhlCnt: number;
|
||||
step2MnhlCnt: number;
|
||||
step3MnhlCnt: number;
|
||||
step4MnhlCnt: number;
|
||||
step5MnhlCnt: number;
|
||||
}
|
||||
|
||||
/** 맨홀 현황 저장 — saveList 항목 */
|
||||
export interface SeweragePipeInputManholeStatusSaveItem {
|
||||
emphsMngSeCd: string | null;
|
||||
admdstCd: string | null;
|
||||
admdstNm: string | null;
|
||||
yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[];
|
||||
emphsMngSeCd: string | null;
|
||||
frlvlMnhlCnt: number;
|
||||
sclvlMnhlCnt: number;
|
||||
thlvlMnhlCnt: number;
|
||||
folvlMnhlCnt: number;
|
||||
filvlMnhlCnt: number;
|
||||
rmrk: string | null;
|
||||
}
|
||||
|
||||
|
||||
+23
-1
@@ -169,9 +169,31 @@ export interface CheckInputPeriodResponse {
|
||||
data: CheckInputPeriodItem[];
|
||||
}
|
||||
|
||||
/** 입력기간(INPT) 중 `current`인 항목 (없으면 null) */
|
||||
export function getCurrentInputPeriod(
|
||||
periods: CheckInputPeriodItem[] | null | undefined,
|
||||
): CheckInputPeriodItem | null {
|
||||
return (periods ?? []).find((p) => p.seType === "INPT" && p.current === true) ?? null;
|
||||
}
|
||||
|
||||
/** 입력기간(INPT) 중 현재 구간이면 true */
|
||||
export function isInputPeriodCurrent(periods: CheckInputPeriodItem[] | null | undefined): boolean {
|
||||
return (periods ?? []).some((p) => p.seType === "INPT" && p.current === true);
|
||||
return getCurrentInputPeriod(periods) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력기간이면 일반검증 항목 등록·수정 차단 안내, 아니면 null
|
||||
*/
|
||||
export function getInputPeriodVerificationManageBlockedMessage(
|
||||
periods: CheckInputPeriodItem[] | null | undefined,
|
||||
): string | null {
|
||||
const v = getCurrentInputPeriod(periods);
|
||||
if (!v) return null;
|
||||
const from = formatCheckInputYmdAsDash(v.bgngYmd);
|
||||
const to = formatCheckInputYmdAsDash(v.endYmd);
|
||||
const range =
|
||||
from && to ? `${from} ~ ${to}` : [from, to].filter(Boolean).join(" ~ ");
|
||||
return `입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.\n(입력기간: ${range})`;
|
||||
}
|
||||
|
||||
/** `YYYYMMDD` → `yyyy-mm-dd` (그 외 형식은 그대로 반환) */
|
||||
|
||||
@@ -256,19 +256,14 @@ export interface SewagePipeReviewManholeItem {
|
||||
displayYear: string;
|
||||
rowType: 'OLD' | 'CURR';
|
||||
emphsMngSeCd: string;
|
||||
emphsMngSeNm?: string;
|
||||
|
||||
totWholMnhlCnt: number;
|
||||
totStep1MnhlCnt: number;
|
||||
totStep2MnhlCnt: number;
|
||||
totStep3MnhlCnt: number;
|
||||
totStep4MnhlCnt: number;
|
||||
totStep5MnhlCnt: number;
|
||||
|
||||
emphsMngSeNm?: string | null;
|
||||
wholMnhlCnt: number;
|
||||
frlvlMnhlCnt: number;
|
||||
sclvlMnhlCnt: number;
|
||||
thlvlMnhlCnt: number;
|
||||
folvlMnhlCnt: number;
|
||||
filvlMnhlCnt: number;
|
||||
rmrk: string | null;
|
||||
|
||||
/** 연도별 동적 필드 (wholMnhlCnt{year} ~ step5MnhlCnt{year}) */
|
||||
[key: string]: string | number | null | undefined;
|
||||
}
|
||||
|
||||
export interface SewagePipeManholeResponseData {
|
||||
|
||||
+7
-12
@@ -162,8 +162,7 @@ export interface SewagePipePipeDiamStatusResponse {
|
||||
|
||||
/**
|
||||
* 맨홀 현황 응답 아이템 인터페이스
|
||||
* 연도별 동적 필드: wholMnhlCnt{year}, step1~5MnhlCnt{year}
|
||||
* ex) wholMnhlCnt2014, step1MnhlCnt2025
|
||||
* rowType: SIDO_SUM(시도 합계/총계), BIZ_SUM(집중강우중점관리구역·그외)
|
||||
*/
|
||||
export interface FcltyManholeSummaryItem {
|
||||
ctpvNm: string;
|
||||
@@ -174,16 +173,12 @@ export interface FcltyManholeSummaryItem {
|
||||
rowType: string;
|
||||
emphsMngSeCd: string;
|
||||
emphsMngSeNm: string;
|
||||
|
||||
totWholMnhlCnt: number;
|
||||
totStep1MnhlCnt: number;
|
||||
totStep2MnhlCnt: number;
|
||||
totStep3MnhlCnt: number;
|
||||
totStep4MnhlCnt: number;
|
||||
totStep5MnhlCnt: number;
|
||||
|
||||
/** 연도별 동적 필드 (wholMnhlCnt{year} ~ step5MnhlCnt{year}) */
|
||||
[key: string]: string | number;
|
||||
wholMnhlCnt: number;
|
||||
frlvlMnhlCnt: number;
|
||||
sclvlMnhlCnt: number;
|
||||
thlvlMnhlCnt: number;
|
||||
folvlMnhlCnt: number;
|
||||
filvlMnhlCnt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,8 +24,8 @@ function LoginPage() {
|
||||
await authService.login({ userId, password });
|
||||
try {
|
||||
await statisticsApi.refreshAllCommonCodes();
|
||||
} catch {
|
||||
// 로그인 성공 후 캐시 동기화 실패는 진입을 막지 않음
|
||||
} catch(error) {
|
||||
console.error('로그인 실패');
|
||||
}
|
||||
window.location.href = "/statistics";
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user