diff --git a/apps/st/src/components/util/column/review/SewagePipeRvwColumn.ts b/apps/st/src/components/util/column/review/SewagePipeRvwColumn.ts
index 1adb4eadf..0178b60e9 100644
--- a/apps/st/src/components/util/column/review/SewagePipeRvwColumn.ts
+++ b/apps/st/src/components/util/column/review/SewagePipeRvwColumn.ts
@@ -6,7 +6,7 @@ import type { GridView } from "@/components/type/DataGrid.type";
const currentYear = dayjs().year() - 1;
const startYear = 1996;
-const totalCount = currentYear - startYear + 1 + 1;
+const totalCount = currentYear - startYear + 1 + 1;
// 하수도 통계 관리 02. 하수관로
const rawList = [
@@ -15,527 +15,535 @@ const rawList = [
tabLabel: '지역별 시설현황',
rowStartNum: 4,
fixedColumns: 2,
- columns: [
- {
- name: 'ctpvNm',
- fieldName: 'ctpvNm',
- header: { text: '시도' },
- mergeCells: true,
- sortdisable: true,
- footer: [
+ columns: [
{
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set
();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
+ name: 'ctpvNm',
+ fieldName: 'ctpvNm',
+ header: { text: '시도' },
+ mergeCells: true,
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ 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) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
- }
- }
- ]
- },
- { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
- { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true },
- {
- name: 'displayYear',
- fieldName: 'displayYear',
- header: { text: '구분' },
- sortdisable: true,
- footer: [
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
- }
- },
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
- }
- }
- ]
- },
-
- /* 하수정비 기본계획 및 총계 */
- { name: 'goalYr', fieldName: 'goalYr', header: { text: '하수정보기본계획목표년도' } },
- { name: 'wholPplMtncPlanPrlg', fieldName: 'wholPplMtncPlanPrlg', header: { text: '총관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'wholPlanPrlg', fieldName: 'wholPlanPrlg', header: { text: '총계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'wholFcltPrlg', fieldName: 'wholFcltPrlg', header: { text: '총시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'swagePplPsplyRt', fieldName: 'swagePplPsplyRt', header: { text: '하수관로\n보급률(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
-
- /* 합류식 */
- { name: 'cbsysPplMtncPlanArea', fieldName: 'cbsysPplMtncPlanArea', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
- { name: 'cbsysPplMtncPlanPrlg', fieldName: 'cbsysPplMtncPlanPrlg', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysPlanPrlg', fieldName: 'cbsysPlanPrlg', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysFcltPrlg', fieldName: 'cbsysFcltPrlg', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysSqrePrlg', fieldName: 'cbsysSqrePrlg', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysCiclPrlg', fieldName: 'cbsysCiclPrlg', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysOpnPrlg', fieldName: 'cbsysOpnPrlg', header: { text: '개거(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysGttrPrlg', fieldName: 'cbsysGttrPrlg', header: { text: '측구(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
-
- /* 분류식 - 오수관로 */
- { name: 'drtwPplMtncPlanArea', fieldName: 'drtwPplMtncPlanArea', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
- { name: 'drtwPplMtncPlanPrlg', fieldName: 'drtwPplMtncPlanPrlg', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'drtwPplPlanPrlg', fieldName: 'drtwPplPlanPrlg', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'drtwPplFcltPrlg', fieldName: 'drtwPplFcltPrlg', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'drtwPplSqrePrlg', fieldName: 'drtwPplSqrePrlg', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'drtwPplCiclPrlg', fieldName: 'drtwPplCiclPrlg', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
-
- /* 분류식 - 우수관로 */
- { name: 'exlnPplMtncPlanArea', fieldName: 'exlnPplMtncPlanArea', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
- { name: 'exlnPplMtncPlanPrlg', fieldName: 'exlnPplMtncPlanPrlg', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'exlnPplPlanPrlg', fieldName: 'exlnPplPlanPrlg', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'exlnPplFcltPrlg', fieldName: 'exlnPplFcltPrlg', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'exlnPplSqrePrlg', fieldName: 'exlnPplSqrePrlg', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'exlnPplCiclPrlg', fieldName: 'exlnPplCiclPrlg', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'exlnPplOpnPrlg', fieldName: 'exlnPplOpnPrlg', header: { text: '개거(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'exlnPplGttrPrlg', fieldName: 'exlnPplGttrPrlg', header: { text: '측구(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
-
- /* 부속시설 */
- { name: 'cbsysMnhlCnt', fieldName: 'cbsysMnhlCnt', header: { text: '합류식맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'sprsysDrtwMnhlCnt', fieldName: 'sprsysDrtwMnhlCnt', header: { text: '오수맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'sprsysExlnMnhlCnt', fieldName: 'sprsysExlnMnhlCnt', header: { text: '우수맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'drtwRcvprpCnt', fieldName: 'drtwRcvprpCnt', header: { text: '오수받이(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'exlnRcvprpCnt', fieldName: 'exlnRcvprpCnt', header: { text: '우수받이(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'stofcbrCnt', fieldName: 'stofcbrCnt', header: { text: '우수토실(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'exlnOtflCnt', fieldName: 'exlnOtflCnt', header: { text: '우수토구(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
-
- /* 대장 및 기타*/
- { name: 'sewerLdgrEdpPrlg', fieldName: 'sewerLdgrEdpPrlg', header: { text: '하수도대장전산화연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'sewerLdgrEdpRt', fieldName: 'sewerLdgrEdpRt', header: { text: '하수도대장전산화율(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
-],
- columnLayout: [
- {
- name: 'areaGroup', header: { text: '행정구역' }, items: [
- { column: 'ctpvNm', footerUserSpans: [{ colspan: 4 }, { colspan: 4 }] },
- 'sggNm',
- 'admdstNm',
- ]
- },
- 'displayYear',
- 'goalYr', 'wholPplMtncPlanPrlg', 'wholPlanPrlg', 'wholFcltPrlg', 'swagePplPsplyRt',
- {
- name: 'combinedGroup', header: { text: '합류식(m)' },
- items: ['cbsysPplMtncPlanArea', 'cbsysPplMtncPlanPrlg', 'cbsysPlanPrlg', 'cbsysFcltPrlg',
- { name: 'cmbnAmGroup', header: { text: '암거' }, items: ['cbsysSqrePrlg', 'cbsysCiclPrlg'] },
- 'cbsysOpnPrlg', 'cbsysGttrPrlg'
- ],
- },
- {
- name: 'sepGroup', header: { text: '분류식(m)' },
- items: [
- {
- name: 'foulPipeGroup', header: { text: '오수관로' },
- items: ['drtwPplMtncPlanArea', 'drtwPplMtncPlanPrlg', 'drtwPplPlanPrlg', 'drtwPplFcltPrlg',
- { name: 'foulAmGroup', header: { text: '암거' }, items: ['drtwPplSqrePrlg', 'drtwPplCiclPrlg'] }]
- },
- {
- name: 'rainPipeGroup', header: { text: '우수관로' },
- items: ['exlnPplMtncPlanArea', 'exlnPplMtncPlanPrlg', 'exlnPplPlanPrlg', 'exlnPplFcltPrlg',
- { name: 'rainAmGroup', header: { text: '암거' }, items: ['exlnPplSqrePrlg', 'exlnPplCiclPrlg'] },
- 'exlnPplOpnPrlg', 'exlnPplGttrPrlg']
- }
- ],
- },
- 'cbsysMnhlCnt',
- { name: 'fcltyGroup', header: { text: '분류식' }, items: ['sprsysDrtwMnhlCnt', 'sprsysExlnMnhlCnt'] },
- 'drtwRcvprpCnt', 'exlnRcvprpCnt', 'stofcbrCnt', 'exlnOtflCnt', 'sewerLdgrEdpPrlg', 'sewerLdgrEdpRt', 'rmrk'
- ]
- },
- {
- tabKey: 'ST00020002',
- tabLabel: '시설별 설치현황',
- rowStartNum: 4,
- fixedColumns: 4,
- columns: [
- {
- name: 'ctpvNm',
- fieldName: 'ctpvNm',
- header: { text: '시도' },
- mergeCells: true,
- sortdisable: true,
- footer: [
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const rowCount = dataSource.getRowCount();
- const uniqueValues = new Set();
- for (let i = 0; i < rowCount; i++) {
- const divisionValue = dataSource.getValue(i, 'displayYear');
- if (divisionValue) uniqueValues.add(String(divisionValue));
- }
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + ' 합계' : '합계';
- }
- },
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const rowCount = dataSource.getRowCount();
- const uniqueValues = new Set();
- for (let i = 0; i < rowCount; i++) {
- const divisionValue = dataSource.getValue(i, 'displayYear');
- if (divisionValue) uniqueValues.add(String(divisionValue));
- }
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + ' 합계' : '합계';
- }
- }
- ]
- },
- { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
- { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
- { name: 'swtrmtFcltNm', fieldName: 'swtrmtFcltNm', header: { text: '하수처리시설 명' }, mergeCells: true, mergeGroupField: 'admdstNm' },
- {
- name: 'displayYear',
- fieldName: 'displayYear',
- header: { text: '구분' },
- sortdisable: true,
- footer: [
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + ' 합계' : '';
- }
- },
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + ' 합계' : '';
- }
- }
- ]
- },
- { name: 'prcsFcltCpct', fieldName: 'prcsFcltCpct', header: { text: '하수처리\n시설용량\n(㎥/일)' },valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'prcsZoneArea', fieldName: 'prcsZoneArea', header: { text: '합계' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
- { name: 'cbsysPrcsZoneArea', fieldName: 'cbsysPrcsZoneArea', header: { text: '합류식' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
- { name: 'sprsysPrcsZoneArea', fieldName: 'sprsysPrcsZoneArea', header: { text: '분류식' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
- { name: 'sprsysVartnRt', fieldName: 'sprsysVartnRt', header: { text: '분류식화' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
- { name: 'mltvEqpmCnt', fieldName: 'mltvEqpmCnt', header: { text: '합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'cbsysMltvEqpmCnt', fieldName: 'cbsysMltvEqpmCnt', header: { text: '합류식' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'sprsysMltvEqpmCnt', fieldName: 'sprsysMltvEqpmCnt', header: { text: '분류식 합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'wholFcltPrlg', fieldName: 'wholFcltPrlg', header: { text: '총\n시설연장\n(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'wholIcptgAtlfcPrlg', fieldName: 'wholIcptgAtlfcPrlg', header: { text: '합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'icptgPrlg', fieldName: 'icptgPrlg', header: { text: '차집' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'atlfcsPrlg', fieldName: 'atlfcsPrlg', header: { text: '오수간선' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysStofcbrCnt', fieldName: 'cbsysStofcbrCnt', header: { text: '우수토실(합류)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'sprsysStofcbrCnt', fieldName: 'sprsysStofcbrCnt', header: { text: '우수토실(분류)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'sprsysExlnOtflCnt', fieldName: 'sprsysExlnOtflCnt', header: { text: '우수토구(분류)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
- { name: 'wholBrchlnPrlg', fieldName: 'wholBrchlnPrlg', header: { text: '합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'cbsysBrchlnPrlg', fieldName: 'cbsysBrchlnPrlg', header: { text: '합류식' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'exlnBrchlnPrlg', fieldName: 'exlnBrchlnPrlg', header: { text: '우수' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'drtwBrchlnPrlg', fieldName: 'drtwBrchlnPrlg', header: { text: '오수' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
- { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
-],
- columnLayout: [
- {
- name: 'addrGroup', header: { text: '행정구역' },
- items: [
- { column: 'ctpvNm', footerUserSpans: [{ colspan: 6 }, { colspan: 6 }] },
- 'sggNm', 'admdstNm'
- ]
- },
- 'swtrmtFcltNm','prcsFcltCpct', 'displayYear',
- { name: 'areaGroup', header: { text: '처리구역면적(㎢)' }, items: ['prcsZoneArea', 'cbsysPrcsZoneArea', 'sprsysPrcsZoneArea'] },
- 'sprsysVartnRt',
- { name: 'drainGroup', header: { text: '배수설비(개소)' }, items: ['mltvEqpmCnt', 'cbsysMltvEqpmCnt', 'sprsysMltvEqpmCnt'] },
- {
- name: 'pipeGroup', header: { text: '하수관로' },
- items: [
- 'wholFcltPrlg',
- { name: 'trunkGroup', header: { text: '차집/오수간선(m)' }, items: ['wholIcptgAtlfcPrlg', 'icptgPrlg', 'atlfcsPrlg'] },
- {
- name: 'siteGroup', header: { text: '토실/토구(개소)' },
- items: [
- { name: 'cmbnSiteGroup', header: { text: '합류식' }, items: ['cbsysStofcbrCnt'] },
- { name: 'sepSiteGroup', header: { text: '분류식' }, items: ['sprsysStofcbrCnt', 'sprsysExlnOtflCnt'] }
]
},
+ { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
+ { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true },
{
- name: 'branchGroup', header: { text: '지선(m)' },
- items: ['wholBrchlnPrlg', 'cbsysBrchlnPrlg', { name: 'sepBranchGroup', header: { text: '분류식' }, items: ['exlnBrchlnPrlg', 'drtwBrchlnPrlg'] }]
- }
+ name: 'displayYear',
+ fieldName: 'displayYear',
+ header: { text: '구분' },
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '';
+ }
+ }
+ ]
+ },
+
+ /* 하수정비 기본계획 및 총계 */
+ { name: 'goalYr', fieldName: 'goalYr', header: { text: '하수정보기본계획목표년도' } },
+ { name: 'wholPplMtncPlanPrlg', fieldName: 'wholPplMtncPlanPrlg', header: { text: '총관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'wholPlanPrlg', fieldName: 'wholPlanPrlg', header: { text: '총계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'wholFcltPrlg', fieldName: 'wholFcltPrlg', header: { text: '총시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'swagePplPsplyRt', fieldName: 'swagePplPsplyRt', header: { text: '하수관로\n보급률(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+
+ /* 합류식 */
+ { name: 'cbsysPplMtncPlanArea', fieldName: 'cbsysPplMtncPlanArea', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
+ { name: 'cbsysPplMtncPlanPrlg', fieldName: 'cbsysPplMtncPlanPrlg', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysPlanPrlg', fieldName: 'cbsysPlanPrlg', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysFcltPrlg', fieldName: 'cbsysFcltPrlg', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysSqrePrlg', fieldName: 'cbsysSqrePrlg', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysCiclPrlg', fieldName: 'cbsysCiclPrlg', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysOpnPrlg', fieldName: 'cbsysOpnPrlg', header: { text: '개거(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysGttrPrlg', fieldName: 'cbsysGttrPrlg', header: { text: '측구(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+
+ /* 분류식 - 오수관로 */
+ { name: 'drtwPplMtncPlanArea', fieldName: 'drtwPplMtncPlanArea', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
+ { name: 'drtwPplMtncPlanPrlg', fieldName: 'drtwPplMtncPlanPrlg', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'drtwPplPlanPrlg', fieldName: 'drtwPplPlanPrlg', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'drtwPplFcltPrlg', fieldName: 'drtwPplFcltPrlg', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'drtwPplSqrePrlg', fieldName: 'drtwPplSqrePrlg', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'drtwPplCiclPrlg', fieldName: 'drtwPplCiclPrlg', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+
+ /* 분류식 - 우수관로 */
+ { name: 'exlnPplMtncPlanArea', fieldName: 'exlnPplMtncPlanArea', header: { text: '관로정비\n계획면적(㎢)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
+ { name: 'exlnPplMtncPlanPrlg', fieldName: 'exlnPplMtncPlanPrlg', header: { text: '관로정비\n계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'exlnPplPlanPrlg', fieldName: 'exlnPplPlanPrlg', header: { text: '계획연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'exlnPplFcltPrlg', fieldName: 'exlnPplFcltPrlg', header: { text: '시설연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'exlnPplSqrePrlg', fieldName: 'exlnPplSqrePrlg', header: { text: '사각형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'exlnPplCiclPrlg', fieldName: 'exlnPplCiclPrlg', header: { text: '원형(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'exlnPplOpnPrlg', fieldName: 'exlnPplOpnPrlg', header: { text: '개거(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'exlnPplGttrPrlg', fieldName: 'exlnPplGttrPrlg', header: { text: '측구(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+
+ /* 부속시설 */
+ { name: 'cbsysMnhlCnt', fieldName: 'cbsysMnhlCnt', header: { text: '합류식맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'sprsysDrtwMnhlCnt', fieldName: 'sprsysDrtwMnhlCnt', header: { text: '오수맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'sprsysExlnMnhlCnt', fieldName: 'sprsysExlnMnhlCnt', header: { text: '우수맨홀(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'drtwRcvprpCnt', fieldName: 'drtwRcvprpCnt', header: { text: '오수받이(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'exlnRcvprpCnt', fieldName: 'exlnRcvprpCnt', header: { text: '우수받이(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'stofcbrCnt', fieldName: 'stofcbrCnt', header: { text: '우수토실(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'exlnOtflCnt', fieldName: 'exlnOtflCnt', header: { text: '우수토구(개소)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+
+ /* 대장 및 기타*/
+ { name: 'sewerLdgrEdpPrlg', fieldName: 'sewerLdgrEdpPrlg', header: { text: '하수도대장전산화연장(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'sewerLdgrEdpRt', fieldName: 'sewerLdgrEdpRt', header: { text: '하수도대장전산화율(%)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
],
+ columnLayout: [
+ {
+ name: 'areaGroup', header: { text: '행정구역' }, items: [
+ { column: 'ctpvNm', footerUserSpans: [{ colspan: 4 }, { colspan: 4 }] },
+ 'sggNm',
+ 'admdstNm',
+ ]
+ },
+ 'displayYear',
+ 'goalYr', 'wholPplMtncPlanPrlg', 'wholPlanPrlg', 'wholFcltPrlg', 'swagePplPsplyRt',
+ {
+ name: 'combinedGroup', header: { text: '합류식(m)' },
+ items: ['cbsysPplMtncPlanArea', 'cbsysPplMtncPlanPrlg', 'cbsysPlanPrlg', 'cbsysFcltPrlg',
+ { name: 'cmbnAmGroup', header: { text: '암거' }, items: ['cbsysSqrePrlg', 'cbsysCiclPrlg'] },
+ 'cbsysOpnPrlg', 'cbsysGttrPrlg'
+ ],
+ },
+ {
+ name: 'sepGroup', header: { text: '분류식(m)' },
+ items: [
+ {
+ name: 'foulPipeGroup', header: { text: '오수관로' },
+ items: ['drtwPplMtncPlanArea', 'drtwPplMtncPlanPrlg', 'drtwPplPlanPrlg', 'drtwPplFcltPrlg',
+ { name: 'foulAmGroup', header: { text: '암거' }, items: ['drtwPplSqrePrlg', 'drtwPplCiclPrlg'] }]
+ },
+ {
+ name: 'rainPipeGroup', header: { text: '우수관로' },
+ items: ['exlnPplMtncPlanArea', 'exlnPplMtncPlanPrlg', 'exlnPplPlanPrlg', 'exlnPplFcltPrlg',
+ { name: 'rainAmGroup', header: { text: '암거' }, items: ['exlnPplSqrePrlg', 'exlnPplCiclPrlg'] },
+ 'exlnPplOpnPrlg', 'exlnPplGttrPrlg']
+ }
+ ],
+ },
+ 'cbsysMnhlCnt',
+ { name: 'fcltyGroup', header: { text: '분류식' }, items: ['sprsysDrtwMnhlCnt', 'sprsysExlnMnhlCnt'] },
+ 'drtwRcvprpCnt', 'exlnRcvprpCnt', 'stofcbrCnt', 'exlnOtflCnt', 'sewerLdgrEdpPrlg', 'sewerLdgrEdpRt', 'rmrk'
+ ]
},
- 'rmrk'
-]
+
+ {
+ tabKey: 'ST00020002',
+ tabLabel: '시설별 설치현황',
+ rowStartNum: 4,
+ fixedColumns: 4,
+ columns: [
+ {
+ name: 'ctpvNm',
+ fieldName: 'ctpvNm',
+ header: { text: '시도' },
+ mergeCells: true,
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const rowCount = dataSource.getRowCount();
+ const uniqueValues = new Set();
+ for (let i = 0; i < rowCount; i++) {
+ const divisionValue = dataSource.getValue(i, 'displayYear');
+ if (divisionValue) uniqueValues.add(String(divisionValue));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + ' 합계' : '합계';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const rowCount = dataSource.getRowCount();
+ const uniqueValues = new Set();
+ for (let i = 0; i < rowCount; i++) {
+ const divisionValue = dataSource.getValue(i, 'displayYear');
+ if (divisionValue) uniqueValues.add(String(divisionValue));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + ' 합계' : '합계';
+ }
+ }
+ ]
+ },
+ { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
+ { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
+ { name: 'swtrmtFcltNm', fieldName: 'swtrmtFcltNm', header: { text: '하수처리시설 명' }, mergeCells: true, mergeGroupField: 'admdstNm' },
+ {
+ name: 'displayYear',
+ fieldName: 'displayYear',
+ header: { text: '구분' },
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + ' 합계' : '';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + ' 합계' : '';
+ }
+ }
+ ]
+ },
+ { name: 'prcsFcltCpct', fieldName: 'prcsFcltCpct', header: { text: '하수처리\n시설용량\n(㎥/일)' }, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'prcsZoneArea', fieldName: 'prcsZoneArea', header: { text: '합계' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
+ { name: 'cbsysPrcsZoneArea', fieldName: 'cbsysPrcsZoneArea', header: { text: '합류식' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
+ { name: 'sprsysPrcsZoneArea', fieldName: 'sprsysPrcsZoneArea', header: { text: '분류식' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
+ { name: 'sprsysVartnRt', fieldName: 'sprsysVartnRt', header: { text: '분류식화' }, footer: footerDecimal3ArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.000' },
+ { name: 'mltvEqpmCnt', fieldName: 'mltvEqpmCnt', header: { text: '합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'cbsysMltvEqpmCnt', fieldName: 'cbsysMltvEqpmCnt', header: { text: '합류식' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'sprsysMltvEqpmCnt', fieldName: 'sprsysMltvEqpmCnt', header: { text: '분류식 합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'wholFcltPrlg', fieldName: 'wholFcltPrlg', header: { text: '총\n시설연장\n(m)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'wholIcptgAtlfcPrlg', fieldName: 'wholIcptgAtlfcPrlg', header: { text: '합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'icptgPrlg', fieldName: 'icptgPrlg', header: { text: '차집' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'atlfcsPrlg', fieldName: 'atlfcsPrlg', header: { text: '오수간선' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysStofcbrCnt', fieldName: 'cbsysStofcbrCnt', header: { text: '우수토실(합류)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'sprsysStofcbrCnt', fieldName: 'sprsysStofcbrCnt', header: { text: '우수토실(분류)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'sprsysExlnOtflCnt', fieldName: 'sprsysExlnOtflCnt', header: { text: '우수토구(분류)' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0' },
+ { name: 'wholBrchlnPrlg', fieldName: 'wholBrchlnPrlg', header: { text: '합계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'cbsysBrchlnPrlg', fieldName: 'cbsysBrchlnPrlg', header: { text: '합류식' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'exlnBrchlnPrlg', fieldName: 'exlnBrchlnPrlg', header: { text: '우수' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'drtwBrchlnPrlg', fieldName: 'drtwBrchlnPrlg', header: { text: '오수' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.00' },
+ { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
+ ],
+ columnLayout: [
+ {
+ name: 'addrGroup', header: { text: '행정구역' },
+ items: [
+ { column: 'ctpvNm', footerUserSpans: [{ colspan: 6 }, { colspan: 6 }] },
+ 'sggNm', 'admdstNm'
+ ]
+ },
+ 'swtrmtFcltNm', 'prcsFcltCpct', 'displayYear',
+ { name: 'areaGroup', header: { text: '처리구역면적(㎢)' }, items: ['prcsZoneArea', 'cbsysPrcsZoneArea', 'sprsysPrcsZoneArea'] },
+ 'sprsysVartnRt',
+ { name: 'drainGroup', header: { text: '배수설비(개소)' }, items: ['mltvEqpmCnt', 'cbsysMltvEqpmCnt', 'sprsysMltvEqpmCnt'] },
+ {
+ name: 'pipeGroup', header: { text: '하수관로' },
+ items: [
+ 'wholFcltPrlg',
+ { name: 'trunkGroup', header: { text: '차집/오수간선(m)' }, items: ['wholIcptgAtlfcPrlg', 'icptgPrlg', 'atlfcsPrlg'] },
+ {
+ name: 'siteGroup', header: { text: '토실/토구(개소)' },
+ items: [
+ { name: 'cmbnSiteGroup', header: { text: '합류식' }, items: ['cbsysStofcbrCnt'] },
+ { name: 'sepSiteGroup', header: { text: '분류식' }, items: ['sprsysStofcbrCnt', 'sprsysExlnOtflCnt'] }
+ ]
+ },
+ {
+ name: 'branchGroup', header: { text: '지선(m)' },
+ items: ['wholBrchlnPrlg', 'cbsysBrchlnPrlg', { name: 'sepBranchGroup', header: { text: '분류식' }, items: ['exlnBrchlnPrlg', 'drtwBrchlnPrlg'] }]
+ }
+ ],
+ },
+ 'rmrk'
+ ]
},
+
{
tabKey: 'ST00020003',
tabLabel: '관종별 현황',
rowStartNum: 2,
fixedColumns: 2,
- columns: [
- {
- name: 'ctpvNm',
- fieldName: 'ctpvNm',
- header: { text: '시도' },
- mergeCells: true,
- sortdisable: true,
- footer: [
+ columns: [
{
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
+ name: 'ctpvNm',
+ fieldName: 'ctpvNm',
+ header: { text: '시도' },
+ mergeCells: true,
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
+ }
}
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
- }
+ ]
},
+ { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
+ { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
+ { name: 'swrgPipeNm', fieldName: 'swrgPipeNm', header: { text: '관종' }, mergeCells: true },
{
- valueCallback: (grid: GridView) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
+ name: 'displayYear',
+ fieldName: 'displayYear',
+ header: { text: '구분' },
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
+ }
}
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
- }
- }
- ]
- },
- { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
- { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
- { name: 'swrgPipeNm', fieldName: 'swrgPipeNm', header: { text: '관종' }, mergeCells: true },
- {
- name: 'displayYear',
- fieldName: 'displayYear',
- header: { text: '구분' },
- sortdisable: true,
- footer: [
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
- }
+ ]
},
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
- }
- }
+
+ { name: 'pipeByPrstWholSum', fieldName: 'pipeByPrstWhol', header: { text: '계' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'lyngPrlgSum', fieldName: 'lyngPrlg', header: { text: '매설연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'dmltnPrlgSum', fieldName: 'dmltnPrlg', header: { text: '철거연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+
+
+ ...Array.from({ length: totalCount }, (_, i) => {
+ const dtoNum = totalCount - i;
+
+ const wholField = `yy${dtoNum}PrlgWhol`;
+ const lyngField = `yy${dtoNum}LyngPrlg`;
+ const dmltnField = `yy${dtoNum}DmltnPrlg`;
+
+ return [
+ { name: wholField, fieldName: wholField, header: { text: '계' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: lyngField, fieldName: lyngField, header: { text: '매설연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: dmltnField, fieldName: dmltnField, header: { text: '철거연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' }
+ ];
+ }).flat(),
+
+ { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
+ ], columnLayout: [
+ {
+ name: 'areaGroup',
+ header: { text: '행정구역' },
+ items: [{ column: 'ctpvNm', footerUserSpans: [{ colspan: 4 }, { colspan: 4 }] },
+ 'sggNm', 'swrgPipeNm'
+ ] },
+ 'displayYear',
+ { name: 'summaryGroup', header: { text: '총계' }, items: ['pipeByPrstWholSum', 'lyngPrlgSum', 'dmltnPrlgSum'] },
+
+ ...Array.from({ length: totalCount }, (_, i) => {
+
+ const dtoNum = totalCount - i;
+ const yearLabel = i === 0
+ ? '1996년이전'
+ : `${startYear + (i - 1)}년`;
+
+ return {
+ name: `group_${yearLabel}`,
+ header: { text: yearLabel },
+ items: [`yy${dtoNum}PrlgWhol`, `yy${dtoNum}LyngPrlg`, `yy${dtoNum}DmltnPrlg`]
+ };
+ }),
+ 'rmrk'
]
},
- { name: 'pipeByPrstWholSum', fieldName: 'pipeByPrstWhol', header: { text: '계' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'lyngPrlgSum', fieldName: 'lyngPrlg', header: { text: '매설연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'dmltnPrlgSum', fieldName: 'dmltnPrlg', header: { text: '철거연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
-
-
- ...Array.from({ length: totalCount }, (_, i) => {
- const dtoNum = totalCount - i;
-
- const wholField = `yy${dtoNum}PrlgWhol`;
- const lyngField = `yy${dtoNum}LyngPrlg`;
- const dmltnField = `yy${dtoNum}DmltnPrlg`;
-
- return [
- { name: wholField, fieldName: wholField, header: { text: '계' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: lyngField, fieldName: lyngField, header: { text: '매설연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: dmltnField, fieldName: dmltnField, header: { text: '철거연장(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' }
- ];
- }).flat(),
-
- { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
- ],columnLayout: [
- { name: 'areaGroup', header: { text: '행정구역' }, items: ['ctpvNm', 'sggNm', 'swrgPipeNm'] },
- 'displayYear',
- { name: 'summaryGroup', header: { text: '총계' }, items: ['pipeByPrstWholSum','lyngPrlgSum', 'dmltnPrlgSum'] },
-
- ...Array.from({ length: totalCount }, (_, i) => {
-
- const dtoNum = totalCount - i;
- const yearLabel = i === 0
- ? '1996년이전'
- : `${startYear + (i - 1)}년`;
-
- return {
- name: `group_${yearLabel}`,
- header: { text: yearLabel },
- items: [`yy${dtoNum}PrlgWhol`, `yy${dtoNum}LyngPrlg`, `yy${dtoNum}DmltnPrlg`]
- };
- }),
- 'rmrk'
- ]
- },
{
tabKey: 'ST00020004',
tabLabel: '관경별 현황',
rowStartNum: 2,
fixedColumns: 3,
- columns: [
- {
- name: 'ctpvNm',
- fieldName: 'ctpvNm',
- header: { text: '시도' },
- mergeCells: true,
- sortdisable: true,
- footer: [
+ columns: [
{
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
+ name: 'ctpvNm',
+ fieldName: 'ctpvNm',
+ header: { text: '시도' },
+ mergeCells: true,
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ const divisionValues = Array.from(uniqueValues);
+ return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
+ }
}
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
- }
+ ]
},
+ { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true }, // gugun -> sggNm
+ { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
+ { name: 'swrgPipeNm', fieldName: 'swrgPipeNm', header: { text: '관종' }, mergeCells: true },
{
- valueCallback: (grid: GridView) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
+ name: 'displayYear',
+ fieldName: 'displayYear',
+ header: { text: '구분' },
+ sortdisable: true,
+ footer: [
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 0;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
+ }
+ },
+ {
+ valueCallback: (grid: GridView) => {
+ const divisionIndex = 1;
+ const dataSource = grid.getDataSource();
+ const uniqueValues = new Set();
+ for (let i = 0; i < dataSource.getRowCount(); i++) {
+ const val = dataSource.getValue(i, 'displayYear');
+ if (val) uniqueValues.add(String(val));
+ }
+ return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
+ }
}
- const divisionValues = Array.from(uniqueValues);
- return divisionValues.length > divisionIndex ? divisionValues[divisionIndex] + '합계' : '합계';
- }
- }
- ]
- },
- { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true }, // gugun -> sggNm
- { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
- { name: 'swrgPipeNm', fieldName: 'swrgPipeNm', header: { text: '관종' }, mergeCells: true },
- {
- name: 'displayYear',
- fieldName: 'displayYear',
- header: { text: '구분' },
- sortdisable: true,
- footer: [
- {
- valueCallback: (grid: GridView) => {
- const divisionIndex = 0;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
- }
+ ]
},
+
+ /* 관경별 수치 필드 */
+ { name: 'pdmtByTsmWhol', fieldName: 'pdmtByTsmWhol', header: { text: '총계(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'step1PdmtPrlg', fieldName: 'step1PdmtPrlg', header: { text: '200mm 미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'step2PdmtPrlg', fieldName: 'step2PdmtPrlg', header: { text: '200mm이상~\n300mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'step3PdmtPrlg', fieldName: 'step3PdmtPrlg', header: { text: '300mm이상~\n500mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'step4PdmtPrlg', fieldName: 'step4PdmtPrlg', header: { text: '500mm이상~\n800mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'step5PdmtPrlg', fieldName: 'step5PdmtPrlg', header: { text: '800mm 이상' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'sqrePdmtPrlg', fieldName: 'sqrePdmtPrlg', header: { text: '사각형(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+ { name: 'etcPdmtPrlg', fieldName: 'etcPdmtPrlg', header: { text: '기타\n(측구/개거 등)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
+
+ { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } }, // rmk -> rmrk
+ ],
+ columnLayout: [
{
- valueCallback: (grid: GridView) => {
- const divisionIndex = 1;
- const dataSource = grid.getDataSource();
- const uniqueValues = new Set();
- for (let i = 0; i < dataSource.getRowCount(); i++) {
- const val = dataSource.getValue(i, 'displayYear');
- if (val) uniqueValues.add(String(val));
- }
- return Array.from(uniqueValues)[divisionIndex] ? Array.from(uniqueValues)[divisionIndex] + '합계' : '';
- }
- }
+ name: 'addrGroup',
+ header: { text: '행정구역' },
+ items: [
+ { column: 'ctpvNm', footerUserSpans: [{ colspan: 6 }, { colspan: 6 }] },
+ 'sggNm',
+ 'admdstNm',
+ ]
+ },
+ 'swrgPipeNm',
+ 'displayYear',
+ 'pdmtByTsmWhol',
+ {
+ name: 'circleGroup',
+ header: { text: '원형(m)' },
+ items: ['step1PdmtPrlg', 'step2PdmtPrlg', 'step3PdmtPrlg', 'step4PdmtPrlg', 'step5PdmtPrlg'] // 이름 일괄 변경
+ },
+ 'sqrePdmtPrlg',
+ 'etcPdmtPrlg',
+ 'rmrk'
]
- },
-
- /* 관경별 수치 필드 */
- { name: 'pdmtByTsmWhol', fieldName: 'pdmtByTsmWhol', header: { text: '총계(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'step1PdmtPrlg', fieldName: 'step1PdmtPrlg', header: { text: '200mm 미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'step2PdmtPrlg', fieldName: 'step2PdmtPrlg', header: { text: '200mm이상~\n300mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'step3PdmtPrlg', fieldName: 'step3PdmtPrlg', header: { text: '300mm이상~\n500mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'step4PdmtPrlg', fieldName: 'step4PdmtPrlg', header: { text: '500mm이상~\n800mm미만' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'step5PdmtPrlg', fieldName: 'step5PdmtPrlg', header: { text: '800mm 이상' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'sqrePdmtPrlg', fieldName: 'sqrePdmtPrlg', header: { text: '사각형(m)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
- { name: 'etcPdmtPrlg', fieldName: 'etcPdmtPrlg', header: { text: '기타\n(측구/개거 등)' }, footer: footerAvgDecimalArrayByDivision, valueType: ValueType.NUMBER, numberFormat: '#,##0.0' },
-
- { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } }, // rmk -> rmrk
-],
- columnLayout: [
- {
- name: 'addrGroup',
- header: { text: '행정구역' },
- items: [
- { column: 'ctpvNm', footerUserSpans: [{ colspan: 6 }, { colspan: 6 }] },
- 'sggNm',
- 'admdstNm',
- ]
- },
- 'swrgPipeNm',
- 'displayYear',
- 'pdmtByTsmWhol',
- {
- name: 'circleGroup',
- header: { text: '원형(m)' },
- items: ['step1PdmtPrlg', 'step2PdmtPrlg', 'step3PdmtPrlg', 'step4PdmtPrlg', 'step5PdmtPrlg'] // 이름 일괄 변경
- },
- 'sqrePdmtPrlg',
- 'etcPdmtPrlg',
- 'rmrk'
-]
}
];
diff --git a/apps/st/src/components/util/column/total/SeweragePentrationRateTotColumn.ts b/apps/st/src/components/util/column/total/SeweragePentrationRateTotColumn.ts
new file mode 100644
index 000000000..d14c5b6c6
--- /dev/null
+++ b/apps/st/src/components/util/column/total/SeweragePentrationRateTotColumn.ts
@@ -0,0 +1,215 @@
+import { ValueType } from "realgrid";
+/**
+ * 하수도 통계 관리 > 01. 하수도 보급률
+ * 단일 Tab
+ */
+export const SeweragePentrationRateTotColumn = {
+ columns: [
+ // 행정구역
+ { name: 'ctpvNm', fieldName: 'ctpvNm', header: { text: '시도' }, editable: false, },
+ { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, editable: false, },
+ { name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, editable: false, },
+
+ // 수계 및 권역
+ { name: 'rvbsn', fieldName: 'rvbsn', header: { text: '수계' }, editable: false, },
+ { name: 'trbtrNm', fieldName: 'trbtrNm', header: { text: '지류' } },
+
+ // 수계영향권별분류
+ { name: 'mdbsn', fieldName: 'mdbsn', header: { text: '세부단위유역' }, editable: false, },
+ { name: 'lgbsn', fieldName: 'lgbsn', header: { text: '중권역' }, editable: false, },
+ { name: 'mdmbsn', fieldName: 'mdmbsn', header: { text: '소권역' }, editable: false, },
+
+ // 특별대책지역
+ { name: 'spcCtpnRgnCn', fieldName: 'spcCtpnRgnCn', header: { text: '특별대책지역' } },
+
+ // 행정참고자료인구
+ { name: 'pbadmsWholPpltnCnt', fieldName: 'pbadmsWholPpltnCnt', header: { text: '총인구' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0', },
+ { name: 'domplWholPpltnCnt', fieldName: 'domplWholPpltnCnt', header: { text: '내국인' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0', },
+ { name: 'frgnrWholPpltnCnt', fieldName: 'frgnrWholPpltnCnt', header: { text: '외국인' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0', },
+
+ // 행정참고자료면적
+ { name: 'refArea', fieldName: 'refArea', header: { text: '행정참고자료면적(㎢)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000', },
+
+ // 총인구
+ {
+ name: 'wholPpltnCnt',
+ fieldName: 'wholPpltnCnt',
+ header: { text: '총인구(명)' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0',
+ },
+
+ // 총면적
+ {
+ name: 'wholArea',
+ fieldName: 'wholArea',
+ header: { text: '총면적(㎢)' },
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0.000',
+ },
+
+ // 하수처리구역 내 > 합계
+ {
+ name: 'wholSwtrmtPpltnCnt',
+ fieldName: 'wholSwtrmtPpltnCnt',
+ header: { text: '합계' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0',
+ },
+
+ // 하수처리구역 내 > 공공하수처리인구
+ {
+ name: 'wholPblSwtrmtPpltnCnt',
+ fieldName: 'wholPblSwtrmtPpltnCnt',
+ header: { text: '소계' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0',
+ },
+ { name: 'ts1SwtrmtPpltnCnt', fieldName: 'ts1SwtrmtPpltnCnt', header: { text: '물리적처리' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+ { name: 'ts2SwtrmtPpltnCnt', fieldName: 'ts2SwtrmtPpltnCnt', header: { text: '생물학적처리' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+ { name: 'ts3SwtrmtPpltnCnt', fieldName: 'ts3SwtrmtPpltnCnt', header: { text: '고도처리' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+
+ // 하수처리구역 내 > 폐수처리인구
+ {
+ name: 'wholWwtPrcsPpltnCnt',
+ fieldName: 'wholWwtPrcsPpltnCnt',
+ header: { text: '소계' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0',
+ },
+ { name: 'ts1WwtPrcsPpltnCnt', fieldName: 'ts1WwtPrcsPpltnCnt', header: { text: '물리적처리' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+ { name: 'ts2WwtPrcsPpltnCnt', fieldName: 'ts2WwtPrcsPpltnCnt', header: { text: '생물학적처리' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+ { name: 'ts3WwtPrcsPpltnCnt', fieldName: 'ts3WwtPrcsPpltnCnt', header: { text: '고도처리' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+
+ // 하수처리구역 내 > 미접속인구
+ { name: 'yetCntnPpltnCnt', fieldName: 'yetCntnPpltnCnt', header: { text: '미접속인구' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+
+ // 하수처리구역 내 > 면적
+ { name: 'staaArea', fieldName: 'staaArea', header: { text: '면적(㎢)' }, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
+
+ // 하수처리구역 외
+ {
+ name: 'wholStaaExcpPpltnCnt',
+ fieldName: 'wholStaaExcpPpltnCnt',
+ header: { text: '합계' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0',
+ },
+ { name: 'unprcsPpltnCnt', fieldName: 'unprcsPpltnCnt', header: { text: '미처리인구' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+ { name: 'drtwPrcsPpltnCnt', fieldName: 'drtwPrcsPpltnCnt', header: { text: '오수처리인구' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+ { name: 'spctnkPpltnCnt', fieldName: 'spctnkPpltnCnt', header: { text: '정화조인구' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
+ { name: 'staaExcpArea', fieldName: 'staaExcpArea', header: { text: '면적(㎢)' }, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
+
+ // 공공하수처리구역 인구보급률 (하수처리구역 내 인구 / 전체 인구 * 100)
+ {
+ name: 'staaPsplyRt',
+ fieldName: 'staaPsplyRt',
+ header: { text: '공공하수처리구역인구보급률(%)' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0.0',
+ },
+
+ // 고도처리 인구보급률 (고도처리 인구 / 전체 인구 * 100)
+ {
+ name: 'altdPrcsPsplyRt',
+ fieldName: 'altdPrcsPsplyRt',
+ header: { text: '고도처리인구보급률(%)' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0.0',
+ },
+
+ // 하수도 설치율
+ {
+ name: 'sewerInstlRt',
+ fieldName: 'sewerInstlRt',
+ header: { text: '하수도설치율(%)' },
+ editable: false,
+ valueType: ValueType.NUMBER,
+ dataFormat: '#,##0.0',
+ },
+
+ // 비고
+ { name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
+
+ { name: 'swagePplPsplyRt', fieldName: 'swagePplPsplyRt', header: { text: '하수관로보급률(%)' }, visible: false },
+ { name: 'admdstCd', fieldName: 'admdstCd', header: { text: '행정코드' }, visible: false },
+ ],
+
+ columnLayout: [
+ {
+ name: 'groupA',
+ hideChildHeaders: false,
+ header: { text: '행정구역' },
+ items: [
+ 'ctpvNm',
+ 'sggNm',
+ 'admdstNm',
+ ],
+ },
+ 'rvbsn',
+ 'trbtrNm',
+ {
+ name: 'groupB',
+ hideChildHeaders: false,
+ header: { text: '수계영향권별분류' },
+ items: ['mdbsn', 'lgbsn', 'mdmbsn'],
+ },
+ 'spcCtpnRgnCn',
+ {
+ name: 'groupC',
+ hideChildHeaders: false,
+ header: { text: '행정참고자료인구' },
+ items: ['pbadmsWholPpltnCnt', 'domplWholPpltnCnt', 'frgnrWholPpltnCnt'],
+ },
+ 'refArea',
+ 'wholPpltnCnt',
+ 'wholArea',
+ {
+ name: 'groupD',
+ hideChildHeaders: false,
+ header: { text: '하수처리구역내' },
+ items: [
+ 'wholSwtrmtPpltnCnt',
+ {
+ name: 'pblswrgGroup',
+ hideChildHeaders: false,
+ header: { text: '공공하수처리인구(명)' },
+ items: ['wholPblSwtrmtPpltnCnt', 'ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt'],
+ },
+ {
+ name: 'wstrGroup',
+ hideChildHeaders: false,
+ header: { text: '폐수처리인구(명)' },
+ items: ['wholWwtPrcsPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt'],
+ },
+ 'yetCntnPpltnCnt',
+ 'staaArea'
+ ],
+ },
+ {
+ name: 'groupE',
+ hideChildHeaders: false,
+ header: { text: '하수처리구역외' },
+ items: [
+ 'wholStaaExcpPpltnCnt',
+ 'unprcsPpltnCnt',
+ 'drtwPrcsPpltnCnt',
+ 'spctnkPpltnCnt',
+ 'staaExcpArea'
+ ],
+ },
+ 'staaPsplyRt',
+ 'altdPrcsPsplyRt',
+ 'sewerInstlRt',
+ 'rmrk',
+ 'swagePplPsplyRt',
+ 'admdstCd',
+ ]
+};
\ No newline at end of file
diff --git a/apps/st/src/entities/auth/api/login-service.ts b/apps/st/src/entities/auth/api/login-service.ts
index c1968fe36..7fd87cc27 100644
--- a/apps/st/src/entities/auth/api/login-service.ts
+++ b/apps/st/src/entities/auth/api/login-service.ts
@@ -1,13 +1,18 @@
import { AxiosError } from "axios";
+
import {
- ENDPOINT,
- JWT_EXPIRATION_TIME,
ACCESS_TOKEN,
AUTH_USER_ID,
CLAIM_NAME,
+ ENDPOINT,
+ JWT_EXPIRATION_TIME,
} from "@/shared/config";
-import type { LoginService, ILogin } from "../model/login-interface";
+import { getCookie } from "@/shared/lib";
+
import { tokenManager } from "../lib/token-manager";
+import type { ILogin,LoginService } from "../model/login-interface";
+
+import { clearTabStorePersist } from "@/store/tab-store";
export class LoginApiService implements LoginService {
private static instance: LoginApiService;
@@ -39,6 +44,11 @@ export class LoginApiService implements LoginService {
throw new Error("Missing required authentication tokens");
}
+ const prevTokenId = getCookie(AUTH_USER_ID);
+ if (prevTokenId !== undefined && prevTokenId !== tokenId) {
+ clearTabStorePersist();
+ }
+
tokenManager.setToken(CLAIM_NAME, accessToken);
tokenManager.setToken(AUTH_USER_ID, tokenId);
tokenManager.setupRefreshTimer(
diff --git a/apps/st/src/entities/auth/lib/token-manager.ts b/apps/st/src/entities/auth/lib/token-manager.ts
index dd9aea352..60cd47de5 100644
--- a/apps/st/src/entities/auth/lib/token-manager.ts
+++ b/apps/st/src/entities/auth/lib/token-manager.ts
@@ -1,5 +1,7 @@
import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config";
-import { getCookie, setCookie, removeCookie } from "@/shared/lib";
+import { getCookie, removeCookie,setCookie } from "@/shared/lib";
+
+import { clearTabStorePersist } from "@/store/tab-store";
export class TokenManager {
private static instance: TokenManager;
@@ -74,6 +76,7 @@ export class TokenManager {
this.refreshTimer = null;
}
+ clearTabStorePersist();
this.removeToken(CLAIM_NAME);
this.removeToken(AUTH_USER_ID);
}
diff --git a/apps/st/src/entities/statistics/api/queries.ts b/apps/st/src/entities/statistics/api/queries.ts
index bd8510421..0f0a9b0fb 100644
--- a/apps/st/src/entities/statistics/api/queries.ts
+++ b/apps/st/src/entities/statistics/api/queries.ts
@@ -2,8 +2,24 @@ import { useQuery } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
+import { stAnlsMstApi } from "./statistics-analysis-master-api";
import { stAnlsRsltApi } from "./statistics-analysis-result-api";
+export const useStAnlsSidoCombo = () => {
+ return useQuery({
+ queryKey: [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST, "sido"],
+ queryFn: () => stAnlsMstApi.getSidoCombo(),
+ });
+};
+
+export const useStAnlsSigunguCombo = (sidoCd: string) => {
+ return useQuery({
+ queryKey: [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST, "sigungu", sidoCd],
+ queryFn: () => stAnlsMstApi.getSigunguCombo(sidoCd),
+ enabled: Boolean(sidoCd),
+ });
+};
+
export const useStAnlsRsltList = (
anlsSn: number,
vrfcTrgtSn: string | null,
@@ -20,7 +36,8 @@ export const useStAnlsRsltList = (
anlsSn,
vrfcTrgtSn: Number(vrfcTrgtSn),
page: 0,
- size: 1000,
+ size: 15000,
+ sort: "admdstCd,asc",
}),
enabled: !!anlsSn && !!vrfcTrgtSn,
});
diff --git a/apps/st/src/entities/statistics/api/analysis-history-api.ts b/apps/st/src/entities/statistics/api/statistics-analysis-master-api.ts
similarity index 56%
rename from apps/st/src/entities/statistics/api/analysis-history-api.ts
rename to apps/st/src/entities/statistics/api/statistics-analysis-master-api.ts
index 316684f99..19a6bee1c 100644
--- a/apps/st/src/entities/statistics/api/analysis-history-api.ts
+++ b/apps/st/src/entities/statistics/api/statistics-analysis-master-api.ts
@@ -2,12 +2,13 @@ import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
+ AdstZoneResponseDto,
StAnlsMstListApiResponse,
StAnlsMstSearchParams,
StAnlsOutlierListResponse,
} from "../model/statistics-analysis/statistics-analysis-master-interface";
-export class AnalysisHistoryApiService {
+export class StAnlsMstApiService {
public async getAnalysisHistoryList(
params: StAnlsMstSearchParams,
): Promise {
@@ -30,6 +31,23 @@ export class AnalysisHistoryApiService {
return response.data;
}
+
+ public async getSidoCombo(): Promise {
+ const response = await client.get(
+ `${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sido`,
+ );
+
+ return response.data;
+ }
+
+ public async getSigunguCombo(sidoCd: string): Promise {
+ const response = await client.get(
+ `${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sigungu`,
+ { params: { sidoCd } },
+ );
+
+ return response.data;
+ }
}
-export const analysisHistoryApi = new AnalysisHistoryApiService();
+export const stAnlsMstApi = new StAnlsMstApiService();
diff --git a/apps/st/src/entities/statistics/api/statistics-analysis-result-api.ts b/apps/st/src/entities/statistics/api/statistics-analysis-result-api.ts
index fa8983233..2e62fab3c 100644
--- a/apps/st/src/entities/statistics/api/statistics-analysis-result-api.ts
+++ b/apps/st/src/entities/statistics/api/statistics-analysis-result-api.ts
@@ -60,6 +60,17 @@ export class StAnlsRsltApiService {
return response.data;
}
+
+ public async downloadExcelImr(anlsSn: number): Promise {
+ const response = await client.get(
+ `${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_RSLT}/excel-down/imr/${anlsSn}`,
+ {
+ responseType: "blob",
+ },
+ );
+
+ return response.data;
+ }
}
export const stAnlsRsltApi = new StAnlsRsltApiService();
diff --git a/apps/st/src/entities/statistics/index.ts b/apps/st/src/entities/statistics/index.ts
index 73cb0fadd..08f32d08b 100644
--- a/apps/st/src/entities/statistics/index.ts
+++ b/apps/st/src/entities/statistics/index.ts
@@ -27,6 +27,7 @@ export {
type StAnlsDtlSearchParams,
} from "./model/statistics-analysis/statistics-analysis-detail-interface";
export {
+ type AdstZoneResponseDto,
type StAnlsMstListApiResponse,
type StAnlsMstResponse,
type StAnlsMstResponseDto,
diff --git a/apps/st/src/entities/statistics/model/statistics-analysis/statistics-analysis-master-interface.ts b/apps/st/src/entities/statistics/model/statistics-analysis/statistics-analysis-master-interface.ts
index f8a539146..046ba891b 100644
--- a/apps/st/src/entities/statistics/model/statistics-analysis/statistics-analysis-master-interface.ts
+++ b/apps/st/src/entities/statistics/model/statistics-analysis/statistics-analysis-master-interface.ts
@@ -1,5 +1,15 @@
import type { PageableList, PageableParams } from "@/shared/model";
+/**
+ * 행정구역(시도·시군구) 콤보 응답 DTO
+ */
+export interface AdstZoneResponseDto {
+ /** 행정구역 코드 */
+ adstCd: string;
+ /** 행정구역 명 */
+ adstNm: string;
+}
+
/**
* 분석 현황 마스터 응답 DTO
*/
diff --git a/apps/st/src/store/tab-store.ts b/apps/st/src/store/tab-store.ts
index ace855808..640cada97 100644
--- a/apps/st/src/store/tab-store.ts
+++ b/apps/st/src/store/tab-store.ts
@@ -1,8 +1,10 @@
import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+
import type { MenuItem } from "@/entities/menu";
export interface Tab {
- id: string; // 고유 ID (menuEngNm)
+ id: string; // 고유 ID (urlPath)
label: string; // 탭에 표시될 이름
path: string; // 메뉴 경로
urlPath: string; // url 경로
@@ -22,96 +24,164 @@ interface TabStore {
closeOtherTabs: (tabId: string) => void;
}
-const useTabStoreHook = create((set, get) => ({
- tabs: [],
- activeTabId: null,
- menuList: null,
- addTab: (menuItem: MenuItem) => {
- const { tabs, menuList } = get();
- const tabId = menuItem.urlPath || '';
+export const TAB_STORE_PERSIST_KEY = "st-tab-store";
+const TAB_STORE_VERSION = 1;
+const MAX_TABS = 10;
- // 이미 존재하는 탭인지 확인
- const existingTab = tabs.find((tab) => tab.id === tabId);
+function tabForPersist(tab: Tab): Tab {
+ return {
+ ...tab,
+ menuItem: { ...tab.menuItem, children: null },
+ };
+}
- if (existingTab) {
- // 이미 존재하면 활성화만
- set({ activeTabId: tabId });
- return true;
- }
+function sanitizePersistedTabsAndActive(
+ tabs: Tab[],
+ activeTabId: string | null,
+): { tabs: Tab[]; activeTabId: string | null } {
+ let nextTabs = Array.isArray(tabs) ? tabs : [];
+ if (nextTabs.length > MAX_TABS) nextTabs = nextTabs.slice(0, MAX_TABS);
- if (tabs.length < 10) {
- const newTab: Tab = {
- id: tabId,
- label: menuItem.menuKornNm,
- path: menuItem.menuPath,
- urlPath: menuItem.urlPath,
- parentEngNm: menuList?.find((m) => m.menuCd === menuItem.parentId)?.menuEngNm || '',
- menuItem,
- };
-
- set({
- tabs: [...tabs, newTab],
- activeTabId: tabId,
- });
+ if (nextTabs.length === 0) {
+ return { tabs: [], activeTabId: null };
+ }
- return true;
- } else {
- return false;
- }
+ let nextActive = activeTabId;
+ if (nextActive && !nextTabs.some((t) => t.id === nextActive)) {
+ nextActive = nextTabs[0]?.id ?? null;
+ }
+ if (nextActive == null && nextTabs.length > 0) {
+ nextActive = nextTabs[0]?.id ?? null;
+ }
- // 새 탭 추가
- },
- removeTab: (tabId: string): void => {
- const { tabs, activeTabId } = get();
- const newTabs = tabs.filter((tab) => tab.id !== tabId);
+ return { tabs: nextTabs, activeTabId: nextActive };
+}
- // 닫는 탭이 현재 활성 탭이면 다른 탭으로 전환
- let newActiveTabId = activeTabId;
- if (activeTabId === tabId) {
- const closedTabIndex = tabs.findIndex((tab) => tab.id === tabId);
- if (newTabs.length > 0) {
- // 닫힌 탭의 이전 탭을 활성화, 없으면 다음 탭
- if (closedTabIndex > 0) {
- const prevTab = tabs[closedTabIndex - 1];
- newActiveTabId = prevTab ? prevTab.id : null;
- } else {
- const firstTab = newTabs[0];
- newActiveTabId = firstTab ? firstTab.id : null;
- }
- } else {
- newActiveTabId = null;
- }
- }
-
- set({
- tabs: newTabs,
- activeTabId: newActiveTabId,
- });
- },
- setActiveTab: (tabId: string) => {
- set({ activeTabId: tabId });
- },
- setMenuList: (menuList: MenuItem[] | null) => {
- set({ menuList });
- },
- closeAllTabs: () => {
- set({
+const useTabStoreHook = create()(
+ persist(
+ (set, get) => ({
tabs: [],
activeTabId: null,
- });
- },
- closeOtherTabs: (tabId: string) => {
- const { tabs } = get();
- const tabToKeep = tabs.find((tab) => tab.id === tabId);
+ menuList: null,
+ addTab: (menuItem: MenuItem) => {
+ const { tabs, menuList } = get();
+ const tabId = menuItem.urlPath || "";
- if (tabToKeep) {
- set({
- tabs: [tabToKeep],
- activeTabId: tabId,
- });
- }
- },
-}));
+ const existingTab = tabs.find((tab) => tab.id === tabId);
+
+ if (existingTab) {
+ set({ activeTabId: tabId });
+ return true;
+ }
+
+ if (tabs.length < MAX_TABS) {
+ const newTab: Tab = {
+ id: tabId,
+ label: menuItem.menuKornNm,
+ path: menuItem.menuPath,
+ urlPath: menuItem.urlPath,
+ parentEngNm:
+ menuList?.find(
+ (m) => m.menuCd === menuItem.parentId,
+ )?.menuEngNm || "",
+ menuItem,
+ };
+
+ set({
+ tabs: [...tabs, newTab],
+ activeTabId: tabId,
+ });
+
+ return true;
+ }
+ return false;
+ },
+ removeTab: (tabId: string): void => {
+ const { tabs, activeTabId } = get();
+ const newTabs = tabs.filter((tab) => tab.id !== tabId);
+
+ let newActiveTabId = activeTabId;
+ if (activeTabId === tabId) {
+ const closedTabIndex = tabs.findIndex(
+ (tab) => tab.id === tabId,
+ );
+ if (newTabs.length > 0) {
+ if (closedTabIndex > 0) {
+ const prevTab = tabs[closedTabIndex - 1];
+ newActiveTabId = prevTab ? prevTab.id : null;
+ } else {
+ const firstTab = newTabs[0];
+ newActiveTabId = firstTab ? firstTab.id : null;
+ }
+ } else {
+ newActiveTabId = null;
+ }
+ }
+
+ set({
+ tabs: newTabs,
+ activeTabId: newActiveTabId,
+ });
+ },
+ setActiveTab: (tabId: string) => {
+ set({ activeTabId: tabId });
+ },
+ setMenuList: (menuList: MenuItem[] | null) => {
+ set({ menuList });
+ },
+ closeAllTabs: () => {
+ set({
+ tabs: [],
+ activeTabId: null,
+ });
+ },
+ closeOtherTabs: (tabId: string) => {
+ const { tabs } = get();
+ const tabToKeep = tabs.find((tab) => tab.id === tabId);
+
+ if (tabToKeep) {
+ set({
+ tabs: [tabToKeep],
+ activeTabId: tabId,
+ });
+ }
+ },
+ }),
+ {
+ name: TAB_STORE_PERSIST_KEY,
+ version: TAB_STORE_VERSION,
+ storage: createJSONStorage(() => localStorage),
+ partialize: (state) => ({
+ tabs: state.tabs.map(tabForPersist),
+ activeTabId: state.activeTabId,
+ }),
+ merge: (persistedState, currentState) => {
+ const p = persistedState as Partial<
+ Pick
+ > | null;
+ const rawTabs = p?.tabs;
+ const rawActive = p?.activeTabId;
+ const { tabs, activeTabId } = sanitizePersistedTabsAndActive(
+ (rawTabs as Tab[]) ?? [],
+ typeof rawActive === "string" || rawActive === null
+ ? rawActive
+ : null,
+ );
+ return {
+ ...currentState,
+ tabs,
+ activeTabId,
+ };
+ },
+ },
+ ),
+);
export const useTabStore = useTabStoreHook;
-export const getTabStoreState = () => useTabStoreHook.getState();
\ No newline at end of file
+export const getTabStoreState = () => useTabStoreHook.getState();
+
+// 로그아웃 또는 사용자 전환 시 로컬 탭 스냅샷 제거 및 메모리 상태 초기화
+export function clearTabStorePersist(): void {
+ useTabStoreHook.getState().closeAllTabs();
+ useTabStoreHook.persist.clearStorage();
+}