st: feat: 하수도보급률 입력 저장, 체출 로직 작업, 도-시 조회 시 버튼 조건 추가

This commit is contained in:
2026-02-25 14:39:40 +09:00
parent f51f6e58d8
commit cc3c5c5d68
9 changed files with 628 additions and 288 deletions
+50 -25
View File
@@ -10,6 +10,7 @@ import type {
FooterItemWithCallback,
ColumnLayoutItem,
CellStyleCallback,
CellTooltipCallback,
} from "../type/DataGrid.type";
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks";
import JSZip from "jszip";
@@ -311,6 +312,7 @@ const DataGrid = ({
setRowData,
getGridDataRef,
cellStyleCallback,
cellTooltipCallback,
onRowClick,
statusInfo,
}: DataGridProps) => {
@@ -321,8 +323,10 @@ const DataGrid = ({
const originalRowsRef = useRef<Record<string, Record<string, string | number>[]>>({});
const rowDataRef = useRef<Record<string, string | number>[]>(rowData);
const cellStyleCallbackRef = useRef<CellStyleCallback | undefined>(cellStyleCallback);
const cellTooltipCallbackRef = useRef<CellTooltipCallback | undefined>(cellTooltipCallback);
rowDataRef.current = rowData;
cellStyleCallbackRef.current = cellStyleCallback;
cellTooltipCallbackRef.current = cellTooltipCallback;
useLayoutEffect(() => {
if (!cellStyleCallback || !gridRef.current?.gridView) return;
@@ -980,38 +984,38 @@ const DataGrid = ({
getGridDataRef,
]);
// 행 클릭 이벤트 설정
// 행 클릭 이벤트 + 검증 오류 셀 클릭 시 showMessage (공식 문서 방식)
useEffect(() => {
if (!gridRef.current?.gridView || !onRowClick) return;
const gridView = gridRef.current?.gridView;
if (!gridView || (!onRowClick && !cellTooltipCallback)) return;
const gridView = gridRef.current.gridView;
// onCellClicked 이벤트 핸들러 설정
gridView.onCellClicked = (grid, clickData) => {
// 데이터 셀만 처리 (헤더, 푸터 등 제외)
if (
clickData.cellType === "data" &&
clickData.itemIndex !== undefined
) {
try {
// 행 전체 데이터 가져오기
const row = rowData[clickData.itemIndex];
// 부모 컴포넌트로 데이터 전달
onRowClick(row ?? {});
} catch (error) {
console.error("행 데이터 가져오기 오류:", error);
if (clickData.cellType !== "data" || clickData.itemIndex === undefined) return;
try {
const row = rowDataRef.current[clickData.itemIndex];
const cellIndex = (grid as { getCurrent?: () => { itemIndex: number; column?: string; fieldName?: string } }).getCurrent?.();
// cellTooltipCallback 있으면 해당 셀 메시지로 showMessage (공식 문서: TooltipOptions + CellIndex)
if (cellTooltipCallbackRef.current && row && cellIndex) {
const fieldName = cellIndex.fieldName ?? cellIndex.column ?? "";
const msg = cellTooltipCallbackRef.current({ row: row as Record<string, string | number>, fieldName });
if (msg) {
const colName = columns.find((c) => c.fieldName === fieldName || c.name === cellIndex.column)?.name ?? cellIndex.column ?? fieldName;
(gridView as { showMessage?: (opts: { message: string; hideDuration?: number }, idx: { itemIndex: number; column: string }) => void }).showMessage?.(
{ message: msg, hideDuration: 5000 },
{ itemIndex: cellIndex.itemIndex, column: colName }
);
}
}
if (onRowClick) onRowClick((row ?? {}) as Record<string, string | number>);
} catch (error) {
console.error("행 데이터 가져오기 오류:", error);
}
};
// cleanup: 컴포넌트 언마운트 시 이벤트 핸들러 제거
return () => {
if (gridView.onCellClicked) {
gridView.onCellClicked = undefined;
}
if (gridView.onCellClicked) gridView.onCellClicked = undefined;
};
}, [onRowClick]);
}, [onRowClick, cellTooltipCallback, columns]);
return (
<div className="mx-[0.6rem] flex flex-col gap-[0.6rem]">
@@ -1034,7 +1038,11 @@ const DataGrid = ({
statusInfo.locgStatus === '3' ? '승인' : '반려'
}
</span>
<span>제출일: {statusInfo.locgDt ? statusInfo.locgDt : '미제출'}</span>
<span>제출일: {statusInfo.locgDt
? (statusInfo.locgDt.length === 8 && /^\d{8}$/.test(statusInfo.locgDt)
? `${statusInfo.locgDt.slice(0, 4)}-${statusInfo.locgDt.slice(4, 6)}-${statusInfo.locgDt.slice(6, 8)}`
: statusInfo.locgDt)
: '미제출'}</span>
<span>담당자: {statusInfo.locgCharger ? statusInfo.locgCharger : '-'}</span>
<span>연락처: {statusInfo.locgCttpc ? statusInfo.locgCttpc : '-'}</span>
</div>
@@ -1083,10 +1091,26 @@ const DataGrid = ({
setTimeout(() => {
const gv = gridRef.current?.gridView;
if (!gv?.columnByName) return;
// 공식 문서: 데이터 영역 툴팁 = renderer.showTooltip + onShowTooltip (displayOptions는 Ellipsis용이라 사용 안 함)
if (cellTooltipCallbackRef.current) {
(gv as { onShowTooltip?: (grid: unknown, index: { itemIndex: number; column: string }, value: string) => string | undefined }).onShowTooltip = (_grid, index, value) => {
const row = rowDataRef.current[index?.itemIndex];
if (row == null) return value;
const column = index.column;
const col = columns.find((c) => c.name === column);
const fieldName = col?.fieldName ?? column;
const custom = cellTooltipCallbackRef.current?.({ row: row as Record<string, string | number>, fieldName });
// verificationResult 등 메시지가 있을 때만 툴팁 표시 (없으면 undefined 반환 → 툴팁 안 띄움)
return custom && custom.length > 0 ? custom : undefined;
};
}
columns.forEach((column) => {
const baseStyleName = column.styleName;
const gridCol = gv.columnByName(column.name) as { styleCallback?: (g: unknown, dataCell: { itemIndex?: number; index?: { itemIndex?: number }; dataField?: string; fieldName?: string }) => string } | null;
const gridCol = gv.columnByName(column.name) as { styleCallback?: (g: unknown, dataCell: { itemIndex?: number; index?: { itemIndex?: number }; dataField?: string; fieldName?: string }) => string; renderer?: { showTooltip?: boolean } } | null;
if (gridCol) {
if (cellTooltipCallbackRef.current) {
(gv as { setColumnProperty?: (col: string, key: string, value: unknown) => void }).setColumnProperty?.(column.name, 'renderer', { showTooltip: true });
}
gridCol.styleCallback = (_g, dataCell) => {
const itemIndex = dataCell?.index?.itemIndex ?? dataCell?.itemIndex ?? -1;
const fieldName = dataCell?.dataField ?? dataCell?.fieldName ?? column.fieldName;
@@ -1117,6 +1141,7 @@ const DataGrid = ({
editable={column.editable}
{...(baseStyleName != null && { styleName: baseStyleName })}
{...(column.visible === false && { visible: false })}
{...(cellTooltipCallback && { renderer: { showTooltip: true } })}
footer={column.footer && !Array.isArray(column.footer) ? {
text: column.footer.text,
expression: column.footer.expression,