Files
sam-react-prod/src/components/business/MainDashboard.tsx
유병철 f344dc7d00 refactor(WEB): 회계/견적/설정/생산 등 전반적 코드 개선 및 공통화 2차
- 회계 모듈 전면 개선: 청구/입금/출금/매입/매출/세금계산서/일반전표/거래처원장 등
- 견적 모듈 금액 포맷/할인/수식/미리보기 등 코드 정리
- 설정 모듈: 계정관리/직급/직책/권한 상세 간소화
- 생산 모듈: 작업지시서/작업자화면/검수 문서 코드 정리
- UniversalListPage 엑셀 다운로드 및 필터 기능 확장
- 대시보드/게시판/수주 등 날짜 유틸 공통화 적용
- claudedocs 문서 인덱스 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 10:45:47 +09:00

2653 lines
147 KiB
TypeScript
Raw Blame History

import { useEffect, useMemo, useState } from "react";
import { getLocalDateString, getTodayString } from "@/lib/utils/date";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { useCurrentTime } from "@/hooks/useCurrentTime";
import { OptimizedChart } from "@/components/ui/chart-wrapper";
import { Calendar } from "@/components/ui/calendar";
import { Checkbox } from "@/components/ui/checkbox";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import {
DollarSign,
TrendingUp,
Package,
AlertTriangle,
Clock,
FileText,
Truck,
BarChart3,
ArrowUpRight,
ArrowDownRight,
Zap,
Activity,
Banknote,
CreditCard,
PieChart,
Calculator,
Building2,
ShoppingBag,
AlertCircle,
Plane,
MapPin,
Warehouse,
RotateCcw,
Layers,
Gauge,
UserCheck,
Calendar as CalendarIcon,
Plus,
Minus,
Filter,
Coffee,
Clock2,
Users2,
Star,
TestTube,
FileCheck
} from "lucide-react";
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, LineChart, Line, Area, AreaChart } from "recharts";
import { formatNumber } from '@/lib/utils/amount';
/**
* MainDashboard - 통합 대시보드
*
* 사용자 역할과 메뉴는 백엔드에서 관리하며,
* 이 대시보드는 모든 역할에 대해 공통으로 사용됩니다.
* 표시되는 데이터는 백엔드 API에서 사용자 권한에 따라 필터링됩니다.
*/
export function MainDashboard() {
const currentTime = useCurrentTime();
// Hydration 불일치 방지: 클라이언트에서만 현재 날짜 설정
const [calendarDate, setCalendarDate] = useState<Date | undefined>(undefined);
useEffect(() => {
setCalendarDate(new Date());
}, []);
const [calendarView, setCalendarView] = useState("month");
const [calendarFilters, setCalendarFilters] = useState({
incoming: true,
outgoing: true,
materials: true,
schedule: true,
vacation: true,
business: true
});
const ceoData = useMemo(() => {
return {
// 매출 현황 및 목표 달성률
salesTarget: {
// 일별 매출
daily: {
actual: 45000000,
target: 50000000,
achievement: 90.0,
receivable: 12000000, // 미수금
collected: 33000000, // 수금액
collectionRate: 73.3 // 수금률
},
// 월별 매출
monthly: {
actual: 1350000000,
target: 1500000000,
achievement: 90.0,
receivable: 420000000,
collected: 930000000,
collectionRate: 68.9
},
// 연간 매출
yearly: {
actual: 8200000000,
target: 10000000000,
achievement: 82.0,
receivable: 2100000000,
collected: 6100000000,
collectionRate: 74.4
},
// 월별 추이 (최근 12개월)
monthlyTrend: [
{ month: "2023-11", sales: 1100, target: 1200, receivable: 350, achievement: 91.7 },
{ month: "2023-12", sales: 1250, target: 1300, receivable: 380, achievement: 96.2 },
{ month: "2024-01", sales: 950, target: 1200, receivable: 320, achievement: 79.2 },
{ month: "2024-02", sales: 1100, target: 1300, receivable: 340, achievement: 84.6 },
{ month: "2024-03", sales: 1250, target: 1400, receivable: 410, achievement: 89.3 },
{ month: "2024-04", sales: 1180, target: 1350, receivable: 390, achievement: 87.4 },
{ month: "2024-05", sales: 1320, target: 1450, receivable: 425, achievement: 91.0 },
{ month: "2024-06", sales: 1450, target: 1500, receivable: 460, achievement: 96.7 },
{ month: "2024-07", sales: 1380, target: 1500, receivable: 440, achievement: 92.0 },
{ month: "2024-08", sales: 1420, target: 1550, receivable: 450, achievement: 91.6 },
{ month: "2024-09", sales: 1350, target: 1500, receivable: 420, achievement: 90.0 },
{ month: "2024-10", sales: 1350, target: 1500, receivable: 420, achievement: 90.0 }
],
// 일별 추이 (최근 30일)
dailyTrend: [
{ day: 1, sales: 42, target: 50, receivable: 11 },
{ day: 2, sales: 38, target: 50, receivable: 10 },
{ day: 3, sales: 52, target: 50, receivable: 14 },
{ day: 4, sales: 45, target: 50, receivable: 12 },
{ day: 5, sales: 48, target: 50, receivable: 13 },
{ day: 6, sales: 41, target: 50, receivable: 11 },
{ day: 7, sales: 55, target: 50, receivable: 15 },
{ day: 8, sales: 46, target: 50, receivable: 12 },
{ day: 9, sales: 49, target: 50, receivable: 13 },
{ day: 10, sales: 43, target: 50, receivable: 11 },
{ day: 11, sales: 51, target: 50, receivable: 14 },
{ day: 12, sales: 47, target: 50, receivable: 13 },
{ day: 13, sales: 44, target: 50, receivable: 12 },
{ day: 14, sales: 50, target: 50, receivable: 14 }
]
},
// 당일 출하기준 매출액 및 증감률
dailySales: {
today: 45000000,
yesterday: 40000000,
lastMonth: 42000000,
yesterdayGrowth: 12.5,
monthlyGrowth: 7.1
},
// TOP 5 고객별 매출 현황
topCustomers: [
{ name: "삼성전자", amount: 12000000, growth: 15.2, rank: 1 },
{ name: "LG전자", amount: 8500000, growth: -3.1, rank: 2 },
{ name: "현대자동차", amount: 7200000, growth: 22.4, rank: 3 },
{ name: "SK하이닉스", amount: 6800000, growth: 8.7, rank: 4 },
{ name: "네이버", amount: 5900000, growth: 12.3, rank: 5 }
],
// 매출총이익률/영업이익률
profitability: {
grossMargin: 28.5,
operatingMargin: 18.3,
netMargin: 14.2
},
// 매출 트렌드 (월별/주별)
salesTrend: {
monthly: [
{ period: "1월", sales: 950, purchase: 650 },
{ period: "2월", sales: 1100, purchase: 720 },
{ period: "3월", sales: 1250, purchase: 850 },
{ period: "4월", sales: 1180, purchase: 780 },
{ period: "5월", sales: 1320, purchase: 890 },
{ period: "6월", sales: 1450, purchase: 920 }
],
weekly: [
{ period: "1주", sales: 280, purchase: 180 },
{ period: "2주", sales: 320, purchase: 210 },
{ period: "3주", sales: 350, purchase: 230 },
{ period: "4주", sales: 410, purchase: 270 }
]
},
// 월별 매입 현황 및 매출 대비 매입률
purchaseData: {
monthlyAmount: 920000000,
salesRatio: 63.4,
lastMonthRatio: 65.8
},
// 주요 거래처별 매입 현황
topSuppliers: [
{ name: "포스코", amount: 150000000, ratio: 16.3 },
{ name: "한화솔루션", amount: 120000000, ratio: 13.0 },
{ name: "LG화학", amount: 95000000, ratio: 10.3 },
{ name: "코오롱인더", amount: 85000000, ratio: 9.2 },
{ name: "효성첨단소재", amount: 72000000, ratio: 7.8 }
],
// 원가율 추이
costTrend: [
{ month: "1월", ratio: 67.2 },
{ month: "2월", ratio: 65.4 },
{ month: "3월", ratio: 68.1 },
{ month: "4월", ratio: 66.0 },
{ month: "5월", ratio: 63.8 },
{ month: "6월", ratio: 63.4 }
],
// 미수금 관련
receivables: {
total: 850000000,
overdue: 210000000,
overdueRatio: 24.7,
over30Days: 120000000,
collectionRate: 85.3
},
// 거래처별 미수금 TOP 5
topReceivables: [
{ name: "ABC전자", amount: 45000000, days: 45 },
{ name: "DEF산업", amount: 38000000, days: 32 },
{ name: "GHI테크", amount: 32000000, days: 28 },
{ name: "JKL코퍼", amount: 28000000, days: 52 },
{ name: "MNO글로벌", amount: 25000000, days: 38 }
],
// 일일 손익 현황
dailyPL: {
sales: 45000000,
purchase: 28000000,
expenses: 8500000,
netIncome: 8500000
},
// 현금 잔고 변동
cashFlow: {
opening: 320000000,
closing: 315000000,
change: -5000000,
inflow: 42000000,
outflow: 47000000
},
// 주요 수입/지출 내역
majorTransactions: [
{ type: "수입", description: "제품 출하대금", amount: 25000000, time: "14:30" },
{ type: "지출", description: "원자재 구매비", amount: -15000000, time: "11:20" },
{ type: "지출", description: "인건비 지급", amount: -12000000, time: "09:00" },
{ type: "수입", description: "수출 대금", amount: 18000000, time: "16:45" }
],
// 모든 프로세스 상태
allProcessStates: [
{
stage: "견적",
count: 45,
color: "#8B5CF6",
details: [
{ customer: "삼성전자", item: "제품 A", amount: 15000000, status: "검토중" },
{ customer: "LG전자", item: "제품 B", amount: 8500000, status: "승인대기" },
{ customer: "현대자동차", item: "제품 C", amount: 12000000, status: "수정중" }
]
},
{
stage: "수주",
count: 32,
color: "#3B82F6",
details: [
{ customer: "SK하이닉스", item: "제품 D", amount: 22000000, status: "확정" },
{ customer: "네이버", item: "제품 E", amount: 9500000, status: "생산준비" },
{ customer: "카카오", item: "제품 F", amount: 7200000, status: "자재대기" }
]
},
{
stage: "생산",
count: 28,
color: "#10B981",
details: [
{ customer: "포스코", item: "제품 G", progress: 75, status: "진행중" },
{ customer: "한화솔루션", item: "제품 H", progress: 45, status: "진행중" },
{ customer: "LG화학", item: "제품 I", progress: 90, status: "완료임박" }
]
},
{
stage: "검사",
count: 18,
color: "#F59E0B",
details: [
{ customer: "삼성전자", item: "제품 J", testResult: "합격", status: "검사완료" },
{ customer: "현대자동차", item: "제품 K", testResult: "대기", status: "검사중" },
{ customer: "SK하이닉스", item: "제품 L", testResult: "재검사", status: "재검중" }
]
},
{
stage: "출고예정",
count: 15,
color: "#F97316",
details: [
{ customer: "네이버", item: "제품 M", scheduleDate: "2024-10-15", status: "포장중" },
{ customer: "LG전자", item: "제품 N", scheduleDate: "2024-10-16", status: "준비완료" },
{ customer: "카카오", item: "제품 O", scheduleDate: "2024-10-14", status: "긴급" }
]
},
{
stage: "출고완료",
count: 67,
color: "#EF4444",
details: [
{ customer: "삼성전자", item: "제품 P", shipDate: "2024-10-13", status: "배송중" },
{ customer: "포스코", item: "제품 Q", shipDate: "2024-10-12", status: "배송완료" },
{ customer: "한화솔루션", item: "제품 R", shipDate: "2024-10-13", status: "인수확인" }
]
}
],
// 출고 관련 현황
shipping: {
unshippedOrders: 23,
delayedOrders: 8,
urgentRequests: 5,
delayedOrdersDetail: [
{ orderNo: "ORD-2024-0156", customer: "삼성전자", daysOverdue: 3, amount: 15000000 },
{ orderNo: "ORD-2024-0142", customer: "LG전자", daysOverdue: 5, amount: 8500000 },
{ orderNo: "ORD-2024-0148", customer: "현대자동차", daysOverdue: 2, amount: 12000000 }
],
urgentRequestsDetail: [
{ orderNo: "URG-2024-0023", customer: "SK하이닉스", requestTime: "2시간 전", priority: "최우선" },
{ orderNo: "URG-2024-0024", customer: "네이버", requestTime: "4시간 전", priority: "긴급" },
{ orderNo: "URG-2024-0025", customer: "카카오", requestTime: "6시간 전", priority: "긴급" }
]
},
// 재고 관련 현황
inventory: {
totalValue: 2800000000, // 재고 총액
turnoverRate: 8.5, // 회전율 (년)
shortageItems: 12, // 안전재고 이하 품목
longTermItems: 8, // 장기재고 품목
overStockItems: 5, // 과재고 품목
shortageDetail: [
{ item: "스테인리스 강판", currentStock: 50, safetyStock: 100, shortage: 50 },
{ item: "구리 파이프", currentStock: 25, safetyStock: 80, shortage: 55 },
{ item: "전자부품 A", currentStock: 200, safetyStock: 300, shortage: 100 }
],
longTermDetail: [
{ item: "알루미늄 봉", stockDays: 120, value: 15000000 },
{ item: "플라스틱 원료", stockDays: 95, value: 8500000 },
{ item: "특수강재", stockDays: 85, value: 12000000 }
]
},
// 주요 자재별 월간 사용량
materialUsage: [
{ material: "스테인리스 강판", thisMonth: 850, lastMonth: 780, unit: "kg" },
{ material: "구리 파이프", thisMonth: 320, lastMonth: 350, unit: "m" },
{ material: "전자부품 A", thisMonth: 1200, lastMonth: 1100, unit: "ea" },
{ material: "알루미늄 봉", thisMonth: 450, lastMonth: 420, unit: "kg" },
{ material: "플라스틱 원료", thisMonth: 280, lastMonth: 310, unit: "kg" }
],
// 자재 효율성 지표
materialEfficiency: {
productionOutput: 1320, // 생산량
materialConsumption: 2800, // 자재 소모량
efficiency: 94.2, // 효율성 %
wasteRate: 5.8 // 폐기율 %
},
// 차량별 가동률 및 유지비용
vehicles: [
{ id: "TR-001", type: "지게차", utilization: 85, maintenanceCost: 1200000, status: "정상" },
{ id: "TR-002", type: "크레인", utilization: 72, maintenanceCost: 2800000, status: "점검필요" },
{ id: "TR-003", type: "운반차", utilization: 91, maintenanceCost: 950000, status: "정상" },
{ id: "TR-004", type: "리프트", utilization: 68, maintenanceCost: 1500000, status: "수리중" }
],
// 인사 현황
hr: {
totalEmployees: 125,
attendanceRate: 96.8, // 출근율
absenteeism: 4, // 결근자 수
lateArrivals: 2, // 지각자 수
attendanceDetail: [
{ department: "생산부", present: 45, absent: 2, late: 1 },
{ department: "품질부", present: 18, absent: 1, late: 0 },
{ department: "관리부", present: 22, absent: 1, late: 1 }
]
},
// 품질검사 결과
quality: {
totalInspections: 850,
passRate: 97.2,
failRate: 2.8,
passed: 826,
failed: 24,
majorDefects: 8,
minorDefects: 16
},
// 승인 관리
approval: {
pendingApprovals: 18,
categories: [
{ type: "구매품의", count: 7, urgent: 2 },
{ type: "투자품의", count: 4, urgent: 1 },
{ type: "인사품의", count: 3, urgent: 0 },
{ type: "기타품의", count: 4, urgent: 1 }
]
},
// 휴가/출장 현황
vacationAndTrip: {
currentVacation: {
total: 32,
onLeave: 5,
scheduled: 12
},
businessTrips: {
total: 8,
ongoing: 3,
upcoming: 5
},
departments: [
{ name: "생산부", vacation: 3, trip: 1 },
{ name: "품질부", vacation: 1, trip: 2 },
{ name: "영업부", vacation: 1, trip: 0 },
{ name: "관리부", vacation: 0, trip: 0 }
],
recentActivity: [
{ employee: "김생산", type: "휴가", period: "12/15-12/17", status: "진행중" },
{ employee: "박품질", type: "출장", period: "12/16-12/18", location: "부산", status: "진행중" },
{ employee: "이영업", type: "휴가", period: "12/20-12/22", status: "예정" },
{ employee: "최관리", type: "출장", period: "12/23-12/25", location: "대구", status: "예정" }
]
},
// 달력 근태 및 작업 데이터
calendarData: {
attendance: [
{ date: "2024-06-10", type: "출근", employees: 128, status: "정상" },
{ date: "2024-06-11", type: "출근", employees: 126, status: "정상" },
{ date: "2024-06-12", type: "출근", employees: 124, status: "정상" },
{ date: "2024-06-13", type: "출근", employees: 127, status: "정상" },
{ date: "2024-06-14", type: "출근", employees: 129, status: "정상" },
{ date: "2024-06-15", type: "출근", employees: 125, status: "정상" },
{ date: "2024-06-16", type: "출근", employees: 123, status: "정상" },
{ date: "2024-06-17", type: "출근", employees: 120, status: "주의" },
{ date: "2024-06-18", type: "출근", employees: 125, status: "정상" },
{ date: "2024-06-19", type: "출근", employees: 122, status: "정상" },
{ date: "2024-06-20", type: "출근", employees: 127, status: "정상" },
{ date: "2024-06-21", type: "출근", employees: 130, status: "우수" },
{ date: "2024-06-22", type: "출근", employees: 128, status: "정상" },
{ date: "2024-06-24", type: "출근", employees: 126, status: "정상" },
{ date: "2024-06-25", type: "출근", employees: 129, status: "정상" }
],
incoming: [
{ date: "2024-06-10", items: ["고급 강재 800kg", "특수 볼트 5000ea"], value: 22000000 },
{ date: "2024-06-12", items: ["전기 케이블 300m", "센서 모듈 50ea"], value: 9500000 },
{ date: "2024-06-14", items: ["내열 합금 200kg", "정밀 베어링 100ea"], value: 18500000 },
{ date: "2024-06-15", items: ["스테인리스 강판 500kg", "구리 파이프 200m"], value: 15000000 },
{ date: "2024-06-17", items: ["전자부품 A 1000ea", "플라스틱 원료 300kg"], value: 8500000 },
{ date: "2024-06-19", items: ["알루미늄 봉 400kg"], value: 12000000 },
{ date: "2024-06-21", items: ["티타늄 합금 150kg", "고성능 모터 20ea"], value: 35000000 },
{ date: "2024-06-23", items: ["실리콘 웨이퍼 500ea", "광학 렌즈 200ea"], value: 28000000 },
{ date: "2024-06-25", items: ["희토류 자석 1000ea", "초전도 케이블 100m"], value: 42000000 }
],
outgoing: [
{ date: "2024-06-10", orders: ["ORD-2024-0150", "ORD-2024-0151"], value: 28000000, customer: "SK하이닉스" },
{ date: "2024-06-12", orders: ["ORD-2024-0152"], value: 15000000, customer: "TSMC" },
{ date: "2024-06-14", orders: ["ORD-2024-0156", "ORD-2024-0157"], value: 25000000, customer: "삼성전자" },
{ date: "2024-06-16", orders: ["ORD-2024-0158"], value: 18000000, customer: "LG전자" },
{ date: "2024-06-18", orders: ["ORD-2024-0159", "ORD-2024-0160"], value: 32000000, customer: "현대자동차" },
{ date: "2024-06-20", orders: ["ORD-2024-0161", "ORD-2024-0162", "ORD-2024-0163"], value: 48000000, customer: "포스코" },
{ date: "2024-06-22", orders: ["ORD-2024-0164"], value: 21000000, customer: "한화시스템" },
{ date: "2024-06-24", orders: ["ORD-2024-0165", "ORD-2024-0166"], value: 36000000, customer: "네이버" },
{ date: "2024-06-26", orders: ["ORD-2024-0167"], value: 19000000, customer: "카카오" }
],
materials: [
{ date: "2024-06-10", activity: "월초 재고 실사", items: 150, status: "완료" },
{ date: "2024-06-12", activity: "긴급 재고 보충", items: 25, status: "완료" },
{ date: "2024-06-14", activity: "재고 최적화 검토", items: 68, status: "완료" },
{ date: "2024-06-15", activity: "재고 조사", items: 85, status: "완료" },
{ date: "2024-06-17", activity: "안전재고 점검", items: 12, status: "진행중" },
{ date: "2024-06-19", activity: "장기재고 정리", items: 8, status: "예정" },
{ date: "2024-06-21", activity: "신규 자재 검수", items: 45, status: "예정" },
{ date: "2024-06-23", activity: "폐기 자재 처리", items: 15, status: "예정" },
{ date: "2024-06-25", activity: "월말 재고 마감", items: 200, status: "예정" }
],
// 일정 관리
schedule: [
{
date: "2024-06-10",
events: [
{ time: "09:00", title: "주간 경영 브리핑", location: "회의실 A", attendees: 10, priority: "high" },
{ time: "11:30", title: "신규 투자안 검토", location: "임원실", attendees: 6, priority: "high" },
{ time: "14:00", title: "품질관리 월례회의", location: "품질관리실", attendees: 12, priority: "medium" }
]
},
{
date: "2024-06-12",
events: [
{ time: "10:00", title: "해외 바이어 화상회의", location: "국제회의실", attendees: 8, priority: "high" },
{ time: "15:30", title: "R&D 진척도 보고", location: "연구소", attendees: 15, priority: "medium" }
]
},
{
date: "2024-06-14",
events: [
{ time: "09:30", title: "협력업체 간담회", location: "대회의실", attendees: 20, priority: "medium" },
{ time: "13:00", title: "ESG 경영 전략회의", location: "회의실 B", attendees: 8, priority: "high" },
{ time: "16:00", title: "IT 시스템 업그레이드 논의", location: "IT실", attendees: 6, priority: "low" }
]
},
{
date: "2024-06-15",
events: [
{ time: "09:00", title: "월례 경영진 회의", location: "회의실 A", attendees: 8, priority: "high" },
{ time: "14:00", title: "신제품 개발 검토", location: "연구소", attendees: 12, priority: "medium" },
{ time: "16:30", title: "고객사 미팅", location: "삼성전자", attendees: 4, priority: "high" }
]
},
{
date: "2024-06-16",
events: [
{ time: "10:00", title: "생산계획 수립회의", location: "생산부", attendees: 6, priority: "medium" },
{ time: "15:00", title: "품질개선 TF", location: "품질관리실", attendees: 8, priority: "medium" }
]
},
{
date: "2024-06-17",
events: [
{ time: "11:00", title: "투자검토 위원회", location: "임원실", attendees: 5, priority: "high" },
{ time: "14:30", title: "안전점검 회의", location: "공장", attendees: 10, priority: "low" }
]
},
{
date: "2024-06-19",
events: [
{ time: "09:00", title: "글로벌 마케팅 전략회의", location: "마케팅실", attendees: 12, priority: "medium" },
{ time: "13:30", title: "재무 실적 분석", location: "재무팀", attendees: 6, priority: "high" },
{ time: "15:00", title: "인사 정책 검토", location: "인사팀", attendees: 8, priority: "medium" }
]
},
{
date: "2024-06-21",
events: [
{ time: "10:30", title: "디지털 전환 추진회의", location: "DT실", attendees: 14, priority: "high" },
{ time: "14:00", title: "지속가능경영 위원회", location: "회의실 C", attendees: 10, priority: "medium" }
]
},
{
date: "2024-06-24",
events: [
{ time: "09:00", title: "월말 성과 점검", location: "회의실 A", attendees: 12, priority: "high" },
{ time: "11:00", title: "차기 분기 계획 수립", location: "기획실", attendees: 8, priority: "high" },
{ time: "15:30", title: "공급망 최적화 검토", location: "SCM실", attendees: 10, priority: "medium" }
]
},
// 오늘 일정 (금일)
{
date: getTodayString(),
events: [
{ time: "09:30", title: "일일 운영회의", location: "회의실 B", attendees: 6, priority: "high" },
{ time: "11:00", title: "고객 컴플레인 대응", location: "CS실", attendees: 4, priority: "high" },
{ time: "14:00", title: "생산성 향상 간담회", location: "생산부", attendees: 15, priority: "medium" },
{ time: "16:00", title: "월말 실적 검토", location: "경영지원팀", attendees: 8, priority: "medium" }
]
}
],
// 휴가 관리
vacation: [
{
date: "2024-06-11",
employees: [
{ name: "최수연", department: "인사부", type: "반차", reason: "육아" },
{ name: "강민호", department: "IT부", type: "연차", reason: "개인사정" }
]
},
{
date: "2024-06-13",
employees: [
{ name: "윤서영", department: "마케팅부", type: "연차", reason: "가족여행" }
]
},
{
date: "2024-06-14",
employees: [
{ name: "김민수", department: "생산부", type: "연차", reason: "개인사정" },
{ name: "이영희", department: "품질부", type: "반차", reason: "병원진료" }
]
},
{
date: "2024-06-17",
employees: [
{ name: "박철수", department: "관리부", type: "연차", reason: "가족행사" },
{ name: "정미진", department: "연구소", type: "특별휴가", reason: "결혼" }
]
},
{
date: "2024-06-18",
employees: [
{ name: "홍길동", department: "영업부", type: "연차", reason: "휴식" }
]
},
{
date: "2024-06-20",
employees: [
{ name: "조현우", department: "재무부", type: "연차", reason: "이사" },
{ name: "신혜원", department: "법무팀", type: "반차", reason: "건강검진" },
{ name: "문진석", department: "생산부", type: "연차", reason: "자녀입학식" }
]
},
{
date: "2024-06-22",
employees: [
{ name: "배소영", department: "구매부", type: "연차", reason: "개인사정" }
]
},
{
date: "2024-06-25",
employees: [
{ name: "유준혁", department: "영업부", type: "특별휴가", reason: "결혼" },
{ name: "안민정", department: "품질부", type: "반차", reason: "병원진료" }
]
}
],
// 출장 관리
business: [
{
date: "2024-06-11",
trips: [
{ name: "정수현", department: "해외영업", destination: "일본 도쿄", purpose: "신규 거래처 개척", duration: "2박3일" },
{ name: "김영철", department: "기술부", destination: "울산", purpose: "설비 점검", duration: "당일" }
]
},
{
date: "2024-06-13",
trips: [
{ name: "박명수", department: "영업부", destination: "창원", purpose: "고객 AS", duration: "당일" }
]
},
{
date: "2024-06-15",
trips: [
{ name: "장영수", department: "영업부", destination: "부산", purpose: "고객사 방문", duration: "당일" },
{ name: "김대리", department: "기술부", destination: "대구", purpose: "기술지원", duration: "1박2일" }
]
},
{
date: "2024-06-16",
trips: [
{ name: "이과장", department: "구매부", destination: "인천", purpose: "협력업체 방문", duration: "당일" }
]
},
{
date: "2024-06-18",
trips: [
{ name: "황민규", department: "품질부", destination: "천안", purpose: "품질 개선 컨설팅", duration: "1박2일" },
{ name: "서지현", department: "마케팅부", destination: "제주", purpose: "전시회 참가", duration: "2박3일" }
]
},
{
date: "2024-06-19",
trips: [
{ name: "최부장", department: "해외영업", destination: "중국 상<><EC8381>", purpose: "해외 바이어 미팅", duration: "3박4일" },
{ name: "신대리", department: "품질부", destination: "광주", purpose: "품질감사", duration: "당일" }
]
},
{
date: "2024-06-22",
trips: [
{ name: "오세훈", department: "해외영업", destination: "베트남 호치민", purpose: "공장 설립 협의", duration: "4박5일" },
{ name: "임지영", department: "구매부", destination: "대전", purpose: "원자재 공급업체 점검", duration: "당일" }
]
},
{
date: "2024-06-24",
trips: [
{ name: "조한솔", department: "R&D", destination: "미국 실리콘밸리", purpose: "기술 세미나 참석", duration: "5박6일" }
]
},
{
date: "2024-06-26",
trips: [
{ name: "노승환", department: "영업부", destination: "수원", purpose: "대기업 미팅", duration: "당일" },
{ name: "한미래", department: "품질부", destination: "포항", purpose: "협력업체 품질감사", duration: "1박2일" }
]
}
]
}
};
}, []);
return (
<div className="p-4 md:p-6 space-y-6 md:space-y-8">
{/* CEO 헤더 */}
<div className="bg-card border border-border/20 rounded-xl p-4 md:p-6 mb-8">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
<div className="flex-1 min-w-0">
<h1 className="text-2xl md:text-3xl font-bold text-foreground mb-1">CEO </h1>
<p className="text-sm text-muted-foreground truncate"> · {currentTime}</p>
</div>
<div className="flex flex-row gap-2 md:gap-3 shrink-0">
<Button variant="outline" className="border-border/50 whitespace-nowrap" size="sm">
<FileText className="h-4 w-4 mr-1 md:mr-2" />
<span className="hidden sm:inline"></span>
<span className="sm:hidden"></span>
</Button>
<Button className="bg-primary text-primary-foreground whitespace-nowrap" size="sm">
<BarChart3 className="h-4 w-4 mr-1 md:mr-2" />
<span className="hidden sm:inline"></span>
<span className="sm:hidden"></span>
</Button>
</div>
</div>
</div>
{/* 모든 프로세스 현황 */}
<Card className="border border-border/20 bg-card rounded-xl col-span-full">
<CardHeader className="pb-3 bg-gradient-to-r from-purple-50 via-blue-50 to-green-50 dark:from-purple-950/30 dark:via-blue-950/30 dark:to-green-950/30 border-b border-border/10">
<CardTitle className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-br from-purple-500 to-blue-600 rounded-xl flex items-center justify-center shadow-lg">
<Activity className="h-6 w-6 text-white" />
</div>
<div>
<span className="text-xl font-bold bg-gradient-to-r from-purple-600 to-blue-600 bg-clip-text text-transparent">
</span>
<p className="text-xs text-muted-foreground mt-0.5"> </p>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-4">
{/* 프로세스 단계별 카드 */}
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3 mb-6">
{ceoData.allProcessStates.map((process, index) => (
<div
key={index}
className="relative p-4 rounded-xl border-2 transition-all hover:shadow-lg hover:-translate-y-1 cursor-pointer"
style={{
borderColor: process.color + '40',
backgroundColor: process.color + '08'
}}
>
<div className="absolute top-2 right-2">
<div
className="w-8 h-8 rounded-full flex items-center justify-center text-white font-bold shadow-md"
style={{ backgroundColor: process.color }}
>
{process.count}
</div>
</div>
<div className="text-center mt-6">
<h3 className="font-bold text-lg mb-1" style={{ color: process.color }}>
{process.stage}
</h3>
<p className="text-xs text-muted-foreground"></p>
</div>
</div>
))}
</div>
{/* 프로세스별 상세 정보 */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{ceoData.allProcessStates.map((process, processIndex) => (
<Card key={processIndex} className="border border-border/20 bg-card/50">
<CardHeader className="pb-3" style={{
background: `linear-gradient(135deg, ${process.color}10 0%, transparent 100%)`
}}>
<CardTitle className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<div
className="w-8 h-8 rounded-lg flex items-center justify-center text-white font-bold"
style={{ backgroundColor: process.color }}
>
{process.count}
</div>
<span className="font-bold" style={{ color: process.color }}>
{process.stage}
</span>
</div>
<Badge variant="outline" style={{ borderColor: process.color, color: process.color }}>
{process.details.length}
</Badge>
</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
{process.details.map((detail, detailIndex) => (
<div
key={detailIndex}
className="p-3 bg-muted/30 dark:bg-muted/10 rounded-lg border border-border/50 hover:bg-muted/50 dark:hover:bg-muted/20 transition-colors"
>
<div className="flex justify-between items-start mb-2">
<div className="flex-1 min-w-0">
<p className="font-medium text-sm text-foreground truncate">{detail.customer}</p>
<p className="text-xs text-muted-foreground truncate">{detail.item}</p>
</div>
<Badge
className="ml-2 whitespace-nowrap text-xs"
style={{
backgroundColor: process.color + '20',
color: process.color,
border: `1px solid ${process.color}40`
}}
>
{detail.status}
</Badge>
</div>
{'amount' in detail && detail.amount && (
<p className="text-xs font-bold text-foreground">
{Math.round(detail.amount / 1000000)}M원
</p>
)}
{'progress' in detail && detail.progress !== undefined && (
<div className="mt-2">
<div className="flex justify-between text-xs mb-1">
<span className="text-muted-foreground"></span>
<span className="font-bold" style={{ color: process.color }}>{detail.progress}%</span>
</div>
<div className="w-full bg-muted/50 rounded-full h-1.5">
<div
className="h-1.5 rounded-full transition-all"
style={{
width: `${detail.progress}%`,
backgroundColor: process.color
}}
/>
</div>
</div>
)}
{'testResult' in detail && detail.testResult && (
<p className="text-xs mt-1">
<span className="text-muted-foreground">: </span>
<span className="font-medium" style={{ color: process.color }}>{detail.testResult}</span>
</p>
)}
{'scheduleDate' in detail && detail.scheduleDate && (
<p className="text-xs mt-1">
<span className="text-muted-foreground">: </span>
<span className="font-medium">{detail.scheduleDate}</span>
</p>
)}
{'shipDate' in detail && detail.shipDate && (
<p className="text-xs mt-1">
<span className="text-muted-foreground">: </span>
<span className="font-medium">{detail.shipDate}</span>
</p>
)}
</div>
))}
</CardContent>
</Card>
))}
</div>
</CardContent>
</Card>
{/* 스마트 워크플로우 캘린더 - 완전 반응형 재설계 */}
<Card className="border border-border/20 bg-card rounded-xl col-span-full overflow-hidden">
<CardHeader className="pb-3 bg-gradient-to-r from-primary/5 via-purple-500/5 to-primary/5 border-b border-border/10">
<div className="flex flex-col gap-4">
<CardTitle className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3">
<div className="flex items-center space-x-3">
<div className="w-12 h-12 bg-gradient-to-br from-primary to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
<CalendarIcon className="h-7 w-7 text-white" />
</div>
<div>
<span className="text-xl font-bold bg-gradient-to-r from-primary to-purple-600 bg-clip-text text-transparent">
</span>
<p className="text-xs text-muted-foreground mt-0.5"> </p>
</div>
</div>
{/* 보기 옵션 - 모바일 친화적 */}
<div className="flex items-center space-x-2">
<Select value={calendarView} onValueChange={setCalendarView}>
<SelectTrigger className="w-24 h-9 bg-card border-border">
<SelectValue placeholder="보기" />
</SelectTrigger>
<SelectContent>
<SelectItem value="day"></SelectItem>
<SelectItem value="week"></SelectItem>
<SelectItem value="month"></SelectItem>
</SelectContent>
</Select>
<Badge variant="outline" className="hidden sm:flex items-center space-x-1 px-2 py-1 h-9">
<Clock2 className="w-3 h-3" />
<span className="text-xs"></span>
</Badge>
</div>
</CardTitle>
{/* 필터 체크박스 - 완전 반응형 */}
<div className="bg-muted/30 dark:bg-muted/20 rounded-lg p-3 border border-border/30">
<div className="flex items-center space-x-2 mb-2">
<Filter className="w-3.5 h-3.5 text-muted-foreground" />
<span className="text-xs font-medium text-muted-foreground"> </span>
</div>
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-2">
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="incoming"
checked={calendarFilters.incoming}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, incoming: !!checked }))
}
/>
<label htmlFor="incoming" className="text-xs font-medium text-blue-600 dark:text-blue-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="outgoing"
checked={calendarFilters.outgoing}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, outgoing: !!checked }))
}
/>
<label htmlFor="outgoing" className="text-xs font-medium text-green-600 dark:text-green-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="materials"
checked={calendarFilters.materials}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, materials: !!checked }))
}
/>
<label htmlFor="materials" className="text-xs font-medium text-orange-600 dark:text-orange-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="schedule"
checked={calendarFilters.schedule}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, schedule: !!checked }))
}
/>
<label htmlFor="schedule" className="text-xs font-medium text-purple-600 dark:text-purple-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="vacation"
checked={calendarFilters.vacation}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, vacation: !!checked }))
}
/>
<label htmlFor="vacation" className="text-xs font-medium text-emerald-600 dark:text-emerald-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="business"
checked={calendarFilters.business}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, business: !!checked }))
}
/>
<label htmlFor="business" className="text-xs font-medium text-indigo-600 dark:text-indigo-400 cursor-pointer"></label>
</div>
</div>
</div>
</div>
</CardHeader>
<CardContent className="p-4">
<p className="text-sm text-muted-foreground text-center py-8">
📅 . .
</p>
</CardContent>
</Card>
{/* 당일 매출 및 핵심 지표 */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-3">
<CardTitle className="text-sm font-medium text-muted-foreground"> </CardTitle>
<div className="w-8 h-8 bg-green-100 rounded-lg flex items-center justify-center">
<DollarSign className="h-4 w-4 text-green-600" />
</div>
</CardHeader>
<CardContent className="space-y-3">
<div className="text-2xl font-bold text-foreground">
{formatNumber(ceoData.dailySales.today)}
</div>
<div className="space-y-1">
<div className="flex items-center space-x-2 text-sm">
<ArrowUpRight className="h-3 w-3 text-green-600" />
<span className="text-green-600"> +{ceoData.dailySales.yesterdayGrowth}%</span>
</div>
<div className="flex items-center space-x-2 text-sm">
<ArrowUpRight className="h-3 w-3 text-blue-600" />
<span className="text-blue-600"> +{ceoData.dailySales.monthlyGrowth}%</span>
</div>
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-3">
<CardTitle className="text-sm font-medium text-muted-foreground"></CardTitle>
<div className="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center">
<PieChart className="h-4 w-4 text-blue-600" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-foreground mb-2">
{ceoData.profitability.grossMargin}%
</div>
<div className="text-sm text-muted-foreground">
: {ceoData.profitability.operatingMargin}%
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-3">
<CardTitle className="text-sm font-medium text-muted-foreground"> </CardTitle>
<div className="w-8 h-8 bg-orange-100 dark:bg-orange-900/30 rounded-lg flex items-center justify-center">
<Clock className="h-4 w-4 text-orange-600 dark:text-orange-400" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-foreground mb-2">
{Math.round(ceoData.receivables.total / 100000000)}
</div>
<div className="text-sm text-red-600">
: {Math.round(ceoData.receivables.overdue / 100000000)} ({ceoData.receivables.overdueRatio}%)
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-3">
<CardTitle className="text-sm font-medium text-muted-foreground"> </CardTitle>
<div className="w-8 h-8 bg-purple-100 dark:bg-purple-900/30 rounded-lg flex items-center justify-center">
<Calculator className="h-4 w-4 text-purple-600 dark:text-purple-400" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-foreground mb-2">
{Math.round(ceoData.dailyPL.netIncome / 1000000)}M원
</div>
<div className="text-sm text-muted-foreground">
--: {Math.round((ceoData.dailyPL.sales - ceoData.dailyPL.purchase - ceoData.dailyPL.expenses) / 1000000)}M
</div>
</CardContent>
</Card>
</div>
{/* 매출 현황 및 목표 달성률 */}
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
{/* 일별 매출 현황 */}
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader className="pb-3">
<div className="flex items-center justify-between mb-2">
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-blue-100 dark:bg-blue-900/30 rounded-lg flex items-center justify-center">
<CalendarIcon className="h-4 w-4 text-blue-600 dark:text-blue-400" />
</div>
<CardTitle className="text-base"> </CardTitle>
</div>
<Badge className="bg-blue-500 text-white">{ceoData.salesTarget.daily.achievement}%</Badge>
</div>
</CardHeader>
<CardContent className="space-y-3">
<div className="grid grid-cols-2 gap-2">
<div className="p-2 bg-blue-50 dark:bg-blue-950/20 rounded-lg">
<p className="text-xs text-muted-foreground mb-0.5"></p>
<p className="font-bold">{(ceoData.salesTarget.daily.target / 1000000).toFixed(0)}M</p>
</div>
<div className="p-2 bg-green-50 dark:bg-green-950/20 rounded-lg">
<p className="text-xs text-muted-foreground mb-0.5"></p>
<p className="font-bold text-green-600">{(ceoData.salesTarget.daily.actual / 1000000).toFixed(0)}M</p>
</div>
</div>
<div className="space-y-1.5">
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="font-bold text-blue-600 text-sm">{ceoData.salesTarget.daily.achievement}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-blue-600 h-2 rounded-full transition-all"
style={{ width: `${Math.min(ceoData.salesTarget.daily.achievement, 100)}%` }}
/>
</div>
</div>
<div className="pt-2 border-t space-y-1.5">
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-medium">{(ceoData.salesTarget.daily.collected / 1000000).toFixed(0)}M</span>
</div>
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-medium text-orange-600">{(ceoData.salesTarget.daily.receivable / 1000000).toFixed(0)}M</span>
</div>
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-bold text-green-600">{ceoData.salesTarget.daily.collectionRate}%</span>
</div>
</div>
</CardContent>
</Card>
{/* 월별 매출 현황 */}
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader className="pb-3">
<div className="flex items-center justify-between mb-2">
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-green-100 dark:bg-green-900/30 rounded-lg flex items-center justify-center">
<BarChart3 className="h-4 w-4 text-green-600 dark:text-green-400" />
</div>
<CardTitle className="text-base"> </CardTitle>
</div>
<Badge className="bg-green-500 text-white">{ceoData.salesTarget.monthly.achievement}%</Badge>
</div>
</CardHeader>
<CardContent className="space-y-3">
<div className="grid grid-cols-2 gap-2">
<div className="p-2 bg-blue-50 dark:bg-blue-950/20 rounded-lg">
<p className="text-xs text-muted-foreground mb-0.5"></p>
<p className="font-bold">{(ceoData.salesTarget.monthly.target / 100000000).toFixed(1)}</p>
</div>
<div className="p-2 bg-green-50 dark:bg-green-950/20 rounded-lg">
<p className="text-xs text-muted-foreground mb-0.5"></p>
<p className="font-bold text-green-600">{(ceoData.salesTarget.monthly.actual / 100000000).toFixed(1)}</p>
</div>
</div>
<div className="space-y-1.5">
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="font-bold text-green-600 text-sm">{ceoData.salesTarget.monthly.achievement}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-green-600 h-2 rounded-full transition-all"
style={{ width: `${Math.min(ceoData.salesTarget.monthly.achievement, 100)}%` }}
/>
</div>
</div>
<div className="pt-2 border-t space-y-1.5">
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-medium">{(ceoData.salesTarget.monthly.collected / 100000000).toFixed(1)}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-medium text-orange-600">{(ceoData.salesTarget.monthly.receivable / 100000000).toFixed(1)}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-bold text-green-600">{ceoData.salesTarget.monthly.collectionRate}%</span>
</div>
</div>
</CardContent>
</Card>
{/* 연간 매출 현황 */}
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader className="pb-3">
<div className="flex items-center justify-between mb-2">
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-purple-100 dark:bg-purple-900/30 rounded-lg flex items-center justify-center">
<TrendingUp className="h-4 w-4 text-purple-600 dark:text-purple-400" />
</div>
<CardTitle className="text-base"> </CardTitle>
</div>
<Badge className="bg-purple-500 text-white">{ceoData.salesTarget.yearly.achievement}%</Badge>
</div>
</CardHeader>
<CardContent className="space-y-3">
<div className="grid grid-cols-2 gap-2">
<div className="p-2 bg-blue-50 dark:bg-blue-950/20 rounded-lg">
<p className="text-xs text-muted-foreground mb-0.5"></p>
<p className="font-bold">{(ceoData.salesTarget.yearly.target / 1000000000).toFixed(0)}0</p>
</div>
<div className="p-2 bg-green-50 dark:bg-green-950/20 rounded-lg">
<p className="text-xs text-muted-foreground mb-0.5"></p>
<p className="font-bold text-green-600">{(ceoData.salesTarget.yearly.actual / 1000000000).toFixed(0)}2</p>
</div>
</div>
<div className="space-y-1.5">
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="font-bold text-purple-600 text-sm">{ceoData.salesTarget.yearly.achievement}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-purple-600 h-2 rounded-full transition-all"
style={{ width: `${Math.min(ceoData.salesTarget.yearly.achievement, 100)}%` }}
/>
</div>
</div>
<div className="pt-2 border-t space-y-1.5">
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-medium">{(ceoData.salesTarget.yearly.collected / 1000000000).toFixed(0)}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-medium text-orange-600">{(ceoData.salesTarget.yearly.receivable / 1000000000).toFixed(0)}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground"></span>
<span className="text-sm font-bold text-green-600">{ceoData.salesTarget.yearly.collectionRate}%</span>
</div>
</div>
</CardContent>
</Card>
</div>
{/* 매출 목표 달성률 추이 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* 월별 매출 추이 및 목표 달성률 */}
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader>
<CardTitle className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="w-6 h-6 bg-blue-100 dark:bg-blue-900/30 rounded-lg flex items-center justify-center">
<BarChart3 className="h-4 w-4 text-blue-600 dark:text-blue-400" />
</div>
<span> ( 12)</span>
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div className="h-80">
<OptimizedChart data={ceoData.salesTarget.monthlyTrend} height={320}>
<ResponsiveContainer width="100%" height={320}>
<BarChart data={ceoData.salesTarget.monthlyTrend}>
<CartesianGrid strokeDasharray="3 3" stroke="#f1f5f9" />
<XAxis
dataKey="month"
stroke="#64748b"
tickFormatter={(value) => value.split('-')[1] + '월'}
tick={{ fontSize: 12 }}
interval={0}
angle={-45}
textAnchor="end"
height={60}
/>
<YAxis stroke="#64748b" tick={{ fontSize: 12 }} />
<Tooltip
contentStyle={{
backgroundColor: 'white',
border: '1px solid #e2e8f0',
borderRadius: '8px',
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)'
}}
formatter={((value: number | string) => [`${value}M원`, '']) as any}
labelFormatter={(label) => `${label.split('-')[1]}`}
/>
<Bar dataKey="target" fill="#94a3b8" name="목표" radius={[4, 4, 0, 0]} />
<Bar dataKey="sales" fill="#3b82f6" name="실적" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</OptimizedChart>
</div>
<div className="mt-4 grid grid-cols-3 gap-3">
<div className="text-center p-2 bg-muted/50 rounded-lg">
<p className="text-xs text-muted-foreground"> </p>
<p className="font-bold text-blue-600">
{(ceoData.salesTarget.monthlyTrend.reduce((sum, m) => sum + m.achievement, 0) / ceoData.salesTarget.monthlyTrend.length).toFixed(1)}%
</p>
</div>
<div className="text-center p-2 bg-muted/50 rounded-lg">
<p className="text-xs text-muted-foreground"> </p>
<p className="font-bold text-green-600">
{Math.max(...ceoData.salesTarget.monthlyTrend.map(m => m.achievement)).toFixed(1)}%
</p>
</div>
<div className="text-center p-2 bg-muted/50 rounded-lg">
<p className="text-xs text-muted-foreground"> </p>
<p className="font-bold text-orange-600">
{Math.min(...ceoData.salesTarget.monthlyTrend.map(m => m.achievement)).toFixed(1)}%
</p>
</div>
</div>
</CardContent>
</Card>
{/* 월별 미수금 추이 */}
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader>
<CardTitle className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="w-6 h-6 bg-orange-100 dark:bg-orange-900/30 rounded-lg flex items-center justify-center">
<Clock className="h-4 w-4 text-orange-600 dark:text-orange-400" />
</div>
<span> </span>
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div className="h-80">
<OptimizedChart data={ceoData.salesTarget.monthlyTrend} height={320}>
<ResponsiveContainer width="100%" height={320}>
<LineChart data={ceoData.salesTarget.monthlyTrend}>
<CartesianGrid strokeDasharray="3 3" stroke="#f1f5f9" />
<XAxis
dataKey="month"
stroke="#64748b"
tickFormatter={(value) => value.split('-')[1] + '월'}
tick={{ fontSize: 12 }}
interval={0}
angle={-45}
textAnchor="end"
height={60}
/>
<YAxis stroke="#64748b" tick={{ fontSize: 12 }} />
<Tooltip
contentStyle={{
backgroundColor: 'white',
border: '1px solid #e2e8f0',
borderRadius: '8px',
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)'
}}
formatter={((value: number | string) => [`${value}M원`, '']) as any}
labelFormatter={(label) => `${label.split('-')[1]}`}
/>
<Line
type="monotone"
dataKey="receivable"
stroke="#f97316"
strokeWidth={3}
name="미수금"
dot={{ fill: '#f97316', r: 4 }}
/>
</LineChart>
</ResponsiveContainer>
</OptimizedChart>
</div>
<div className="mt-4 grid grid-cols-3 gap-3">
<div className="text-center p-2 bg-orange-50 dark:bg-orange-950/20 rounded-lg">
<p className="text-xs text-muted-foreground"> </p>
<p className="font-bold text-orange-600">
{(ceoData.salesTarget.monthlyTrend.reduce((sum, m) => sum + m.receivable, 0) / ceoData.salesTarget.monthlyTrend.length).toFixed(0)}M원
</p>
</div>
<div className="text-center p-2 bg-red-50 dark:bg-red-950/20 rounded-lg">
<p className="text-xs text-muted-foreground"> </p>
<p className="font-bold text-red-600">
{Math.max(...ceoData.salesTarget.monthlyTrend.map(m => m.receivable))}M원
</p>
</div>
<div className="text-center p-2 bg-green-50 dark:bg-green-950/20 rounded-lg">
<p className="text-xs text-muted-foreground"> </p>
<p className="font-bold text-green-600">
{Math.min(...ceoData.salesTarget.monthlyTrend.map(m => m.receivable))}M원
</p>
</div>
</div>
</CardContent>
</Card>
</div>
{/* 매출 트렌드 및 매입 현황 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-green-100 rounded-lg flex items-center justify-center">
<TrendingUp className="h-4 w-4 text-green-600" />
</div>
<span> ()</span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="h-80">
<OptimizedChart data={ceoData.salesTrend.monthly} height={320}>
<ResponsiveContainer width="100%" height={320}>
<AreaChart data={ceoData.salesTrend.monthly}>
<CartesianGrid strokeDasharray="3 3" stroke="#f1f5f9" />
<XAxis dataKey="period" stroke="#64748b" tick={{ fontSize: 12 }} />
<YAxis stroke="#64748b" tick={{ fontSize: 12 }} />
<Tooltip
contentStyle={{
backgroundColor: 'white',
border: '1px solid #e2e8f0',
borderRadius: '8px',
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)'
}}
/>
<Area type="monotone" dataKey="sales" stackId="1" stroke="#10b981" fill="#10b981" fillOpacity={0.2} name="매출" />
<Area type="monotone" dataKey="purchase" stackId="2" stroke="#f59e0b" fill="#f59e0b" fillOpacity={0.2} name="매입" />
</AreaChart>
</ResponsiveContainer>
</OptimizedChart>
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-orange-100 dark:bg-orange-900/30 rounded-lg flex items-center justify-center">
<Package className="h-4 w-4 text-orange-600 dark:text-orange-400" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<p className="text-sm text-muted-foreground"> </p>
<p className="font-bold text-lg text-foreground">{Math.round(ceoData.purchaseData.monthlyAmount / 100000000)}</p>
</div>
<div className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<p className="text-sm text-muted-foreground"> </p>
<p className="font-bold text-lg text-primary dark:text-primary">{ceoData.purchaseData.salesRatio}%</p>
</div>
</div>
<div className="space-y-2">
{ceoData.topSuppliers.map((supplier, index) => (
<div key={index} className="flex justify-between items-center p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<span className="font-medium text-foreground">{supplier.name}</span>
<div className="text-right">
<p className="font-bold text-foreground">{Math.round(supplier.amount / 1000000)}M원</p>
<p className="text-sm text-muted-foreground">{supplier.ratio}%</p>
</div>
</div>
))}
</div>
</div>
</CardContent>
</Card>
</div>
{/* 미수금 관리 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="border border-border/20 bg-card rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-red-100 dark:bg-red-900/30 rounded-lg flex items-center justify-center">
<CreditCard className="h-4 w-4 text-red-600 dark:text-red-400" />
</div>
<span> TOP 5</span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{ceoData.topReceivables.map((receivable, index) => (
<div key={index} className="flex justify-between items-center p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div>
<p className="font-medium text-foreground">{receivable.name}</p>
<p className="text-sm text-muted-foreground">{receivable.days} </p>
</div>
<div className="text-right">
<p className="font-bold text-red-600 dark:text-red-400">{formatNumber(receivable.amount)}</p>
<Badge className={`${receivable.days > 30 ? 'bg-red-500' : 'bg-yellow-500'} text-white text-xs`}>
{receivable.days > 30 ? '위험' : '주의'}
</Badge>
</div>
</div>
))}
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-green-100 rounded-lg flex items-center justify-center">
<Banknote className="h-4 w-4 text-green-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="p-3 bg-green-50 rounded-lg">
<p className="text-sm text-muted-foreground"></p>
<p className="font-bold text-lg text-foreground">{Math.round(ceoData.cashFlow.opening / 100000000)}</p>
</div>
<div className="p-3 bg-blue-50 rounded-lg">
<p className="text-sm text-muted-foreground"></p>
<p className="font-bold text-lg text-foreground">{Math.round(ceoData.cashFlow.closing / 100000000)}</p>
</div>
</div>
<div className="space-y-2">
<h4 className="font-medium text-foreground"> / </h4>
{ceoData.majorTransactions.map((transaction, index) => (
<div key={index} className="flex justify-between items-center p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div>
<p className="font-medium text-foreground">{transaction.description}</p>
<p className="text-sm text-muted-foreground">{transaction.time}</p>
</div>
<div className={`font-bold ${transaction.amount > 0 ? 'text-green-600' : 'text-red-600'}`}>
{transaction.amount > 0 ? '+' : ''}{Math.round(transaction.amount / 1000000)}M원
</div>
</div>
))}
</div>
</div>
</CardContent>
</Card>
</div>
{/* 출고 관리 현황 */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-blue-100 rounded-lg flex items-center justify-center">
<ShoppingBag className="h-4 w-4 text-blue-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center mb-4">
<div className="text-3xl font-bold text-blue-600 mb-2">
{ceoData.shipping.unshippedOrders}
</div>
<p className="text-sm text-muted-foreground"> </p>
</div>
<div className="space-y-2">
<div className="flex justify-between items-center p-2 bg-blue-50 rounded-lg">
<span className="text-sm"> </span>
<span className="font-bold text-blue-600">8</span>
</div>
<div className="flex justify-between items-center p-2 bg-muted/50 dark:bg-muted/20 rounded-lg">
<span className="text-sm"> </span>
<span className="font-bold">15</span>
</div>
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-red-100 rounded-lg flex items-center justify-center">
<AlertCircle className="h-4 w-4 text-red-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center mb-4">
<div className="text-3xl font-bold text-red-600 mb-2">
{ceoData.shipping.delayedOrders}
</div>
<p className="text-sm text-muted-foreground"> </p>
</div>
<div className="space-y-2">
{ceoData.shipping.delayedOrdersDetail.slice(0, 2).map((order, index) => (
<div key={index} className="p-2 bg-red-50 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">{order.customer}</span>
<Badge className="bg-red-500 text-white text-xs">{order.daysOverdue} </Badge>
</div>
<p className="text-xs text-muted-foreground">{order.orderNo}</p>
</div>
))}
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-orange-100 rounded-lg flex items-center justify-center">
<Zap className="h-4 w-4 text-orange-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center mb-4">
<div className="text-3xl font-bold text-orange-600 mb-2">
{ceoData.shipping.urgentRequests}
</div>
<p className="text-sm text-muted-foreground"> </p>
</div>
<div className="space-y-2">
{ceoData.shipping.urgentRequestsDetail.slice(0, 2).map((request, index) => (
<div key={index} className="p-2 bg-orange-50 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">{request.customer}</span>
<Badge className={`text-white text-xs ${
request.priority === '최우선' ? 'bg-red-500' : 'bg-orange-500'
}`}>
{request.priority}
</Badge>
</div>
<p className="text-xs text-muted-foreground">{request.requestTime}</p>
</div>
))}
</div>
</CardContent>
</Card>
</div>
{/* 재고 관리 현황 */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-green-100 rounded-lg flex items-center justify-center">
<Warehouse className="h-4 w-4 text-green-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center mb-4">
<div className="text-3xl font-bold text-green-600 mb-2">
{Math.round(ceoData.inventory.totalValue / 100000000)}
</div>
<p className="text-sm text-muted-foreground"> </p>
</div>
<div className="space-y-2">
<div className="flex justify-between items-center p-2 bg-green-50 rounded-lg">
<span className="text-sm"> </span>
<span className="font-bold text-green-600">{ceoData.inventory.turnoverRate}/</span>
</div>
<div className="flex justify-between items-center p-2 bg-muted/50 dark:bg-muted/20 rounded-lg">
<span className="text-sm"> </span>
<span className="font-bold">{Math.round(365 / ceoData.inventory.turnoverRate)}</span>
</div>
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-red-100 rounded-lg flex items-center justify-center">
<AlertTriangle className="h-4 w-4 text-red-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center mb-4">
<div className="text-3xl font-bold text-red-600 mb-2">
{ceoData.inventory.shortageItems}
</div>
<p className="text-sm text-muted-foreground"> </p>
</div>
<div className="space-y-2">
{ceoData.inventory.shortageDetail.slice(0, 2).map((item, index) => (
<div key={index} className="p-2 bg-red-50 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">{item.item}</span>
<Badge className="bg-red-500 text-white text-xs"> {item.shortage}</Badge>
</div>
<p className="text-xs text-muted-foreground">: {item.currentStock} / : {item.safetyStock}</p>
</div>
))}
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-yellow-100 rounded-lg flex items-center justify-center">
<Layers className="h-4 w-4 text-yellow-600" />
</div>
<span>/ </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-3 mb-4">
<div className="text-center p-2 bg-yellow-50 rounded-lg">
<div className="text-xl font-bold text-yellow-600">{ceoData.inventory.longTermItems}</div>
<p className="text-xs text-muted-foreground"></p>
</div>
<div className="text-center p-2 bg-orange-50 rounded-lg">
<div className="text-xl font-bold text-orange-600">{ceoData.inventory.overStockItems}</div>
<p className="text-xs text-muted-foreground"></p>
</div>
</div>
<div className="space-y-2">
{ceoData.inventory.longTermDetail.slice(0, 2).map((item, index) => (
<div key={index} className="p-2 bg-yellow-50 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">{item.item}</span>
<Badge className="bg-yellow-500 text-white text-xs">{item.stockDays}</Badge>
</div>
<p className="text-xs text-muted-foreground">{Math.round(item.value / 1000000)}M원</p>
</div>
))}
</div>
</CardContent>
</Card>
</div>
{/* 자재 효율성 및 사용량 현황 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-purple-100 rounded-lg flex items-center justify-center">
<RotateCcw className="h-4 w-4 text-purple-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{ceoData.materialUsage.map((material, index) => (
<div key={index} className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex justify-between items-center mb-2">
<span className="font-medium text-foreground">{material.material}</span>
<span className="text-sm text-muted-foreground">{material.unit}</span>
</div>
<div className="flex justify-between items-center">
<div className="text-sm">
<span className="text-muted-foreground">: </span>
<span className="font-bold text-blue-600">{formatNumber(material.thisMonth)}</span>
</div>
<div className="text-sm">
<span className="text-muted-foreground">: </span>
<span className="font-bold">{formatNumber(material.lastMonth)}</span>
</div>
<div className={`text-sm font-bold ${
material.thisMonth > material.lastMonth ? 'text-red-600' : 'text-green-600'
}`}>
{material.thisMonth > material.lastMonth ? '+' : ''}{Math.round(((material.thisMonth - material.lastMonth) / material.lastMonth) * 100)}%
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-blue-100 rounded-lg flex items-center justify-center">
<Gauge className="h-4 w-4 text-blue-600" />
</div>
<span> <EFBFBD><EFBFBD> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="p-3 bg-blue-50 rounded-lg text-center">
<p className="text-sm text-muted-foreground"> </p>
<p className="font-bold text-2xl text-blue-600">{ceoData.materialEfficiency.efficiency}%</p>
</div>
<div className="p-3 bg-red-50 rounded-lg text-center">
<p className="text-sm text-muted-foreground"> </p>
<p className="font-bold text-2xl text-red-600">{ceoData.materialEfficiency.wasteRate}%</p>
</div>
</div>
<div className="space-y-3">
<div className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"> </span>
<span className="font-bold text-foreground">{formatNumber(ceoData.materialEfficiency.productionOutput)}ea</span>
</div>
</div>
<div className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"> </span>
<span className="font-bold text-foreground">{formatNumber(ceoData.materialEfficiency.materialConsumption)}kg</span>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
{/* 차량 가동률 및 인사 현황 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-orange-100 rounded-lg flex items-center justify-center">
<Truck className="h-4 w-4 text-orange-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{ceoData.vehicles.map((vehicle, index) => (
<div key={index} className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex justify-between items-center mb-2">
<div>
<span className="font-medium text-foreground">{vehicle.id}</span>
<span className="text-sm text-muted-foreground ml-2">({vehicle.type})</span>
</div>
<Badge className={`text-white text-xs ${
vehicle.status === '정상' ? 'bg-green-500' :
vehicle.status === '점검필요' ? 'bg-yellow-500' : 'bg-red-500'
}`}>
{vehicle.status}
</Badge>
</div>
<div className="flex justify-between items-center">
<div className="text-sm">
<span className="text-muted-foreground">: </span>
<span className="font-bold text-blue-600">{vehicle.utilization}%</span>
</div>
<div className="text-sm">
<span className="text-muted-foreground">: </span>
<span className="font-bold text-red-600">{Math.round(vehicle.maintenanceCost / 10000)}</span>
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-teal-100 rounded-lg flex items-center justify-center">
<UserCheck className="h-4 w-4 text-teal-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-3 gap-3 mb-4">
<div className="text-center p-3 bg-green-50 rounded-lg">
<div className="text-xl font-bold text-green-600">{ceoData.hr.attendanceRate}%</div>
<p className="text-xs text-muted-foreground"></p>
</div>
<div className="text-center p-3 bg-red-50 rounded-lg">
<div className="text-xl font-bold text-red-600">{ceoData.hr.absenteeism}</div>
<p className="text-xs text-muted-foreground"></p>
</div>
<div className="text-center p-3 bg-yellow-50 rounded-lg">
<div className="text-xl font-bold text-yellow-600">{ceoData.hr.lateArrivals}</div>
<p className="text-xs text-muted-foreground"></p>
</div>
</div>
<div className="space-y-2">
{ceoData.hr.attendanceDetail.map((dept, index) => (
<div key={index} className="p-2 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">{dept.department}</span>
<div className="text-xs space-x-2">
<span className="text-green-600"> {dept.present}</span>
<span className="text-red-600"> {dept.absent}</span>
<span className="text-yellow-600"> {dept.late}</span>
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
{/* 품질검사 및 승인 현황 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-emerald-100 rounded-lg flex items-center justify-center">
<TestTube className="h-4 w-4 text-emerald-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4 mb-4">
<div className="text-center p-3 bg-green-50 rounded-lg">
<div className="text-2xl font-bold text-green-600">{ceoData.quality.passRate}%</div>
<p className="text-sm text-muted-foreground"></p>
</div>
<div className="text-center p-3 bg-red-50 rounded-lg">
<div className="text-2xl font-bold text-red-600">{ceoData.quality.failRate}%</div>
<p className="text-sm text-muted-foreground"></p>
</div>
</div>
<div className="space-y-3">
<div className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"> </span>
<span className="font-bold text-foreground">{ceoData.quality.totalInspections}</span>
</div>
</div>
<div className="p-3 bg-green-50 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"></span>
<span className="font-bold text-green-600">{ceoData.quality.passed}</span>
</div>
</div>
<div className="p-3 bg-red-50 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"> (/)</span>
<span className="font-bold text-red-600">{ceoData.quality.failed} ({ceoData.quality.majorDefects}/{ceoData.quality.minorDefects})</span>
</div>
</div>
</div>
</CardContent>
</Card>
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-indigo-100 rounded-lg flex items-center justify-center">
<FileCheck className="h-4 w-4 text-indigo-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center mb-4">
<div className="text-3xl font-bold text-indigo-600 mb-2">
{ceoData.approval.pendingApprovals}
</div>
<p className="text-sm text-muted-foreground"> </p>
</div>
<div className="space-y-2">
{ceoData.approval.categories.map((category, index) => (
<div key={index} className="p-3 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">{category.type}</span>
<div className="flex items-center space-x-2">
<span className="font-bold text-foreground">{category.count}</span>
{category.urgent > 0 && (
<Badge className="bg-red-500 text-white text-xs"> {category.urgent}</Badge>
)}
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* 휴가/출장 현황 요약 - 완전히 재설계된 반응형 레이아웃 */}
<Card className="border border-border/20 bg-card rounded-xl overflow-hidden">
<CardHeader className="pb-2 bg-gradient-to-r from-blue-50/50 to-green-50/50 dark:from-blue-950/20 dark:to-green-950/20">
<CardTitle className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div className="flex items-center space-x-3">
<div className="w-12 h-12 bg-gradient-to-br from-blue-500 to-green-500 rounded-xl flex items-center justify-center shadow-lg">
<Plane className="w-6 h-6 text-white" />
</div>
<div>
<h3 className="text-xl font-bold text-foreground">/ </h3>
<p className="text-sm text-muted-foreground"> </p>
</div>
</div>
<div className="flex items-center space-x-2 bg-white/80 dark:bg-muted/50 px-3 py-2 rounded-lg border">
<Clock2 className="w-4 h-4 text-muted-foreground" />
<span className="text-sm font-medium text-muted-foreground"> </span>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-4 md:p-6 space-y-6">
{/* 메인 통계 - 모바일 친화적 그리드 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 md:gap-6">
{/* 휴가 현황 */}
<div className="relative p-4 md:p-6 bg-gradient-to-br from-blue-50 via-blue-50/50 to-indigo-50 dark:from-blue-950/30 dark:via-blue-950/20 dark:to-indigo-950/30 rounded-xl md:rounded-2xl border border-blue-200/60 dark:border-blue-800/30 overflow-hidden">
<div className="absolute top-0 right-0 w-16 h-16 md:w-20 md:h-20 bg-blue-400/10 rounded-full transform translate-x-6 -translate-y-6"></div>
<div className="relative z-10">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-4">
<div className="flex items-center space-x-3 min-w-0">
<div className="w-9 h-9 md:w-10 md:h-10 bg-blue-500 rounded-lg md:rounded-xl flex items-center justify-center shadow-md flex-shrink-0">
<Coffee className="w-4 h-4 md:w-5 md:h-5 text-white" />
</div>
<div className="min-w-0">
<h4 className="font-bold text-blue-800 dark:text-blue-200 truncate"> </h4>
<p className="text-xs text-blue-600 dark:text-blue-400 truncate">Vacation Status</p>
</div>
</div>
<Badge className="bg-blue-500 text-white px-3 py-1 shadow-sm whitespace-nowrap self-start sm:self-auto">
{ceoData.vacationAndTrip.currentVacation.total}
</Badge>
</div>
<div className="grid grid-cols-2 gap-3 md:gap-4">
<div className="p-3 md:p-4 bg-white/80 dark:bg-blue-900/30 rounded-lg md:rounded-xl border border-blue-200/50 dark:border-blue-700/50">
<div className="text-center">
<div className="text-2xl md:text-3xl font-bold text-blue-600 dark:text-blue-400 mb-1">
{ceoData.vacationAndTrip.currentVacation.onLeave}
</div>
<div className="text-xs md:text-sm font-medium text-blue-700 dark:text-blue-300"> </div>
<div className="text-xs text-muted-foreground mt-0.5 md:mt-1">On Leave</div>
</div>
</div>
<div className="p-3 md:p-4 bg-white/80 dark:bg-blue-900/30 rounded-lg md:rounded-xl border border-blue-200/50 dark:border-blue-700/50">
<div className="text-center">
<div className="text-2xl md:text-3xl font-bold text-blue-500 dark:text-blue-300 mb-1">
{ceoData.vacationAndTrip.currentVacation.scheduled}
</div>
<div className="text-xs md:text-sm font-medium text-blue-700 dark:text-blue-300"> </div>
<div className="text-xs text-muted-foreground mt-0.5 md:mt-1">Scheduled</div>
</div>
</div>
</div>
</div>
</div>
{/* 출장 현황 */}
<div className="relative p-4 md:p-6 bg-gradient-to-br from-green-50 via-green-50/50 to-emerald-50 dark:from-green-950/30 dark:via-green-950/20 dark:to-emerald-950/30 rounded-xl md:rounded-2xl border border-green-200/60 dark:border-green-800/30 overflow-hidden">
<div className="absolute top-0 right-0 w-16 h-16 md:w-20 md:h-20 bg-green-400/10 rounded-full transform translate-x-6 -translate-y-6"></div>
<div className="relative z-10">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-4">
<div className="flex items-center space-x-3 min-w-0">
<div className="w-9 h-9 md:w-10 md:h-10 bg-green-500 rounded-lg md:rounded-xl flex items-center justify-center shadow-md flex-shrink-0">
<Plane className="w-4 h-4 md:w-5 md:h-5 text-white" />
</div>
<div className="min-w-0">
<h4 className="font-bold text-green-800 dark:text-green-200 truncate"> </h4>
<p className="text-xs text-green-600 dark:text-green-400 truncate">Business Trip Status</p>
</div>
</div>
<Badge className="bg-green-500 text-white px-3 py-1 shadow-sm whitespace-nowrap self-start sm:self-auto">
{ceoData.vacationAndTrip.businessTrips.total}
</Badge>
</div>
<div className="grid grid-cols-2 gap-3 md:gap-4">
<div className="p-3 md:p-4 bg-white/80 dark:bg-green-900/30 rounded-lg md:rounded-xl border border-green-200/50 dark:border-green-700/50">
<div className="text-center">
<div className="text-2xl md:text-3xl font-bold text-green-600 dark:text-green-400 mb-1">
{ceoData.vacationAndTrip.businessTrips.ongoing}
</div>
<div className="text-xs md:text-sm font-medium text-green-700 dark:text-green-300"> </div>
<div className="text-xs text-muted-foreground mt-0.5 md:mt-1">On Trip</div>
</div>
</div>
<div className="p-3 md:p-4 bg-white/80 dark:bg-green-900/30 rounded-lg md:rounded-xl border border-green-200/50 dark:border-green-700/50">
<div className="text-center">
<div className="text-2xl md:text-3xl font-bold text-green-500 dark:text-green-300 mb-1">
{ceoData.vacationAndTrip.businessTrips.upcoming}
</div>
<div className="text-xs md:text-sm font-medium text-green-700 dark:text-green-300"> </div>
<div className="text-xs text-muted-foreground mt-0.5 md:mt-1">Scheduled</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* 상세 정보 - 완전 반응형 레이아웃 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 md:gap-6">
{/* 부서별 현황 */}
<div className="bg-gradient-to-br from-muted/40 to-muted/20 dark:from-muted/30 dark:to-muted/10 rounded-xl md:rounded-2xl p-4 md:p-5 border border-border/50">
<div className="flex items-center space-x-3 mb-4 md:mb-5">
<div className="w-7 h-7 md:w-8 md:h-8 bg-purple-500 rounded-lg flex items-center justify-center flex-shrink-0">
<Users2 className="w-3.5 h-3.5 md:w-4 md:h-4 text-white" />
</div>
<div className="min-w-0">
<h4 className="font-bold text-foreground truncate"> </h4>
<p className="text-xs text-muted-foreground truncate">Department Status</p>
</div>
</div>
<div className="space-y-2 md:space-y-3">
{ceoData.vacationAndTrip.departments.map((dept, index) => (
<div key={index} className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 md:gap-3 p-3 md:p-4 bg-card rounded-lg md:rounded-xl border border-border/30 shadow-sm">
<div className="font-medium text-foreground text-sm md:text-base">{dept.name}</div>
<div className="flex items-center justify-start sm:justify-end space-x-2 md:space-x-3">
<div className="flex items-center space-x-1.5 md:space-x-2 bg-blue-50 dark:bg-blue-950/40 px-2 md:px-3 py-1.5 md:py-2 rounded-md md:rounded-lg border border-blue-200/50 dark:border-blue-800/30">
<Coffee className="w-3 h-3 text-blue-600 dark:text-blue-400 flex-shrink-0" />
<span className="text-xs md:text-sm font-bold text-blue-600 dark:text-blue-400">{dept.vacation}</span>
</div>
<div className="flex items-center space-x-1.5 md:space-x-2 bg-green-50 dark:bg-green-950/40 px-2 md:px-3 py-1.5 md:py-2 rounded-md md:rounded-lg border border-green-200/50 dark:border-green-800/30">
<Plane className="w-3 h-3 text-green-600 dark:text-green-400 flex-shrink-0" />
<span className="text-xs md:text-sm font-bold text-green-600 dark:text-green-400">{dept.trip}</span>
</div>
</div>
</div>
))}
</div>
</div>
{/* 최근 활동 */}
<div className="bg-gradient-to-br from-muted/40 to-muted/20 dark:from-muted/30 dark:to-muted/10 rounded-xl md:rounded-2xl p-4 md:p-5 border border-border/50">
<div className="flex items-center space-x-3 mb-4 md:mb-5">
<div className="w-7 h-7 md:w-8 md:h-8 bg-orange-500 rounded-lg flex items-center justify-center flex-shrink-0">
<Clock2 className="w-3.5 h-3.5 md:w-4 md:h-4 text-white" />
</div>
<div className="min-w-0">
<h4 className="font-bold text-foreground truncate"> </h4>
<p className="text-xs text-muted-foreground truncate">Recent Activities</p>
</div>
</div>
<div className="space-y-2 md:space-y-3 max-h-64 md:max-h-72 overflow-y-auto custom-scrollbar">
{ceoData.vacationAndTrip.recentActivity.map((activity, index) => (
<div key={index} className="p-3 md:p-4 bg-card rounded-lg md:rounded-xl border border-border/30 shadow-sm">
<div className="flex flex-col gap-2 md:gap-3">
<div className="flex items-start space-x-2 md:space-x-3 flex-1 min-w-0">
<div className={`w-3 h-3 md:w-4 md:h-4 rounded-full mt-1 shadow-sm flex-shrink-0 ${
activity.type === '휴가' ? 'bg-blue-500' : 'bg-green-500'
}`}></div>
<div className="flex-1 min-w-0">
<div className="flex flex-wrap items-center gap-1.5 md:gap-2 mb-1.5 md:mb-2">
<span className="font-medium text-foreground text-sm md:text-base">{activity.employee}</span>
<Badge className={`text-xs whitespace-nowrap ${
activity.type === '휴가' ? 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300' :
'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
}`}>
{activity.type}
</Badge>
<Badge className={`text-xs whitespace-nowrap ${
activity.status === '진행중' ? 'bg-orange-500 text-white' : 'bg-muted text-muted-foreground'
}`}>
{activity.status}
</Badge>
</div>
<div className="text-xs md:text-sm text-muted-foreground">
<span className="block">{activity.period}</span>
{activity.location && (
<span className="block mt-0.5">📍 {activity.location}</span>
)}
</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</CardContent>
</Card>
</div>
{/* 원가율 추이 및 미수금 회수 */}
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-indigo-100 rounded-lg flex items-center justify-center">
<BarChart3 className="h-4 w-4 text-indigo-600" />
</div>
<span> </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="p-3 bg-yellow-50 rounded-lg">
<p className="text-sm text-muted-foreground">30 </p>
<p className="font-bold text-lg text-orange-600">{Math.round(ceoData.receivables.over30Days / 100000000)}</p>
</div>
<div className="p-3 bg-green-50 rounded-lg">
<p className="text-sm text-muted-foreground"> </p>
<p className="font-bold text-lg text-green-600">{ceoData.receivables.collectionRate}%</p>
</div>
</div>
</div>
<div className="h-40">
<OptimizedChart data={ceoData.costTrend} height={160}>
<ResponsiveContainer width="100%" height={320}>
<LineChart data={ceoData.costTrend}>
<CartesianGrid strokeDasharray="3 3" stroke="#f1f5f9" />
<XAxis dataKey="month" stroke="#64748b" />
<YAxis stroke="#64748b" />
<Tooltip
contentStyle={{
backgroundColor: 'white',
border: '1px solid #e2e8f0',
borderRadius: '8px'
}}
/>
<Line type="monotone" dataKey="ratio" stroke="#8b5cf6" strokeWidth={2} dot={{ fill: '#8b5cf6', r: 4 }} />
</LineChart>
</ResponsiveContainer>
</OptimizedChart>
</div>
</div>
</CardContent>
</Card>
{/* 스마트 워크플로우 캘린더 - 완전 반응형 재설계 */}
<Card className="border border-border/20 bg-card rounded-xl col-span-full overflow-hidden">
<CardHeader className="pb-3 bg-gradient-to-r from-primary/5 via-purple-500/5 to-primary/5 border-b border-border/10">
<div className="flex flex-col gap-4">
<CardTitle className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3">
<div className="flex items-center space-x-3">
<div className="w-12 h-12 bg-gradient-to-br from-primary to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
<CalendarIcon className="h-7 w-7 text-white" />
</div>
<div>
<span className="text-xl font-bold bg-gradient-to-r from-primary to-purple-600 bg-clip-text text-transparent">
</span>
<p className="text-xs text-muted-foreground mt-0.5"> </p>
</div>
</div>
{/* 보기 옵션 - 모바일 친화적 */}
<div className="flex items-center space-x-2">
<Select value={calendarView} onValueChange={setCalendarView}>
<SelectTrigger className="w-24 h-9 bg-card border-border">
<SelectValue placeholder="보기" />
</SelectTrigger>
<SelectContent>
<SelectItem value="day"></SelectItem>
<SelectItem value="week"></SelectItem>
<SelectItem value="month"></SelectItem>
</SelectContent>
</Select>
<Badge variant="outline" className="hidden sm:flex items-center space-x-1 px-2 py-1 h-9">
<Clock2 className="w-3 h-3" />
<span className="text-xs"></span>
</Badge>
</div>
</CardTitle>
{/* 필터 체크박스 - 완전 반응형 */}
<div className="bg-muted/30 dark:bg-muted/20 rounded-lg p-3 border border-border/30">
<div className="flex items-center space-x-2 mb-2">
<Filter className="w-3.5 h-3.5 text-muted-foreground" />
<span className="text-xs font-medium text-muted-foreground"> </span>
</div>
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-2">
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="incoming"
checked={calendarFilters.incoming}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, incoming: !!checked }))
}
/>
<label htmlFor="incoming" className="text-xs font-medium text-blue-600 dark:text-blue-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="outgoing"
checked={calendarFilters.outgoing}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, outgoing: !!checked }))
}
/>
<label htmlFor="outgoing" className="text-xs font-medium text-green-600 dark:text-green-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="materials"
checked={calendarFilters.materials}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, materials: !!checked }))
}
/>
<label htmlFor="materials" className="text-xs font-medium text-orange-600 dark:text-orange-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="schedule"
checked={calendarFilters.schedule}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, schedule: !!checked }))
}
/>
<label htmlFor="schedule" className="text-xs font-medium text-purple-600 dark:text-purple-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="vacation"
checked={calendarFilters.vacation}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, vacation: !!checked }))
}
/>
<label htmlFor="vacation" className="text-xs font-medium text-emerald-600 dark:text-emerald-400 cursor-pointer"></label>
</div>
<div className="flex items-center space-x-1.5 p-1.5 bg-card rounded-md border border-border/50">
<Checkbox
id="business"
checked={calendarFilters.business}
onCheckedChange={(checked) =>
setCalendarFilters(prev => ({ ...prev, business: !!checked }))
}
/>
<label htmlFor="business" className="text-xs font-medium text-indigo-600 dark:text-indigo-400 cursor-pointer"></label>
</div>
</div>
</div>
</div>
</CardHeader>
<CardContent className="p-0">
<div className="grid grid-cols-1 2xl:grid-cols-2 gap-0 2xl:h-[850px]">
{/* 달력 영역 - 최적화된 레이아웃 */}
<div className="p-3 md:p-4 pb-0 border-b 2xl:border-b-0 2xl:border-r border-border/20 flex flex-col">
<div className="bg-gradient-to-br from-primary/3 via-card to-purple-500/3 dark:from-primary/8 dark:via-card dark:to-purple-500/8 rounded-xl md:rounded-2xl p-3 md:p-4 pb-2 md:pb-3 border border-primary/20 dark:border-primary/30 shadow-sm flex-1 flex flex-col min-h-[600px]">
<div className="mb-2 md:mb-3 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 flex-shrink-0">
<h3 className="text-base md:text-lg font-bold text-foreground truncate">
{calendarDate ? calendarDate.toLocaleDateString('ko-KR', {
year: 'numeric',
month: 'long'
}) : new Date().toLocaleDateString('ko-KR', {
year: 'numeric',
month: 'long'
})}
</h3>
<div className="flex items-center space-x-2 text-xs text-muted-foreground bg-muted/50 px-2 py-1.5 rounded-lg border shrink-0">
<Activity className="w-3 h-3 md:w-3.5 md:h-3.5" />
<span className="whitespace-nowrap"> </span>
</div>
</div>
<div className="calendar-container flex-1 min-h-0">
<Calendar
mode="single"
selected={calendarDate}
onSelect={setCalendarDate}
className="w-full calendar-expanded"
/>
</div>
</div>
</div>
{/* 선택된 날짜 상세 정보 - 최적화된 사이드 패널 */}
<div className="bg-gradient-to-b from-card via-muted/10 to-accent/5 dark:from-card dark:via-muted/5 dark:to-accent/10 flex flex-col">
<div className="p-3 md:p-4 flex-1 flex flex-col overflow-y-auto">
<div className="border-l-4 border-primary dark:border-primary/80 pl-3 bg-gradient-to-r from-primary/5 to-transparent dark:from-primary/10 rounded-r-lg py-2 md:py-3 mb-3 md:mb-4 flex-shrink-0">
<h3 className="font-bold text-base md:text-lg text-foreground mb-1 md:mb-2">
{calendarDate ? calendarDate.toLocaleDateString('ko-KR', {
month: 'long',
day: 'numeric',
weekday: 'long'
}) : '날짜를 선택하세요'}
</h3>
<p className="text-xs md:text-sm text-muted-foreground">
{calendarDate ? '선택된 날짜의 상세 정보와 일정을 확인하세요' : '캘린더에서 날짜를 클릭하여 상세 정보를 확인하세요'}
</p>
</div>
{calendarDate && (() => {
const selectedDateStr = getLocalDateString(calendarDate);
const today = getTodayString();
const isToday = selectedDateStr === today;
const dayIncoming = ceoData.calendarData.incoming.find(item => item.date === selectedDateStr);
const dayOutgoing = ceoData.calendarData.outgoing.find(item => item.date === selectedDateStr);
const dayMaterials = ceoData.calendarData.materials.find(item => item.date === selectedDateStr);
const daySchedule = ceoData.calendarData.schedule.find(item => item.date === selectedDateStr);
const dayVacation = ceoData.calendarData.vacation.find(item => item.date === selectedDateStr);
const dayBusiness = ceoData.calendarData.business.find(item => item.date === selectedDateStr);
const dayAttendance = ceoData.calendarData.attendance.find(item => item.date === selectedDateStr);
const hasAnyEvent = dayIncoming || dayOutgoing || dayMaterials || daySchedule || dayVacation || dayBusiness || dayAttendance;
return (
<div className="space-y-3 md:space-y-4 max-h-[500px] 2xl:max-h-[550px] overflow-y-auto pr-2 custom-scrollbar">
{/* 오늘 표시 */}
{isToday && (
<div className="p-3 bg-gradient-to-r from-yellow-50 to-orange-50 border border-yellow-200 rounded-lg">
<div className="flex items-center space-x-2">
<Star className="w-4 h-4 text-yellow-500 fill-yellow-500" />
<span className="font-bold text-yellow-800"> </span>
</div>
</div>
)}
{/* 일정 현황 */}
{daySchedule && calendarFilters.schedule && (
<div className="p-2.5 md:p-3 bg-purple-50 dark:bg-purple-950/30 rounded-lg border border-purple-200/50 dark:border-purple-800/30">
<div className="flex justify-between items-center mb-2 md:mb-3">
<div className="flex items-center space-x-2">
<Clock2 className="w-3.5 h-3.5 md:w-4 md:h-4 text-purple-600 dark:text-purple-400" />
<span className="font-medium text-sm md:text-base text-purple-800 dark:text-purple-200"></span>
</div>
<Badge className="bg-purple-500 text-white text-xs">
{daySchedule.events.length}
</Badge>
</div>
<div className="space-y-1.5 md:space-y-2">
{daySchedule.events.map((event, index) => (
<div key={index} className="flex justify-between items-start p-2 bg-card dark:bg-card/80 rounded border-l-4 border-l-purple-400 dark:border-l-purple-500">
<div className="flex-1 min-w-0">
<div className="flex items-center space-x-2 mb-1">
<span className="text-xs font-mono bg-purple-100 dark:bg-purple-900/50 text-purple-700 dark:text-purple-300 px-2 py-0.5 rounded">
{event.time}
</span>
{event.priority === 'high' && <Star className="w-3 h-3 text-red-500 fill-red-500 flex-shrink-0" />}
</div>
<p className="font-medium text-xs md:text-sm text-foreground truncate">{event.title}</p>
<div className="flex items-center space-x-2 md:space-x-3 text-xs text-muted-foreground mt-1">
<div className="flex items-center space-x-1 min-w-0">
<MapPin className="w-3 h-3 flex-shrink-0" />
<span className="truncate">{event.location}</span>
</div>
<div className="flex items-center space-x-1 flex-shrink-0">
<Users2 className="w-3 h-3" />
<span>{event.attendees}</span>
</div>
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* 휴가 현황 */}
{dayVacation && calendarFilters.vacation && (
<div className="p-2.5 md:p-3 bg-emerald-50 dark:bg-emerald-950/30 rounded-lg border border-emerald-200/50 dark:border-emerald-800/30">
<div className="flex justify-between items-center mb-2 md:mb-3">
<div className="flex items-center space-x-2">
<Coffee className="w-3.5 h-3.5 md:w-4 md:h-4 text-emerald-600 dark:text-emerald-400" />
<span className="font-medium text-sm md:text-base text-emerald-800 dark:text-emerald-200"></span>
</div>
<Badge className="bg-emerald-500 text-white text-xs">
{dayVacation.employees.length}
</Badge>
</div>
<div className="space-y-1.5 md:space-y-2">
{dayVacation.employees.map((employee, index) => (
<div key={index} className="flex justify-between items-center gap-2 p-2 bg-card dark:bg-card/80 rounded">
<div className="min-w-0">
<p className="font-medium text-xs md:text-sm text-foreground truncate">{employee.name}</p>
<p className="text-xs text-muted-foreground truncate">{employee.department}</p>
</div>
<div className="text-right flex-shrink-0">
<Badge className={`text-xs ${
employee.type === '연차' ? 'bg-emerald-500' :
employee.type === '반차' ? 'bg-blue-500' : 'bg-purple-500'
} text-white`}>
{employee.type}
</Badge>
<p className="text-xs text-muted-foreground/80 mt-0.5 md:mt-1">{employee.reason}</p>
</div>
</div>
))}
</div>
</div>
)}
{/* 출장 현황 */}
{dayBusiness && calendarFilters.business && (
<div className="p-2.5 md:p-3 bg-indigo-50 dark:bg-indigo-950/30 rounded-lg border border-indigo-200/50 dark:border-indigo-800/30">
<div className="flex justify-between items-center mb-2 md:mb-3">
<div className="flex items-center space-x-2">
<Plane className="w-3.5 h-3.5 md:w-4 md:h-4 text-indigo-600 dark:text-indigo-400" />
<span className="font-medium text-sm md:text-base text-indigo-800 dark:text-indigo-200"></span>
</div>
<Badge className="bg-indigo-500 text-white text-xs">
{dayBusiness.trips.length}
</Badge>
</div>
<div className="space-y-1.5 md:space-y-2">
{dayBusiness.trips.map((trip, index) => (
<div key={index} className="flex justify-between items-start gap-2 p-2 bg-card dark:bg-card/80 rounded">
<div className="flex-1 min-w-0">
<p className="font-medium text-xs md:text-sm text-foreground truncate">{trip.name}</p>
<p className="text-xs text-muted-foreground truncate">{trip.department}</p>
<p className="text-xs text-indigo-600 dark:text-indigo-400 mt-0.5 md:mt-1 truncate">{trip.purpose}</p>
</div>
<div className="text-right flex-shrink-0">
<p className="font-medium text-xs md:text-sm text-indigo-700 dark:text-indigo-300">{trip.destination}</p>
<Badge className="bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 text-xs mt-0.5 md:mt-1">
{trip.duration}
</Badge>
</div>
</div>
))}
</div>
</div>
)}
{/* 근태 현황 */}
{dayAttendance && (
<div className="p-2.5 md:p-3 bg-teal-50 dark:bg-teal-950/30 rounded-lg border border-teal-200/50 dark:border-teal-800/30">
<div className="flex justify-between items-center mb-2">
<div className="flex items-center space-x-2">
<UserCheck className="w-3.5 h-3.5 md:w-4 md:h-4 text-teal-600 dark:text-teal-400" />
<span className="font-medium text-sm md:text-base text-teal-800 dark:text-teal-200"> </span>
</div>
<Badge className={`${
dayAttendance.status === '정상' ? 'bg-green-500' : 'bg-yellow-500'
} text-white text-xs`}>
{dayAttendance.status}
</Badge>
</div>
<p className="text-sm text-teal-600">: {dayAttendance.employees}</p>
<div className="flex space-x-2 mt-2">
<Button size="sm" variant="outline" className="text-xs">
<Plus className="h-3 w-3 mr-1" />
</Button>
<Button size="sm" variant="outline" className="text-xs">
<Minus className="h-3 w-3 mr-1" />
</Button>
</div>
</div>
)}
{/* 입고 현황 */}
{dayIncoming && calendarFilters.incoming && (
<div className="p-3 bg-blue-50 rounded-lg">
<div className="flex justify-between items-center mb-2">
<div className="flex items-center space-x-2">
<Package className="w-4 h-4 text-blue-600" />
<span className="font-medium text-blue-800"> </span>
</div>
<Badge className="bg-blue-500 text-white text-xs">
{Math.round(dayIncoming.value / 1000000)}M원
</Badge>
</div>
<div className="space-y-1">
{dayIncoming.items.map((item, index) => (
<div key={index} className="text-sm text-blue-600 p-1 bg-white rounded">
{item}
</div>
))}
</div>
</div>
)}
{/* 출고 현황 */}
{dayOutgoing && calendarFilters.outgoing && (
<div className="p-3 bg-green-50 rounded-lg">
<div className="flex justify-between items-center mb-2">
<div className="flex items-center space-x-2">
<Truck className="w-4 h-4 text-green-600" />
<span className="font-medium text-green-800"> </span>
</div>
<Badge className="bg-green-500 text-white text-xs">
{Math.round(dayOutgoing.value / 1000000)}M원
</Badge>
</div>
<p className="text-sm text-green-600 mb-2">: {dayOutgoing.customer}</p>
<div className="space-y-1">
{dayOutgoing.orders.map((order, index) => (
<div key={index} className="text-sm text-green-600 p-1 bg-white rounded">
{order}
</div>
))}
</div>
</div>
)}
{/* 자재관리 현황 */}
{dayMaterials && calendarFilters.materials && (
<div className="p-3 bg-orange-50 rounded-lg">
<div className="flex justify-between items-center mb-2">
<div className="flex items-center space-x-2">
<Package className="w-4 h-4 text-orange-600" />
<span className="font-medium text-orange-800"></span>
</div>
<Badge className={`text-xs ${
dayMaterials.status === '완료' ? 'bg-green-500' :
dayMaterials.status === '진행중' ? 'bg-blue-500' : 'bg-muted'
} ${dayMaterials.status === '완료' || dayMaterials.status === '진행중' ? 'text-white' : 'text-muted-foreground'}`}>
{dayMaterials.status}
</Badge>
</div>
<p className="text-sm text-orange-600 mb-1">: {dayMaterials.activity}</p>
<p className="text-sm text-orange-600">: {dayMaterials.items}</p>
</div>
)}
{/* 이벤트가 없는 경우 */}
{!hasAnyEvent && (
<div className="p-4 text-center text-muted-foreground">
<CalendarIcon className="h-8 w-8 mx-auto mb-2 opacity-50" />
<p className="text-sm"> .</p>
<Button size="sm" className="mt-3" variant="outline">
<Plus className="h-3 w-3 mr-1" />
</Button>
</div>
)}
</div>
);
})()}
</div>
</div>
</div>
{/* 범례 */}
<div className="mt-6 p-4 bg-muted/50 dark:bg-muted/20 rounded-xl border border-border/20 dark:border-border/30">
<h4 className="font-semibold text-foreground mb-4 flex items-center space-x-2">
<Filter className="w-4 h-4 text-muted-foreground" />
<span> </span>
</h4>
<div className="grid grid-cols-3 lg:grid-cols-7 gap-4 mb-4">
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-blue-500 rounded-full shadow-sm"></div>
<span className="text-sm font-medium text-muted-foreground"></span>
</div>
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-green-500 rounded-full shadow-sm"></div>
<span className="text-sm font-medium text-muted-foreground"></span>
</div>
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-orange-500 rounded-full shadow-sm"></div>
<span className="text-sm font-medium text-muted-foreground"></span>
</div>
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-purple-500 rounded-full shadow-sm"></div>
<span className="text-sm font-medium text-muted-foreground"></span>
</div>
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-emerald-500 rounded-full shadow-sm"></div>
<span className="text-sm font-medium text-muted-foreground"></span>
</div>
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-indigo-500 rounded-full shadow-sm"></div>
<span className="text-sm font-medium text-muted-foreground"></span>
</div>
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-teal-500 rounded-full text-white text-xs flex items-center justify-center shadow-sm"></div>
<span className="text-sm font-medium text-muted-foreground"></span>
</div>
</div>
<div className="pt-3 border-t border-border/30">
<div className="flex items-center justify-center space-x-6">
<div className="flex items-center space-x-2">
<Star className="w-4 h-4 text-yellow-500 fill-yellow-500" />
<span className="text-sm font-medium text-muted-foreground"> </span>
</div>
<div className="flex items-center space-x-2">
<div className="w-4 h-4 bg-primary/20 rounded border-2 border-primary"></div>
<span className="text-sm font-medium text-muted-foreground"> </span>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
{/* TOP 5 고객별 매출 현황 */}
<Card className="border border-border/20 bg-white rounded-xl">
<CardHeader>
<CardTitle className="flex items-center space-x-3">
<div className="w-6 h-6 bg-blue-100 rounded-lg flex items-center justify-center">
<Building2 className="h-4 w-4 text-blue-600" />
</div>
<span>TOP 5 </span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{ceoData.topCustomers.map((customer, index) => (
<div key={index} className="flex items-center justify-between p-4 bg-muted/50 dark:bg-muted/20 rounded-lg">
<div className="flex items-center space-x-4">
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center text-white text-sm font-bold">
{customer.rank}
</div>
<div>
<p className="font-medium text-foreground">{customer.name}</p>
<p className="text-sm text-muted-foreground">{formatNumber(customer.amount)}</p>
</div>
</div>
<div className="text-right">
<div className={`flex items-center space-x-1 text-sm font-medium ${
customer.growth > 0 ? 'text-green-600' : 'text-red-600'
}`}>
{customer.growth > 0 ? (
<ArrowUpRight className="h-3 w-3" />
) : (
<ArrowDownRight className="h-3 w-3" />
)}
<span>{Math.abs(customer.growth)}%</span>
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
);
}