feat: [집계표] 12.하수및 분뇨관리사업

This commit is contained in:
yangsein
2026-06-15 00:59:03 +09:00
parent 84ae60edd6
commit 64e5c26e8c
5 changed files with 282 additions and 3 deletions
@@ -1,10 +1,162 @@
import { useRef, useState } from "react";
import { useAlertStore } from "@/shared/lib";
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } 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 CellColorInfo from "./CellColorInfo";
// 12. 하수 및 분뇨 관리 산업 탭 설정 (경로 확인 필수)
import { PublicSewageStaffTab1ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/PublicSewageStaffTab1Column";
import { PublicHumanWasteStaffTab2ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/PublicHumanWasteStaffTab2Column";
import { HumanWasteCollectionTab3ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/HumanWasteCollectionTab3Column";
import { IndividualSewageTab4ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/IndividualSewageTab4Column";
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
import type {
SewerageIndustry,
PublicSewageStaffTab1Response,
PublicHumanWasteStaffTab2Response,
HumanWasteCollectionTab3Response,
IndividualSewageTab4Response
} from "@/entities/statistics/model/statistics-total/statistics-sewerage-industry-interface";
const SewageExcretaIndustryColumnListTot = [PublicSewageStaffTab1ColumnConfig,PublicHumanWasteStaffTab2ColumnConfig,HumanWasteCollectionTab3ColumnConfig,IndividualSewageTab4ColumnConfig].filter(Boolean);
const firstTabKey = SewageExcretaIndustryColumnListTot[0]?.tabKey ?? "ST00120001";
const SewageExcretaRelatedTot = () => {
const { setMessage: alert } = useAlertStore((state) => state);
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
const [isLoading, setIsLoading] = useState(false);
const [activeTab, setActiveTab] = useState(firstTabKey);
const lastSearchedValuesRef = useRef<SearchFormValues | null>(null);
const handleReset = () => {
setRowDataMap(new Map());
setActiveTab(firstTabKey);
lastSearchedValuesRef.current = null;
};
const loadGridData = async (tabKey: string, values: SearchFormValues): Promise<boolean> => {
setIsLoading(true);
const param: SewerageIndustry = {
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 {
if (tabKey === "ST00120001") {
const response: PublicSewageStaffTab1Response = await statisticsTotalStatusApi.getPublicSewageStaffTab1List(param);
if (response?.status === "success") {
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
return true;
}
}
else if (tabKey === "ST00120002") {
const response: PublicHumanWasteStaffTab2Response = await statisticsTotalStatusApi.getPublicHumanWasteStaffTab2List(param);
if (response?.status === "success") {
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
return true;
}
}
else if (tabKey === "ST00120003") {
const response: HumanWasteCollectionTab3Response = await statisticsTotalStatusApi.getHumanWasteCollectionTab3List(param);
if (response?.status === "success") {
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
return true;
}
}
// [TAB4] 개인하수처리관련업
else if (tabKey === "ST00120004") {
const response: IndividualSewageTab4Response = await statisticsTotalStatusApi.getIndividualSewageTab4List(param);
if (response?.status === "success") {
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
return true;
}
}
return false;
} catch {
alert("서버 연결 중 오류가 발생했습니다.");
return false;
} finally {
setIsLoading(false);
}
};
const handleSearch = async (values: SearchFormValues) => {
lastSearchedValuesRef.current = values;
await loadGridData(activeTab, values);
};
const handleActiveTabChange = async (tabKey: string) => {
setActiveTab(tabKey);
const values = lastSearchedValuesRef.current;
if (!values || rowDataMap.has(tabKey)) return;
await loadGridData(tabKey, values);
};
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]">
<Tabs value={activeTab} onValueChange={(v) => void handleActiveTabChange(v)} className="w-full" variant="default">
<TabsList>
{SewageExcretaIndustryColumnListTot.map((info) => (
<TabsTrigger key={info.tabKey} value={info.tabKey}>{info.tabLabel}</TabsTrigger>
))}
</TabsList>
{SewageExcretaIndustryColumnListTot.map((info) => (
<TabsContent key={info.tabKey} value={info.tabKey}>
<DataGrid
columnInfo={{ columns: info.columns, columnLayout: info.columnLayout }}
rowStartNum={info.rowStartNum}
rowData={rowDataMap.get(info.tabKey) ?? []}
excelExportFileSuffix={info.tabLabel}
setRowData={(updater) => {
setRowDataMap((prev) => {
const next = new Map(prev);
const cur = next.get(info.tabKey) ?? [];
const n = typeof updater === "function" ? updater(cur) : updater;
next.set(info.tabKey, n);
return next;
});
}}
isExcelImport={false}
isExcelExport={true}
showHeaderCheckbox={false}
fixedColumns={info.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';
}}
/>
</TabsContent>
))}
</Tabs>
</div>
</div>
);
};
@@ -0,0 +1,31 @@
import { ValueType } from "realgrid";
export const HumanWasteCollectionTab3ColumnConfig = {
tabKey: "ST00120003",
tabLabel: "분뇨수집·운반업",
rowStartNum: 3,
fixedColumns: 3,
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: "bzentyCnt", fieldName: "bzentyCnt", header: { text: "업체수(개소)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "empNope", fieldName: "empNope", header: { text: "종사인원(명)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "fcltSecrPrstCnt", fieldName: "fcltSecrPrstCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "n3TonUdrCnt", fieldName: "n3TonUdrCnt", header: { text: "3톤이하" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "n4TonUdrCnt", fieldName: "n4TonUdrCnt", header: { text: "4.5톤이하" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "n8TonUdrCnt", fieldName: "n8TonUdrCnt", header: { text: "8톤이하" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "etcCnt", fieldName: "etcCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "clctCnvncPrfmncQnt", fieldName: "clctCnvncPrfmncQnt", header: { text: "수집·운반실적(m³/년)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false }
],
columnLayout: [
{ name: "areaGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm", "admdstNm"] },
"bzentyCnt", "empNope",
{
name: "fcltGroup",
header: { text: "시설(차량) 확보현황(대수)" },
items: ["fcltSecrPrstCnt", "n3TonUdrCnt", "n4TonUdrCnt", "n8TonUdrCnt", "etcCnt"]
},
"clctCnvncPrfmncQnt"
]
};
@@ -0,0 +1,25 @@
import { ValueType } from "realgrid";
export const IndividualSewageTab4ColumnConfig = {
tabKey: "ST00120004",
tabLabel: "개인하수처리관련업",
rowStartNum: 3,
fixedColumns: 1,
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: "designMdsrCnt", fieldName: "designMdsrCnt", header: { text: "업소수" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "designMdsrNope", fieldName: "designMdsrNope", header: { text: "종사인원(명)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "mfbizCnt", fieldName: "mfbizCnt", header: { text: "업소수" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "mfbizMdsrNope", fieldName: "mfbizMdsrNope", header: { text: "종사인원(명)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "mngCnt", fieldName: "mngCnt", header: { text: "업소수" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "mngMdsrNope", fieldName: "mngMdsrNope", header: { text: "종사인원(명)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false }
],
columnLayout: [
{ name: "areaGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm", "admdstNm"] },
{ name: "designGroup", header: { text: "개인하수처리시설 설계·시공업" }, items: ["designMdsrCnt", "designMdsrNope"] },
{ name: "mfbizGroup", header: { text: "개인하수처리시설 제조업" }, items: ["mfbizCnt", "mfbizMdsrNope"] },
{ name: "mngGroup", header: { text: "개인하수처리시설 관리업" }, items: ["mngCnt", "mngMdsrNope"] }
]
};
@@ -0,0 +1,36 @@
import { ValueType } from "realgrid";
export const PublicHumanWasteStaffTab2ColumnConfig = {
tabKey: "ST00120002",
tabLabel: "공공기관 분뇨분야",
rowStartNum: 3,
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: "ognzNm", fieldName: "ognzNm", header: { text: "직제" }, editable: false },
{ name: "empGrssCnt", fieldName: "empGrssCnt", header: { text: "직원총수" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "pbadmsNope", fieldName: "pbadmsNope", header: { text: "행정직" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "techWholNope", fieldName: "techWholNope", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "engrkCnt", fieldName: "engrkCnt", header: { text: "토목" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "mchnCnt", fieldName: "mchnCnt", header: { text: "기계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "prvtmCnt", fieldName: "prvtmCnt", header: { text: "전기" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "chmengCnt", fieldName: "chmengCnt", header: { text: "화공" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "envCnt", fieldName: "envCnt", header: { text: "환경" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "enjbEtcCnt", fieldName: "enjbEtcCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "etcCnt", fieldName: "etcCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false }
],
columnLayout: [
{ name: "areaGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm", "admdstNm"] },
"ognzNm",
"empGrssCnt",
"pbadmsNope",
{
name: "techGroup",
header: { text: "기술직" },
items: ["techWholNope", "engrkCnt", "mchnCnt", "prvtmCnt", "chmengCnt", "envCnt", "enjbEtcCnt"]
},
"etcCnt"
]
};
@@ -0,0 +1,35 @@
import { ValueType } from "realgrid";
export const PublicSewageStaffTab1ColumnConfig = {
tabKey: "ST00120001",
tabLabel: "공공기관 하수분야",
rowStartNum: 3,
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: "ognzNm", fieldName: "ognzNm", header: { text: "직제" }, editable: false },
{ name: "empGrssCnt", fieldName: "empGrssCnt", header: { text: "직원총수" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "pbadmsNope", fieldName: "pbadmsNope", header: { text: "행정직" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
// 기술직
{ name: "techWholNope", fieldName: "techWholNope", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "engrkCnt", fieldName: "engrkCnt", header: { text: "토목" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "mchnCnt", fieldName: "mchnCnt", header: { text: "기계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "prvtmCnt", fieldName: "prvtmCnt", header: { text: "전기" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "chmengCnt", fieldName: "chmengCnt", header: { text: "화공" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "envCnt", fieldName: "envCnt", header: { text: "환경" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "enjbEtcCnt", fieldName: "enjbEtcCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
{ name: "etcCnt", fieldName: "etcCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false }
],
columnLayout: [
{ name: "areaGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm", "admdstNm"] },
"ognzNm", "empGrssCnt", "pbadmsNope",
{
name: "techGroup",
header: { text: "기술직" },
items: ["techWholNope", "engrkCnt", "mchnCnt", "prvtmCnt", "chmengCnt", "envCnt", "enjbEtcCnt"]
},
"etcCnt"
]
};