feat(frontend): 누락된 메뉴 14개 페이지 일괄 구현

신규 페이지 (모두 ProTable / ProCard 패턴):
- org/OrgTree: 조직 트리 + 선택 시 우측에 소속 설계사 ProTable
- product/CompanyList: 보험사 목록
- product/ProductList: 상품 목록 (보험종 필터)
- rule/CommissionRateList: 수수료율 (보험사 통보)
- rule/PayoutRuleList: 지급율 (직급 × 보험종 × 회차)
- rule/OverrideRuleList: 오버라이드 규정 (직급 페어)
- rule/ChargebackRuleList: 환수 규정 (실효 월수 구간)
- rule/ExceptionCodeList: 예외 코드 마스터
- ledger/MaintainLedger: 유지수수료 원장
- receive/ReceiveData: 보험사 raw 수신 데이터
- receive/ReceiveMapping: 보험사 프로파일 + 필드 매핑 규칙
- system/MenuManage: 메뉴 트리 표시 (Tree)
- system/SystemConfig: 키-값 설정 (그룹별 필터)
- system/SystemLog: 로그인/API/변경 이력 3 탭

신규 API 모듈:
- api/org.ts (조직 트리)
- api/company.ts, api/product.ts
- api/rule.ts (5종 통합)
- api/receive.ts (profile/field/raw/error)
- api/config.ts, api/log.ts

App.tsx: 14 라우트 추가 (org/tree, companies, products, rules/*,
receive/*, ledger/maintain, system/menus, system/config, system/logs)

검증:
- tsc -b 통과
- 12개 백엔드 엔드포인트 200 OK 확인
- dev 서버 HMR 자동 반영

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
GA Pro
2026-05-10 22:36:51 +09:00
parent 020939e563
commit f176b9702c
22 changed files with 1212 additions and 4 deletions
+25
View File
@@ -0,0 +1,25 @@
import api, { PageResponse, unwrap } from './request';
export interface CompanyResp {
companyId: number;
companyCode: string;
companyName: string;
companyType?: string;
bizNo?: string;
contactName?: string;
contactPhone?: string;
contactEmail?: string;
isActive: string;
}
export interface CompanySearchParam {
pageNum?: number;
pageSize?: number;
searchKeyword?: string;
isActive?: string;
}
export const companyApi = {
list: (p: CompanySearchParam) =>
unwrap<PageResponse<CompanyResp>>(api.get('/api/companies', { params: p })),
};
+20
View File
@@ -0,0 +1,20 @@
import api, { unwrap } from './request';
export interface SystemConfigResp {
configKey: string;
configValue?: string;
configDesc?: string;
configGroup?: string;
valueType?: string;
isEncrypted?: string;
isEditable?: string;
updatedAt?: string;
updatedBy?: number;
}
export const configApi = {
list: (group?: string) =>
unwrap<SystemConfigResp[]>(api.get('/api/system/config', { params: { group } })),
update: (key: string, value: string) =>
unwrap<void>(api.put(`/api/system/config/${key}`, { value })),
};
+48
View File
@@ -0,0 +1,48 @@
import api, { PageResponse, unwrap } from './request';
export interface LoginLogResp {
logId: number;
userId?: number;
username?: string;
loginType: string;
ipAddress?: string;
userAgent?: string;
failReason?: string;
loginAt?: string;
}
export interface ApiAccessLogResp {
logId: number;
userId?: number;
username?: string;
requestMethod: string;
requestUrl: string;
responseStatus?: number;
responseTime?: number;
ipAddress?: string;
errorMessage?: string;
createdAt?: string;
}
export interface DataChangeLogResp {
logId: number;
tableName: string;
recordId?: string;
actionType: string;
changeData?: any;
changeReason?: string;
userId?: number;
username?: string;
ipAddress?: string;
menuCode?: string;
createdAt?: string;
}
export const logApi = {
login: (p: { pageNum?: number; pageSize?: number; username?: string; startDate?: string; endDate?: string }) =>
unwrap<PageResponse<LoginLogResp>>(api.get('/api/system/logs/login', { params: p })),
api: (p: { pageNum?: number; pageSize?: number; username?: string; startDate?: string; endDate?: string }) =>
unwrap<PageResponse<ApiAccessLogResp>>(api.get('/api/system/logs/api', { params: p })),
change: (p: { pageNum?: number; pageSize?: number; tableName?: string; username?: string; startDate?: string; endDate?: string }) =>
unwrap<PageResponse<DataChangeLogResp>>(api.get('/api/system/logs/data-change', { params: p })),
};
+20
View File
@@ -0,0 +1,20 @@
import api, { unwrap } from './request';
export interface OrgNode {
orgId: number;
parentOrgId?: number;
orgName: string;
orgType: string; // HQ / BR / TM
orgLevel: number;
region?: string;
effectiveFrom?: string;
effectiveTo?: string;
isActive: string;
children?: OrgNode[];
}
export const orgApi = {
tree: () => unwrap<OrgNode[]>(api.get('/api/orgs/tree')),
list: () => unwrap<OrgNode[]>(api.get('/api/orgs')),
detail: (id: number) => unwrap<OrgNode>(api.get(`/api/orgs/${id}`)),
};
+29
View File
@@ -0,0 +1,29 @@
import api, { PageResponse, unwrap } from './request';
export interface ProductResp {
productId: number;
companyId: number;
companyName?: string;
productCode: string;
productName: string;
insuranceType: string;
productGroup?: string;
payPeriodType?: string;
isActive: string;
launchDate?: string;
endDate?: string;
}
export interface ProductSearchParam {
pageNum?: number;
pageSize?: number;
searchKeyword?: string;
companyId?: number;
insuranceType?: string;
isActive?: string;
}
export const productApi = {
list: (p: ProductSearchParam) =>
unwrap<PageResponse<ProductResp>>(api.get('/api/products', { params: p })),
};
+75
View File
@@ -0,0 +1,75 @@
import api, { unwrap } from './request';
export interface CompanyProfileResp {
companyCode: string;
dataFormat?: string;
receiveMethod?: string;
fileEncoding?: string;
delimiter?: string;
headerRow?: number;
dataStartRow?: number;
sheetName?: string;
dateFormat?: string;
amountFormat?: string;
apiUrl?: string;
ftpHost?: string;
ftpPath?: string;
receiveSchedule?: string;
isActive: string;
}
export interface FieldMappingResp {
mappingId: number;
companyCode: string;
sourceField: string;
sourceColIndex?: number;
targetTable: string;
targetField: string;
dataType?: string;
transformRule?: string;
defaultValue?: string;
isRequired?: string;
sortOrder: number;
version?: number;
effectiveFrom?: string;
}
export interface RawCommissionResp {
rawId: number;
companyCode: string;
batchId?: string;
settleMonth: string;
dataType: string;
parseStatus: string;
mappedLedgerId?: number;
mappedTable?: string;
fileName?: string;
rowNumber?: number;
receivedAt?: string;
parsedAt?: string;
}
export interface ParseErrorResp {
errorId: number;
rawId?: number;
companyCode: string;
errorType: string;
errorField?: string;
errorValue?: string;
errorMessage?: string;
resolveStatus: string;
resolvedBy?: number;
resolveNote?: string;
resolvedAt?: string;
createdAt?: string;
}
export const receiveApi = {
profiles: () => unwrap<CompanyProfileResp[]>(api.get('/api/receive/profiles')),
fields: (companyCode: string) =>
unwrap<FieldMappingResp[]>(api.get(`/api/receive/mapping/${companyCode}/fields`)),
raw: (params: { companyCode?: string; settleMonth?: string; parseStatus?: string }) =>
unwrap<RawCommissionResp[]>(api.get('/api/receive/raw', { params })),
errors: (params: { companyCode?: string; resolveStatus?: string }) =>
unwrap<ParseErrorResp[]>(api.get('/api/receive/errors', { params })),
};
+79
View File
@@ -0,0 +1,79 @@
import api, { unwrap } from './request';
export interface CommissionRateResp {
rateId: number;
productId: number;
productName?: string;
commissionYear: number;
ratePct: number;
payMethodCond?: string;
minPremium?: number;
effectiveFrom?: string;
effectiveTo?: string;
version: number;
}
export interface PayoutRuleResp {
ruleId: number;
gradeId: number;
gradeName?: string;
insuranceType: string;
commissionYear: number;
payoutPct: number;
payMethodCond?: string;
performanceGrade?: string;
effectiveFrom?: string;
effectiveTo?: string;
version: number;
}
export interface OverrideRuleResp {
overrideId: number;
fromGrade: number;
toGrade: number;
fromGradeName?: string;
toGradeName?: string;
overridePct: number;
calcType?: string;
insuranceTypeCond?: string;
capAmount?: number;
effectiveFrom?: string;
effectiveTo?: string;
}
export interface ChargebackRuleResp {
cbRuleId: number;
companyCode: string;
insuranceType: string;
lapseMonthFrom: number;
lapseMonthTo: number;
cbRate: number;
includeOverride: string;
installmentAllowed: string;
maxInstallments?: number;
effectiveFrom?: string;
effectiveTo?: string;
}
export interface ExceptionCodeResp {
exceptionCode: string;
exceptionName: string;
category?: string;
direction: string;
autoCalcYn: string;
approvalRequired: string;
taxIncluded: string;
description?: string;
isActive: string;
}
export const ruleApi = {
commissionRates: (params?: { productId?: number; year?: number }) =>
unwrap<CommissionRateResp[]>(api.get('/api/rules/commission-rates', { params })),
payoutRules: (params?: { gradeId?: number; insuranceType?: string }) =>
unwrap<PayoutRuleResp[]>(api.get('/api/rules/payout', { params })),
overrideRules: () => unwrap<OverrideRuleResp[]>(api.get('/api/rules/override')),
chargebackRules: (params?: { companyCode?: string }) =>
unwrap<ChargebackRuleResp[]>(api.get('/api/rules/chargeback', { params })),
exceptionCodes: () => unwrap<ExceptionCodeResp[]>(api.get('/api/rules/exception-codes')),
};