feat: 테스트 데이터(V17) + 실 DB 프로파일 + 프론트 화면 확장
V17 (192.168.0.60:55432/trading_ai/ga 적용 완료):
- insurance_company 5 (삼성/한화/교보/디비/KB)
- product 20 (보험사별 4개)
- organization 7 (본부 1, 지점 3, 팀 3)
- agent 50 (GM 3 / DM 3 / SMGR 6 / SFC 12 / FC 26)
- contract 200 (ACTIVE 190 + LAPSE 10)
- commission_rate 100 (5상품 × 5년차 × 5보험사 = 일부)
실제 INSERT는 상품 20개 × 1년차 + 20 × 4년차 = 100건
- payout_rule 120 (직급 6 × 보험종류 4 × 연차 5)
- override_rule 10 (FC/SFC/MGR/SMGR/DM 직급 간 오버라이드)
- chargeback_rule 4 (실효월수 구간별 환수율)
운영 DB 프로파일:
- application-trading_ai.yml (ga-api, ga-batch)
- 192.168.0.60:55432 / trading_ai / currentSchema=ga
- Flyway baseline-version=17 (수동 적용 분 인정)
DB 포트 변경 반영: 5432 → 55432 (운영 변경)
프론트 추가 화면:
- DataGrid (AG Grid Community 래퍼; 합계행/셀편집/로딩 오버레이)
- 예외원장 (ExceptionLedger): 승인/반려 액션
- 지급관리 (PaymentList)
- 정산 배치 (BatchRun): 실행 + 진행률 폴링
- 시스템관리:
* UserList: 비밀번호 초기화 + 잠금 해제
* RoleList: 좌측 역할 + 우측 권한 매트릭스 (메뉴 × 6권한)
* CodeList: 좌측 그룹 + 우측 상세 코드, 시스템그룹 경고
설계사 상세/등록 폼:
- AgentDetail: 통계 카드 + 기본정보 + 수정 버튼
- AgentForm: 등록/수정 통합 (id='new' 또는 :id/edit)
라우터:
- /org/agents/{new|:id|:id/edit}
- /ledger/exception, /payments, /settle/batch
- /system/{users|roles|codes}
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { AgGridReact } from '@ag-grid-community/react';
|
||||
import { ModuleRegistry } from '@ag-grid-community/core';
|
||||
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
|
||||
import type { ColDef, GridReadyEvent, GridApi } from '@ag-grid-community/core';
|
||||
import '@ag-grid-community/styles/ag-grid.css';
|
||||
import '@ag-grid-community/styles/ag-theme-quartz.css';
|
||||
|
||||
ModuleRegistry.registerModules([ClientSideRowModelModule]);
|
||||
|
||||
interface Props<T> {
|
||||
rows: T[] | undefined;
|
||||
columns: ColDef<T>[];
|
||||
loading?: boolean;
|
||||
height?: number | string;
|
||||
/** 합계행 데이터 */
|
||||
pinnedBottomRow?: Partial<T>;
|
||||
/** 셀 편집 가능 시 콜백 */
|
||||
onCellChanged?: (row: T, field: string, newValue: unknown) => void;
|
||||
rowKey?: keyof T;
|
||||
}
|
||||
|
||||
/**
|
||||
* AG Grid Community 클라이언트사이드 래퍼.
|
||||
* - 100건 이상 / 셀 편집 / 합계행이 필요한 화면용
|
||||
* - 서버사이드는 별도 SSRM 모듈 필요 (Community 한정 → enterprise만 지원)
|
||||
* 여기서는 현실적인 절충안으로 클라이언트사이드 + 외부 페이징 사용
|
||||
*/
|
||||
export default function DataGrid<T extends Record<string, unknown>>({
|
||||
rows,
|
||||
columns,
|
||||
loading,
|
||||
height = 600,
|
||||
pinnedBottomRow,
|
||||
onCellChanged,
|
||||
rowKey,
|
||||
}: Props<T>) {
|
||||
const apiRef = useRef<GridApi<T> | null>(null);
|
||||
|
||||
const defaultColDef = useMemo<ColDef>(
|
||||
() => ({
|
||||
sortable: true,
|
||||
filter: true,
|
||||
resizable: true,
|
||||
suppressMovable: false,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const onGridReady = (e: GridReadyEvent<T>) => {
|
||||
apiRef.current = e.api;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (apiRef.current) {
|
||||
if (loading) apiRef.current.showLoadingOverlay();
|
||||
else apiRef.current.hideOverlay();
|
||||
}
|
||||
}, [loading]);
|
||||
|
||||
return (
|
||||
<div className="ag-theme-quartz" style={{ height, width: '100%' }}>
|
||||
<AgGridReact<T>
|
||||
rowData={rows}
|
||||
columnDefs={columns}
|
||||
defaultColDef={defaultColDef}
|
||||
animateRows
|
||||
rowSelection="single"
|
||||
getRowId={rowKey ? (p) => String(p.data[rowKey]) : undefined}
|
||||
pinnedBottomRowData={pinnedBottomRow ? [pinnedBottomRow as T] : undefined}
|
||||
onCellValueChanged={(e) => {
|
||||
if (onCellChanged && e.data) {
|
||||
onCellChanged(e.data, String(e.colDef.field), e.newValue);
|
||||
}
|
||||
}}
|
||||
onGridReady={onGridReady}
|
||||
loadingOverlayComponent={() => <span>불러오는 중...</span>}
|
||||
noRowsOverlayComponent={() => <span>데이터가 없습니다</span>}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user