st: fix & refactor: 하수도 보급률 입력 조회 response 수정 및 TadaGrid 컴포넌트 Tab state 부모 컴포넌트에서 prop로 전달하도록 수정, grid 데이터를 가져오기 위한 ref prop 수정(TabDataGrid.tsx는 아직 미구현)
This commit is contained in:
@@ -164,7 +164,7 @@ function createOnSortingHandler(
|
||||
const mergeCellCols = columns.filter((c) => c.mergeCells === true && c.fieldName);
|
||||
const mergeCellCol = mergeCellCols.find((c) => c.fieldName === 'gugun') || mergeCellCols[0];
|
||||
const groupField = mergeCellCol?.fieldName || null;
|
||||
const orderByField = 'rgnNm'; // 고정값 또는 설정 가능하게 할 수 있음
|
||||
const orderByField = 'displayYear'; // 고정값 또는 설정 가능하게 할 수 있음
|
||||
const hasMergeCells = mergeCellCols.length > 0;
|
||||
|
||||
return function onSorting(g: unknown, fields: unknown[], _directions: unknown[]) {
|
||||
@@ -289,7 +289,7 @@ function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueT
|
||||
});
|
||||
}
|
||||
|
||||
const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport = true, fixedColumns, showHeaderCheckbox = false, rowData, setRowData }: DataGridProps) => {
|
||||
const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport = true, fixedColumns, showHeaderCheckbox = false, rowData, setRowData, getGridDataRef }: DataGridProps) => {
|
||||
const { columns, columnLayout } = columnInfo;
|
||||
const gridRef = useRef<RealGridReact>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -748,8 +748,28 @@ const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport
|
||||
});
|
||||
}, 200);
|
||||
|
||||
}, [columns, columnLayout, fixedColumns, rowData, showHeaderCheckbox]);
|
||||
if (getGridDataRef) {
|
||||
const fieldNames = columns.map((c) => c.fieldName).filter(Boolean) as string[];
|
||||
getGridDataRef.current = () => {
|
||||
const gv = gridRef.current?.gridView as { getDataSource?: () => { getRowCount(): number; getValue(r: number, f: string): unknown } } | undefined;
|
||||
if (!gv?.getDataSource) return [];
|
||||
const ds = gv.getDataSource();
|
||||
if (!ds) return [];
|
||||
const cnt = ds.getRowCount();
|
||||
const rows: Record<string, string | number>[] = [];
|
||||
for (let i = 0; i < cnt; i++) {
|
||||
const r: Record<string, string | number> = {};
|
||||
for (const f of fieldNames) r[f] = ds.getValue(i, f) as string | number;
|
||||
rows.push(r);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (getGridDataRef) getGridDataRef.current = null;
|
||||
};
|
||||
}, [columns, columnLayout, fixedColumns, rowData, showHeaderCheckbox, getGridDataRef]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-[0.6rem] mx-[0.6rem]">
|
||||
@@ -782,13 +802,14 @@ const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport
|
||||
rows={rowData}
|
||||
onInitialized={(grid) => {
|
||||
(grid as { onSorting?: (g: unknown, f: unknown[], d: unknown[]) => boolean }).onSorting = createOnSortingHandler(columns, setRowData, sortDirRef, originalRowsRef);
|
||||
const dp = gridRef.current?.dataProvider as { setFields?: (fields: unknown[]) => void; setRows?: (rows: Record<string, string | number>[]) => void } | undefined;
|
||||
if (dp?.setFields) {
|
||||
dp.setFields(buildFieldsFromColumns(columns));
|
||||
const dataProvider = gridRef.current?.dataProvider as unknown as
|
||||
| { setFields?(f: unknown[]): void; setRows?(r: Record<string, string | number>[]): void; getJsonRow?(r: number): Record<string, unknown> }
|
||||
| undefined;
|
||||
if (dataProvider?.setFields) {
|
||||
dataProvider.setFields(buildFieldsFromColumns(columns));
|
||||
}
|
||||
// setFields 호출 직후 행 데이터 적용 (realgrid-react의 setRows 타이밍 이슈 방지)
|
||||
if (dp?.setRows && rowData?.length) {
|
||||
dp.setRows(rowData);
|
||||
if (dataProvider?.setRows && rowData?.length) {
|
||||
dataProvider.setRows(rowData);
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -162,7 +162,7 @@ function createOnSortingHandler(
|
||||
const mergeCellCols = columns.filter((c) => c.mergeCells === true && c.fieldName);
|
||||
const mergeCellCol = mergeCellCols.find((c) => c.fieldName === 'gugun') || mergeCellCols[0];
|
||||
const groupField = mergeCellCol?.fieldName || null;
|
||||
const orderByField = 'rgnNm'; // 고정값 또는 설정 가능하게 할 수 있음
|
||||
const orderByField = 'displayYear'; // 고정값 또는 설정 가능하게 할 수 있음
|
||||
const hasMergeCells = mergeCellCols.length > 0;
|
||||
|
||||
return function onSorting(g: unknown, fields: unknown[], _directions: unknown[]) {
|
||||
@@ -306,7 +306,7 @@ function createNumberComparer(dp: RealGridDataProviderComparer): (field: string
|
||||
};
|
||||
}
|
||||
|
||||
const TabDataGrid = ({ columnInfo, isExcelImport = true, isExcelExport = true, rows = [], showHeaderCheckbox = false, rowDataMap, setRowDataMap }: TabDataGridProps) => {
|
||||
const TabDataGrid = ({ columnInfo, isExcelImport = true, isExcelExport = true, rows = [], showHeaderCheckbox = false, rowDataMap, setRowDataMap, activeTab: activeTabProp, onActiveTabChange }: TabDataGridProps) => {
|
||||
// 각 탭별로 그리드 ref와 데이터를 관리
|
||||
const gridRefs = useRef<Map<string, RealGridReact>>(new Map());
|
||||
const fileInputRefs = useRef<Map<string, HTMLInputElement>>(new Map());
|
||||
@@ -316,11 +316,14 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, isExcelExport = true, r
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const activeTabId = useTabStore((state) => state.activeTabId);
|
||||
const menuList = useTabStore((state) => state.menuList);
|
||||
const [activeTab, setActiveTab] = useState<string>(() => {
|
||||
// 초기 활성 탭을 첫 번째 tabKey로 설정
|
||||
|
||||
const [internalActiveTab, setInternalActiveTab] = useState<string>(() => {
|
||||
const firstTab = columnInfo[0];
|
||||
return firstTab?.tabKey || '';
|
||||
});
|
||||
const isControlled = activeTabProp !== undefined;
|
||||
const activeTab = isControlled ? activeTabProp : internalActiveTab;
|
||||
const setActiveTab = isControlled ? (onActiveTabChange ?? (() => {})) : setInternalActiveTab;
|
||||
|
||||
const exportExcel = (tabKey: string) => {
|
||||
const currentRowData = rowDataMap.get(tabKey) || [];
|
||||
@@ -803,10 +806,15 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, isExcelExport = true, r
|
||||
|
||||
const columns = currentInfo.columns;
|
||||
|
||||
const dp = el.dataProvider as { setFields?: (fields: unknown[]) => void } | undefined;
|
||||
const dp = el.dataProvider as { setFields?: (fields: unknown[]) => void; setRows?: (rows: Record<string, string | number>[]) => void } | undefined;
|
||||
if (dp?.setFields) {
|
||||
dp.setFields(buildFieldsFromColumns(columns));
|
||||
}
|
||||
// setFields 호출 직후 행 데이터 적용 (realgrid-react의 setRows 타이밍 이슈 방지)
|
||||
const tabRowData = rowDataMap.get(tabKey) || [];
|
||||
if (dp?.setRows && tabRowData.length) {
|
||||
dp.setRows(tabRowData);
|
||||
}
|
||||
|
||||
gridView.setDisplayOptions({
|
||||
fitStyle: GridFitStyle.EVEN
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import { useState, useMemo, useRef } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
// import { DataGrid } from "@rsone/components";
|
||||
@@ -8,6 +8,7 @@ import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsInputAPi } from "@/entities/statistics/api/statistics-input-service";
|
||||
@@ -15,9 +16,13 @@ import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import type {
|
||||
SewerageSupplyRateItem,
|
||||
SewerageSupplyRateRequestParams,
|
||||
SewerageSupplyRateSaveItem,
|
||||
} from "@/entities/statistics/model/statistics-input-interface";
|
||||
import { SeweragePenetrationRateInpColumn } from "@/components/util/column/input/SeweragePenetrationRateInpColumn";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { getFooterSummary } from "@/components/util/grid/footerSummary";
|
||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
function getSewerageSupplyRateParams(
|
||||
values: SearchFormValues,
|
||||
@@ -28,7 +33,6 @@ function getSewerageSupplyRateParams(
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
bsnmCd: values.bsnmCd,
|
||||
yr: overrides?.yr ?? values.year,
|
||||
demoYr: overrides?.demoYr ?? values.year,
|
||||
...(overrides?.mode && { mode: overrides.mode }),
|
||||
};
|
||||
}
|
||||
@@ -41,22 +45,38 @@ const SeweragePenetrationRateInp = () => {
|
||||
const [searchValues, setSearchValues] = useState<SearchFormValues | null>(null);
|
||||
const [isEnterable, setIsEnterable] = useState<boolean>(true);
|
||||
const [lastSearchedYear, setLastSearchedYear] = useState<string | null>(null);
|
||||
const { confirm } = useConfirm();
|
||||
|
||||
const [footerFromApi, setFooterFromApi] = useState<{ totalPopl?: number; poplSm?: number; frgnrPoplSm?: number } | null>(null);
|
||||
const getGridDataRef = useRef<(() => Record<string, string | number>[]) | null>(null);
|
||||
|
||||
const footerFieldNames = ['totalPopl', 'poplSm', 'frgnrPoplSm'] as const;
|
||||
const footerWithApiDefault = (fieldName: (typeof footerFieldNames)[number], numberFormat: string) => ({
|
||||
expression: 'sum' as const,
|
||||
numberFormat,
|
||||
valueCallback: (grid: Parameters<typeof getFooterSummary>[0], column: Parameters<typeof getFooterSummary>[1]) =>
|
||||
(footerFromApi && footerFromApi[fieldName] != null ? footerFromApi[fieldName] : null) ?? getFooterSummary(grid, column),
|
||||
});
|
||||
|
||||
// 최상위 관리자일땐 모든 상황에서 edit 가능하게 수정 필요.
|
||||
const columnInfo = useMemo(() => {
|
||||
const { columns, columnLayout } = SeweragePenetrationRateInpColumn;
|
||||
const base = isEnterable ? columns : columns.map((col) => ({ ...col, editable: false as const }));
|
||||
return {
|
||||
columnLayout,
|
||||
columns: isEnterable
|
||||
? columns
|
||||
: columns.map((col) => ({ ...col, editable: false as const })),
|
||||
columns: base.map((col) => {
|
||||
if (col.fieldName === 'totalPopl') return { ...col, footer: footerWithApiDefault('totalPopl', '#,##0') };
|
||||
if (col.fieldName === 'poplSm') return { ...col, footer: footerWithApiDefault('poplSm', '#,##0') };
|
||||
if (col.fieldName === 'frgnrPoplSm') return { ...col, footer: footerWithApiDefault('frgnrPoplSm', '#,##0') };
|
||||
return col;
|
||||
}),
|
||||
};
|
||||
}, [isEnterable]);
|
||||
}, [isEnterable, footerFromApi]);
|
||||
|
||||
const handleReset = () => {
|
||||
setRowData([]);
|
||||
setLastSearchedYear(null);
|
||||
setFooterFromApi(null);
|
||||
};
|
||||
|
||||
const fetchSewerageSupplyRate = async (params: SewerageSupplyRateRequestParams) => {
|
||||
@@ -64,18 +84,30 @@ const SeweragePenetrationRateInp = () => {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputAPi.getSewerageSupplyRateList(params);
|
||||
if (response.status === 'success' && response.data) {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const convertedData: SewerageSupplyRateItem[] = response.data.sewerageSupplyRateList.map((d) => ({
|
||||
...d,
|
||||
sido: commonInfo.sido,
|
||||
speclCntrplnAr: d.speclCntrplnAr === '' || d.speclCntrplnAr === null ? '해당없음' : d.speclCntrplnAr,
|
||||
}));
|
||||
|
||||
setRowData(toGridRows(convertedData));
|
||||
|
||||
setFooterFromApi(
|
||||
commonInfo
|
||||
? {
|
||||
totalPopl: commonInfo.bsnmTotalPopl,
|
||||
poplSm: commonInfo.bsnmPoplSm,
|
||||
frgnrPoplSm: commonInfo.bsnmFrgnrPoplSm,
|
||||
}
|
||||
: null
|
||||
);
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
setRowData([]);
|
||||
setFooterFromApi(null);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -126,11 +158,91 @@ const SeweragePenetrationRateInp = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
const saveFunc = async () => {
|
||||
try {
|
||||
if (await confirm('저장 하시겠습니까?')) {
|
||||
setIsLoading(true);
|
||||
|
||||
const userInfo = await getUserInfo();
|
||||
const currentData = getGridDataRef.current?.();
|
||||
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('저장할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 컬럼 정의에서 dataFormat 추출 (소수점 자리수 맞추기 위해)
|
||||
const columnFormatMap = new Map<string, string>();
|
||||
SeweragePenetrationRateInpColumn.columns.forEach((col) => {
|
||||
if (col.fieldName && col.dataFormat) {
|
||||
columnFormatMap.set(col.fieldName, col.dataFormat);
|
||||
}
|
||||
});
|
||||
|
||||
// 숫자 포맷팅 함수 (dataFormat에 따라 소수점 자리수 맞춤)
|
||||
const formatNumber = (value: string | number | null | undefined, fieldName: string): number => {
|
||||
if (value === null || value === undefined || value === '') return 0;
|
||||
const num = typeof value === 'string' ? parseFloat(value.replace(/,/g, '')) : value;
|
||||
if (isNaN(num)) return 0;
|
||||
|
||||
const format = columnFormatMap.get(fieldName);
|
||||
if (!format) return num;
|
||||
|
||||
// #,##0.000 → 소수점 3자리, #,##0.0 → 소수점 1자리, #,##0 → 정수
|
||||
const decimalPlaces = format.match(/\.(\d+)/)?.[1]?.length ?? 0;
|
||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||
};
|
||||
|
||||
// SaveItem 타입에 정의된 필드만 추출
|
||||
const convertedData: SewerageSupplyRateSaveItem[] = currentData.map((d) => ({
|
||||
bsnmCd: searchValues?.bsnmCd ?? '',
|
||||
sido: d.sido as string,
|
||||
gugun: (d.gugun as string) || null,
|
||||
yr: searchValues?.year ?? '',
|
||||
adstCd: d.adstCd as string,
|
||||
adstDong: d.adstDong as string,
|
||||
bstrm: d.bstrm as string,
|
||||
speclCntrplnAr: d.speclCntrplnAr === '해당없음' ? null : (d.speclCntrplnAr as string | null),
|
||||
pblswrgPrmTrt: formatNumber(d.pblswrgPrmTrt, 'pblswrgPrmTrt'),
|
||||
pblswrgScdTrt: formatNumber(d.pblswrgScdTrt, 'pblswrgScdTrt'),
|
||||
pblswrgTertTrt: formatNumber(d.pblswrgTertTrt, 'pblswrgTertTrt'),
|
||||
wstrPrmTrt: formatNumber(d.wstrPrmTrt, 'wstrPrmTrt'),
|
||||
wstrScdTrt: formatNumber(d.wstrScdTrt, 'wstrScdTrt'),
|
||||
wstrTertTrt: formatNumber(d.wstrTertTrt, 'wstrTertTrt'),
|
||||
notConectPopltn: formatNumber(d.notConectPopltn, 'notConectPopltn'),
|
||||
swgeProcZoneInnerAr: formatNumber(d.swgeProcZoneInnerAr, 'swgeProcZoneInnerAr'),
|
||||
townUnprocPopltn: formatNumber(d.townUnprocPopltn, 'townUnprocPopltn'),
|
||||
townSwttPopltn: formatNumber(d.townSwttPopltn, 'townSwttPopltn'),
|
||||
townWrrtnPopltn: formatNumber(d.townWrrtnPopltn, 'townWrrtnPopltn'),
|
||||
swgeProcZoneOuterAr: formatNumber(d.swgeProcZoneOuterAr, 'swgeProcZoneOuterAr'),
|
||||
rmk: (d.rmk as string) ?? '',
|
||||
popltnSm: formatNumber(d.popltnSm, 'popltnSm'),
|
||||
arSm: formatNumber(d.arSm, 'arSm'),
|
||||
swgeProcZoneInnerSm: formatNumber(d.swgeProcZoneInnerSm, 'swgeProcZoneInnerSm'),
|
||||
pblswrgPopltnSm: formatNumber(d.pblswrgPopltnSm, 'pblswrgPopltnSm'),
|
||||
wstrPopltnSm: formatNumber(d.wstrPopltnSm, 'wstrPopltnSm'),
|
||||
swgeProcZoneOuterSm: formatNumber(d.swgeProcZoneOuterSm, 'swgeProcZoneOuterSm'),
|
||||
pblswrgPopltnSuprt: formatNumber(d.pblswrgPopltnSuprt, 'pblswrgPopltnSuprt'),
|
||||
adtrtPopltnSuprt: formatNumber(d.adtrtPopltnSuprt, 'adtrtPopltnSuprt'),
|
||||
swrgInstlrt: formatNumber(d.swrgInstlrt, 'swrgInstlrt'),
|
||||
userId: userInfo.userName,
|
||||
}));
|
||||
|
||||
const response = await statisticsInputAPi.saveSewerageSupplyRate(convertedData);
|
||||
console.log(convertedData)
|
||||
console.log(response);
|
||||
} else {
|
||||
// 저장 취소
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 저장 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} onValuesChange={setSearchValues} />
|
||||
{rowData.length > 0 &&
|
||||
@@ -159,8 +271,11 @@ const SeweragePenetrationRateInp = () => {
|
||||
fixedColumns={1}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
getGridDataRef={getGridDataRef}
|
||||
/>
|
||||
</div>
|
||||
<ConfirmDialog isOpen={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import { useState, useMemo, act } from "react";
|
||||
import TabDataGrid from "@/components/module/TabDataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
@@ -18,6 +18,7 @@ const SewagePipeRvw = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, any[]>>(new Map());
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [activeTab, setActiveTab] = useState<string>('a');
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
return SewagePipeColumnInfoListRvw.map((tab: any) => ({
|
||||
@@ -40,23 +41,29 @@ const SewagePipeRvw = () => {
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsManagementApi.getSewagePipeReviewList({
|
||||
|
||||
const searchParam = {
|
||||
sido: values.sido,
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
bsnmCd: values.bsnmCd,
|
||||
yr: values.year,
|
||||
});
|
||||
};
|
||||
|
||||
if (response.status === 'success' && response.data) {
|
||||
let response;
|
||||
|
||||
if (activeTab === 'a') {
|
||||
response = await statisticsManagementApi.getSewagePipeReviewList(searchParam);
|
||||
}
|
||||
|
||||
if (response?.status === 'success' && response.data) {
|
||||
const rawList = response.data;
|
||||
const newRowDataMap = new Map<string, any[]>();
|
||||
|
||||
newRowDataMap.set('a', toGridRows(rawList));
|
||||
|
||||
|
||||
newRowDataMap.set(activeTab, toGridRows(rawList));
|
||||
|
||||
setRowDataMap(newRowDataMap);
|
||||
} else {
|
||||
handleReset();
|
||||
alert(response.message || "데이터가 없습니다.");
|
||||
alert(response?.message || "데이터가 없습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("조회 에러:", error);
|
||||
@@ -68,30 +75,32 @@ const SewagePipeRvw = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
|
||||
|
||||
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={() => {}} />
|
||||
<ApproveButton approveFunc={() => {}} />
|
||||
<ReturnButton returnFunc={() => {}} />
|
||||
<SaveButton saveFunc={() => {}} />
|
||||
<ReviewOpinionButton reviewOpinionFunc={() => { }} />
|
||||
<ApproveButton approveFunc={() => { }} />
|
||||
<ReturnButton returnFunc={() => { }} />
|
||||
<SaveButton saveFunc={() => { }} />
|
||||
</div>
|
||||
</div>
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent bg-white/50 rounded-lg p-10 flex justify-center items-center">
|
||||
<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>
|
||||
)}
|
||||
|
||||
<TabDataGrid
|
||||
columnInfo={columnInfo}
|
||||
isExcelImport={false}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
<TabDataGrid
|
||||
columnInfo={columnInfo}
|
||||
isExcelImport={false}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
activeTab={activeTab}
|
||||
onActiveTabChange={setActiveTab}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -93,7 +93,7 @@ const SeweragePenetrationRateRvw = () => {
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent bg-white/50 rounded-lg p-10 flex justify-center items-center">
|
||||
<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>
|
||||
|
||||
@@ -91,7 +91,7 @@ const StatsInputStatusRvw = () => {
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent bg-white/50 rounded-lg p-10 flex justify-center items-center">
|
||||
<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>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { DataGrid } from "@rsone/components";
|
||||
// import { DataGrid } from "@rsone/components";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import {
|
||||
Button,
|
||||
|
||||
@@ -150,6 +150,8 @@ export type DataGridProps = {
|
||||
showHeaderCheckbox?: boolean; // 헤더 체크박스 표시 여부 (기본값: true)
|
||||
rowData: Record<string, string | number>[];
|
||||
setRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>;
|
||||
/** 저장 등 시점에 그리드 현재 데이터를 가져올 수 있도록 할당 (편집 반영된 값) */
|
||||
getGridDataRef?: { current: (() => Record<string, string | number>[]) | null };
|
||||
};
|
||||
|
||||
export type TabDataGridProps = {
|
||||
@@ -162,6 +164,10 @@ export type TabDataGridProps = {
|
||||
rowDataMap: Map<string, Record<string, string | number>[]>;
|
||||
setRowDataMap: React.Dispatch<React.SetStateAction<Map<string, Record<string, string | number>[]>>>;
|
||||
isSplitGrid?: boolean; // 5:5 분리형 그리드 유무
|
||||
/** 활성 탭 키 (제어 모드). 부모에서 넘기면 해당 탭이 선택됨 */
|
||||
activeTab?: string;
|
||||
/** 활성 탭 변경 시 호출 (제어 모드). activeTab과 함께 넘기면 부모가 탭 상태를 가짐 */
|
||||
onActiveTabChange?: (tabKey: string) => void;
|
||||
};
|
||||
|
||||
export type SplitDataGridProps = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { footerInt, footerDecimal1, footerDecimal3, footerAvgDecimal } from "@/components/util/grid/footerSummary";
|
||||
import { footerInt, footerDecimal3, footerAvgDecimal } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
/**
|
||||
* 하수도 통계 관리 > 01. 하수도 보급률
|
||||
@@ -32,7 +32,17 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
{ name: 'area', fieldName: 'area', header: { text: '행정참고자료면적(㎢)' }, footer: footerDecimal3, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 총인구
|
||||
{ name: 'popltnSm', fieldName: 'popltnSm', header: { text: '총인구(명)' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{
|
||||
name: 'popltnSm',
|
||||
fieldName: 'popltnSm',
|
||||
header: { text: '총인구(명)' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 총면적
|
||||
{
|
||||
@@ -55,7 +65,7 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt'], type: 'sum' as const },
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
@@ -170,6 +180,7 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
{ name: 'rmk', fieldName: 'rmk', header: { text: '비고' } },
|
||||
|
||||
{ name: 'piplSupprt', fieldName: 'piplSupprt', header: { text: '하수관로보급률(%)' }, visible: false },
|
||||
{ name: 'adstCd', fieldName: 'adstCd', header: { text: '행정코드' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
@@ -240,5 +251,6 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
'swrgInstlrt',
|
||||
'rmk',
|
||||
'piplSupprt',
|
||||
'adstCd',
|
||||
]
|
||||
};
|
||||
@@ -18,142 +18,144 @@ const rawList = [
|
||||
mergeCells: true,
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
footer: [
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 0;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
footer: [
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 0;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
}
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
if (divisionValues.length > divisionIndex) return divisionValues[divisionIndex] + '합계';
|
||||
return '합계';
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
if (divisionValues.length > divisionIndex) return divisionValues[divisionIndex] + '합계';
|
||||
return '합계';
|
||||
}
|
||||
},
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 1;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
},
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 1;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
}
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
if (divisionValues.length > divisionIndex) return divisionValues[divisionIndex] + '합계';
|
||||
return '합계';
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
if (divisionValues.length > divisionIndex) return divisionValues[divisionIndex] + '합계';
|
||||
return '합계';
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{ name: 'gugun', fieldName: 'gugun', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: 'adstDong', fieldName: 'adstDong', header: { text: '행정구역명' }, editable: false },
|
||||
{
|
||||
name: 'displayYear',
|
||||
fieldName: 'displayYear',
|
||||
header: { text: '구분' },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
footer: [
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 0;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
{
|
||||
name: 'displayYear',
|
||||
fieldName: 'displayYear',
|
||||
header: { text: '구분' },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
footer: [
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 0;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
}
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
|
||||
}
|
||||
},
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 1;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
},
|
||||
{
|
||||
valueCallback: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => {
|
||||
const divisionIndex = 1;
|
||||
const dataSource = grid.getDataSource();
|
||||
const rowCount = dataSource.getRowCount();
|
||||
const uniqueValues = new Set<string>();
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const divisionValue = dataSource.getValue(i, 'displayYear');
|
||||
if (divisionValue !== null && divisionValue !== undefined && divisionValue !== '') {
|
||||
uniqueValues.add(String(divisionValue));
|
||||
}
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
|
||||
}
|
||||
const divisionValues = Array.from(uniqueValues);
|
||||
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
/* 하수정비 기본계획 */
|
||||
{ name: 'targetYr', fieldName: 'targetYr', header: { text: '하수정보기본계획목표년도' } },
|
||||
{ name: 'piplImprmnPlanExtn', fieldName: 'piplImprmnPlanExtn', header: { text: '총관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'piplPlanExtn', fieldName: 'piplPlanExtn', header: { text: '총계획연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'piplFcltyExtn', fieldName: 'piplFcltyExtn', header: { text: '총시설연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'piplSupprt', fieldName: 'piplSupprt', header: { text: '하수관로\n보급률(%)' }, footer: footerAvgDecimalArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'piplPlanExtn', fieldName: 'piplPlanExtn', header: { text: '총계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'piplFcltyExtn', fieldName: 'piplFcltyExtn', header: { text: '총시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'piplSupprt', fieldName: 'piplSupprt', header: { text: '하수관로\n보급률(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
|
||||
/* 합류식(m) */
|
||||
{ name: 'cmbnPlanAr', fieldName: 'cmbnPlanAr', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
|
||||
{ name: 'cmbnImprmnPlanExtn', fieldName: 'cmbnImprmnPlanExtn', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnPlanExtn', fieldName: 'cmbnPlanExtn', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnFcltyExtn', fieldName: 'cmbnFcltyExtn', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnRctglExtn', fieldName: 'cmbnRctglExtn', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnCicleExtn', fieldName: 'cmbnCicleExtn', header: { text: '원형(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnOpswrExtn', fieldName: 'cmbnOpswrExtn', header: { text: '개거(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnSdgttrExtn', fieldName: 'cmbnSdgttrExtn', header: { text: '측구(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnPlanAr', fieldName: 'cmbnPlanAr', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
|
||||
{ name: 'cmbnImprmnPlanExtn', fieldName: 'cmbnImprmnPlanExtn', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnPlanExtn', fieldName: 'cmbnPlanExtn', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnFcltyExtn', fieldName: 'cmbnFcltyExtn', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnRctglExtn', fieldName: 'cmbnRctglExtn', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnCicleExtn', fieldName: 'cmbnCicleExtn', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnOpswrExtn', fieldName: 'cmbnOpswrExtn', header: { text: '개거(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'cmbnSdgttrExtn', fieldName: 'cmbnSdgttrExtn', header: { text: '측구(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
|
||||
/* 분류식 - 오수관로 */
|
||||
{ name: 'pltwtrPlanAr', fieldName: 'pltwtrPlanAr', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerDecimal3ArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
|
||||
{ name: 'pltwtrImprmnPlanExtn', fieldName: 'pltwtrImprmnPlanExtn', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrPlanExtn', fieldName: 'pltwtrPlanExtn', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrFlctyExtn', fieldName: 'pltwtrFlctyExtn', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrSqreExtn', fieldName: 'pltwtrSqreExtn', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrCiclExtn', fieldName: 'pltwtrCiclExtn', header: { text: '원형(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrPlanAr', fieldName: 'pltwtrPlanAr', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
|
||||
{ name: 'pltwtrImprmnPlanExtn', fieldName: 'pltwtrImprmnPlanExtn', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrPlanExtn', fieldName: 'pltwtrPlanExtn', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrFlctyExtn', fieldName: 'pltwtrFlctyExtn', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrSqreExtn', fieldName: 'pltwtrSqreExtn', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'pltwtrCiclExtn', fieldName: 'pltwtrCiclExtn', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
|
||||
/* 분류식 - 우수관로 */
|
||||
{ name: 'rainwtrPlanAr', fieldName: 'rainwtrPlanAr', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
|
||||
{ name: 'rainwtrImprmnPlanExtn', fieldName: 'rainwtrImprmnPlanExtn', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrPlanExtn', fieldName: 'rainwtrPlanExtn', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrFlctyExtn', fieldName: 'rainwtrFlctyExtn', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrSqreExtn', fieldName: 'rainwtrSqreExtn', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrCiclExtn', fieldName: 'rainwtrCiclExtn', header: { text: '원형(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrOpswrExtn', fieldName: 'rainwtrOpswrExtn', header: { text: '개거(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrSdgttrExtn', fieldName: 'rainwtrSdgttrExtn', header: { text: '측구(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrPlanAr', fieldName: 'rainwtrPlanAr', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
|
||||
{ name: 'rainwtrImprmnPlanExtn', fieldName: 'rainwtrImprmnPlanExtn', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrPlanExtn', fieldName: 'rainwtrPlanExtn', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrFlctyExtn', fieldName: 'rainwtrFlctyExtn', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrSqreExtn', fieldName: 'rainwtrSqreExtn', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrCiclExtn', fieldName: 'rainwtrCiclExtn', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrOpswrExtn', fieldName: 'rainwtrOpswrExtn', header: { text: '개거(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
{ name: 'rainwtrSdgttrExtn', fieldName: 'rainwtrSdgttrExtn', header: { text: '측구(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
|
||||
|
||||
/* 부속시설 */
|
||||
{ name: 'mnhleSite', fieldName: 'mnhleSite', header: { text: '합류식맨홀(개소)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'pltwtrMnhleSite', fieldName: 'pltwtrMnhleSite', header: { text: '오수맨홀(개소)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'rainwtrMnhleSite', fieldName: 'rainwtrMnhleSite', header: { text: '우수맨홀(개소)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'pltwtrRcvrSite', fieldName: 'pltwtrRcvrSite', header: { text: '오수받이(개소)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'rainwtrRcvrSite', fieldName: 'rainwtrRcvrSite', header: { text: '빗물받이(개소)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'soilspllSite', fieldName: 'soilspllSite', header: { text: '우수토실(개소)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'soilholeSite', fieldName: 'soilholeSite', header: { text: '우수토구(개소)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'mnhleSite', fieldName: 'mnhleSite', header: { text: '합류식맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'pltwtrMnhleSite', fieldName: 'pltwtrMnhleSite', header: { text: '오수맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'rainwtrMnhleSite', fieldName: 'rainwtrMnhleSite', header: { text: '우수맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'pltwtrRcvrSite', fieldName: 'pltwtrRcvrSite', header: { text: '오수받이(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'rainwtrRcvrSite', fieldName: 'rainwtrRcvrSite', header: { text: '빗물받이(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'soilspllSite', fieldName: 'soilspllSite', header: { text: '우수토실(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'soilholeSite', fieldName: 'soilholeSite', header: { text: '우수토구(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
|
||||
/* 대장 및 기타 */
|
||||
{ name: 'sewerRegstrCmptExtn', fieldName: 'sewerRegstrCmptExtn', header: { text: '하수도대장전산화연장(m)' }, footer: footerIntArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'sewerRegstrCmptRt', fieldName: 'sewerRegstrCmptRt', header: { text: '하수도대장전산화율(%)' }, footer: footerAvgDecimalArrayByDivision,valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
|
||||
{ name: 'sewerRegstrCmptExtn', fieldName: 'sewerRegstrCmptExtn', header: { text: '하수도대장전산화연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
|
||||
{ name: 'sewerRegstrCmptRt', fieldName: 'sewerRegstrCmptRt', header: { text: '하수도대장전산화율(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
|
||||
{ name: 'rmk', fieldName: 'rmk', header: { text: '비고' } },
|
||||
],
|
||||
columnLayout: [
|
||||
{ name: 'areaGroup', header: { text: '행정구역' }, items: [
|
||||
{ column: 'sido', footerUserSpans: [{ colspan: 4 }, { colspan: 4 }] },
|
||||
'gugun',
|
||||
'adstDong',
|
||||
] },
|
||||
{
|
||||
name: 'areaGroup', header: { text: '행정구역' }, items: [
|
||||
{ column: 'sido', footerUserSpans: [{ colspan: 4 }, { colspan: 4 }] },
|
||||
'gugun',
|
||||
'adstDong',
|
||||
]
|
||||
},
|
||||
'displayYear',
|
||||
'targetYr', 'piplImprmnPlanExtn', 'piplPlanExtn', 'piplFcltyExtn', 'piplSupprt',
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
type SewerageSupplyRateRequestParams,
|
||||
type SewerageSupplyRateApiResponse,
|
||||
type CheckInputPeriodResponse,
|
||||
type SewerageSupplyRateSaveItem,
|
||||
type SewerageSupplyRateSaveApiResponse,
|
||||
} from "../model/statistics-input-interface";
|
||||
|
||||
export class StatisticsInputAPiService implements StatisticsInputService {
|
||||
@@ -27,6 +29,15 @@ export class StatisticsInputAPiService implements StatisticsInputService {
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async saveSewerageSupplyRate(params: SewerageSupplyRateSaveItem[]): Promise<SewerageSupplyRateSaveApiResponse> {
|
||||
const response = await axios.post<SewerageSupplyRateSaveApiResponse> (
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewerage-supply-rate`,
|
||||
params
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const statisticsInputAPi = new StatisticsInputAPiService();
|
||||
@@ -67,7 +67,7 @@ export class StatisticsManagementApiService {
|
||||
}
|
||||
): Promise<SewagePipeReviewApiResponse> {
|
||||
const response = await axios.get<SewagePipeReviewApiResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.REVIEW}/pipe/tab1`,
|
||||
`${ENDPOINT.ST_SERVICE.REVIEW}/sewer-pipe/regional-status`,
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
|
||||
@@ -13,6 +13,28 @@ export interface SewerageSupplyRateStatusInfo {
|
||||
returnOpinionSm: string | null;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateCommonInfo {
|
||||
bsnmArea: number;
|
||||
bsnmCd: string;
|
||||
bsnmFrgnrPoplSm: number;
|
||||
bsnmPoplSm: number;
|
||||
bsnmTotalPopl: number;
|
||||
piplFcltyExtn: number;
|
||||
piplPlanExtn: number;
|
||||
piplSupprt: number;
|
||||
sido: string;
|
||||
yr: string;
|
||||
}
|
||||
|
||||
/** 검증 결과 한 건 (필드별 메시지) */
|
||||
export interface VerificationResultItem {
|
||||
type: string;
|
||||
rsn: string;
|
||||
}
|
||||
|
||||
/** 필드명 → 검증 결과 배열. 예: { popltnSm: [{ type, rsn }], wstrPrmTrt: [...] } */
|
||||
export type SewerageSupplyRateVerificationResult = Record<string, VerificationResultItem[]>;
|
||||
|
||||
export interface SewerageSupplyRateItem {
|
||||
sido: string;
|
||||
gugun: string;
|
||||
@@ -93,11 +115,13 @@ export interface SewerageSupplyRateItem {
|
||||
chkAdtrtPopltnSuprt: string;
|
||||
chkSwrgInstlrt: string;
|
||||
chkNotConectPopltn: string;
|
||||
verificationResult?: SewerageSupplyRateVerificationResult;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateResponseData {
|
||||
statusInfo: SewerageSupplyRateStatusInfo;
|
||||
sewerageSupplyRateList: SewerageSupplyRateItem[];
|
||||
commonInfo: SewerageSupplyRateCommonInfo;
|
||||
}
|
||||
|
||||
export type SewerageSupplyRateApiResponse = ApiResponse<SewerageSupplyRateResponseData> & {
|
||||
@@ -109,10 +133,53 @@ export interface SewerageSupplyRateRequestParams {
|
||||
gugun?: string;
|
||||
bsnmCd?: string;
|
||||
yr?: string;
|
||||
demoYr?: string;
|
||||
mode?: string;
|
||||
}
|
||||
|
||||
/** 하수도 보급률 저장 API 요청 body (한 행) */
|
||||
export interface SewerageSupplyRateSaveItem {
|
||||
bsnmCd: string;
|
||||
sido: string;
|
||||
gugun: string | null;
|
||||
yr: string;
|
||||
adstCd: string;
|
||||
adstDong: string;
|
||||
bstrm: string;
|
||||
speclCntrplnAr: string | null;
|
||||
pblswrgPrmTrt: number;
|
||||
pblswrgScdTrt: number;
|
||||
pblswrgTertTrt: number;
|
||||
wstrPrmTrt: number;
|
||||
wstrScdTrt: number;
|
||||
wstrTertTrt: number;
|
||||
notConectPopltn: number;
|
||||
swgeProcZoneInnerAr: number;
|
||||
townUnprocPopltn: number;
|
||||
townSwttPopltn: number;
|
||||
townWrrtnPopltn: number;
|
||||
swgeProcZoneOuterAr: number;
|
||||
rmk: string;
|
||||
popltnSm: number;
|
||||
arSm: number;
|
||||
swgeProcZoneInnerSm: number;
|
||||
pblswrgPopltnSm: number;
|
||||
wstrPopltnSm: number;
|
||||
swgeProcZoneOuterSm: number;
|
||||
pblswrgPopltnSuprt: number;
|
||||
adtrtPopltnSuprt: number;
|
||||
swrgInstlrt: number;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateSaveData {
|
||||
hasMismatch?: boolean;
|
||||
mismatchIdList?: string[];
|
||||
httpStatus?: number;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
export type SewerageSupplyRateSaveApiResponse = ApiResponse<SewerageSupplyRateSaveData>;
|
||||
|
||||
// 하수도 통계 입력 기간 조회
|
||||
export interface CheckInputPeriodResponse {
|
||||
status: string;
|
||||
@@ -122,4 +189,6 @@ export interface CheckInputPeriodResponse {
|
||||
|
||||
export interface StatisticsInputService {
|
||||
getSewerageSupplyRateList(params: SewerageSupplyRateRequestParams): Promise<SewerageSupplyRateApiResponse>;
|
||||
checkInputPeriod(params: string): Promise<CheckInputPeriodResponse>;
|
||||
saveSewerageSupplyRate(params: SewerageSupplyRateSaveItem[]): Promise<SewerageSupplyRateSaveApiResponse>;
|
||||
}
|
||||
Reference in New Issue
Block a user