st: refactor: DataGrid 설정 수정 중
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface OperateDataButtonProps {
|
||||
getOperateDataFunc: () => void;
|
||||
}
|
||||
|
||||
const OperateDataButton = ({ getOperateDataFunc }: OperateDataButtonProps) => {
|
||||
return (
|
||||
<Button color="emerald" className="px-6" onClick={getOperateDataFunc}>
|
||||
<i className="diveicon di-arrow-left-right" />
|
||||
<span>운영 데이터 가져오기</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default OperateDataButton;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useRef, useEffect, useState } from "react"
|
||||
import { useRef, useEffect } from "react"
|
||||
|
||||
import RealGrid, { GridFitStyle, type DisplayOptions } from "realgrid"
|
||||
import { RealGridReact, RGDataColumn } from "realgrid-react"
|
||||
@@ -13,9 +13,10 @@ import { useTabStore } from "@/store/tab-store"
|
||||
// RealGrid 타입 확장
|
||||
declare module "realgrid" {
|
||||
interface GridView {
|
||||
setOptions(options: {
|
||||
setOptions(options: {
|
||||
footer?: { visible?: boolean };
|
||||
summaryMode?: 'aggregate' | 'statistical' | 'none';
|
||||
checkBar?: { visible?: boolean };
|
||||
}): void;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +35,7 @@ if (typeof window !== "undefined") {
|
||||
|
||||
RealGrid.setLicenseKey(process.env.NEXT_PUBLIC_ST_REALGRID_KEY || '');
|
||||
|
||||
const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fixedColumns }: DataGridProps) => {
|
||||
const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, fixedColumns, onRowsChange, showHeaderCheckbox = false, rowData, setRowData }: DataGridProps) => {
|
||||
const { columns, columnLayout } = columnInfo;
|
||||
const gridRef = useRef<RealGridReact>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -42,29 +43,6 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
const activeTabId = useTabStore((state) => state.activeTabId);
|
||||
const menuList = useTabStore((state) => state.menuList);
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
// footer가 있는 컬럼의 데이터를 숫자로 변환
|
||||
const convertNumericData = (data: Record<string, string>[]): Record<string, string | number>[] => {
|
||||
const footerColumns = columns.filter(col => col.footer);
|
||||
const footerFieldNames = new Set(footerColumns.map(col => col.fieldName));
|
||||
|
||||
return data.map(row => {
|
||||
const convertedRow: Record<string, string | number> = { ...row };
|
||||
footerFieldNames.forEach(fieldName => {
|
||||
const value = row[fieldName];
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
// 쉼표 제거 후 숫자로 변환
|
||||
const numericValue = Number(String(value).replace(/,/g, ''));
|
||||
if (!isNaN(numericValue)) {
|
||||
convertedRow[fieldName] = numericValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
return convertedRow;
|
||||
});
|
||||
};
|
||||
|
||||
const exportExcel = () => {
|
||||
if (rowData.length === 0) {
|
||||
alert('데이터가 없습니다.');
|
||||
@@ -157,20 +135,34 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
const dataStartRow = maxHeaderRowIndex + 1;
|
||||
|
||||
// 데이터 행 읽기
|
||||
const dataRows: Record<string, string>[] = [];
|
||||
const dataRows: Record<string, string | number>[] = [];
|
||||
for (let row = dataStartRow; row <= range.e.r; row++) {
|
||||
const rowData: Record<string, string> = {};
|
||||
const rowData: Record<string, string | number> = {};
|
||||
let hasData = false;
|
||||
|
||||
for (let colIndex = 0; colIndex < headers.length; colIndex++) {
|
||||
const col = range.s.c + colIndex;
|
||||
const cell = worksheet[XLSX.utils.encode_cell({ r: row, c: col })];
|
||||
const headerName = headers[colIndex] || `Column${colIndex + 1}`;
|
||||
const cellValue = cell && cell.v !== undefined && cell.v !== null
|
||||
? String(cell.v)
|
||||
: '';
|
||||
|
||||
if (cellValue !== '') {
|
||||
let cellValue: string | number = '';
|
||||
if (cell && cell.v !== undefined && cell.v !== null) {
|
||||
// 엑셀 셀 타입이 숫자이거나 값이 숫자인 경우 숫자로 변환
|
||||
if (cell.t === 'n' || (typeof cell.v === 'number' && !isNaN(cell.v))) {
|
||||
cellValue = cell.v as number;
|
||||
} else {
|
||||
const stringValue = String(cell.v);
|
||||
// 문자열이지만 숫자로 변환 가능한 경우 숫자로 변환
|
||||
const numericValue = Number(stringValue.replace(/,/g, ''));
|
||||
if (!isNaN(numericValue) && stringValue.trim() !== '') {
|
||||
cellValue = numericValue;
|
||||
} else {
|
||||
cellValue = stringValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cellValue !== '' && cellValue !== null && cellValue !== undefined) {
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
@@ -182,9 +174,7 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
dataRows.push(rowData);
|
||||
}
|
||||
}
|
||||
|
||||
const convertedDataRows = convertNumericData(dataRows);
|
||||
setRowData(convertedDataRows);
|
||||
setRowData(dataRows);
|
||||
} catch (error) {
|
||||
console.error('엑셀 파일 파싱 오류:', error);
|
||||
alert('엑셀 파일 파싱 중 오류가 발생했습니다.');
|
||||
@@ -220,6 +210,12 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
(gridView.displayOptions as DisplayOptions).fitStyle = GridFitStyle.EVEN;
|
||||
gridView.header.height = 60;
|
||||
|
||||
// 헤더 체크박스 표시 여부 설정
|
||||
gridView.setOptions({
|
||||
checkBar: { visible: showHeaderCheckbox },
|
||||
rowIndicator: { visible: false },
|
||||
});
|
||||
|
||||
// footer가 있는 컬럼이 있으면 footer 높이 설정
|
||||
const hasFooter = columns.some(col => col.footer);
|
||||
if (hasFooter) {
|
||||
@@ -247,12 +243,26 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
}
|
||||
});
|
||||
|
||||
if (rows.length > 0) {
|
||||
const convertedRows = convertNumericData(rows);
|
||||
setRowData(convertedRows);
|
||||
}
|
||||
|
||||
}, [rows, columns, columnLayout, fixedColumns, rowData]);
|
||||
// mergeCells가 true인 컬럼에 대해 2개씩 병합하는 mergeRule 설정
|
||||
columns.forEach(col => {
|
||||
if (col.mergeCells === true) {
|
||||
try {
|
||||
const column = gridView.columnByName(col.name);
|
||||
if (column) {
|
||||
// mergeRule: 2개 행씩 병합 (row div 2)
|
||||
(column as { mergeRule?: { criteria: string; breakMergeOnEmpty?: boolean } }).mergeRule = {
|
||||
criteria: 'row div 2',
|
||||
breakMergeOnEmpty: false
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to set mergeRule for column ${col.name}:`, error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}, [columns, columnLayout, fixedColumns, rowData, showHeaderCheckbox]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-[0.6rem] mx-[0.6rem]">
|
||||
@@ -288,6 +298,7 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
name={column.name}
|
||||
fieldName={column.fieldName}
|
||||
header={column.header}
|
||||
editable={column.editable}
|
||||
footer={column.footer ? {
|
||||
text: column.footer.text,
|
||||
expression: column.footer.expression,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useRef, useEffect, useState } from "react"
|
||||
|
||||
import RealGrid, { GridFitStyle } from "realgrid"
|
||||
import RealGrid, { GridFitStyle, type DisplayOptions } from "realgrid"
|
||||
import { RealGridReact, RGDataColumn } from "realgrid-react"
|
||||
import type { TabDataGridProps } from "../type/DataGrid.type"
|
||||
import JSZip from "jszip"
|
||||
@@ -11,6 +11,17 @@ import { useTabStore } from "@/store/tab-store"
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@common/components";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
// RealGrid 타입 확장
|
||||
declare module "realgrid" {
|
||||
interface GridView {
|
||||
setOptions(options: {
|
||||
footer?: { visible?: boolean };
|
||||
summaryMode?: 'aggregate' | 'statistical' | 'none';
|
||||
checkBar?: { visible?: boolean };
|
||||
}): void;
|
||||
}
|
||||
}
|
||||
|
||||
// Window 인터페이스 확장
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -25,7 +36,7 @@ if (typeof window !== "undefined") {
|
||||
|
||||
RealGrid.setLicenseKey(process.env.NEXT_PUBLIC_ST_REALGRID_KEY || '');
|
||||
|
||||
const TabDataGrid = ({ columnInfo, isExcelImport = true, rows = [] }: TabDataGridProps) => {
|
||||
const TabDataGrid = ({ columnInfo, isExcelImport = true, rows = [], showHeaderCheckbox = false }: TabDataGridProps) => {
|
||||
// 각 탭별로 그리드 ref와 데이터를 관리
|
||||
const gridRefs = useRef<Map<string, RealGridReact>>(new Map());
|
||||
const fileInputRefs = useRef<Map<string, HTMLInputElement>>(new Map());
|
||||
@@ -34,7 +45,7 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, rows = [] }: TabDataGri
|
||||
const menuList = useTabStore((state) => state.menuList);
|
||||
|
||||
// 각 탭별로 데이터를 관리 (key: tabKey)
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string>[]>>(new Map());
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
const [activeTab, setActiveTab] = useState<string>(() => {
|
||||
// 초기 활성 탭을 첫 번째 tabKey로 설정
|
||||
const firstTab = columnInfo[0];
|
||||
@@ -143,20 +154,34 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, rows = [] }: TabDataGri
|
||||
const dataStartRow = maxHeaderRowIndex + 1;
|
||||
|
||||
// 데이터 행 읽기
|
||||
const dataRows: Record<string, string>[] = [];
|
||||
const dataRows: Record<string, string | number>[] = [];
|
||||
for (let row = dataStartRow; row <= range.e.r; row++) {
|
||||
const rowData: Record<string, string> = {};
|
||||
const rowData: Record<string, string | number> = {};
|
||||
let hasData = false;
|
||||
|
||||
for (let colIndex = 0; colIndex < headers.length; colIndex++) {
|
||||
const col = range.s.c + colIndex;
|
||||
const cell = worksheet[XLSX.utils.encode_cell({ r: row, c: col })];
|
||||
const headerName = headers[colIndex] || `Column${colIndex + 1}`;
|
||||
const cellValue = cell && cell.v !== undefined && cell.v !== null
|
||||
? String(cell.v)
|
||||
: '';
|
||||
|
||||
let cellValue: string | number = '';
|
||||
if (cell && cell.v !== undefined && cell.v !== null) {
|
||||
// 엑셀 셀 타입이 숫자이거나 값이 숫자인 경우 숫자로 변환
|
||||
if (cell.t === 'n' || (typeof cell.v === 'number' && !isNaN(cell.v))) {
|
||||
cellValue = cell.v as number;
|
||||
} else {
|
||||
const stringValue = String(cell.v);
|
||||
// 문자열이지만 숫자로 변환 가능한 경우 숫자로 변환
|
||||
const numericValue = Number(stringValue.replace(/,/g, ''));
|
||||
if (!isNaN(numericValue) && stringValue.trim() !== '') {
|
||||
cellValue = numericValue;
|
||||
} else {
|
||||
cellValue = stringValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cellValue !== '') {
|
||||
if (cellValue !== '' && cellValue !== null && cellValue !== undefined) {
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
@@ -308,14 +333,60 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, rows = [] }: TabDataGri
|
||||
const gridView = el.gridView;
|
||||
if (!gridView) return;
|
||||
|
||||
const currentInfo = columnInfo.find(info => info.tabKey === tabKey);
|
||||
if (!currentInfo) return;
|
||||
|
||||
gridView.setDisplayOptions({
|
||||
fitStyle: GridFitStyle.EVEN
|
||||
});
|
||||
gridView.header.height = 60;
|
||||
|
||||
// 헤더 체크박스 표시 여부 설정
|
||||
gridView.setOptions({
|
||||
checkBar: { visible: showHeaderCheckbox },
|
||||
rowIndicator: { visible: false },
|
||||
});
|
||||
|
||||
// footer가 있는 컬럼이 있으면 footer 높이 설정
|
||||
const hasFooter = currentInfo.columns.some(col => col.footer);
|
||||
if (hasFooter) {
|
||||
gridView.footer.height = 40;
|
||||
}
|
||||
|
||||
gridView.setOptions({
|
||||
summaryMode: "aggregate"
|
||||
});
|
||||
|
||||
// footer의 valueCallback 설정
|
||||
currentInfo.columns.forEach(col => {
|
||||
if (col.footer && col.footer.valueCallback) {
|
||||
const column = gridView.columnByName(col.name);
|
||||
if (column && column.footer) {
|
||||
(column.footer as { valueCallback?: typeof col.footer.valueCallback }).valueCallback = col.footer.valueCallback;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// mergeCells가 true인 컬럼에 대해 2개씩 병합하는 mergeRule 설정
|
||||
currentInfo.columns.forEach(col => {
|
||||
if (col.mergeCells === true) {
|
||||
try {
|
||||
const column = gridView.columnByName(col.name);
|
||||
if (column) {
|
||||
// mergeRule: 2개 행씩 병합 (row div 2)
|
||||
(column as { mergeRule?: { criteria: string; breakMergeOnEmpty?: boolean } }).mergeRule = {
|
||||
criteria: 'row div 2',
|
||||
breakMergeOnEmpty: false
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to set mergeRule for column ${col.name}:`, error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 고정 컬럼 설정
|
||||
const currentInfo = columnInfo.find(info => info.tabKey === tabKey);
|
||||
if (currentInfo?.fixedColumns !== undefined && currentInfo.fixedColumns > 0) {
|
||||
if (currentInfo.fixedColumns !== undefined && currentInfo.fixedColumns > 0) {
|
||||
gridView.setFixedOptions({
|
||||
colCount: currentInfo.fixedColumns,
|
||||
});
|
||||
@@ -336,6 +407,12 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, rows = [] }: TabDataGri
|
||||
name={column.name}
|
||||
fieldName={column.fieldName}
|
||||
header={column.header}
|
||||
editable={column.editable}
|
||||
footer={column.footer ? {
|
||||
text: column.footer.text,
|
||||
expression: column.footer.expression,
|
||||
numberFormat: column.footer.numberFormat,
|
||||
} : undefined}
|
||||
/>
|
||||
))}
|
||||
</RealGridReact>
|
||||
|
||||
@@ -4,6 +4,7 @@ import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import { useState } from "react";
|
||||
|
||||
// 하수도 통계 관리 > 07. 분뇨처리시설
|
||||
const ExcretaTreatmentFacilityMng = () => {
|
||||
@@ -126,6 +127,8 @@ const ExcretaTreatmentFacilityMng = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
@@ -137,7 +140,7 @@ const ExcretaTreatmentFacilityMng = () => {
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} fixedColumns={2} isExcelImport={true} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} fixedColumns={2} isExcelImport={true} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,8 +2,9 @@ import SearchForm from '@/components/module/SearchForm';
|
||||
import DataGrid from '@/components/module/DataGrid';
|
||||
import SubmitButton from '@/components/button/SumitButton';
|
||||
import SaveButton from '@/components/button/SaveButton';
|
||||
import LastYearDataButton from '@/components/button/LastYearDataButton';
|
||||
import SubmitExceptionButton from '@/components/button/SubmitExceptionButton';
|
||||
import OperateDataButton from '@/components/button/OperateDataButton';
|
||||
import { useState } from 'react';
|
||||
|
||||
// 하수도 통계 관리 > 06. 공공하수처리시설
|
||||
const PublicSewageFacilityMng = () => {
|
||||
@@ -212,9 +213,9 @@ const PublicSewageFacilityMng = () => {
|
||||
// 제출 로직: 데이터 검증 후 제출 팝업 호출
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
console.log('get last year data');
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
const getOperateDataFunc = () => {
|
||||
console.log('get operate data');
|
||||
// 운영 데이터 가져오기
|
||||
};
|
||||
|
||||
const SubmitExceptionFunc = () => {
|
||||
@@ -222,16 +223,18 @@ const PublicSewageFacilityMng = () => {
|
||||
// 예외제출 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<OperateDataButton getOperateDataFunc={getOperateDataFunc} />
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={3} fixedColumns={2} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={3} fixedColumns={2} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import { useState } from "react";
|
||||
|
||||
// 하수도 통계 관리 > 05. 펌프장
|
||||
const PumpingStationMng = () => {
|
||||
@@ -159,6 +160,8 @@ const PumpingStationMng = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
@@ -168,7 +171,7 @@ const PumpingStationMng = () => {
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{columns, columnLayout}} rowStartNum={3} isExcelImport={true} fixedColumns={3} />
|
||||
<DataGrid columnInfo={{columns, columnLayout}} rowStartNum={3} isExcelImport={true} fixedColumns={3} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import type { GridView, DataColumn } from "@/components/type/DataGrid.type";
|
||||
import { getFooterSummary } from "@/components/util/grid/footerSummary";
|
||||
import { useState } from "react";
|
||||
|
||||
// 하수도 통계 관리 > 01. 하수도 보급률
|
||||
const SeweragePenetrationRateMng = () => {
|
||||
@@ -143,6 +144,8 @@ const SeweragePenetrationRateMng = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
@@ -152,7 +155,7 @@ const SeweragePenetrationRateMng = () => {
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={3} isExcelImport={true} fixedColumns={1} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={3} isExcelImport={true} fixedColumns={1} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import ApproveButton from "@/components/button/ApproveButton";
|
||||
import RejectButton from "@/components/button/RejectButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import { useState } from "react";
|
||||
|
||||
// 하수도 통계 관리 > 00. 통계 입력 현황
|
||||
const StatsInputSatusMng = () => {
|
||||
@@ -55,6 +56,8 @@ const StatsInputSatusMng = () => {
|
||||
// 검토 의견 작성 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
@@ -66,7 +69,7 @@ const StatsInputSatusMng = () => {
|
||||
<RejectButton rejectFunc={rejectFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} fixedColumns={3} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} fixedColumns={3} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { useState } from "react";
|
||||
|
||||
|
||||
const ExcretaTreatmentFacilityRvw = () => {
|
||||
@@ -126,6 +127,8 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
// 반려
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} fctName={true} />
|
||||
@@ -135,7 +138,7 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={2} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={2} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { useState } from "react";
|
||||
|
||||
const PublicSewageFacilityRvw = () => {
|
||||
const columns = [
|
||||
@@ -187,6 +188,8 @@ const PublicSewageFacilityRvw = () => {
|
||||
// 반려
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} fctName={true} />
|
||||
@@ -196,7 +199,7 @@ const PublicSewageFacilityRvw = () => {
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={3} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={3} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { useState } from "react";
|
||||
|
||||
const PumpingStationRvw = () => {
|
||||
const columns = [
|
||||
@@ -146,6 +147,8 @@ const PumpingStationRvw = () => {
|
||||
// 반려
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} fctName={true} />
|
||||
@@ -155,7 +158,7 @@ const PumpingStationRvw = () => {
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={3} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={3} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,12 +5,16 @@ import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
const SeweragePenetrationRateRvw = () => {
|
||||
const columns = [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' } },
|
||||
{ name: 'sgg', fieldName: '구군', header: { text: '구군' } },
|
||||
{ name: '구분', fieldName: '구분', header: { text: '구분' } },
|
||||
const columns: ColumnConfig[] = [
|
||||
{ name: 'sn', fieldName: '순번', header: { text: '순번' }, mergeCells: true, editable: false },
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, mergeCells: true, editable: false },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' }, mergeCells: true, editable: false },
|
||||
{ name: '구분', fieldName: '구분', header: { text: '구분' }, editable: false },
|
||||
{ name: '수계', fieldName: '수계', header: { text: '수계' } },
|
||||
{ name: 'bstrm', fieldName: '지류', header: { text: '지류' } },
|
||||
{ name: 'mdbsn', fieldName: '세부단위유역', header: { text: '세부단위유역' } },
|
||||
@@ -49,6 +53,7 @@ const SeweragePenetrationRateRvw = () => {
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
'sn',
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
@@ -121,6 +126,8 @@ const SeweragePenetrationRateRvw = () => {
|
||||
// 반려
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
@@ -130,7 +137,7 @@ const SeweragePenetrationRateRvw = () => {
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={2} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={3} isExcelImport={true} fixedColumns={3} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { useState } from "react";
|
||||
|
||||
const StatsInputSatusRvw = () => {
|
||||
const columns = [
|
||||
@@ -197,6 +198,8 @@ const StatsInputSatusRvw = () => {
|
||||
// 반려
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
@@ -206,7 +209,7 @@ const StatsInputSatusRvw = () => {
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={2} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} isExcelImport={false} fixedColumns={2} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import { useState } from "react";
|
||||
|
||||
const SeweragePenetrationRateTot = () => {
|
||||
const columns = [
|
||||
@@ -122,6 +123,8 @@ const SeweragePenetrationRateTot = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
@@ -131,7 +134,7 @@ const SeweragePenetrationRateTot = () => {
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{columns, columnLayout}} rowStartNum={2} isExcelImport={true} fixedColumns={1} />
|
||||
<DataGrid columnInfo={{columns, columnLayout}} rowStartNum={2} isExcelImport={true} fixedColumns={1} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import React from "react";
|
||||
|
||||
// RealGrid 타입 정의
|
||||
export type GridView = {
|
||||
getSummary(field: string, summary: 'sum' | 'avg' | 'count' | 'max' | 'min'): number | undefined;
|
||||
getDataSource(): {
|
||||
getRowCount(): number;
|
||||
getValue(rowIndex: number, field: string): number;
|
||||
getValue(rowIndex: number, field: string): number | string;
|
||||
getDataRowId(dataRow: number): number | string;
|
||||
};
|
||||
getDataRow(itemIndex: number): number;
|
||||
};
|
||||
|
||||
export type MergeCallback = (grid: GridView, column: DataColumn, itemIndex: number, value: number | string | null | undefined) => number | null;
|
||||
|
||||
export type DataColumn = {
|
||||
name: string;
|
||||
fieldName: string;
|
||||
@@ -22,6 +28,8 @@ export type ColumnConfig = {
|
||||
name: string;
|
||||
fieldName: string;
|
||||
header: { text: string };
|
||||
editable?: boolean; // 셀 편집 가능 여부
|
||||
mergeCells?: boolean; // 같은 값이 연속될 때 셀 병합 여부
|
||||
footer?: {
|
||||
text?: string;
|
||||
expression?: 'sum' | 'avg' | 'count' | 'max' | 'min';
|
||||
@@ -53,11 +61,13 @@ export type ColumnInfoList = {
|
||||
|
||||
export type DataGridProps = {
|
||||
columnInfo: ColumnInfo;
|
||||
rows?: Record<string, string>[];
|
||||
rowStartNum?: number; // 헤더 행 개수 (1부터 시작, 예: 2면 1행과 2행까지 헤더로 간주)
|
||||
isExcelImport?: boolean; // 엑셀 가져오기 유무
|
||||
onRowsChange?: (rows: Record<string, string>[]) => void;
|
||||
onRowsChange?: (rows: Record<string, string | number>[]) => void;
|
||||
fixedColumns?: number; // 고정할 컬럼 개수 (좌측부터)
|
||||
showHeaderCheckbox?: boolean; // 헤더 체크박스 표시 여부 (기본값: true)
|
||||
rowData: Record<string, string | number>[];
|
||||
setRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>;
|
||||
};
|
||||
|
||||
export type TabDataGridProps = {
|
||||
@@ -65,4 +75,5 @@ export type TabDataGridProps = {
|
||||
rows?: Record<string, string>[];
|
||||
isExcelImport?: boolean; // 엑셀 가져오기 유무
|
||||
onRowsChange?: (rows: Record<string, string>[]) => void;
|
||||
showHeaderCheckbox?: boolean; // 헤더 체크박스 표시 여부 (기본값: true)
|
||||
};
|
||||
Reference in New Issue
Block a user