feat: 02.하수관로 tab4관경별 현황 조회 기능

This commit is contained in:
2026-02-16 16:33:25 +09:00
parent ca83ac22aa
commit 37e3b6ebdb
4 changed files with 193 additions and 32 deletions
@@ -96,6 +96,8 @@ const SewagePipeRvw = () => {
response = await statisticsManagementApi.getSewagePipeFacilityList(searchParamRef.current);
}else if(tabKey === 'c'){
response = await statisticsManagementApi.getSewagePipeTypeList(searchParamRef.current);
}else if(tabKey === 'd'){
response = await statisticsManagementApi.getSewagePipeDiamList(searchParamRef.current);
}
if (response?.status === 'success' && response.data) {
@@ -436,7 +436,6 @@ const rawList = [
{ name: 'layingExtnSum', fieldName: 'layingExtnSum', header: { text: '매설연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'remvlExtnSum', fieldName: 'remvlExtnSum', header: { text: '철거연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
/* 30개년 동적 컬럼 생성 (SewerPipeTypeItem 필드 매핑) */
...Array.from({ length: 30 }, (_, i) => {
const yNum = (30 - i).toString().padStart(2, '0');
const yrOffset = 29 - i;
@@ -455,7 +454,7 @@ const rawList = [
name: 'areaGroup',
header: { text: '행정구역' },
items: [
// sido부터 swrgPipeNm(관종)까지 푸터 병합
{ column: 'sido', footerUserSpans: [{ colspan: 4 }, { colspan: 4 }] },
'gugun',
'swrgPipeNm',
@@ -478,33 +477,131 @@ const rawList = [
'rmk'
]
},
{
tabKey: 'd',
tabLabel: '관경별 현황',
rowStartNum: 2,
fixedColumns: 3,
columns: [
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' } },
{ name: 'GUGUN', fieldName: '시군구', header: { text: '구군' } },
{ name: 'SWRG_PIPE_NM', fieldName: '관종', header: { text: '관종' } },
{ name: 'YR_GBN', fieldName: '구분', header: { text: '구분' } },
{ name: 'TOTAL_EXTN_M', fieldName: '총계(m)', header: { text: '총계(m)' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'UNDER_200', fieldName: '200mm 미만', header: { text: '200mm 미만' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'OVER_200_UNDEV_300', fieldName: '200mm이상~300mm미만', header: { text: '200mm이상~\n300mm미만' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'OVER_300_UNDEV_500', fieldName: '300mm이상~500mm미만', header: { text: '300mm이상~\n500mm미만' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'OVER_500_UNDEV_800', fieldName: '500mm이상~800mm미만', header: { text: '500mm이상~\n800mm미만' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'OVER_800', fieldName: '800mm 이상', header: { text: '800mm 이상' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'BOX', fieldName: '사각형(m)', header: { text: '사각형(m)' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'ETC', fieldName: '기타(측구/개거 등)', header: { text: '기타\n(측구/개거 등)' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
],
columnLayout: [
{ name: 'addrGroup', header: { text: '행정구역' }, items: ['SIDO', 'GUGUN'] },
'SWRG_PIPE_NM', 'YR_GBN', 'TOTAL_EXTN_M',
{ name: 'circleGroup', header: { text: '원형(m)' }, items: ['UNDER_200', 'OVER_200_UNDEV_300', 'OVER_300_UNDEV_500', 'OVER_500_UNDEV_800', 'OVER_800'] },
'BOX', 'ETC', 'RMK',
]
}
{
tabKey: 'd',
tabLabel: '관경별 현황',
rowStartNum: 2,
fixedColumns: 3,
columns: [
{
name: 'sido',
fieldName: 'sido',
header: { text: '시도' },
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));
}
}
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));
}
}
const divisionValues = Array.from(uniqueValues);
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
}
}
]
},
{ name: 'gugun', fieldName: 'gugun', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
{ name: 'swrgPipeNm', fieldName: 'swrgPipeNm', header: { text: '관종' }, mergeCells: true, 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));
}
}
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));
}
}
const divisionValues = Array.from(uniqueValues);
return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
}
}
]
},
{ name: 'totalExtnM', fieldName: 'totalExtnM', header: { text: '총계(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'under200', fieldName: 'under200', header: { text: '200mm 미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'over200Undev300', fieldName: 'over200Undev300', header: { text: '200mm이상~\n300mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'over300Undev500', fieldName: 'over300Undev500', header: { text: '300mm이상~\n500mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'over500Undev500', fieldName: 'over500Undev500', header: { text: '500mm이상~\n800mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'over800', fieldName: 'over800', header: { text: '800mm 이상' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'box', fieldName: 'box', header: { text: '사각형(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'etc', fieldName: 'etc', header: { text: '기타\n(측구/개거 등)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
{ name: 'rmk', fieldName: 'rmk', header: { text: '비고' } },
],
columnLayout: [
{
name: 'addrGroup',
header: { text: '행정구역' },
items: [
{ column: 'sido', footerUserSpans: [{ colspan: 4 }, { colspan: 4 }] },
'gugun',
'swrgPipeNm',
]
},
'displayYear',
'totalExtnM',
{
name: 'circleGroup',
header: { text: '원형(m)' },
items: ['under200', 'over200Undev300', 'over300Undev500', 'over500Undev500', 'over800']
},
'box',
'etc',
'rmk'
]
}
];
export const SewagePipeColumnInfoListRvw = rawList.map(tab => ({
@@ -13,6 +13,7 @@ import {
type SewagePipeReviewRegionalApiResponse ,
type SewagePipeFacilityApiResponse,
type SewerPipeTypeApiResponse,
type SewerPipeDiamApiResponse
} from "../model/statistics-sewage-pipe-review-interface";
@@ -95,7 +96,7 @@ export class StatisticsManagementApiService {
}
/**
* 02. 하수관로 관종별 시설현황 조회 (Tab2)
* 02. 하수관로 관종별 시설현황 조회 (Tab3)
* @param params (sido, gugun, yr, bsnmCd)
*/
public async getSewagePipeTypeList(
@@ -112,6 +113,25 @@ export class StatisticsManagementApiService {
);
return response.data;
}
/**
* 02. 하수관로 관경별 시설현황 조회 (Tab 4)
* @param params (sido, gugun, yr, bsnmCd)
*/
public async getSewagePipeDiamList(
params: {
yr?: string;
bsnmCd?: string;
sido?: string;
gugun?: string;
}
): Promise<SewerPipeDiamApiResponse> {
const response = await axios.get<SewerPipeDiamApiResponse>(
`${ENDPOINT.ST_SERVICE.REVIEW}/sewer-pipe/diam-status`,
{ params }
);
return response.data;
}
}
// 통합 인스턴스 수출
@@ -82,7 +82,10 @@ export interface SewagePipeReviewService {
}): Promise<SewagePipeReviewRegionalApiResponse>;
}
/**
* 02. 하수관로 시설별 시설현황 (Tab 2)
*
*/
export interface SewagePipeReviewFacilityItem {
// 1. 행정구역 및 기본 정보
sido: string; // 시도
@@ -152,7 +155,7 @@ export interface SewagePipeFacilityService {
}
/**
* 02. 하수관로 관종별 시설현황 (PipeType)
* 02. 하수관로 관종별 시설현황 (Tab 3)
*
*/
export interface SewerPipeTypeItem {
@@ -196,4 +199,43 @@ export interface SewagePipeTypeService {
sido?: string; // 시도
gugun?: string; // 구군
}): Promise<SewerPipeTypeApiResponse>;
}
/**
* 02. 하수관로 관경별 시설현황 아이템 (Tab 4)
*/
export interface SewerPipeDiamItem {
sido: string; // 시도
gugun: string; // 시군구
adstCd: string; // 행정코드
swrgPipeNm: string; // 관종명 (또는 관경 관련 명칭)
displayYear: string; // 구분 (예: 2023년 확정 / 2024년)
// 관경별 수치 데이터
under200: number; // 200미만
over200Undev300: number; // 200~300
over300Undev500: number; // 300~500
over500Undev500: number; // 500~800 (DTO 명칭 기준)
over800: number; // 800이상
box: number; // BOX
etc: number; // 기타
rmk: string; // 비고
}
export interface SewerPipeDiamResponseData {
pipeDiamStatusList: SewerPipeDiamItem[];
}
export type SewerPipeDiamApiResponse = ApiResponse<SewerPipeDiamResponseData>;
export interface SewagePipeDiamService {
getSewagePipeDiamList(params: {
yr?: string; // 조회 연도
bsnmCd?: string; // 사업장 코드
sido?: string; // 시도
gugun?: string; // 구군
}): Promise<SewerPipeDiamApiResponse>;
}