[st] feat: 통계 검증 리포트 페이지 작업

This commit is contained in:
2026-04-21 18:09:11 +09:00
parent 34a0324124
commit a5e50fc576
8 changed files with 812 additions and 587 deletions
+33 -3
View File
@@ -319,8 +319,10 @@ const DataGrid = ({
rowData,
setRowData,
getGridDataRef,
getGridRef,
cellStyleCallback,
cellTooltipCallback,
onCellEdited,
onRowClick,
onItemChecked,
onItemAllChecked,
@@ -345,6 +347,7 @@ const DataGrid = ({
const cellTooltipCallbackRef = useRef<CellTooltipCallback | undefined>(
cellTooltipCallback,
);
const onCellEditedRef = useRef<typeof onCellEdited>(onCellEdited);
const onScrollToBottomRef = useRef<(() => void) | undefined>(
onScrollToBottom,
);
@@ -357,6 +360,7 @@ const DataGrid = ({
onScrollToBottomRef.current = onScrollToBottom;
onItemCheckedRef.current = onItemChecked;
onItemAllCheckedRef.current = onItemAllChecked;
onCellEditedRef.current = onCellEdited;
// highlightedRowId가 변경될 때 해당 행으로 스크롤 및 선택
useEffect(() => {
@@ -1149,6 +1153,33 @@ const DataGrid = ({
};
}, [onItemChecked, onItemAllChecked]);
useEffect(() => {
const gridView = gridRef.current?.gridView;
if (!gridView) return;
gridView.onCellEdited = (grid, itemIndex, _row, field) => {
const fieldName = columns[field]?.fieldName;
if (!fieldName) return;
const newValue = grid.getValue(itemIndex, fieldName);
const prevRow = rowDataRef.current[itemIndex];
const oldValue = prevRow?.[fieldName] ?? "";
onCellEditedRef.current?.({
itemIndex,
fieldName,
oldValue,
newValue,
});
};
return () => {
if (gridView.onCellEdited) {
gridView.onCellEdited = undefined;
}
};
}, [columns, setRowData]);
return (
<div className="mx-[0.6rem] flex flex-col gap-[0.6rem]">
<input
@@ -1223,7 +1254,6 @@ const DataGrid = ({
ref={gridRef}
autoGenerateField={true}
layout={columnLayout}
rows={rowData}
onInitialized={(grid) => {
if (!grid) return;
(
@@ -1259,9 +1289,9 @@ const DataGrid = ({
buildFieldsFromColumns(columns),
);
}
if (dataProvider?.setRows && rowData?.length) {
if (dataProvider?.setRows)
dataProvider.setRows(rowData);
}
if (getGridRef) getGridRef.current = gridRef.current;
const gridView = gridRef.current?.gridView ?? grid;
if (!gridView?.columnByName) return;
setTimeout(() => {
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,7 @@
import React from "react";
import { ValueType } from "realgrid";
import type { RealGridReact } from "realgrid-react";
import { type SewerageSupplyRateStatusInfo } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
@@ -241,6 +242,17 @@ export type CellTooltipCallback = (
params: CellTooltipCallbackParams,
) => string | undefined;
/** 셀 편집 완료 시 호출되는 콜백 (RealGrid onEditRowChanged) */
export type CellEditedCallbackParams = {
itemIndex: number;
fieldName: string;
oldValue: string | number;
newValue: string | number;
};
export type CellEditedCallback = (
params: CellEditedCallbackParams,
) => void;
export type DataGridProps = {
columnInfo: ColumnInfo;
rowStartNum?: number; // 헤더 행 개수 (1부터 시작, 예: 2면 1행과 2행까지 헤더로 간주)
@@ -259,10 +271,14 @@ export type DataGridProps = {
cellStyleCallback?: CellStyleCallback;
/** 셀 hover 시 툴팁 문구 (예: verificationResult의 rsnExpln) */
cellTooltipCallback?: CellTooltipCallback;
/** 셀 편집 완료 시 호출 (RealGrid onEditRowChanged) */
onCellEdited?: CellEditedCallback;
/** 저장 등 시점에 그리드 현재 데이터를 가져올 수 있도록 할당 (편집 반영된 값) */
getGridDataRef?: {
current: (() => Record<string, string | number>[]) | null;
};
/** 외부에서 gridRef에 직접 접근하기 위한 ref (setRows/addRows/setValue 직접 호출용) */
getGridRef?: React.MutableRefObject<RealGridReact | null>;
onRowClick?: (rowData: Record<string, string | number>) => void; // 행 클릭 이벤트
/** CheckBar 행 체크 변경 */
onItemChecked?: (itemIndex: number, checked: boolean) => void;
@@ -2,17 +2,28 @@ import { stClient } from "@/shared/api/client";
import { ENDPOINT } from "@/shared/config";
import type {
ApprovalRequest,
ApprovalResponse,
ApproveRequest,
RejectRequest,
StatisticsApprovalService,
} from "../model/statistics-approval-interface";
class StatisticsApprovalApiService implements StatisticsApprovalService {
public async approveStats(
params: ApprovalRequest[],
params: ApproveRequest[],
): Promise<ApprovalResponse> {
const response = await stClient.post<ApprovalResponse>(
`${ENDPOINT.ST_SERVICE.APPROVAL}?type=VRFC&action=APPROVE`,
`${ENDPOINT.ST_SERVICE.APPROVAL}/approve?type=VRFC`,
params,
);
return response.data;
}
public async rejectStats(
params: RejectRequest[],
): Promise<ApprovalResponse> {
const response = await stClient.post<ApprovalResponse>(
`${ENDPOINT.ST_SERVICE.APPROVAL}/reject?type=VRFC`,
params,
);
return response.data;
+4 -3
View File
@@ -64,12 +64,13 @@ export {
export { verificationHistoryColumns } from "./model/statistics-analysis/verification-history-columns";
export { getVerificationListColumns } from "./model/statistics-analysis/verification-list-columns";
export {
type ApprovalRequest,
type ApprovalResponse,
type ApproveRequest,
type RejectRequest,
} from "./model/statistics-approval-interface";
export {
statisticsVerificationDetailColumnInfo,
statisticsVerificationSummaryColumnInfo,
statisticsVerificationReportColumnInfo,
statisticsVerificationResultColumnInfo,
} from "./model/statistics-verification-report/statistics-verification-report-columns";
export {
type StatisticsVerificationFilterState,
@@ -1,13 +1,21 @@
export interface ApprovalRequest {
export interface ApproveRequest {
statsYr: string;
sewerBzmnCd: string;
statsCd: string;
mdfrId: string;
rjctOpnnCn: string;
lastCfmtnPicNm: string;
lastCfmtnPicTelNo: string;
lastCfmtnPicDeptNm: string;
lastCfmtnPicJbgdNm: string;
lastCfmtnPicNm?: string;
lastCfmtnPicTelNo?: string;
lastCfmtnPicDeptNm?: string;
lastCfmtnPicJbgdNm?: string;
}
export interface RejectRequest {
vrfcSn: number;
statsYr: string;
sewerBzmnCd: string;
statsCd: string;
mdfrId: string;
rjctOpnnCn?: string;
}
export interface ApprovalResponse {
@@ -18,5 +26,6 @@ export interface ApprovalResponse {
}
export interface StatisticsApprovalService {
approveStats(params: ApprovalRequest[]): Promise<ApprovalResponse>;
approveStats(params: ApproveRequest[]): Promise<ApprovalResponse>;
rejectStats(params: RejectRequest[]): Promise<ApprovalResponse>;
}
@@ -2,7 +2,7 @@ import type { ColumnInfo } from "@/components/type/DataGrid.type";
const READ_ONLY_STYLE = "rg-cell-readonly";
export const statisticsVerificationSummaryColumnInfo: ColumnInfo = {
export const statisticsVerificationReportColumnInfo: ColumnInfo = {
columns: [
{
name: "ctpvNm",
@@ -111,19 +111,21 @@ export const statisticsVerificationSummaryColumnInfo: ColumnInfo = {
],
};
export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
export const statisticsVerificationResultColumnInfo: ColumnInfo = {
columns: [
{
name: "ctpvNm",
fieldName: "ctpvNm",
header: { text: "시도" },
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "sggNm",
fieldName: "sggNm",
header: { text: "시군구" },
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "statsNm",
@@ -131,6 +133,7 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "지표" },
width: 140,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "vrfcTrgtNm",
@@ -138,6 +141,7 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "세부항목" },
width: 180,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "regDt",
@@ -145,6 +149,7 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "검증날짜" },
width: 150,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "rsnExpln",
@@ -152,6 +157,7 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "오류내역" },
width: 200,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "nowVlCn",
@@ -159,6 +165,7 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "입력값" },
width: 90,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "compVlCn",
@@ -166,6 +173,7 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "비교값" },
width: 90,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "prcsYn",
@@ -173,6 +181,7 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "상태" },
width: 90,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "prcsOpnnExpln",
@@ -180,13 +189,14 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "예외사유" },
width: 170,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "rjctOpnnCn",
fieldName: "rjctOpnnCn",
header: { text: "반려의견" },
width: 170,
styleName: READ_ONLY_STYLE,
editable: true,
},
{
name: "pbcpAprvYn",
@@ -194,12 +204,14 @@ export const statisticsVerificationDetailColumnInfo: ColumnInfo = {
header: { text: "승인여부" },
width: 90,
styleName: READ_ONLY_STYLE,
editable: false,
},
{
name: "vrfcSn",
fieldName: "vrfcSn",
header: { text: "vrfcSn" },
visible: false,
editable: false,
},
],
columnLayout: [
+1 -1
View File
@@ -73,7 +73,7 @@ export const ENDPOINT = {
INPUTCOMMON: "/st-input-service/api/v1/common",
INPUTVERIFY: "/st-input-service/api/v1/verify",
TOTAL: "/st-management-service/api/v1/stats",
APPROVAL: "/st-management-service/api/stats/approval",
APPROVAL: "/st-management-service/api/stats",
},
STATVERIFY_SERVICE: {
VRFCTGT_MNG: "/statverify-service/api/v1/vrfc-trgt-mng",