From fd4909bba7be8abc1eeab9ae1b4621c66a61604a Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Sun, 23 Nov 2025 16:40:37 +0900 Subject: (김준회) 돌체 재개발 - 1차 (다운로드 오류 수정 필요) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/dolce/dialogs/detail-drawing-dialog.tsx | 311 ++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 lib/dolce/dialogs/detail-drawing-dialog.tsx (limited to 'lib/dolce/dialogs/detail-drawing-dialog.tsx') diff --git a/lib/dolce/dialogs/detail-drawing-dialog.tsx b/lib/dolce/dialogs/detail-drawing-dialog.tsx new file mode 100644 index 00000000..a06c9688 --- /dev/null +++ b/lib/dolce/dialogs/detail-drawing-dialog.tsx @@ -0,0 +1,311 @@ +"use client"; + +import { useState, useEffect, useCallback } from "react"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; +import { Plus, RefreshCw, Upload, Loader2 } from "lucide-react"; +import { toast } from "sonner"; +import { + UnifiedDwgReceiptItem, + DetailDwgReceiptItem, + FileInfoItem, + fetchDetailDwgReceiptList, + fetchFileInfoList, +} from "../actions"; +import { DrawingListTable } from "../table/drawing-list-table"; +import { detailDrawingColumns } from "../table/detail-drawing-columns"; +import { createFileListColumns } from "../table/file-list-columns"; +import { AddDetailDrawingDialog } from "./add-detail-drawing-dialog"; +import { UploadFilesToDetailDialog } from "./upload-files-to-detail-dialog"; + +interface DetailDrawingDialogProps { + drawing: UnifiedDwgReceiptItem | null; + open: boolean; + onOpenChange: (open: boolean) => void; + vendorCode: string; + userId: string; + userName: string; + userEmail: string; + drawingKind: "B3" | "B4"; +} + +export function DetailDrawingDialog({ + drawing, + open, + onOpenChange, + vendorCode, + userId, + userName, + userEmail, + drawingKind, +}: DetailDrawingDialogProps) { + const [detailDrawings, setDetailDrawings] = useState([]); + const [selectedDetail, setSelectedDetail] = useState(null); + const [files, setFiles] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [isLoadingFiles, setIsLoadingFiles] = useState(false); + const [addDialogOpen, setAddDialogOpen] = useState(false); + const [uploadFilesDialogOpen, setUploadFilesDialogOpen] = useState(false); + + // 상세도면 목록 로드 + const loadDetailDrawings = useCallback(async () => { + if (!drawing) return; + + try { + setIsLoading(true); + const data = await fetchDetailDwgReceiptList({ + project: drawing.ProjectNo, + drawingNo: drawing.DrawingNo, + discipline: drawing.Discipline, + drawingKind: drawing.DrawingKind, + userId: "", // 조회 시 모든 사용자의 상세도면을 보기 위해 빈 문자열 전달 + }); + setDetailDrawings(data); + + // 첫 번째 상세도면 자동 선택 + if (data.length > 0 && !selectedDetail) { + setSelectedDetail(data[0]); + } + } catch (error) { + console.error("상세도면 로드 실패:", error); + toast.error("상세도면 로드에 실패했습니다"); + } finally { + setIsLoading(false); + } + }, [drawing, selectedDetail]); + + // 파일 목록 로드 + const loadFiles = useCallback(async () => { + if (!selectedDetail) { + setFiles([]); + return; + } + + try { + setIsLoadingFiles(true); + const data = await fetchFileInfoList(selectedDetail.UploadId); + setFiles(data); + } catch (error) { + console.error("파일 목록 로드 실패:", error); + toast.error("파일 목록 로드에 실패했습니다"); + } finally { + setIsLoadingFiles(false); + } + }, [selectedDetail]); + + // 다이얼로그 열릴 때 데이터 로드 + useEffect(() => { + if (open && drawing) { + loadDetailDrawings(); + } else { + setDetailDrawings([]); + setSelectedDetail(null); + setFiles([]); + } + }, [open, drawing, loadDetailDrawings]); + + // 선택된 상세도면 변경 시 파일 목록 로드 + useEffect(() => { + if (selectedDetail) { + loadFiles(); + } + }, [selectedDetail, loadFiles]); + + const handleDownload = async (file: FileInfoItem) => { + try { + toast.info("파일 다운로드를 준비 중입니다..."); + + // 파일 생성자의 userId를 사용하여 다운로드 + const response = await fetch("/api/dolce/download", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + fileId: file.FileId, + userId: file.CreateUserId, // 파일 생성자의 ID 사용 + fileName: file.FileName, + }), + }); + + if (!response.ok) { + throw new Error("파일 다운로드 실패"); + } + + const blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = file.FileName; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + + toast.success("파일 다운로드가 완료되었습니다"); + } catch (error) { + console.error("파일 다운로드 실패:", error); + toast.error("파일 다운로드에 실패했습니다"); + } + }; + + const handleRefresh = () => { + loadDetailDrawings(); + }; + + const handleAddComplete = () => { + setAddDialogOpen(false); + loadDetailDrawings(); + }; + + const handleUploadComplete = () => { + setUploadFilesDialogOpen(false); + loadFiles(); + }; + + const fileColumns = createFileListColumns({ onDownload: handleDownload }); + + // RegisterId + UploadId 조합으로 고유 ID 생성 + const getDetailDrawingId = (detail: DetailDwgReceiptItem) => { + return `${detail.RegisterId}_${detail.UploadId}`; + }; + + // B4인 경우 "도면입수"인 건만 상세도면 추가 및 파일 첨부 가능 + // B3인 경우 모든 건에 대해 가능 + const canAddDetailDrawing = drawingKind === "B3" || + (drawingKind === "B4" && drawing && 'DrawingMoveGbn' in drawing && drawing.DrawingMoveGbn === "도면입수"); + + return ( + <> + + + + + 상세도면 정보 + {drawing && ( + + {drawing.DrawingNo} | 프로젝트: {drawing.ProjectNo} | Discipline: {drawing.Discipline} | 종류: {drawing.DrawingKind} + + )} + + + +
+ {/* 상단: 상세도면 리스트 */} + + + 상세도면 목록 +
+ + {canAddDetailDrawing && ( + + )} +
+
+ + + columns={detailDrawingColumns} + data={detailDrawings} + onRowClick={setSelectedDetail} + selectedRow={selectedDetail || undefined} + getRowId={(row) => getDetailDrawingId(row)} + /> + +
+ + {/* 하단: 첨부파일 리스트 */} + + + + 첨부파일 목록 + {selectedDetail && ` - Rev. ${selectedDetail.DrawingRevNo}`} + + {selectedDetail && canAddDetailDrawing && ( + + )} + + + {!selectedDetail ? ( +
+ 상세도면을 선택하세요 +
+ ) : isLoadingFiles ? ( +
+
+ + Loading files... +
+
+ + + +
+
+ ) : ( + + )} +
+
+
+
+
+ + + + {selectedDetail && ( + + )} + + ); +} + -- cgit v1.2.3