Merge remote-tracking branch 'origin/iipbs/st/dev' into feature/review-skeleton-sein
This commit is contained in:
@@ -178,6 +178,7 @@ const CompactDataGrid = ({ columnInfo, fixedColumns, showHeaderCheckbox = false,
|
||||
editable: col.editable,
|
||||
valueType: col.valueType,
|
||||
dataFormat: col.dataFormat,
|
||||
...(col.styleName != null && { styleName: col.styleName }),
|
||||
...(col.mergeCells && { mergeRule: { criteria: 'value' as const } }),
|
||||
};
|
||||
|
||||
|
||||
@@ -591,6 +591,7 @@ const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport
|
||||
editable: col.editable,
|
||||
valueType: col.valueType,
|
||||
dataFormat: col.dataFormat,
|
||||
...(col.styleName != null && { styleName: col.styleName }),
|
||||
...(col.mergeCells && { mergeRule: { criteria: 'value' as const } }),
|
||||
};
|
||||
|
||||
|
||||
@@ -40,10 +40,11 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
|
||||
const [values, setValues] = useState<SearchFormValues>({
|
||||
sido: props.defaultValues?.sido || "",
|
||||
gugun: props.defaultValues?.gugun || "",
|
||||
gugun: props.defaultValues?.gugun || '',
|
||||
year: props.defaultValues?.year || String(defaultYear),
|
||||
order: props.defaultValues?.order || "",
|
||||
fctName: props.defaultValues?.fctName || "",
|
||||
order: props.defaultValues?.order || '',
|
||||
fctName: props.defaultValues?.fctName || '',
|
||||
bsnmCd: props.defaultValues?.bsnmCd || '',
|
||||
});
|
||||
|
||||
const { data: sidoList } = useSWR<ApiResponse<Sido[]>>(
|
||||
@@ -98,16 +99,28 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
|
||||
const handleReset = () => {
|
||||
const resetValues: SearchFormValues = {
|
||||
sido: "",
|
||||
gugun: "",
|
||||
sido: '',
|
||||
gugun: '',
|
||||
year: String(defaultYear),
|
||||
order: "",
|
||||
fctName: "",
|
||||
order: '',
|
||||
fctName: '',
|
||||
bsnmCd: '',
|
||||
};
|
||||
setValues(resetValues);
|
||||
props.onReset?.();
|
||||
};
|
||||
|
||||
const handleSidoChange = (value: string) => {
|
||||
const selectedBsnm = sidoList?.data.find((v) => v.sido === value)?.bsnmCd || '';
|
||||
|
||||
setValues((prev) => ({
|
||||
...prev,
|
||||
sido: value,
|
||||
gugun: '',
|
||||
bsnmCd: selectedBsnm,
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card card-border">
|
||||
<form onSubmit={handleSubmit}>
|
||||
@@ -117,7 +130,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
<Label className="text-label">
|
||||
시도
|
||||
</Label>
|
||||
<Select value={values.sido} onValueChange={(value) => setValues((prev) => ({ ...prev, sido: value, gugun: "" }))}>
|
||||
<Select value={values.sido} onValueChange={handleSidoChange}>
|
||||
<SelectTrigger className="w-[12rem]">
|
||||
<SelectValue placeholder="선택"></SelectValue>
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -793,6 +793,7 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, isExcelExport = true, r
|
||||
editable: col.editable,
|
||||
valueType: col.valueType,
|
||||
dataFormat: col.dataFormat,
|
||||
...(col.styleName != null && { styleName: col.styleName }),
|
||||
...(col.mergeCells && { mergeRule: { criteria: 'value' as const } }),
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
const response = await statisticsInputAPi.getSewerageSupplyRateList({
|
||||
sido: values.sido,
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
bsnmCd: '4139000000',
|
||||
bsnmCd: values.bsnmCd,
|
||||
yr: values.year,
|
||||
demoYr: values.year,
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ export type RealGridColumnInfo = {
|
||||
editable?: boolean;
|
||||
valueType?: import("realgrid").ValueType;
|
||||
dataFormat?: string;
|
||||
styleName?: string;
|
||||
mergeRule?: { criteria: 'value' };
|
||||
footer?: {
|
||||
text?: string;
|
||||
|
||||
@@ -4,6 +4,7 @@ export type SearchFormValues = {
|
||||
year?: string;
|
||||
order?: string;
|
||||
fctName?: string;
|
||||
bsnmCd?: string;
|
||||
};
|
||||
|
||||
export type SearchFormProps = {
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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');
|
||||
export const footerAvgDecimal = createAvgFooter('#,##0.0');
|
||||
|
||||
// "구분" 값에 따라 필터링하는 평균 Footer 배열 (소수점 1자리, 2줄)
|
||||
export const footerAvgDecimalArrayByDivision = createAvgFooterArrayByDivision('#,##0.0');
|
||||
@@ -1,11 +1,13 @@
|
||||
export interface Sido {
|
||||
adstDstrCd: string;
|
||||
sido: string;
|
||||
bsnmCd: string;
|
||||
}
|
||||
|
||||
export interface Sgg {
|
||||
adstDstrCd: string;
|
||||
gugun: string;
|
||||
bsnmCd: string;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
|
||||
Reference in New Issue
Block a user