From c72d0897f7b37843109c86f61d97eba05ba3ca0d Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 13 Jun 2025 07:08:01 +0000
Subject: (대표님) 20250613 16시 08분 b-rfq, document 등
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/b-rfq/attachment/vendor-responses-panel.tsx | 205 ++++++++++++++++++++++++
 1 file changed, 205 insertions(+)
 create mode 100644 lib/b-rfq/attachment/vendor-responses-panel.tsx

(limited to 'lib/b-rfq/attachment/vendor-responses-panel.tsx')

diff --git a/lib/b-rfq/attachment/vendor-responses-panel.tsx b/lib/b-rfq/attachment/vendor-responses-panel.tsx
new file mode 100644
index 00000000..901af3bf
--- /dev/null
+++ b/lib/b-rfq/attachment/vendor-responses-panel.tsx
@@ -0,0 +1,205 @@
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Skeleton } from "@/components/ui/skeleton"
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
+import { RefreshCw, Download, MessageSquare, Clock, CheckCircle2, XCircle, AlertCircle } from "lucide-react"
+import { formatDate } from "@/lib/utils"
+
+interface VendorResponsesPanelProps {
+  attachment: any
+  responses: any[]
+  isLoading: boolean
+  onRefresh: () => void
+}
+
+export function VendorResponsesPanel({
+  attachment,
+  responses,
+  isLoading,
+  onRefresh
+}: VendorResponsesPanelProps) {
+  
+  const getStatusIcon = (status: string) => {
+    switch (status) {
+      case 'RESPONDED':
+        return <CheckCircle2 className="h-4 w-4 text-green-600" />
+      case 'NOT_RESPONDED':
+        return <Clock className="h-4 w-4 text-orange-600" />
+      case 'WAIVED':
+        return <XCircle className="h-4 w-4 text-gray-500" />
+      case 'REVISION_REQUESTED':
+        return <AlertCircle className="h-4 w-4 text-yellow-600" />
+      default:
+        return <Clock className="h-4 w-4 text-gray-400" />
+    }
+  }
+
+  const getStatusBadgeVariant = (status: string) => {
+    switch (status) {
+      case 'RESPONDED':
+        return 'default'
+      case 'NOT_RESPONDED':
+        return 'secondary'
+      case 'WAIVED':
+        return 'outline'
+      case 'REVISION_REQUESTED':
+        return 'destructive'
+      default:
+        return 'secondary'
+    }
+  }
+
+  if (isLoading) {
+    return (
+      <div className="space-y-4">
+        <div className="flex items-center justify-between">
+          <Skeleton className="h-6 w-48" />
+          <Skeleton className="h-9 w-24" />
+        </div>
+        <div className="space-y-3">
+          {Array.from({ length: 3 }).map((_, i) => (
+            <Skeleton key={i} className="h-12 w-full" />
+          ))}
+        </div>
+      </div>
+    )
+  }
+
+  return (
+    <div className="space-y-4">
+      {/* 헤더 */}
+      <div className="flex items-center justify-between">
+        <div className="space-y-1">
+          <h3 className="text-lg font-medium flex items-center gap-2">
+            <MessageSquare className="h-5 w-5" />
+            벤더 응답 현황: {attachment.originalFileName}
+          </h3>
+          <div className="flex flex-wrap gap-2 text-sm text-muted-foreground">
+            <Badge variant="outline">
+              {attachment.attachmentType}
+            </Badge>
+            <span>시리얼: {attachment.serialNo}</span>
+            <span>등록: {formatDate(attachment.createdAt)}</span>
+            {attachment.responseStats && (
+              <Badge variant="secondary">
+                응답률: {attachment.responseStats.responseRate}%
+              </Badge>
+            )}
+          </div>
+        </div>
+        <Button
+          variant="outline"
+          size="sm"
+          onClick={onRefresh}
+          className="flex items-center gap-2"
+        >
+          <RefreshCw className="h-4 w-4" />
+          새로고침
+        </Button>
+      </div>
+      
+      {/* 테이블 */}
+      {responses.length === 0 ? (
+        <div className="text-center py-8 text-muted-foreground border rounded-lg">
+          이 문서에 대한 벤더 응답 정보가 없습니다.
+        </div>
+      ) : (
+        <div className="border rounded-lg">
+          <Table>
+            <TableHeader>
+              <TableRow>
+                <TableHead>벤더</TableHead>
+                <TableHead>국가</TableHead>
+                <TableHead>응답 상태</TableHead>
+                <TableHead>리비전</TableHead>
+                <TableHead>요청일</TableHead>
+                <TableHead>응답일</TableHead>
+                <TableHead>벤더 코멘트</TableHead>
+                <TableHead className="w-[100px]">액션</TableHead>
+              </TableRow>
+            </TableHeader>
+            <TableBody>
+              {responses.map((response) => (
+                <TableRow key={response.id}>
+                  <TableCell className="font-medium">
+                    <div>
+                      <div>{response.vendorName}</div>
+                      <div className="text-xs text-muted-foreground">
+                        {response.vendorCode}
+                      </div>
+                    </div>
+                  </TableCell>
+                  
+                  <TableCell>
+                    {response.vendorCountry}
+                  </TableCell>
+                  
+                  <TableCell>
+                    <div className="flex items-center gap-2">
+                      {getStatusIcon(response.responseStatus)}
+                      <Badge variant={getStatusBadgeVariant(response.responseStatus)}>
+                        {response.responseStatus}
+                      </Badge>
+                    </div>
+                  </TableCell>
+                  
+                  <TableCell>
+                    <div className="text-sm">
+                      <div>현재: {response.currentRevision}</div>
+                      {response.respondedRevision && (
+                        <div className="text-muted-foreground">
+                          응답: {response.respondedRevision}
+                        </div>
+                      )}
+                    </div>
+                  </TableCell>
+                  
+                  <TableCell>
+                    {formatDate(response.requestedAt)}
+                  </TableCell>
+                  
+                  <TableCell>
+                    {response.respondedAt ? formatDate(response.respondedAt) : '-'}
+                  </TableCell>
+                  
+                  <TableCell>
+                    {response.vendorComment ? (
+                      <div className="max-w-[200px] truncate" title={response.vendorComment}>
+                        {response.vendorComment}
+                      </div>
+                    ) : (
+                      '-'
+                    )}
+                  </TableCell>
+                  
+                  <TableCell>
+                    <div className="flex items-center gap-1">
+                      {response.responseStatus === 'RESPONDED' && (
+                        <Button
+                          variant="ghost"
+                          size="sm"
+                          className="h-8 w-8 p-0"
+                          title="첨부파일 다운로드"
+                        >
+                          <Download className="h-4 w-4" />
+                        </Button>
+                      )}
+                      <Button
+                        variant="ghost"
+                        size="sm"
+                        className="h-8 w-8 p-0"
+                        title="상세 보기"
+                      >
+                        <MessageSquare className="h-4 w-4" />
+                      </Button>
+                    </div>
+                  </TableCell>
+                </TableRow>
+              ))}
+            </TableBody>
+          </Table>
+        </div>
+      )}
+    </div>
+  )
+}
\ No newline at end of file
-- 
cgit v1.2.3

