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 { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" import { RefreshCw, Download, MessageSquare, Clock, CheckCircle2, XCircle, AlertCircle, FileText, Files, AlertTriangle } from "lucide-react" import { formatDate, formatFileSize } from "@/lib/utils" import { RequestRevisionDialog } from "./request-revision-dialog" interface VendorResponsesPanelProps { attachment: any responses: any[] isLoading: boolean onRefresh: () => void } // 파일 다운로드 핸들러 async function handleFileDownload(filePath: string, fileName: string, fileId: number) { try { const params = new URLSearchParams({ path: filePath, type: "vendor", responseFileId: fileId.toString(), }); const response = await fetch(`/api/rfq-attachments/download?${params.toString()}`); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || `Download failed: ${response.status}`); } const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); console.log("✅ 파일 다운로드 성공:", fileName); } catch (error) { console.error("❌ 파일 다운로드 실패:", error); alert(`파일 다운로드에 실패했습니다: ${error instanceof Error ? error.message : '알 수 없는 오류'}`); } } // 파일 목록 컴포넌트 function FilesList({ files }: { files: any[] }) { if (files.length === 0) { return (
업로드된 파일이 없습니다.
); } return (
{files.map((file, index) => (
{file.originalFileName}
{formatFileSize(file.fileSize)} • {formatDate(file.uploadedAt)}
{file.description && (
{file.description}
)}
))}
); } export function VendorResponsesPanel({ attachment, responses, isLoading, onRefresh }: VendorResponsesPanelProps) { console.log(responses) const getStatusIcon = (status: string) => { switch (status) { case 'RESPONDED': return case 'NOT_RESPONDED': return case 'WAIVED': return case 'REVISION_REQUESTED': return default: return } } 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 (
{Array.from({ length: 3 }).map((_, i) => ( ))}
) } return (
{/* 헤더 */}

벤더 응답 현황: {attachment.originalFileName}

{attachment.attachmentType} 시리얼: {attachment.serialNo} 등록: {formatDate(attachment.createdAt)} {attachment.responseStats && ( 응답률: {attachment.responseStats.responseRate}% )}
{/* 테이블 */} {responses.length === 0 ? (
이 문서에 대한 벤더 응답 정보가 없습니다.
) : (
벤더 국가 응답 상태 리비전 요청일 응답일 응답 파일 코멘트 액션 {responses.map((response) => (
{response.vendorName}
{response.vendorCode}
{response.vendorCountry}
{getStatusIcon(response.responseStatus)} {response.responseStatus}
현재: {response.currentRevision}
{response.respondedRevision && (
응답: {response.respondedRevision}
)}
{formatDate(response.requestedAt)} {response.respondedAt ? formatDate(response.respondedAt) : '-'} {/* 응답 파일 컬럼 */} {response.totalFiles > 0 ? (
{response.totalFiles}개 {response.totalFiles === 1 ? ( // 파일이 1개면 바로 다운로드 ) : ( // 파일이 여러 개면 Popover로 목록 표시
응답 파일 목록 ({response.totalFiles}개)
)}
) : ( - )}
{/* 벤더 응답 코멘트 */} {response.responseComment && (
{response.responseComment}
)} {/* 수정 요청 사유 */} {response.revisionRequestComment && (
{response.revisionRequestComment}
)} {!response.responseComment && !response.revisionRequestComment && ( - )}
{/* 액션 컬럼 - 수정 요청 기능으로 변경 */}
{response.responseStatus === 'RESPONDED' && ( 수정요청 } /> )} {response.responseStatus === 'REVISION_REQUESTED' && ( 수정 요청됨 )} {(response.responseStatus === 'NOT_RESPONDED' || response.responseStatus === 'WAIVED') && ( - )}
))}
)}
) }