From 830cbf97d1b4d65075b8ae0558c2c3f29bb26666 Mon Sep 17 00:00:00 2001 From: rsone001 Date: Tue, 3 Feb 2026 16:46:06 +0900 Subject: [PATCH] =?UTF-8?q?st:=20refactor:=20=EA=B5=AC=EB=B6=84=20?= =?UTF-8?q?=EB=B3=84=20footer=20=ED=8F=89=EA=B7=A0=20=EA=B0=92=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SeweragePenetrationRateRvwColumn.ts | 8 +- .../src/components/util/grid/footerSummary.ts | 88 ++++++++++++++++++- 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/apps/st/src/components/util/column/review/SeweragePenetrationRateRvwColumn.ts b/apps/st/src/components/util/column/review/SeweragePenetrationRateRvwColumn.ts index acb635784..f9833685b 100644 --- a/apps/st/src/components/util/column/review/SeweragePenetrationRateRvwColumn.ts +++ b/apps/st/src/components/util/column/review/SeweragePenetrationRateRvwColumn.ts @@ -1,5 +1,5 @@ import { ValueType } from "realgrid"; -import { footerIntArrayByDivision, footerDecimal3ArrayByDivision } from "@/components/util/grid/footerSummary"; +import { footerIntArrayByDivision, footerDecimal3ArrayByDivision, footerAvgDecimalArrayByDivision } from "@/components/util/grid/footerSummary"; import type { GridView, DataColumn, ColumnFooter } from "@/components/type/DataGrid.type"; // 하수도 통계 관리 01. 하수도 보급률 @@ -166,9 +166,9 @@ export const SeweragePenetrationRateInfoList = { { name: 'town_swtt_popltn', fieldName: '오수처리인구', header: { text: '오수처리인구' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' }, { name: 'town_wrrtn_popltn', fieldName: '정화조인구', header: { text: '정화조인구' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' }, { name: 'swge_proc_zone_outer_ar', fieldName: 'swge_proc_zone_outer_ar', header: { text: '면적(㎢)' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' }, - { name: 'pblswrg_popltn_suprt', fieldName: '공공하수처리구역인구보급율(%)', header: { text: '공공하수처리구역인구보급율(%)' } }, - { name: 'adtrt_popltn_suprt', fieldName: '고도처리인구보급율(%)', header: { text: `고도처리인구보급율(%)` } }, - { name: 'swrg_instlrt', fieldName: '하수도설치율(%)', header: { text: '하수도설치율(%)' } }, + { name: 'pblswrg_popltn_suprt', fieldName: '공공하수처리구역인구보급율(%)', header: { text: '공공하수처리구역인구보급율(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' }, + { name: 'adtrt_popltn_suprt', fieldName: '고도처리인구보급율(%)', header: { text: `고도처리인구보급율(%)` }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' }, + { name: 'swrg_instlrt', fieldName: '하수도설치율(%)', header: { text: '하수도설치율(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' }, { name: 'rmk', fieldName: '비고', header: { text: '비고' } }, ], columnLayout: [ diff --git a/apps/st/src/components/util/grid/footerSummary.ts b/apps/st/src/components/util/grid/footerSummary.ts index 3ae0b0982..cbf60db84 100644 --- a/apps/st/src/components/util/grid/footerSummary.ts +++ b/apps/st/src/components/util/grid/footerSummary.ts @@ -107,6 +107,55 @@ export const getFooterSummaryByDivision = ( return sum; }; +// "구분" 필드 값에 따라 필터링하여 평균 계산하는 함수 +// divisionIndex: 0 = 첫 번째 고유값, 1 = 두 번째 고유값 +export const getFooterAvgSummaryByDivision = ( + grid: GridView, + column: DataColumn, + divisionIndex: number, + divisionFieldName: string = '구분' +) => { + const dataSource = grid.getDataSource(); + const rowCount = dataSource.getRowCount(); + let sum = 0; + let count = 0; + + // "구분" 필드의 고유값 찾기 + const divisionValues = getDivisionValues(grid, divisionFieldName); + if (divisionValues.length <= divisionIndex) { + return 0; // 해당 인덱스의 고유값이 없으면 0 반환 + } + + const targetDivision = divisionValues[divisionIndex]; + + for (let i = 0; i < rowCount; i++) { + // "구분" 필드 값 확인 + const divisionValue = dataSource.getValue(i, divisionFieldName); + if (String(divisionValue) !== targetDivision) { + continue; // 해당 "구분" 값이 아니면 스킵 + } + + const cellValue = dataSource.getValue(i, column.fieldName); + + // 문자열인 경우 숫자로 변환 + const numericValue = typeof cellValue === 'string' + ? Number(String(cellValue).replace(/,/g, '')) + : Number(cellValue); + + if (!isNaN(numericValue) && numericValue !== null && numericValue !== undefined) { + sum += numericValue; + count += 1; + } + } + + if (count === 0) { + return 0; + } + + const avg = sum / count; + return Math.floor(avg * 10) / 10; +}; + // Footer 설정 객체 생성 함수 const createSumFooter = (format: string) => ({ expression: 'sum' as const, @@ -156,6 +205,38 @@ const createSumFooterArrayByDivision = (format: string) => [ }, ]; +// "구분" 값에 따라 필터링하는 평균 Footer 배열 생성 함수 (2줄) +const createAvgFooterArrayByDivision = (format: string) => [ + { + numberFormat: format, + valueCallback: ( + grid: GridView, + column: DataColumn, + footerIndex: number, + columnFooter: unknown, + value: number | string | undefined + ) => { + // footerIndex: 0 = 첫 번째 footer 행 (첫 번째 "구분" 값), 1 = 두 번째 footer 행 (두 번째 "구분" 값) + // footerIndex를 divisionIndex로 사용 + return getFooterAvgSummaryByDivision(grid, column, footerIndex); + }, + }, + { + numberFormat: format, + valueCallback: ( + grid: GridView, + column: DataColumn, + footerIndex: number, + columnFooter: unknown, + value: number | string | undefined + ) => { + // footerIndex: 0 = 첫 번째 footer 행 (첫 번째 "구분" 값), 1 = 두 번째 footer 행 (두 번째 "구분" 값) + // footerIndex를 divisionIndex로 사용 + return getFooterAvgSummaryByDivision(grid, column, footerIndex); + }, + }, +]; + // 1. 정수형 : #,##0 export const footerInt = createSumFooter('#,##0'); @@ -171,12 +252,17 @@ export const footerDecimal3 = createSumFooter('#,##0.000'); // "구분" 값에 따라 필터링하는 Footer 배열 (정수형, 2줄) export const footerIntArrayByDivision = createSumFooterArrayByDivision('#,##0'); +// "구분" 값에 따라 필터링하는 Footer 배열 (소수점 1자리, 2줄) export const footerDecimal1ArrayByDivision = createSumFooterArrayByDivision('#,##0.0'); +// "구분" 값에 따라 필터링하는 Footer 배열 (소수점 2자리, 2줄) export const footerDecimal2ArrayByDivision = createSumFooterArrayByDivision('#,##0.00'); // "구분" 값에 따라 필터링하는 Footer 배열 (소수점 3자리, 2줄) export const footerDecimal3ArrayByDivision = createSumFooterArrayByDivision('#,##0.000'); // 률(%) 평균 값(기본 소수점 1자리) -export const footerAvgDecimal = createAvgFooter('#,##0.0'); \ No newline at end of file +export const footerAvgDecimal = createAvgFooter('#,##0.0'); + +// "구분" 값에 따라 필터링하는 평균 Footer 배열 (소수점 1자리, 2줄) +export const footerAvgDecimalArrayByDivision = createAvgFooterArrayByDivision('#,##0.0'); \ No newline at end of file