st: feat: 멀티 footer, footer 병합 작업중

This commit is contained in:
2026-01-16 11:54:36 +09:00
parent 8252561050
commit e94782f56a
4 changed files with 60 additions and 20 deletions
+36 -7
View File
@@ -19,6 +19,8 @@ declare module "realgrid" {
summaryMode?: 'aggregate' | 'statistical' | 'none';
checkBar?: { visible?: boolean };
}): void;
setFooters?(footers: Array<{ height?: number }>): void;
setColumnLayout?(layout: unknown[]): void; // footerUserSpans를 포함한 레이아웃 설정
}
}
@@ -270,7 +272,13 @@ const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport
// footer가 있는 컬럼이 있으면 footer 높이 설정
const hasFooter = columns.some(col => col.footer);
if (hasFooter) {
gridView.footer.height = 40;
// multiRow가 true인 footer가 있으면 멀티푸터 설정 (여러 행)
const hasMultiRowFooter = columns.some(col => col.footer && col.footer.multiRow);
if (hasMultiRowFooter) {
gridView.setFooters?.([{height: 40}, {height: 40}]);
} else {
gridView.footer.height = 40;
}
}
// 고정 컬럼 설정
@@ -284,6 +292,27 @@ const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport
summaryMode: "aggregate"
});
// footerUserSpans가 있는 경우 setColumnLayout으로 설정
const checkFooterUserSpans = (layout: unknown[]): boolean => {
return layout.some(item => {
if (typeof item === 'string') return false;
if (item && typeof item === 'object' && 'footerUserSpans' in item) return true;
if (item && typeof item === 'object' && 'items' in item && Array.isArray(item.items)) {
return checkFooterUserSpans(item.items);
}
return false;
});
};
if (checkFooterUserSpans(columnLayout) && gridView.setColumnLayout) {
// setColumnLayout은 그리드가 완전히 렌더링된 후 호출해야 함
setTimeout(() => {
if (gridRef.current?.gridView && columnLayout) {
gridRef.current.gridView.setColumnLayout?.(columnLayout);
}
}, 100);
}
// footer의 valueCallback 설정
columns.forEach(col => {
if (col.footer && col.footer.valueCallback) {
@@ -320,12 +349,12 @@ const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport
}
</div>
<div className="h-[65vh]">
<RealGridReact
ref={gridRef}
autoGenerateField={true}
layout={columnLayout}
rows={rowData}
>
<RealGridReact
ref={gridRef}
autoGenerateField={true}
layout={columnLayout}
rows={rowData}
>
{columns.map((column) => (
<RGDataColumn
key={column.name}
@@ -1,6 +1,7 @@
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 SaveButton from "@/components/button/SaveButton";
import ApproveButton from "@/components/button/ApproveButton";
@@ -45,7 +46,7 @@ const SeweragePenetrationRateRvw = () => {
</div>
<DataGrid
columnInfo={SeweragePenetrationRateInfoList}
isExcelImport={false}
isExcelImport={true}
fixedColumns={SeweragePenetrationRateInfoList.fixedColumns}
rowStartNum={SeweragePenetrationRateInfoList.rowStartNum}
rowData={rowData}
@@ -39,14 +39,25 @@ export type ColumnConfig = {
expression?: 'sum' | 'avg' | 'count' | 'max' | 'min';
numberFormat?: string;
valueCallback?: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => number | string;
multiRow?: boolean; // 여러 행 footer 사용 여부
},
};
export type FooterUserSpan = {
rowspan?: number; // 병합할 행 수
colspan?: number; // 병합할 컬럼 수
text?: string; // 표시할 텍스트
};
export type ColumnLayoutItem = string | {
name: string;
hideChildHeaders?: boolean;
header: { text: string };
items: (string | ColumnLayoutItem)[];
footerUserSpans?: FooterUserSpan[]; // footer 병합 설정
} | {
column: string; // 컬럼 이름 (footerUserSpans 사용 시)
footerUserSpans?: FooterUserSpan[]; // footer 병합 설정
};
export type ColumnInfo = {
@@ -1,9 +1,9 @@
import { ValueType } from "realgrid";
import type { ColumnConfig } from "@rsone/components";
import { footerInt, footerDecimal3 } from "@/components/util/grid/footerSummary";
export const SeweragePenetrationRateInfoList = {
columns: [
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, mergeCells: true, editable: false, sortdisable: true },
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, mergeCells: true, editable: false, sortdisable: true, footer: { text: '합계', multiRow: true } },
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
{ name: '구분', fieldName: '구분', header: { text: '구분' }, editable: false, sortdisable: true },
{ name: '수계', fieldName: '수계', header: { text: '수계' } },
@@ -12,12 +12,8 @@ export const SeweragePenetrationRateInfoList = {
{ name: 'lgbsn', fieldName: '중권역', header: { text: '중권역' } },
{ name: 'mdmbsn', fieldName: '소권역', header: { text: '소권역' } },
{ name: 'specl_cntrpln_ar', fieldName: '특별대책지역', header: { text: '특별대책지역' } },
{ name: 'total_popl', fieldName: '총인구', header: { text: '총인구' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
{ name: 'popl_sm', fieldName: '내국인', header: { text: '내국인' } },
{ name: 'frgnr_popl_sm', fieldName: '외국인', header: { text: '외국인' } },
{ name: 'area', fieldName: '행정참고자료면적(㎢)', header: { text: '행정참고자료면적(㎢)' } },
{ name: 'popltn_sm', fieldName: '총인구(명)', header: { text: '총인구(명)' } },
{ name: 'ar_sm', fieldName: '총면적(㎢)', header: { text: '총면적(㎢)' }, valueType: ValueType.NUMBER },
{ name: 'total_popl', fieldName: '총인구', header: { text: '총인구' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
{ name: 'ar_sm', fieldName: '총면적(㎢)', header: { text: '총면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
{ name: '계', fieldName: '계', header: { text: '계' } },
//공공하수처리인구
{ name: '합계', fieldName: '합계', header: { text: '합계' } },
@@ -41,13 +37,16 @@ export const SeweragePenetrationRateInfoList = {
{ name: 'adtrt_popltn_suprt', fieldName: '고도처리인구보급율(%)', header: { text: `고도처리인구보급율(%)` } },
{ name: 'swrg_instlrt', fieldName: '하수도설치율(%)', header: { text: '하수도설치율(%)' } },
{ name: 'rmk', fieldName: '비고', header: { text: '비고' } },
] as ColumnConfig[],
],
columnLayout: [
{
name: 'groupA',
hideChildHeaders: false,
header: { text: '행정구역' },
items: ['sido', 'sgg'],
items: [
{ column: 'sido', footerUserSpans: [{ colspan: 3 }] },
'sgg',
]
},
'구분',
'수계',
@@ -59,7 +58,7 @@ export const SeweragePenetrationRateInfoList = {
items: ['mdbsn', 'lgbsn', 'mdmbsn'],
},
'specl_cntrpln_ar',
'popltn_sm',
'total_popl',
'ar_sm',
{
name: 'groupD',