feat:[집계표]분뇨처리시설

This commit is contained in:
yangsein
2026-06-15 00:50:54 +09:00
parent 85ba9fe0ab
commit 3c701359fd
3 changed files with 241 additions and 3 deletions
@@ -1,10 +1,123 @@
import { useRef, useState } from "react";
import { useAlertStore } from "@/shared/lib";
import { LoadingWithAnimation } from "@common/components";
import SearchForm from "@/components/module/SearchForm";
import DataGrid from "@/components/module/DataGrid";
import type { ColumnInfo } from "@/components/type/DataGrid.type";
import type { SearchFormValues } from "@/components/type/SearchForm.type";
import { toGridRows } from "@/components/util/grid/gridFunction";
// 분리된 분뇨처리시설용 컬럼 구성 임포트
import { ExcretaTreatmentStatusColumnConfig } from "@/components/util/column/total/SewerExcretaTreatmentStatusColumn";
// 집계표(TOTAL) API 및 인터페이스 명세 호출
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
import type {
ExcretaTreatmentMaintainTotalRequest
} from "@/entities/statistics/model/statistics-total/statistics-excreta-treatment-total-interface";
import CellColorInfo from "./CellColorInfo";
const ExcretaTreatmentFacilityTot = () => {
const { setMessage: alert } = useAlertStore((state) => state);
// null 타입 컴파일 에러를 방지하기 위해 엄격하게 정의한 데이터 상태
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
const [isLoading, setIsLoading] = useState(false);
const lastSearchedValuesRef = useRef<SearchFormValues | null>(null);
const config = ExcretaTreatmentStatusColumnConfig;
const handleReset = () => {
setRowData([]);
lastSearchedValuesRef.current = null;
};
const loadGridData = async (values: SearchFormValues): Promise<boolean> => {
const param: ExcretaTreatmentMaintainTotalRequest = {
ctpvNm: values.sido === "ALL" ? "" : values.sido,
sggNm: values.gugun === "ALL" ? "" : values.gugun,
sewerBzmnCd: values.bsnmCd,
statsYr: values.year,
rowDataYn: values.isDetail,
summaryYn: values.isSummary !== 'ALL',
summaryYearCnt: values.isSummary !== 'ALL' ? Number(values.isSummary) : undefined
};
try {
const response = await statisticsTotalStatusApi.getExcretaTreatmentStatusTotalList(param);
if (response && response.status === "success" && response.data) {
// object[]로 변환하여 주입함으로써 상위 컴포넌트 간 null 에러 완벽 차단
setRowData(toGridRows(response.data as object[]));
return true;
}
alert(response?.message || "데이터 조회 중 오류가 발생했습니다.");
return false;
} catch {
alert("서버 연결 중 오류가 발생했습니다.");
return false;
}
};
const handleSearch = async (values: SearchFormValues) => {
try {
setIsLoading(true);
const ok = await loadGridData(values);
if (ok) {
lastSearchedValuesRef.current = values;
} else {
lastSearchedValuesRef.current = null;
}
} catch {
alert("데이터 조회 중 오류가 발생했습니다.");
lastSearchedValuesRef.current = null;
} finally {
setIsLoading(false);
}
};
const gridColumnInfo: ColumnInfo = {
columns: config.columns,
columnLayout: config.columnLayout,
};
return (
<>
<SearchForm />
</>
<div className="relative">
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
{isLoading && (
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
<div className="relative size-[5rem]">
<LoadingWithAnimation color="primary" />
</div>
</div>
)}
<CellColorInfo />
<div className="flex flex-col gap-[0.6rem] mx-[0.6rem] mt-[0.6rem]">
<DataGrid
columnInfo={gridColumnInfo}
rowStartNum={config.rowStartNum}
excelExportFileSuffix={config.tabLabel}
rowData={rowData}
setRowData={setRowData} // 필수 프로퍼티 에러 해결
isExcelImport={false}
isExcelExport={true}
showHeaderCheckbox={false}
fixedColumns={config.fixedColumns}
enableSort={false}
cellStyleCallback={({ row }) => {
const rowType = String(row.rowType ?? '');
if (rowType === 'DETAIL') return undefined;
if (rowType === 'BIZ_SUM') return 'rg-cell-rowtype-biz-sum';
if (rowType === 'SUMMARY') return 'rg-cell-rowtype-summary';
return 'rg-cell-rowtype-other';
}}
/>
</div>
</div>
);
};
@@ -0,0 +1,63 @@
import { ValueType } from "realgrid";
export const ExcretaTreatmentStatusColumnConfig = {
tabKey: "ST00070001",
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: "fcltNm", fieldName: "fcltNm", header: { text: "시설명" }, editable: false },
{ name: "fcltPstnCn", fieldName: "fcltPstnCn", header: { text: "소재지" }, editable: false },
{ name: "telNo", fieldName: "telNo", header: { text: "전화번호" }, editable: false },
{ name: "cmptnStrtYmd", fieldName: "cmptnStrtYmd", header: { text: "준공일" }, editable: false },
{ name: "oprtngStrtYmd", fieldName: "oprtngStrtYmd", header: { text: "가동개시일" }, editable: false },
{ name: "wholPjtcoAmt", fieldName: "wholPjtcoAmt", header: { text: "사업비\n(백만원)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "prcsFcltCpct", fieldName: "prcsFcltCpct", header: { text: "시설용량\n(㎥/일)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
{ name: "cpct", fieldName: "cpct", header: { text: "처리량\n(㎥/일)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
{ name: "oprtngDayCnt", fieldName: "oprtngDayCnt", header: { text: "가동일수\n(일/년)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "prcsMthdExpln", fieldName: "prcsMthdExpln", header: { text: "처리공법" }, editable: false },
{ name: "linkTmplntCn", fieldName: "linkTmplntCn", header: { text: "연계처리장명" }, editable: false },
{ name: "linkPrcsQnt", fieldName: "linkPrcsQnt", header: { text: "연계처리량\n(㎥/일)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
// 유입수질(mg/L, 개/mL) 그룹 소속
{ name: "inflwBodWqVl", fieldName: "inflwBodWqVl", header: { text: "BOD" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "inflwTocWqVl", fieldName: "inflwTocWqVl", header: { text: "TOC" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "inflwSsWqVl", fieldName: "inflwSsWqVl", header: { text: "SS" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "inflwTnWqVl", fieldName: "inflwTnWqVl", header: { text: "T-N" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "inflwTpWqVl", fieldName: "inflwTpWqVl", header: { text: "T-P" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.000", editable: false },
{ name: "inflwClfgCnt", fieldName: "inflwClfgCnt", header: { text: "대장균\n군수" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
// 방류수질(mg/L, 개/mL) 그룹 소속
{ name: "dschgBodWqVl", fieldName: "dschgBodWqVl", header: { text: "BOD" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "dschgTocWqVl", fieldName: "dschgTocWqVl", header: { text: "TOC" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "dschgSsWqVl", fieldName: "dschgSsWqVl", header: { text: "SS" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "dschgTnWqVl", fieldName: "dschgTnWqVl", header: { text: "T-N" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false },
{ name: "dschgTpWqVl", fieldName: "dschgTpWqVl", header: { text: "T-P" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.000", editable: false },
{ name: "dschgClfgCnt", fieldName: "dschgClfgCnt", header: { text: "대장균\n군수" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
// 방류수역 그룹 소속
{ name: "wtsysNm", fieldName: "wtsysNm", header: { text: "수계" }, editable: false },
{ name: "trbtrNm", fieldName: "trbtrNm", header: { text: "지류" }, editable: false },
{ name: "msirbCn", fieldName: "msirbCn", header: { text: "중권역" }, editable: false },
{ name: "ssirbCn", fieldName: "ssirbCn", header: { text: "소권역" }, editable: false },
// 단일 미그룹 성격 컬럼들
{ name: "operMthdCdCn", fieldName: "operMthdCdCn", header: { text: "운영주체\n(자체/공기업/\n민간위탁)" }, editable: false },
{ name: "wholNope", fieldName: "wholNope", header: { text: "직원총수\n(명)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "sftyAcdntEvntcsCnt", fieldName: "sftyAcdntEvntcsCnt", header: { text: "안전사고\n건수\n(건/인/년)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.00", editable: false }
],
columnLayout: [
{ name: "areaGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm", "admdstNm"] },
"fcltNm", "fcltPstnCn", "telNo", "cmptnStrtYmd", "oprtngStrtYmd", "wholPjtcoAmt", "prcsFcltCpct", "cpct", "oprtngDayCnt", "prcsMthdExpln", "linkTmplntCn", "linkPrcsQnt",
{ name: "inflwWqGroup", header: { text: "유입수질(mg/L, 개/mL)" }, items: ["inflwBodWqVl", "inflwTocWqVl", "inflwSsWqVl", "inflwTnWqVl", "inflwTpWqVl", "inflwClfgCnt"] },
{ name: "dschgWqGroup", header: { text: "방류수질(mg/L, 개/mL)" }, items: ["dschgBodWqVl", "dschgTocWqVl", "dschgSsWqVl", "dschgTnWqVl", "dschgTpWqVl", "dschgClfgCnt"] },
{ name: "wtrAreaGroup", header: { text: "방류수역" }, items: ["wtsysNm", "trbtrNm", "msirbCn", "ssirbCn"] },
"operMthdCdCn", "wholNope", "sftyAcdntEvntcsCnt"
]
};
@@ -0,0 +1,62 @@
/** 07. 분뇨처리시설 현황 검색 조건 파라미터 DTO */
export interface ExcretaTreatmentMaintainTotalRequest {
ctpvNm?: string;
sggNm?: string;
statsYr?: string;
swtrmtFcltNm?: string;
sewerBzmnCd?: string;
rowDataYn?: boolean;
summaryYn?: boolean;
summaryYearCnt?: number;
}
/** 분뇨처리시설 목록 데이터 행 구조 */
export interface ExcretaTreatmentStatusTotalItem {
ctpvNm: string;
sggNm: string | null;
statsYr: string;
admdstNm: string;
admdstCd: string;
fcltNm: string;
rowType: string;
fcltPstnCn: string;
telNo: string;
cmptnStrtYmd: string;
oprtngStrtYmd: string;
wholPjtcoAmt: number;
prcsFcltCpct: number;
cpct: number;
oprtngDayCnt: number;
prcsMthdExpln: string;
linkTmplntCn: string;
linkPrcsQnt: number;
// 유입수질
inflwBodWqVl: number;
inflwTocWqVl: number;
inflwSsWqVl: number;
inflwTnWqVl: number;
inflwTpWqVl: number;
inflwClfgCnt: number;
// 방류수질
dschgBodWqVl: number;
dschgTocWqVl: number;
dschgSsWqVl: number;
dschgTnWqVl: number;
dschgTpWqVl: number;
dschgClfgCnt: number;
// 방류수역 및 기타 정보
wtsysNm: string;
trbtrNm: string;
msirbCn: string;
ssirbCn: string;
operMthdCdCn: string;
wholNope: number;
sftyAcdntEvntcsCnt: number;
}
/** 분뇨처리시설 API 응답 인터페이스 */
export interface ExcretaTreatmentStatusTotalResponse {
status: string;
message?: string;
data: ExcretaTreatmentStatusTotalItem[];
}