diff --git a/src/components/business/CEODashboard/CEODashboard.tsx b/src/components/business/CEODashboard/CEODashboard.tsx index 71e82547..f1063822 100644 --- a/src/components/business/CEODashboard/CEODashboard.tsx +++ b/src/components/business/CEODashboard/CEODashboard.tsx @@ -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(DEFAULT_DASHBOARD_SETTINGS); + // WelfareDetail Hook (모달용 상세 API) - dashboardSettings 이후에 선언 + const welfareDetailData = useWelfareDetail({ + calculationType: dashboardSettings.welfare.calculationType, + }); + // 상세 모달 상태 const [isDetailModalOpen, setIsDetailModalOpen] = useState(false); const [detailModalConfig, setDetailModalConfig] = useState(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(() => { diff --git a/src/components/business/CEODashboard/modalConfigs/welfareConfigs.ts b/src/components/business/CEODashboard/modalConfigs/welfareConfigs.ts index 00f6ad67..bbb24c0a 100644 --- a/src/components/business/CEODashboard/modalConfigs/welfareConfigs.ts +++ b/src/components/business/CEODashboard/modalConfigs/welfareConfigs.ts @@ -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 { diff --git a/src/hooks/useCEODashboard.ts b/src/hooks/useCEODashboard.ts index 55377f16..77d6c8a4 100644 --- a/src/hooks/useCEODashboard.ts +++ b/src/hooks/useCEODashboard.ts @@ -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(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(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(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; diff --git a/src/lib/api/dashboard/transformers.ts b/src/lib/api/dashboard/transformers.ts index 360c2d68..e7fb91e4 100644 --- a/src/lib/api/dashboard/transformers.ts +++ b/src/lib/api/dashboard/transformers.ts @@ -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) || '', + }, + ], + }, + }; } \ No newline at end of file diff --git a/src/lib/api/dashboard/types.ts b/src/lib/api/dashboard/types.ts index 1f3d6555..c4154163 100644 --- a/src/lib/api/dashboard/types.ts +++ b/src/lib/api/dashboard/types.ts @@ -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; } \ No newline at end of file