summaryrefslogtreecommitdiff
path: root/lib/bidding/list/biddings-stats-cards.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/list/biddings-stats-cards.tsx')
-rw-r--r--lib/bidding/list/biddings-stats-cards.tsx122
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>
+ )
+}