212 lines
9.7 KiB
TypeScript
212 lines
9.7 KiB
TypeScript
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 { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
|
|
// 4개 탭 컬럼 설정 임포트
|
|
import { SludgeProcessingTab1ColumnConfig } from "@/components/util/column/total/sludgeProcessing/SludgeProcessingTab1Column";
|
|
import { DigestionTankTab2ColumnConfig } from "@/components/util/column/total/sludgeProcessing/DigestionTankTab2Column";
|
|
import { SewageSludgeOperTab3ColumnConfig } from "@/components/util/column/total/sludgeProcessing/SewageSludgeOperTab3Column";
|
|
import { HumanWasteSludgeTab4ColumnConfig } from "@/components/util/column/total/sludgeProcessing/HumanWasteSludgeTab4Column";
|
|
|
|
// API 인스턴스 및 인터페이스 임포트 (타입 안전성 확보)
|
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
|
import type {
|
|
SludgeSummaryRequest,
|
|
SludgeProcessingTab1Response,
|
|
DigestionTankOperTab2Response,
|
|
SewageSludgeOperTab3Response,
|
|
HumanWasteSludgeTab4Response
|
|
} from "@/entities/statistics/model/statistics-total/statistics-sludge-total-interface";
|
|
import CellColorInfo from "./CellColorInfo";
|
|
|
|
// 탭 순회 설정
|
|
const SludgeColumnListTot = [
|
|
SludgeProcessingTab1ColumnConfig,
|
|
DigestionTankTab2ColumnConfig,
|
|
SewageSludgeOperTab3ColumnConfig,
|
|
HumanWasteSludgeTab4ColumnConfig
|
|
].filter(Boolean);
|
|
|
|
const firstTabKey = SludgeColumnListTot[0]?.tabKey ?? "ST00110001";
|
|
|
|
const SewageExcretaSlurgeTot = () => {
|
|
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 columnInfo = SludgeColumnListTot;
|
|
|
|
const handleReset = () => {
|
|
setRowDataMap(new Map());
|
|
setActiveTab(firstTabKey);
|
|
lastSearchedValuesRef.current = null;
|
|
};
|
|
|
|
const loadGridData = async (tabKey: string, values: SearchFormValues): Promise<boolean> => {
|
|
setIsLoading(true);
|
|
const param: SludgeSummaryRequest = {
|
|
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 {
|
|
// [TAB1] 하수및분뇨찌꺼기 > 찌꺼기처리시설현황
|
|
if (tabKey === "ST00110001") {
|
|
const response: SludgeProcessingTab1Response = await statisticsTotalStatusApi.getSludgeProcessingTab1List(param);
|
|
if (response?.status === "success") {
|
|
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
|
|
return true;
|
|
}
|
|
}
|
|
// [TAB2] 소화조 운영현황
|
|
else if (tabKey === "ST00110002") {
|
|
const response: DigestionTankOperTab2Response = await statisticsTotalStatusApi.getSludgeTab2List(param);
|
|
if (response?.status === "success") {
|
|
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
|
|
return true;
|
|
}
|
|
}
|
|
// [TAB3] 하수찌꺼기 처리시설 운영현황
|
|
else if (tabKey === "ST00110003") {
|
|
const response: SewageSludgeOperTab3Response = await statisticsTotalStatusApi.getSludgeTab3List(param);
|
|
if (response?.status === "success") {
|
|
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
|
|
return true;
|
|
}
|
|
}
|
|
// [TAB4] 분뇨찌꺼기 처리현황
|
|
else if (tabKey === "ST00110004") {
|
|
const response: HumanWasteSludgeTab4Response = await statisticsTotalStatusApi.getSludgeTab4List(param);
|
|
if (response?.status === "success") {
|
|
setRowDataMap((prev) => new Map(prev).set(tabKey, toGridRows(response.data as object[])));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
alert("데이터 조회 중 오류가 발생했습니다.");
|
|
return false;
|
|
} catch {
|
|
alert("서버 연결 중 오류가 발생했습니다.");
|
|
return false;
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
/** 검색 버튼 이벤트: SearchForm의 Values 타입을 기반으로 호출 */
|
|
const handleSearch = async (values: SearchFormValues) => {
|
|
try {
|
|
setIsLoading(true);
|
|
// 탭 변경 없이 현재 탭(activeTab)에 대해서만 명시적 타입 호출
|
|
const ok = await loadGridData(activeTab, values);
|
|
if (ok) {
|
|
lastSearchedValuesRef.current = values;
|
|
} else {
|
|
lastSearchedValuesRef.current = null;
|
|
}
|
|
} catch {
|
|
alert("데이터 조회 중 오류가 발생했습니다.");
|
|
lastSearchedValuesRef.current = null;
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
/** 탭 변경 이벤트: 현재 탭 상태와 SearchForm의 마지막 값을 동기화 */
|
|
const handleActiveTabChange = async (tabKey: string) => {
|
|
setActiveTab(tabKey);
|
|
|
|
// 마지막 검색 값이 있으면 해당 탭만 새로 로드
|
|
const values = lastSearchedValuesRef.current;
|
|
if (!values || rowDataMap.has(tabKey)) return;
|
|
|
|
try {
|
|
setIsLoading(true);
|
|
await loadGridData(tabKey, values);
|
|
} catch {
|
|
alert("데이터 조회 중 오류가 발생했습니다.");
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="relative">
|
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
|
|
|
{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>
|
|
{columnInfo.map((info) => (
|
|
<TabsTrigger key={info.tabKey} value={info.tabKey}>{info.tabLabel}</TabsTrigger>
|
|
))}
|
|
</TabsList>
|
|
|
|
{columnInfo.map((info) => {
|
|
const tabKey = info.tabKey;
|
|
const rowData = rowDataMap.get(tabKey) ?? [];
|
|
|
|
return (
|
|
<TabsContent key={tabKey} value={tabKey}>
|
|
<DataGrid
|
|
columnInfo={{ columns: info.columns, columnLayout: info.columnLayout }}
|
|
rowStartNum={info.rowStartNum}
|
|
rowData={rowData}
|
|
excelExportFileSuffix={info.tabLabel}
|
|
setRowData={(updater) => {
|
|
setRowDataMap((prev) => {
|
|
const next = new Map(prev);
|
|
const cur = next.get(tabKey) ?? [];
|
|
const n = typeof updater === "function" ? updater(cur) : updater;
|
|
next.set(tabKey, n);
|
|
return next;
|
|
});
|
|
}}
|
|
isExcelImport={false}
|
|
isExcelExport={true}
|
|
excelExportApplyStyles
|
|
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>
|
|
);
|
|
};
|
|
|
|
export default SewageExcretaSlurgeTot; |