From ba8cd44a0ed2c613a5f2cee06bfc9bd0f61f21c7 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 7 Nov 2025 08:39:04 +0000 Subject: (최겸) 입찰/견적 수정사항 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bidding/list/bidding-pr-documents-dialog.tsx | 405 +++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 lib/bidding/list/bidding-pr-documents-dialog.tsx (limited to 'lib/bidding/list/bidding-pr-documents-dialog.tsx') diff --git a/lib/bidding/list/bidding-pr-documents-dialog.tsx b/lib/bidding/list/bidding-pr-documents-dialog.tsx new file mode 100644 index 00000000..ad377ee5 --- /dev/null +++ b/lib/bidding/list/bidding-pr-documents-dialog.tsx @@ -0,0 +1,405 @@ +"use client" + +import * as React from "react" +import { useState, useEffect, useCallback } from "react" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { ScrollArea } from "@/components/ui/scroll-area" +import { + CalendarIcon, + FileTextIcon, + PackageIcon, + HashIcon, + DollarSignIcon, +} from "lucide-react" +import { BiddingListItem } from "@/db/schema" +import { formatFileSize } from "@/lib/file-download" +import { getPRDetailsAction, type PRDetails } from "../service" + +// 파일 다운로드 컴포넌트 +const FileDownloadLink = ({ + filePath, + fileName, + fileSize, + title, + className = "" +}: { + filePath: string; + fileName: string; + fileSize: number; + title?: string | null; + className?: string; +}) => { + return ( + + {title || fileName} ({formatFileSize(fileSize)}) + + ); +}; + +const FileDownloadButton = ({ + filePath, + fileName, + variant = "download", + size = "sm" +}: { + filePath: string; + fileName: string; + variant?: "download" | "preview"; + size?: "sm" | "default"; +}) => { + return ( + + ); +}; + +// PR 문서 다이얼로그 +interface PrDocumentsDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + bidding: BiddingListItem | null; +} + +export function PrDocumentsDialog({ + open, + onOpenChange, + bidding +}: PrDocumentsDialogProps) { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const fetchPRData = useCallback(async () => { + if (!bidding) return; + + setLoading(true); + setError(null); + + try { + const result = await getPRDetailsAction(bidding.id); + + if (result.success && result.data) { + setData(result.data as PRDetails); + } else { + setError(result.error || "PR 문서 정보를 불러올 수 없습니다."); + } + } catch (err) { + setError("데이터 로딩 중 오류가 발생했습니다."); + console.error("Failed to fetch PR data:", err); + } finally { + setLoading(false); + } + }, [bidding]); + + useEffect(() => { + if (open && bidding) { + fetchPRData(); + } + }, [open, bidding, fetchPRData]); + + const formatCurrency = (amount: number | null, currency: string | null) => { + if (amount == null) return "-"; + return `${amount.toLocaleString()} ${currency || ""}`; + }; + + return ( + + + + + + PR 및 문서 정보 + + + {bidding?.title}의 PR 문서 및 아이템 정보입니다. + + + + + {loading ? ( +
+
+
+

로딩 중...

+
+
+ ) : error ? ( +
+
+

{error}

+ +
+
+ ) : data ? ( +
+ {/* PR 문서 목록 */} + {data.documents.length > 0 && ( + + + + + PR 문서 ({data.documents.length}개) + + + + + + + 문서명 + 파일명 + 버전 + 크기 + 등록일 + 등록자 + 다운로드 + + + + {data.documents.map((doc) => ( + + + {doc.documentName} + {doc.description && ( +
+ {doc.description} +
+ )} +
+ + + + + {doc.version ? ( + {doc.version} + ) : "-"} + + {formatFileSize(doc.fileSize)} + + {new Date(doc.registeredAt).toLocaleDateString('ko-KR')} + + {doc.registeredBy || "-"} + + + +
+ ))} +
+
+
+
+ )} + + {/* PR 아이템 테이블 */} + {data.items.length > 0 && ( + + + + + PR 아이템 ({data.items.length}개) + + + +
+ + + + 아이템 번호 + PR 번호 + 자재그룹 + 자재 + 품목정보 + 수량 + 구매단위 + 내정단가 + 내정금액 + 예산금액 + 실적금액 + WBS코드 + 요청 납기 + 스펙 문서 + + + + {data.items.map((item) => ( + + + {item.itemNumber || "-"} + + + {item.prNumber || "-"} + + +
+ {item.materialGroupNumber && ( +
{item.materialGroupNumber}
+ )} + {item.materialGroupInfo && ( +
{item.materialGroupInfo}
+ )} + {!item.materialGroupNumber && !item.materialGroupInfo && "-"} +
+
+ +
+ {item.materialNumber && ( +
{item.materialNumber}
+ )} + {item.materialInfo && ( +
{item.materialInfo}
+ )} + {!item.materialNumber && !item.materialInfo && "-"} +
+
+ +
+ {item.itemInfo || "-"} +
+
+ +
+ + + {item.quantity ? `${item.quantity.toLocaleString()} ${item.quantityUnit || ""}` : "-"} + +
+
+ + {item.purchaseUnit || "-"} + + +
+ + + {formatCurrency(item.targetUnitPrice, item.targetCurrency)} + +
+
+ +
+ {formatCurrency(item.targetAmount, item.targetCurrency)} +
+
+ +
+ {formatCurrency(item.budgetAmount, item.budgetCurrency)} +
+
+ +
+ {formatCurrency(item.actualAmount, item.actualCurrency)} +
+
+ +
+ {item.wbsCode && ( +
{item.wbsCode}
+ )} + {item.wbsName && ( +
{item.wbsName}
+ )} + {!item.wbsCode && !item.wbsName && "-"} +
+
+ + {item.requestedDeliveryDate ? ( +
+ + + {new Date(item.requestedDeliveryDate).toLocaleDateString('ko-KR')} + +
+ ) : "-"} +
+ +
+
+ + {item.hasSpecDocument ? "있음" : "없음"} + + {item.specDocuments.length > 0 && ( + + ({item.specDocuments.length}개) + + )} +
+ {item.specDocuments.length > 0 && ( +
+ {item.specDocuments.map((doc) => ( +
+ +
+ ))} +
+ )} +
+
+
+ ))} +
+
+
+
+
+ )} + + {/* 데이터가 없는 경우 */} + {data.documents.length === 0 && data.items.length === 0 && ( +
+ +

PR 문서가 없습니다.

+
+ )} +
+ ) : null} +
+
+
+ ); +} + -- cgit v1.2.3