summaryrefslogtreecommitdiff
path: root/lib/bidding/list/biddings-transmission-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/list/biddings-transmission-dialog.tsx')
-rw-r--r--lib/bidding/list/biddings-transmission-dialog.tsx144
1 files changed, 132 insertions, 12 deletions
diff --git a/lib/bidding/list/biddings-transmission-dialog.tsx b/lib/bidding/list/biddings-transmission-dialog.tsx
index 035ab583..61207327 100644
--- a/lib/bidding/list/biddings-transmission-dialog.tsx
+++ b/lib/bidding/list/biddings-transmission-dialog.tsx
@@ -2,7 +2,7 @@
import * as React from "react"
import {
- Send, CheckCircle, FileText, Truck
+ Send, CheckCircle, FileText, Truck, Calculator, Package
} from "lucide-react"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
@@ -16,8 +16,10 @@ import {
} from "@/components/ui/dialog"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Label } from "@/components/ui/label"
+import { Badge } from "@/components/ui/badge"
+import { Separator } from "@/components/ui/separator"
import { BiddingListItem } from "@/db/schema"
-import { transmitToContract, transmitToPO } from "@/lib/bidding/actions"
+import { transmitToContract, transmitToPO, getWinnerDetails } from "@/lib/bidding/actions"
interface TransmissionDialogProps {
open: boolean
@@ -26,8 +28,60 @@ interface TransmissionDialogProps {
userId: number
}
+interface WinnerDetail {
+ id: number
+ companyId: number
+ vendorName: string | null
+ vendorCode: string | null
+ awardRatio: number
+ totalFinalAmount: number
+ items: Array<{
+ itemNumber: string | null
+ itemInfo: string | null
+ materialDescription: string | null
+ quantity: string | null
+ quantityUnit: string | null
+ totalWeight: string | null
+ weightUnit: string | null
+ bidUnitPrice: string | null
+ currency: string | null
+ finalQuantity: number
+ finalWeight: number
+ finalAmount: number
+ awardRatio: number
+ }>
+}
+
export function TransmissionDialog({ open, onOpenChange, bidding, userId }: TransmissionDialogProps) {
const [isLoading, setIsLoading] = React.useState(false)
+ const [winnerDetails, setWinnerDetails] = React.useState<WinnerDetail[]>([])
+ const [isLoadingDetails, setIsLoadingDetails] = React.useState(false)
+
+ // 낙찰 업체 상세 정보 로드
+ const loadWinnerDetails = React.useCallback(async () => {
+ if (!bidding) return
+
+ try {
+ setIsLoadingDetails(true)
+ const result = await getWinnerDetails(bidding.id)
+ if (result.success) {
+ setWinnerDetails(result.data || [])
+ } else {
+ toast.error(result.error || '낙찰 업체 정보를 불러오는데 실패했습니다.')
+ }
+ } catch (error) {
+ console.error('Failed to load winner details:', error)
+ toast.error('낙찰 업체 정보를 불러오는데 실패했습니다.')
+ } finally {
+ setIsLoadingDetails(false)
+ }
+ }, [bidding])
+
+ React.useEffect(() => {
+ if (open && bidding) {
+ loadWinnerDetails()
+ }
+ }, [open, bidding, loadWinnerDetails])
if (!bidding) return null
@@ -102,19 +156,85 @@ export function TransmissionDialog({ open, onOpenChange, bidding, userId }: Tran
</CardContent>
</Card>
- {/* 선정된 업체 정보 (임시로 표시) */}
+ {/* 선정된 업체 상세 정보 */}
<Card>
<CardHeader className="pb-3">
- <CardTitle className="text-base">선정된 업체</CardTitle>
- </CardHeader>
- <CardContent>
- <div className="flex items-center gap-2">
+ <CardTitle className="text-base flex items-center gap-2">
<CheckCircle className="w-4 h-4 text-green-600" />
- <span className="text-sm">업체 선정이 완료되었습니다.</span>
- </div>
- <p className="text-xs text-muted-foreground mt-2">
- 자세한 업체 정보는 전송 후 확인할 수 있습니다.
- </p>
+ 선정된 업체 ({winnerDetails.length}개)
+ </CardTitle>
+ </CardHeader>
+ <CardContent className="space-y-4">
+ {isLoadingDetails ? (
+ <div className="text-center py-4">
+ <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary mx-auto"></div>
+ <p className="text-sm text-muted-foreground mt-2">업체 정보를 불러오는 중...</p>
+ </div>
+ ) : winnerDetails.length === 0 ? (
+ <p className="text-sm text-muted-foreground">선정된 업체가 없습니다.</p>
+ ) : (
+ winnerDetails.map((winner) => (
+ <div key={winner.id} className="border rounded-lg p-4 space-y-3">
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-2">
+ <Package className="w-4 h-4 text-primary" />
+ <span className="font-medium">{winner.vendorName || `업체 ${winner.companyId}`}</span>
+ <Badge variant="outline">{winner.vendorCode}</Badge>
+ </div>
+ <div className="text-right">
+ <div className="text-sm font-medium">
+ 발주비율: {winner.awardRatio.toFixed(1)}%
+ </div>
+ <div className="text-sm text-muted-foreground">
+ 최종 견적가: {winner.totalFinalAmount.toLocaleString()} {winner.items[0]?.currency || 'KRW'}
+ </div>
+ </div>
+ </div>
+
+ <Separator />
+
+ <div className="space-y-2">
+ <div className="text-sm font-medium flex items-center gap-2">
+ <Calculator className="w-4 h-4" />
+ 품목별 상세 ({winner.items.length}개 품목)
+ </div>
+
+ <div className="space-y-2 max-h-40 overflow-y-auto">
+ {winner.items.map((item, itemIndex) => (
+ <div key={itemIndex} className="bg-muted/50 rounded p-2 text-xs">
+ <div className="grid grid-cols-2 gap-2">
+ <div>
+ <span className="font-medium">품목:</span> {item.itemInfo || item.itemNumber}
+ </div>
+ <div>
+ <span className="font-medium">규격:</span> {item.materialDescription}
+ </div>
+ <div>
+ <span className="font-medium">원래 수량:</span> {Number(item.quantity).toLocaleString()} {item.quantityUnit}
+ </div>
+ <div>
+ <span className="font-medium">발주 수량:</span> {item.finalQuantity.toLocaleString()} {item.quantityUnit}
+ </div>
+ <div>
+ <span className="font-medium">원래 중량:</span> {Number(item.totalWeight).toLocaleString()} {item.weightUnit}
+ </div>
+ <div>
+ <span className="font-medium">발주 중량:</span> {item.finalWeight.toLocaleString()} {item.weightUnit}
+ </div>
+ <div>
+ <span className="font-medium">단가:</span> {Number(item.bidUnitPrice).toLocaleString()} {item.currency}
+ </div>
+ <div>
+ <span className="font-medium">최종 금액:</span> {item.finalAmount.toLocaleString()} {item.currency}
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+ </div>
+ ))
+ )}
</CardContent>
</Card>
</div>