feat(WEB): CEO 대시보드 Phase 2 API 연동 완료

- StatusBoard(현황판) API Hook 및 타입 추가
- TodayIssue(오늘의 이슈) API Hook 및 타입 추가
- Calendar(캘린더) API Hook 및 타입 추가
- Vat(부가세) API Hook 및 타입 추가
- Entertainment(접대비) API Hook 및 타입 추가
- Welfare(복리후생비) API Hook 및 타입 추가
- CEODashboard.tsx에 모든 Phase 2 Hook 통합
- API 응답 → Frontend 타입 변환 transformer 추가
- WelfareCalculationType 'percentage' → 'ratio' 타입 일치 수정
This commit is contained in:
2026-01-21 10:38:09 +09:00
parent e6ef80f17f
commit fb1d7bf241
5 changed files with 774 additions and 9 deletions

View File

@@ -10,6 +10,12 @@ import type {
BadDebtApiResponse,
ExpectedExpenseApiResponse,
CardTransactionApiResponse,
StatusBoardApiResponse,
TodayIssueApiResponse,
CalendarApiResponse,
VatApiResponse,
EntertainmentApiResponse,
WelfareApiResponse,
} from './types';
import type {
@@ -18,8 +24,16 @@ import type {
DebtCollectionData,
MonthlyExpenseData,
CardManagementData,
TodayIssueItem,
TodayIssueListItem,
TodayIssueListBadgeType,
CalendarScheduleItem,
CheckPoint,
CheckPointType,
VatData,
EntertainmentData,
WelfareData,
HighlightColor,
} from '@/components/business/CEODashboard/types';
// ============================================
@@ -428,4 +442,201 @@ export function transformCardManagementResponse(
],
checkPoints: generateCardManagementCheckPoints(api),
};
}
// ============================================
// 6. StatusBoard 변환
// ============================================
/**
* StatusBoard API 응답 → Frontend 타입 변환
* API 응답 형식이 TodayIssueItem과 거의 동일하므로 단순 매핑
*/
export function transformStatusBoardResponse(api: StatusBoardApiResponse): TodayIssueItem[] {
return api.items.map((item) => ({
id: item.id,
label: item.label,
count: item.count,
path: item.path,
isHighlighted: item.isHighlighted,
}));
}
// ============================================
// 7. TodayIssue 변환
// ============================================
/** 유효한 뱃지 타입 목록 */
const VALID_BADGE_TYPES: TodayIssueListBadgeType[] = [
'수주 성공',
'주식 이슈',
'직정 제고',
'지출예상내역서',
'세금 신고',
'결재 요청',
'기타',
];
/**
* API 뱃지 문자열 → Frontend 뱃지 타입 변환
* 유효하지 않은 뱃지는 '기타'로 폴백
*/
function validateBadgeType(badge: string): TodayIssueListBadgeType {
if (VALID_BADGE_TYPES.includes(badge as TodayIssueListBadgeType)) {
return badge as TodayIssueListBadgeType;
}
return '기타';
}
/**
* TodayIssue API 응답 → Frontend 타입 변환
* 오늘의 이슈 리스트 데이터 변환
*/
export function transformTodayIssueResponse(api: TodayIssueApiResponse): {
items: TodayIssueListItem[];
totalCount: number;
} {
return {
items: api.items.map((item) => ({
id: item.id,
badge: validateBadgeType(item.badge),
content: item.content,
time: item.time,
date: item.date,
needsApproval: item.needsApproval ?? false,
path: item.path,
})),
totalCount: api.total_count,
};
}
// ============================================
// 8. Calendar 변환
// ============================================
/**
* Calendar API 응답 → Frontend 타입 변환
* API 응답 형식이 CalendarScheduleItem과 동일하므로 단순 매핑
*/
export function transformCalendarResponse(api: CalendarApiResponse): {
items: CalendarScheduleItem[];
totalCount: number;
} {
return {
items: api.items.map((item) => ({
id: item.id,
title: item.title,
startDate: item.startDate,
endDate: item.endDate,
startTime: item.startTime,
endTime: item.endTime,
isAllDay: item.isAllDay,
type: item.type,
department: item.department,
personName: item.personName,
color: item.color,
})),
totalCount: api.total_count,
};
}
// ============================================
// 9. Vat 변환
// ============================================
/** 유효한 하이라이트 색상 목록 */
const VALID_HIGHLIGHT_COLORS: HighlightColor[] = ['red', 'green', 'blue'];
/**
* API 색상 문자열 → Frontend 하이라이트 색상 변환
* 유효하지 않은 색상은 'blue'로 폴백
*/
function validateHighlightColor(color: string): HighlightColor {
if (VALID_HIGHLIGHT_COLORS.includes(color as HighlightColor)) {
return color as HighlightColor;
}
return 'blue';
}
/**
* Vat API 응답 → Frontend 타입 변환
* 부가세 현황 데이터 변환
*/
export function transformVatResponse(api: VatApiResponse): VatData {
return {
cards: api.cards.map((card) => ({
id: card.id,
label: card.label,
amount: card.amount,
subLabel: card.subLabel,
unit: card.unit,
})),
checkPoints: api.check_points.map((cp) => ({
id: cp.id,
type: cp.type as CheckPointType,
message: cp.message,
highlights: cp.highlights?.map((h) => ({
text: h.text,
color: validateHighlightColor(h.color),
})),
})),
};
}
// ============================================
// 10. Entertainment 변환
// ============================================
/**
* Entertainment API 응답 → Frontend 타입 변환
* 접대비 현황 데이터 변환
*/
export function transformEntertainmentResponse(api: EntertainmentApiResponse): EntertainmentData {
return {
cards: api.cards.map((card) => ({
id: card.id,
label: card.label,
amount: card.amount,
subLabel: card.subLabel,
unit: card.unit,
})),
checkPoints: api.check_points.map((cp) => ({
id: cp.id,
type: cp.type as CheckPointType,
message: cp.message,
highlights: cp.highlights?.map((h) => ({
text: h.text,
color: validateHighlightColor(h.color),
})),
})),
};
}
// ============================================
// 11. Welfare 변환
// ============================================
/**
* Welfare API 응답 → Frontend 타입 변환
* 복리후생비 현황 데이터 변환
*/
export function transformWelfareResponse(api: WelfareApiResponse): WelfareData {
return {
cards: api.cards.map((card) => ({
id: card.id,
label: card.label,
amount: card.amount,
subLabel: card.subLabel,
unit: card.unit,
})),
checkPoints: api.check_points.map((cp) => ({
id: cp.id,
type: cp.type as CheckPointType,
message: cp.message,
highlights: cp.highlights?.map((h) => ({
text: h.text,
color: validateHighlightColor(h.color),
})),
})),
};
}

View File

@@ -117,4 +117,170 @@ export interface DashboardErrorState {
debtCollection: string | null;
monthlyExpense: string | null;
cardManagement: string | null;
}
// ============================================
// 6. StatusBoard (현황판) API 응답 타입
// ============================================
/** 현황판 카드 아이템 */
export interface StatusBoardItemApiResponse {
id: string; // 카드 ID (orders, bad_debts, etc.)
label: string; // 카드 라벨
count: number | string; // 건수 또는 텍스트 (예: "부가세 신고 D-15")
path: string; // 이동 경로
isHighlighted: boolean; // 강조 표시 여부
}
/** GET /api/proxy/status-board/summary 응답 */
export interface StatusBoardApiResponse {
items: StatusBoardItemApiResponse[];
}
// ============================================
// 7. TodayIssue (오늘의 이슈 리스트) API 응답 타입
// ============================================
/** 오늘의 이슈 아이템 */
export interface TodayIssueItemApiResponse {
id: string; // 항목 고유 ID
badge: string; // 이슈 카테고리 뱃지
content: string; // 이슈 내용
time: string; // 상대 시간 (예: "10분 전")
date?: string; // 날짜 (ISO 형식)
needsApproval?: boolean; // 승인/반려 버튼 표시 여부
path?: string; // 클릭 시 이동할 경로
}
/** GET /api/proxy/today-issues/summary 응답 */
export interface TodayIssueApiResponse {
items: TodayIssueItemApiResponse[];
total_count: number; // 전체 이슈 건수
}
// ============================================
// 8. Calendar (캘린더) API 응답 타입
// ============================================
/** 캘린더 일정 타입 */
export type CalendarScheduleType = 'schedule' | 'order' | 'construction' | 'other';
/** 캘린더 일정 아이템 */
export interface CalendarScheduleItemApiResponse {
id: string; // 일정 ID (타입_ID 형식, 예: "wo_123")
title: string; // 일정 제목
startDate: string; // 시작일 (Y-m-d)
endDate: string; // 종료일 (Y-m-d)
startTime: string | null; // 시작 시간 (HH:mm) 또는 null
endTime: string | null; // 종료 시간 (HH:mm) 또는 null
isAllDay: boolean; // 종일 여부
type: CalendarScheduleType; // 일정 타입
department: string | null; // 부서명
personName: string | null; // 담당자명
color: string | null; // 일정 색상
}
/** GET /api/proxy/calendar/schedules 응답 */
export interface CalendarApiResponse {
items: CalendarScheduleItemApiResponse[];
total_count: number; // 총 일정 수
}
// ============================================
// 9. Vat (부가세) API 응답 타입
// ============================================
/** 부가세 금액 카드 아이템 */
export interface VatAmountCardApiResponse {
id: string; // 카드 ID (vat_sales_tax, vat_purchases_tax, etc.)
label: string; // 카드 라벨
amount: number; // 금액 또는 건수
subLabel?: string; // 부가 라벨 (예: "환급")
unit?: string; // 단위 (예: "건")
}
/** 부가세 체크포인트 하이라이트 아이템 */
export interface VatHighlightItemApiResponse {
text: string; // 하이라이트 텍스트
color: string; // 색상 (red, blue, green 등)
}
/** 부가세 체크포인트 아이템 */
export interface VatCheckPointApiResponse {
id: string; // 체크포인트 ID
type: string; // 타입 (success, warning, error)
message: string; // 메시지
highlights?: VatHighlightItemApiResponse[]; // 하이라이트 아이템 목록
}
/** GET /api/proxy/vat/summary 응답 */
export interface VatApiResponse {
cards: VatAmountCardApiResponse[];
check_points: VatCheckPointApiResponse[];
}
// ============================================
// 10. Entertainment (접대비) API 응답 타입
// ============================================
/** 접대비 금액 카드 아이템 */
export interface EntertainmentAmountCardApiResponse {
id: string; // 카드 ID (et_sales, et_limit, etc.)
label: string; // 카드 라벨
amount: number; // 금액
subLabel?: string; // 부가 라벨
unit?: string; // 단위
}
/** 접대비 체크포인트 하이라이트 아이템 */
export interface EntertainmentHighlightItemApiResponse {
text: string; // 하이라이트 텍스트
color: string; // 색상 (red, green, orange 등)
}
/** 접대비 체크포인트 아이템 */
export interface EntertainmentCheckPointApiResponse {
id: string; // 체크포인트 ID
type: string; // 타입 (success, warning, error)
message: string; // 메시지
highlights?: EntertainmentHighlightItemApiResponse[]; // 하이라이트 아이템 목록
}
/** GET /api/proxy/entertainment/summary 응답 */
export interface EntertainmentApiResponse {
cards: EntertainmentAmountCardApiResponse[];
check_points: EntertainmentCheckPointApiResponse[];
}
// ============================================
// 11. Welfare (복리후생비) API 응답 타입
// ============================================
/** 복리후생비 금액 카드 아이템 */
export interface WelfareAmountCardApiResponse {
id: string; // 카드 ID (wf_annual_limit, wf_period_limit, etc.)
label: string; // 카드 라벨
amount: number; // 금액
subLabel?: string; // 부가 라벨
unit?: string; // 단위
}
/** 복리후생비 체크포인트 하이라이트 아이템 */
export interface WelfareHighlightItemApiResponse {
text: string; // 하이라이트 텍스트
color: string; // 색상 (red, green, orange 등)
}
/** 복리후생비 체크포인트 아이템 */
export interface WelfareCheckPointApiResponse {
id: string; // 체크포인트 ID
type: string; // 타입 (success, warning, error)
message: string; // 메시지
highlights?: WelfareHighlightItemApiResponse[]; // 하이라이트 아이템 목록
}
/** GET /api/proxy/welfare/summary 응답 */
export interface WelfareApiResponse {
cards: WelfareAmountCardApiResponse[];
check_points: WelfareCheckPointApiResponse[];
}