diff options
Diffstat (limited to 'lib/bidding/list/biddings-stats-cards.tsx')
| -rw-r--r-- | lib/bidding/list/biddings-stats-cards.tsx | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/lib/bidding/list/biddings-stats-cards.tsx b/lib/bidding/list/biddings-stats-cards.tsx new file mode 100644 index 00000000..2926adac --- /dev/null +++ b/lib/bidding/list/biddings-stats-cards.tsx @@ -0,0 +1,122 @@ +"use client" + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { + FileText, + Clock, + CheckCircle, + TrendingUp, + Users, + DollarSign, + Calendar, + BarChart3 +} from "lucide-react" +import { biddingStatusLabels, biddingTypeLabels } from "@/db/schema" + +interface BiddingsStatsCardsProps { + total: number + statusCounts: Record<string, number> + typeCounts: Record<string, number> + managerCounts: Record<string, number> + monthlyStats: Array<{ month: number; count: number }> +} + +export function BiddingsStatsCards({ + total, + statusCounts, + typeCounts, + managerCounts, + monthlyStats +}: BiddingsStatsCardsProps) { + // 이번 달 생성 건수 + const currentMonth = new Date().getMonth() + 1 + const thisMonthCount = monthlyStats.find(stat => stat.month === currentMonth)?.count || 0 + + // 지난 달 대비 증감 + const lastMonthCount = monthlyStats.find(stat => stat.month === currentMonth - 1)?.count || 0 + const monthlyGrowth = lastMonthCount > 0 ? ((thisMonthCount - lastMonthCount) / lastMonthCount * 100).toFixed(1) : '0' + + // 진행중인 입찰 수 (active 상태들) + const activeStatuses = ['bidding_opened', 'bidding_closed', 'evaluation_of_bidding'] + const activeBiddingsCount = activeStatuses.reduce((sum, status) => sum + (statusCounts[status] || 0), 0) + + // 완료된 입찰 수 + const completedCount = statusCounts['vendor_selected'] || 0 + + // 가장 많은 담당자 + const topManager = Object.entries(managerCounts).sort(([,a], [,b]) => b - a)[0] + + // 가장 많은 입찰 유형 + const topBiddingType = Object.entries(typeCounts).sort(([,a], [,b]) => b - a)[0] + + return ( + <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4"> + {/* 전체 입찰 수 */} + <Card> + <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> + <CardTitle className="text-sm font-medium">전체 입찰</CardTitle> + <FileText className="h-4 w-4 text-muted-foreground" /> + </CardHeader> + <CardContent> + <div className="text-2xl font-bold">{total.toLocaleString()}</div> + <p className="text-xs text-muted-foreground"> + 이번 달 <span className="font-medium text-green-600">+{thisMonthCount}</span>건 + </p> + </CardContent> + </Card> + + {/* 진행중인 입찰 */} + <Card> + <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> + <CardTitle className="text-sm font-medium">진행중</CardTitle> + <Clock className="h-4 w-4 text-muted-foreground" /> + </CardHeader> + <CardContent> + <div className="text-2xl font-bold text-orange-600">{activeBiddingsCount}</div> + <div className="flex gap-1 mt-1"> + {activeStatuses.map(status => ( + statusCounts[status] > 0 && ( + <Badge key={status} variant="outline" className="text-xs"> + {biddingStatusLabels[status]}: {statusCounts[status]} + </Badge> + ) + ))} + </div> + </CardContent> + </Card> + + {/* 완료된 입찰 */} + <Card> + <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> + <CardTitle className="text-sm font-medium">완료</CardTitle> + <CheckCircle className="h-4 w-4 text-muted-foreground" /> + </CardHeader> + <CardContent> + <div className="text-2xl font-bold text-green-600">{completedCount}</div> + <p className="text-xs text-muted-foreground"> + 완료율 {total > 0 ? ((completedCount / total) * 100).toFixed(1) : 0}% + </p> + </CardContent> + </Card> + + {/* 월별 증감 */} + <Card> + <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> + <CardTitle className="text-sm font-medium">월별 증감</CardTitle> + <TrendingUp className="h-4 w-4 text-muted-foreground" /> + </CardHeader> + <CardContent> + <div className="text-2xl font-bold"> + <span className={Number(monthlyGrowth) >= 0 ? 'text-green-600' : 'text-red-600'}> + {Number(monthlyGrowth) >= 0 ? '+' : ''}{monthlyGrowth}% + </span> + </div> + <p className="text-xs text-muted-foreground"> + 지난 달 대비 + </p> + </CardContent> + </Card> + </div> + ) +} |
