From 50adedf48ee4674ebe00f1ee72d93485183cdc51 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 5 Sep 2025 11:44:32 +0000 Subject: (대표님, 최겸, 임수민) EDP 입력 진행률, 견적목록관리, EDP excel import 오류수정, GTC-Contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attachment/revision-historty-dialog.tsx | 305 +++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 lib/rfq-last/attachment/revision-historty-dialog.tsx (limited to 'lib/rfq-last/attachment/revision-historty-dialog.tsx') diff --git a/lib/rfq-last/attachment/revision-historty-dialog.tsx b/lib/rfq-last/attachment/revision-historty-dialog.tsx new file mode 100644 index 00000000..6e4772cb --- /dev/null +++ b/lib/rfq-last/attachment/revision-historty-dialog.tsx @@ -0,0 +1,305 @@ +// @/lib/rfq-last/attachment/revision-history-dialog.tsx + +"use client"; + +import * as React from "react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Skeleton } from "@/components/ui/skeleton"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { + Download, + Eye, + FileText, + Clock, + User, + MessageSquare, + AlertCircle, + CheckCircle, +} from "lucide-react"; +import { format, formatDistanceToNow } from "date-fns"; +import { ko } from "date-fns/locale"; +import { toast } from "sonner"; +import { downloadFile } from "@/lib/file-download"; +import { + getRevisionHistory, + type AttachmentWithHistory, + type RevisionHistory, +} from "../service"; +import { formatFileSize } from "@/lib/utils"; + +interface RevisionHistoryDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + attachmentId: number; + attachmentName?: string; +} + +export function RevisionHistoryDialog({ + open, + onOpenChange, + attachmentId, + attachmentName, +}: RevisionHistoryDialogProps) { + const [loading, setLoading] = React.useState(false); + const [historyData, setHistoryData] = React.useState(null); + const [error, setError] = React.useState(null); + + // 다이얼로그가 열릴 때 데이터 로드 + React.useEffect(() => { + if (open && attachmentId) { + loadRevisionHistory(); + } + }, [open, attachmentId]); + + const loadRevisionHistory = async () => { + setLoading(true); + setError(null); + try { + const result = await getRevisionHistory(attachmentId); + if (result.success && result.data) { + setHistoryData(result.data); + } else { + setError(result.error || "리비전 히스토리를 불러올 수 없습니다."); + } + } catch (err) { + console.error("Load revision history error:", err); + setError("리비전 히스토리 조회 중 오류가 발생했습니다."); + } finally { + setLoading(false); + } + }; + + // 리비전 다운로드 + const handleDownloadRevision = async (revision: RevisionHistory) => { + try { + await downloadFile(revision.filePath, revision.originalFileName, { + action: 'download', + showToast: true, + }); + } catch (err) { + console.error("Download revision error:", err); + toast.error("파일 다운로드 중 오류가 발생했습니다."); + } + }; + + // 리비전 미리보기 + const handlePreviewRevision = async (revision: RevisionHistory) => { + try { + await downloadFile(revision.filePath, revision.originalFileName, { + action: 'preview', + showToast: true, + }); + } catch (err) { + console.error("Preview revision error:", err); + toast.error("파일 미리보기 중 오류가 발생했습니다."); + } + }; + + // 리비전 번호에 따른 색상 결정 + const getRevisionBadgeVariant = (isLatest: boolean) => { + return isLatest ? "default" : "secondary"; + }; + + return ( + + + + + + 리비전 히스토리 + + + {historyData?.originalFileName || attachmentName || "파일"}의 모든 버전 히스토리를 확인할 수 있습니다. + + + +
+ {loading ? ( +
+ + + +
+ ) : error ? ( + + + {error} + + ) : historyData ? ( + <> + {/* 파일 정보 헤더 */} +
+
+
+ 일련번호:{" "} + {historyData.serialNo || "-"} +
+
+ 현재 리비전:{" "} + + Rev. {historyData.currentRevision || "A"} + +
+ {historyData.description && ( +
+ 설명:{" "} + {historyData.description} +
+ )} +
+
+ + {/* 리비전 테이블 */} + + + + + 리비전 + 파일명 + 크기 + 업로드자 + 업로드일시 + 코멘트 + 작업 + + + + {historyData.revisions.length > 0 ? ( + historyData.revisions.map((revision) => ( + + + + Rev. {revision.revisionNo} + {revision.isLatest && ( + + )} + + + +
+ + {revision.originalFileName} + + {revision.fileName !== revision.originalFileName && ( + + ({revision.fileName}) + + )} +
+
+ + + {formatFileSize(revision.fileSize)} + + + +
+ + + {revision.createdByName || "Unknown"} + +
+
+ +
+ + + {format(new Date(revision.createdAt), "yyyy-MM-dd HH:mm")} + +
+ + {formatDistanceToNow(new Date(revision.createdAt), { + addSuffix: true, + locale: ko, + })} + +
+ + {revision.revisionComment ? ( +
+ + + {revision.revisionComment} + +
+ ) : ( + - + )} +
+ +
+ + +
+
+
+ )) + ) : ( + + + 리비전 히스토리가 없습니다. + + + )} +
+
+
+ + {/* 요약 정보 */} +
+ 총 {historyData.revisions.length}개의 리비전 + + 최초 업로드:{" "} + {historyData.revisions.length > 0 + ? format( + new Date( + historyData.revisions[historyData.revisions.length - 1].createdAt + ), + "yyyy년 MM월 dd일" + ) + : "-"} + +
+ + ) : null} +
+
+
+ ); +} \ No newline at end of file -- cgit v1.2.3