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:
@@ -25,7 +25,7 @@ import { DEFAULT_DASHBOARD_SETTINGS } from './types';
|
||||
import { ScheduleDetailModal, DetailModal } from './modals';
|
||||
import { DashboardSettingsDialog } from './dialogs/DashboardSettingsDialog';
|
||||
import { mockData } from './mockData';
|
||||
import { useCEODashboard, useTodayIssue, useCalendar, useVat, useEntertainment, useWelfare } from '@/hooks/useCEODashboard';
|
||||
import { useCEODashboard, useTodayIssue, useCalendar, useVat, useEntertainment, useWelfare, useWelfareDetail } from '@/hooks/useCEODashboard';
|
||||
import {
|
||||
getMonthlyExpenseModalConfig,
|
||||
getCardManagementModalConfig,
|
||||
@@ -100,6 +100,11 @@ export function CEODashboard() {
|
||||
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
||||
const [dashboardSettings, setDashboardSettings] = useState<DashboardSettings>(DEFAULT_DASHBOARD_SETTINGS);
|
||||
|
||||
// WelfareDetail Hook (모달용 상세 API) - dashboardSettings 이후에 선언
|
||||
const welfareDetailData = useWelfareDetail({
|
||||
calculationType: dashboardSettings.welfare.calculationType,
|
||||
});
|
||||
|
||||
// 상세 모달 상태
|
||||
const [isDetailModalOpen, setIsDetailModalOpen] = useState(false);
|
||||
const [detailModalConfig, setDetailModalConfig] = useState<DetailModalConfig | null>(null);
|
||||
@@ -179,11 +184,16 @@ export function CEODashboard() {
|
||||
}, []);
|
||||
|
||||
// 복리후생비 현황 카드 클릭 (모든 카드가 동일한 상세 모달)
|
||||
const handleWelfareCardClick = useCallback(() => {
|
||||
const config = getWelfareModalConfig(dashboardSettings.welfare.calculationType);
|
||||
// 복리후생비 클릭 - API 데이터로 모달 열기 (fallback: 정적 config)
|
||||
const handleWelfareCardClick = useCallback(async () => {
|
||||
// 1. 먼저 API에서 데이터 fetch 시도
|
||||
await welfareDetailData.refetch();
|
||||
|
||||
// 2. API 데이터가 있으면 사용, 없으면 fallback config 사용
|
||||
const config = welfareDetailData.modalConfig ?? getWelfareModalConfig(dashboardSettings.welfare.calculationType);
|
||||
setDetailModalConfig(config);
|
||||
setIsDetailModalOpen(true);
|
||||
}, [dashboardSettings.welfare.calculationType]);
|
||||
}, [welfareDetailData, dashboardSettings.welfare.calculationType]);
|
||||
|
||||
// 부가세 클릭 (모든 카드가 동일한 상세 모달)
|
||||
const handleVatClick = useCallback(() => {
|
||||
|
||||
@@ -2,7 +2,21 @@ import type { DetailModalConfig } from '../types';
|
||||
|
||||
/**
|
||||
* 복리후생비 현황 모달 설정
|
||||
* 모든 카드가 동일한 상세 모달
|
||||
*
|
||||
* @deprecated 정적 목업 데이터 - API 연동 후에는 useWelfareDetail hook 사용 권장
|
||||
*
|
||||
* API 연동 방법:
|
||||
* 1. useWelfareDetail hook 호출하여 modalConfig 가져오기
|
||||
* 2. API 호출 실패 시 이 fallback config 사용
|
||||
*
|
||||
* @example
|
||||
* const { modalConfig, loading, error, refetch } = useWelfareDetail({
|
||||
* calculationType: 'fixed',
|
||||
* year: 2026,
|
||||
* quarter: 1,
|
||||
* });
|
||||
* const config = modalConfig ?? getWelfareModalConfig('fixed'); // fallback
|
||||
*
|
||||
* @param calculationType - 계산 방식 ('fixed': 직원당 정액 금액/월, 'ratio': 연봉 총액 비율)
|
||||
*/
|
||||
export function getWelfareModalConfig(calculationType: 'fixed' | 'ratio'): DetailModalConfig {
|
||||
|
||||
@@ -21,6 +21,7 @@ import type {
|
||||
VatApiResponse,
|
||||
EntertainmentApiResponse,
|
||||
WelfareApiResponse,
|
||||
WelfareDetailApiResponse,
|
||||
} from '@/lib/api/dashboard/types';
|
||||
|
||||
import {
|
||||
@@ -35,6 +36,7 @@ import {
|
||||
transformVatResponse,
|
||||
transformEntertainmentResponse,
|
||||
transformWelfareResponse,
|
||||
transformWelfareDetailResponse,
|
||||
} from '@/lib/api/dashboard/transformers';
|
||||
|
||||
import type {
|
||||
@@ -49,6 +51,7 @@ import type {
|
||||
VatData,
|
||||
EntertainmentData,
|
||||
WelfareData,
|
||||
DetailModalConfig,
|
||||
} from '@/components/business/CEODashboard/types';
|
||||
|
||||
// ============================================
|
||||
@@ -553,6 +556,71 @@ export function useWelfare(options: UseWelfareOptions = {}) {
|
||||
return { data, loading, error, refetch: fetchData };
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 12. WelfareDetail Hook (복리후생비 상세 - 모달용)
|
||||
// ============================================
|
||||
|
||||
export interface UseWelfareDetailOptions {
|
||||
/** 계산 방식 (fixed: 1인당 정액, ratio: 급여 대비 비율) */
|
||||
calculationType?: 'fixed' | 'ratio';
|
||||
/** 1인당 월 정액 (calculation_type=fixed일 때 사용, 기본: 200000) */
|
||||
fixedAmountPerMonth?: number;
|
||||
/** 급여 대비 비율 (calculation_type=ratio일 때 사용, 기본: 0.05) */
|
||||
ratio?: number;
|
||||
/** 연도 (기본: 현재 연도) */
|
||||
year?: number;
|
||||
/** 분기 번호 (1-4, 기본: 현재 분기) */
|
||||
quarter?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 복리후생비 상세 데이터 Hook (모달용)
|
||||
* API에서 상세 데이터를 가져와 DetailModalConfig로 변환
|
||||
*/
|
||||
export function useWelfareDetail(options: UseWelfareDetailOptions = {}) {
|
||||
const {
|
||||
calculationType = 'fixed',
|
||||
fixedAmountPerMonth,
|
||||
ratio,
|
||||
year,
|
||||
quarter,
|
||||
} = options;
|
||||
const [modalConfig, setModalConfig] = useState<DetailModalConfig | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
// 쿼리 파라미터 구성
|
||||
const params = new URLSearchParams();
|
||||
params.append('calculation_type', calculationType);
|
||||
if (fixedAmountPerMonth) params.append('fixed_amount_per_month', fixedAmountPerMonth.toString());
|
||||
if (ratio) params.append('ratio', ratio.toString());
|
||||
if (year) params.append('year', year.toString());
|
||||
if (quarter) params.append('quarter', quarter.toString());
|
||||
|
||||
const queryString = params.toString();
|
||||
const endpoint = `welfare/detail?${queryString}`;
|
||||
|
||||
const apiData = await fetchApi<WelfareDetailApiResponse>(endpoint);
|
||||
const transformed = transformWelfareDetailResponse(apiData);
|
||||
setModalConfig(transformed);
|
||||
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : '데이터 로딩 실패';
|
||||
setError(errorMessage);
|
||||
console.error('WelfareDetail API Error:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [calculationType, fixedAmountPerMonth, ratio, year, quarter]);
|
||||
|
||||
return { modalConfig, loading, error, refetch: fetchData };
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 통합 Dashboard Hook (선택적 사용)
|
||||
// ============================================
|
||||
@@ -568,7 +636,7 @@ export interface UseCEODashboardOptions {
|
||||
monthlyExpense?: boolean;
|
||||
/** CardManagement 섹션 활성화 */
|
||||
cardManagement?: boolean;
|
||||
/** CardManagement fallback 데이터 */
|
||||
/** CardManagement fallback 데이터 (가지급금, 법인세, 종합세 등) */
|
||||
cardManagementFallback?: CardManagementData;
|
||||
/** StatusBoard 섹션 활성화 */
|
||||
statusBoard?: boolean;
|
||||
|
||||
@@ -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) || '',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -93,6 +93,31 @@ export interface CardTransactionApiResponse {
|
||||
total_amount: number; // 총 금액
|
||||
}
|
||||
|
||||
/** 카드 목록 아이템 (대시보드용) */
|
||||
export interface CardListItemApiResponse {
|
||||
id: number;
|
||||
card_company: string;
|
||||
card_number_last4: string;
|
||||
card_name: string;
|
||||
status: 'active' | 'inactive';
|
||||
assigned_user?: {
|
||||
id: number;
|
||||
name: string;
|
||||
} | null;
|
||||
// 카드별 사용액 (선택적 - API 지원 시)
|
||||
current_month_amount?: number;
|
||||
previous_month_amount?: number;
|
||||
}
|
||||
|
||||
/** GET /api/v1/cards 응답 (대시보드용) */
|
||||
export interface CardListApiResponse {
|
||||
data: CardListItemApiResponse[];
|
||||
current_page: number;
|
||||
last_page: number;
|
||||
per_page: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 공통 API 응답 Wrapper
|
||||
// ============================================
|
||||
@@ -290,4 +315,250 @@ export interface WelfareCheckPointApiResponse {
|
||||
export interface WelfareApiResponse {
|
||||
cards: WelfareAmountCardApiResponse[];
|
||||
check_points: WelfareCheckPointApiResponse[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 12. Welfare Detail (복리후생비 상세) API 응답 타입
|
||||
// ============================================
|
||||
|
||||
/** 복리후생비 상세 요약 */
|
||||
export interface WelfareDetailSummaryApiResponse {
|
||||
annual_account: number; // 당해년도 복리후생비 계정 잔액
|
||||
annual_limit: number; // 당해년도 복리후생비 한도
|
||||
annual_used: number; // 당해년도 복리후생비 사용액
|
||||
annual_remaining: number; // 당해년도 잔여한도
|
||||
quarterly_limit: number; // 분기 복리후생비 총 한도
|
||||
quarterly_remaining: number; // 분기 복리후생비 잔여한도
|
||||
quarterly_used: number; // 분기 복리후생비 사용금액
|
||||
quarterly_exceeded: number; // 분기 복리후생비 초과 금액
|
||||
}
|
||||
|
||||
/** 복리후생비 월별 사용 추이 */
|
||||
export interface WelfareMonthlyUsageApiResponse {
|
||||
month: string; // "2026-01"
|
||||
label: string; // "1월"
|
||||
amount: number; // 사용 금액
|
||||
}
|
||||
|
||||
/** 복리후생비 항목별 사용 비율 */
|
||||
export interface WelfareCategoryDistributionApiResponse {
|
||||
category: string; // meal, health_check, congratulation, other
|
||||
category_label: string; // 식비, 건강검진, 경조사비, 기타
|
||||
amount: number; // 금액
|
||||
percentage: number; // 비율
|
||||
color: string; // 차트 색상
|
||||
}
|
||||
|
||||
/** 복리후생비 거래 내역 */
|
||||
export interface WelfareTransactionApiResponse {
|
||||
id: number;
|
||||
card_name: string; // 카드명
|
||||
user_name: string; // 사용자명
|
||||
transaction_date: string; // 사용일자
|
||||
merchant_name: string; // 가맹점명
|
||||
amount: number; // 사용금액
|
||||
usage_type: string; // 사용항목 (meal, health_check, etc.)
|
||||
usage_type_label: string; // 사용항목 라벨 (식비, 건강검진, etc.)
|
||||
}
|
||||
|
||||
/** 복리후생비 계산 정보 */
|
||||
export interface WelfareCalculationApiResponse {
|
||||
type: 'fixed' | 'ratio'; // 계산 방식
|
||||
employee_count: number; // 직원 수
|
||||
fixed_amount_per_month?: number; // 1인당 월 정액 (fixed 방식)
|
||||
annual_amount_per_employee?: number; // 1인당 연간 금액 (fixed 방식)
|
||||
total_salary?: number; // 연봉 총액 (ratio 방식)
|
||||
ratio?: number; // 비율 (ratio 방식)
|
||||
annual_limit: number; // 계산된 연간 한도
|
||||
}
|
||||
|
||||
/** 복리후생비 분기별 현황 */
|
||||
export interface WelfareQuarterlyStatusApiResponse {
|
||||
quarter: number; // 분기 (1-4)
|
||||
quarter_label: string; // "1분기"
|
||||
limit: number; // 한도금액
|
||||
carryover: number | null; // 이월금액 (1분기만 0, 나머지는 null 또는 계산값)
|
||||
used: number | null; // 사용금액
|
||||
remaining: number | null; // 잔여한도
|
||||
exceeded: number | null; // 초과금액
|
||||
}
|
||||
|
||||
/** GET /api/proxy/welfare/detail 응답 */
|
||||
export interface WelfareDetailApiResponse {
|
||||
summary: WelfareDetailSummaryApiResponse;
|
||||
monthly_usage: WelfareMonthlyUsageApiResponse[];
|
||||
category_distribution: WelfareCategoryDistributionApiResponse[];
|
||||
transactions: WelfareTransactionApiResponse[];
|
||||
calculation: WelfareCalculationApiResponse;
|
||||
quarterly: WelfareQuarterlyStatusApiResponse[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 13. Purchase Dashboard Detail (매입 상세) API 응답 타입
|
||||
// ============================================
|
||||
|
||||
/** 매입 상세 요약 */
|
||||
export interface PurchaseDashboardSummaryApiResponse {
|
||||
current_month_amount: number; // 당월 매입액
|
||||
previous_month_amount: number; // 전월 매입액
|
||||
change_rate: number; // 전월 대비 변화율
|
||||
}
|
||||
|
||||
/** 매입 월별 추이 */
|
||||
export interface PurchaseMonthlyTrendApiResponse {
|
||||
month: string; // "2026-01"
|
||||
label: string; // "1월"
|
||||
amount: number; // 금액
|
||||
}
|
||||
|
||||
/** 매입 유형별 분포 */
|
||||
export interface PurchaseByTypeApiResponse {
|
||||
type: string; // 매입 유형 코드
|
||||
type_label: string; // 유형 라벨 (원자재, 부자재, 외주, 기타)
|
||||
amount: number; // 금액
|
||||
count: number; // 건수
|
||||
color: string; // 차트 색상
|
||||
}
|
||||
|
||||
/** 매입 거래 내역 */
|
||||
export interface PurchaseItemApiResponse {
|
||||
id: number;
|
||||
vendor_name: string; // 거래처명
|
||||
purchase_date: string; // 매입일자
|
||||
amount: number; // 금액
|
||||
type: string; // 유형 코드
|
||||
type_label: string; // 유형 라벨
|
||||
}
|
||||
|
||||
/** GET /api/v1/purchases/dashboard-detail 응답 */
|
||||
export interface PurchaseDashboardDetailApiResponse {
|
||||
summary: PurchaseDashboardSummaryApiResponse;
|
||||
monthly_trend: PurchaseMonthlyTrendApiResponse[];
|
||||
by_type: PurchaseByTypeApiResponse[];
|
||||
items: PurchaseItemApiResponse[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 14. Card Transaction Dashboard Detail (카드 상세) API 응답 타입
|
||||
// ============================================
|
||||
|
||||
/** 카드 상세 요약 */
|
||||
export interface CardDashboardSummaryApiResponse {
|
||||
current_month_total: number; // 당월 사용액
|
||||
previous_month_total: number; // 전월 사용액
|
||||
total_count: number; // 총 건수
|
||||
current_month_count: number; // 당월 건수
|
||||
}
|
||||
|
||||
/** 카드 월별 추이 */
|
||||
export interface CardMonthlyTrendApiResponse {
|
||||
month: string; // "2026-01"
|
||||
label: string; // "1월"
|
||||
amount: number; // 금액
|
||||
}
|
||||
|
||||
/** 카드 사용자별 분포 */
|
||||
export interface CardByUserApiResponse {
|
||||
user_name: string; // 사용자명
|
||||
amount: number; // 금액
|
||||
count: number; // 건수
|
||||
color: string; // 차트 색상
|
||||
}
|
||||
|
||||
/** 카드 거래 내역 */
|
||||
export interface CardTransactionItemApiResponse {
|
||||
id: number;
|
||||
card_name: string; // 카드명
|
||||
user_name: string; // 사용자명
|
||||
transaction_date: string; // 사용일자
|
||||
merchant_name: string; // 가맹점명
|
||||
amount: number; // 금액
|
||||
usage_type: string; // 사용항목
|
||||
}
|
||||
|
||||
/** GET /api/v1/card-transactions/dashboard 응답 */
|
||||
export interface CardDashboardDetailApiResponse {
|
||||
summary: CardDashboardSummaryApiResponse;
|
||||
monthly_trend: CardMonthlyTrendApiResponse[];
|
||||
by_user: CardByUserApiResponse[];
|
||||
items: CardTransactionItemApiResponse[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 15. Bill Dashboard Detail (발행어음 상세) API 응답 타입
|
||||
// ============================================
|
||||
|
||||
/** 발행어음 상세 요약 */
|
||||
export interface BillDashboardSummaryApiResponse {
|
||||
current_month_amount: number; // 당월 어음액
|
||||
previous_month_amount: number; // 전월 어음액
|
||||
change_rate: number; // 전월 대비 변화율
|
||||
}
|
||||
|
||||
/** 발행어음 월별 추이 */
|
||||
export interface BillMonthlyTrendApiResponse {
|
||||
month: string; // "2026-01"
|
||||
label: string; // "1월"
|
||||
amount: number; // 금액
|
||||
}
|
||||
|
||||
/** 발행어음 거래처별 분포 */
|
||||
export interface BillByVendorApiResponse {
|
||||
vendor_name: string; // 거래처명
|
||||
amount: number; // 금액
|
||||
count: number; // 건수
|
||||
}
|
||||
|
||||
/** 발행어음 거래 내역 */
|
||||
export interface BillItemApiResponse {
|
||||
id: number;
|
||||
vendor_name: string; // 거래처명
|
||||
issue_date: string; // 발행일
|
||||
due_date: string; // 만기일
|
||||
amount: number; // 금액
|
||||
status: string; // 상태 코드
|
||||
status_label: string; // 상태 라벨
|
||||
}
|
||||
|
||||
/** GET /api/v1/bills/dashboard-detail 응답 */
|
||||
export interface BillDashboardDetailApiResponse {
|
||||
summary: BillDashboardSummaryApiResponse;
|
||||
monthly_trend: BillMonthlyTrendApiResponse[];
|
||||
by_vendor: BillByVendorApiResponse[];
|
||||
items: BillItemApiResponse[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 16. Expected Expense Dashboard Detail (지출예상 상세) API 응답 타입
|
||||
// ============================================
|
||||
|
||||
/** 지출예상 상세 요약 */
|
||||
export interface ExpectedExpenseDashboardSummaryApiResponse {
|
||||
total_amount: number; // 총 지출 예상액
|
||||
previous_month_amount: number; // 전월 지출액
|
||||
change_rate: number; // 전월 대비 변화율
|
||||
remaining_balance: number; // 지출 후 예상 잔액
|
||||
}
|
||||
|
||||
/** 지출예상 거래 내역 */
|
||||
export interface ExpectedExpenseItemApiResponse {
|
||||
id: number;
|
||||
payment_date: string; // 결제예정일
|
||||
item_name: string; // 항목명
|
||||
amount: number; // 금액
|
||||
vendor_name: string; // 거래처명
|
||||
account_title: string; // 계정과목
|
||||
}
|
||||
|
||||
/** 지출예상 합계 정보 */
|
||||
export interface ExpectedExpenseFooterSummaryApiResponse {
|
||||
total_amount: number; // 합계 금액
|
||||
item_count: number; // 건수
|
||||
}
|
||||
|
||||
/** GET /api/v1/expected-expenses/dashboard-detail 응답 */
|
||||
export interface ExpectedExpenseDashboardDetailApiResponse {
|
||||
summary: ExpectedExpenseDashboardSummaryApiResponse;
|
||||
items: ExpectedExpenseItemApiResponse[];
|
||||
footer_summary: ExpectedExpenseFooterSummaryApiResponse;
|
||||
}
|
||||
Reference in New Issue
Block a user