feat: [대시보드] 복리후생비 현황 섹션 Phase 2 - 프론트엔드 API 연동

Phase 2 프론트엔드 연동 완료:
- WelfareDetailApiResponse 타입 정의 추가 (types.ts)
- useWelfareDetail hook 추가 (useCEODashboard.ts)
- transformWelfareDetailResponse 변환 함수 추가 (transformers.ts)
- CEODashboard에 API 연동 및 Mock fallback 구현

변경 파일:
- src/lib/api/dashboard/types.ts: 복리후생비 상세 API 응답 타입
- src/hooks/useCEODashboard.ts: useWelfareDetail hook
- src/lib/api/dashboard/transformers.ts: API → DetailModalConfig 변환
- src/components/business/CEODashboard/CEODashboard.tsx: 모달 API 연동
- src/components/business/CEODashboard/modalConfigs/welfareConfigs.ts: deprecation 문서화
This commit is contained in:
2026-01-22 22:48:29 +09:00
parent b1e444930b
commit f8d93e2851
5 changed files with 553 additions and 13 deletions

View File

@@ -16,6 +16,11 @@ import type {
VatApiResponse,
EntertainmentApiResponse,
WelfareApiResponse,
WelfareDetailApiResponse,
PurchaseDashboardDetailApiResponse,
CardDashboardDetailApiResponse,
BillDashboardDetailApiResponse,
ExpectedExpenseDashboardDetailApiResponse,
} from './types';
import type {
@@ -480,42 +485,46 @@ function generateCardManagementCheckPoints(api: CardTransactionApiResponse): Che
/**
* CardTransaction API 응답 → Frontend 타입 변환
* 주의: 가지급금, 법인세 예상 가중 등은 별도 API 필요 (현재 목업 유지)
* 4개 카드 구조 유지: 카드, 가지급금, 법인세 예상 가중, 대표자 종합세 예상 가중
* 주의: 가지급금, 법인세, 종합세 관련 데이터는 별도 API 필요 (현재 목업 유지)
*/
export function transformCardManagementResponse(
api: CardTransactionApiResponse,
summaryApi: CardTransactionApiResponse,
fallbackData?: CardManagementData
): CardManagementData {
const changeRate = calculateChangeRate(api.current_month_total, api.previous_month_total);
const changeRate = calculateChangeRate(summaryApi.current_month_total, summaryApi.previous_month_total);
return {
// 가지급금 관련 경고는 API 데이터가 없으므로 fallback 사용
// 가지급금 관련 경고 배너 (별도 API 필요)
warningBanner: fallbackData?.warningBanner,
cards: [
// cm1: 카드 사용액 (API 데이터)
{
id: 'cm1',
label: '카드',
amount: api.current_month_total,
amount: summaryApi.current_month_total,
previousLabel: `전월 대비 ${changeRate > 0 ? '+' : ''}${changeRate.toFixed(1)}%`,
},
// 아래 항목들은 API에서 제공하지 않으므로 fallback 사용
// cm2: 가지급금 (별도 API 필요 - 현재 fallback)
fallbackData?.cards[1] ?? {
id: 'cm2',
label: '가지급금',
amount: 0,
},
// cm3: 법인세 예상 가중 (별도 API 필요 - 현재 fallback)
fallbackData?.cards[2] ?? {
id: 'cm3',
label: '법인세 예상 가중',
amount: 0,
},
// cm4: 대표자 종합세 예상 가중 (별도 API 필요 - 현재 fallback)
fallbackData?.cards[3] ?? {
id: 'cm4',
label: '대표자 종합세 예상 가중',
amount: 0,
},
],
checkPoints: generateCardManagementCheckPoints(api),
checkPoints: generateCardManagementCheckPoints(summaryApi),
};
}
@@ -714,4 +723,172 @@ export function transformWelfareResponse(api: WelfareApiResponse): WelfareData {
})),
})),
};
}
// ============================================
// 12. Welfare Detail 변환
// ============================================
import type { DetailModalConfig } from '@/components/business/CEODashboard/types';
/**
* WelfareDetail API 응답 → DetailModalConfig 변환
* 복리후생비 상세 모달 설정 생성
*/
export function transformWelfareDetailResponse(api: WelfareDetailApiResponse): DetailModalConfig {
const { summary, monthly_usage, category_distribution, transactions, calculation, quarterly } = api;
// 계산 방식에 따른 calculationCards 생성
const calculationCards = calculation.type === 'fixed'
? {
title: '복리후생비 계산',
subtitle: `직원당 정액 금액/월 ${(calculation.fixed_amount_per_month ?? 200000).toLocaleString()}`,
cards: [
{ label: '직원 수', value: calculation.employee_count, unit: '명' },
{ label: '연간 직원당 월급 금액', value: calculation.annual_amount_per_employee ?? 0, unit: '원', operator: '×' as const },
{ label: '당해년도 복리후생비 총 한도', value: calculation.annual_limit, unit: '원', operator: '=' as const },
],
}
: {
title: '복리후생비 계산',
subtitle: `연봉 총액 기준 비율 ${((calculation.ratio ?? 0.05) * 100).toFixed(1)}%`,
cards: [
{ label: '연봉 총액', value: calculation.total_salary ?? 0, unit: '원' },
{ label: '비율', value: (calculation.ratio ?? 0.05) * 100, unit: '%', operator: '×' as const },
{ label: '당해년도 복리후생비 총 한도', value: calculation.annual_limit, unit: '원', operator: '=' as const },
],
};
// 분기 라벨 가져오기 (현재 분기 기준)
const currentQuarter = quarterly.find(q => q.used !== null)?.quarter ?? 1;
const quarterLabel = `${currentQuarter}사분기`;
return {
title: '복리후생비 상세',
summaryCards: [
// 1행: 당해년도 기준
{ label: '당해년도 복리후생비 계정', value: summary.annual_account, unit: '원' },
{ label: '당해년도 복리후생비 한도', value: summary.annual_limit, unit: '원' },
{ label: '당해년도 복리후생비 사용', value: summary.annual_used, unit: '원' },
{ label: '당해년도 잔여한도', value: summary.annual_remaining, unit: '원' },
// 2행: 분기 기준
{ label: `${quarterLabel} 복리후생비 총 한도`, value: summary.quarterly_limit, unit: '원' },
{ label: `${quarterLabel} 복리후생비 잔여한도`, value: summary.quarterly_remaining, unit: '원' },
{ label: `${quarterLabel} 복리후생비 사용금액`, value: summary.quarterly_used, unit: '원' },
{ label: `${quarterLabel} 복리후생비 초과 금액`, value: summary.quarterly_exceeded, unit: '원' },
],
barChart: {
title: '월별 복리후생비 사용 추이',
data: monthly_usage.map(item => ({
name: item.label,
value: item.amount,
})),
dataKey: 'value',
xAxisKey: 'name',
color: '#60A5FA',
},
pieChart: {
title: '항목별 사용 비율',
data: category_distribution.map(item => ({
name: item.category_label,
value: item.amount,
percentage: item.percentage,
color: item.color,
})),
},
table: {
title: '일별 복리후생비 사용 내역',
columns: [
{ key: 'no', label: 'No.', align: 'center' },
{ key: 'cardName', label: '카드명', align: 'left' },
{ key: 'user', label: '사용자', align: 'center' },
{ key: 'date', label: '사용일자', align: 'center', format: 'date' },
{ key: 'store', label: '가맹점명', align: 'left' },
{ key: 'amount', label: '사용금액', align: 'right', format: 'currency' },
{ key: 'usageType', label: '사용항목', align: 'center' },
],
data: transactions.map((tx, idx) => ({
no: idx + 1,
cardName: tx.card_name,
user: tx.user_name,
date: tx.transaction_date,
store: tx.merchant_name,
amount: tx.amount,
usageType: tx.usage_type_label,
})),
filters: [
{
key: 'usageType',
options: [
{ value: 'all', label: '전체' },
{ value: '식비', label: '식비' },
{ value: '건강검진', label: '건강검진' },
{ value: '경조사비', label: '경조사비' },
{ value: '기타', label: '기타' },
],
defaultValue: 'all',
},
{
key: 'sortOrder',
options: [
{ value: 'latest', label: '최신순' },
{ value: 'oldest', label: '등록순' },
{ value: 'amountDesc', label: '금액 높은순' },
{ value: 'amountAsc', label: '금액 낮은순' },
],
defaultValue: 'latest',
},
],
showTotal: true,
totalLabel: '합계',
totalValue: transactions.reduce((sum, tx) => sum + tx.amount, 0),
totalColumnKey: 'amount',
},
calculationCards,
quarterlyTable: {
title: '복리후생비 현황',
rows: [
{
label: '한도금액',
q1: quarterly[0]?.limit ?? 0,
q2: quarterly[1]?.limit ?? 0,
q3: quarterly[2]?.limit ?? 0,
q4: quarterly[3]?.limit ?? 0,
total: quarterly.reduce((sum, q) => sum + (q.limit ?? 0), 0),
},
{
label: '이월금액',
q1: quarterly[0]?.carryover ?? 0,
q2: quarterly[1]?.carryover ?? '',
q3: quarterly[2]?.carryover ?? '',
q4: quarterly[3]?.carryover ?? '',
total: '',
},
{
label: '사용금액',
q1: quarterly[0]?.used ?? '',
q2: quarterly[1]?.used ?? '',
q3: quarterly[2]?.used ?? '',
q4: quarterly[3]?.used ?? '',
total: quarterly.reduce((sum, q) => sum + (q.used ?? 0), 0) || '',
},
{
label: '잔여한도',
q1: quarterly[0]?.remaining ?? '',
q2: quarterly[1]?.remaining ?? '',
q3: quarterly[2]?.remaining ?? '',
q4: quarterly[3]?.remaining ?? '',
total: '',
},
{
label: '초과금액',
q1: quarterly[0]?.exceeded ?? '',
q2: quarterly[1]?.exceeded ?? '',
q3: quarterly[2]?.exceeded ?? '',
q4: quarterly[3]?.exceeded ?? '',
total: quarterly.reduce((sum, q) => sum + (q.exceeded ?? 0), 0) || '',
},
],
},
};
}