From 39fc95095ac4b99186294f21fe6d8ac0cfab1f6e Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Fri, 24 Oct 2025 18:55:27 +0900 Subject: (김준회) 리비전, 파일 조회는 dialog 로 분리(옥프로 요청) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/swp/table/swp-table.tsx | 300 +++++++++++++++++++++++++++++--------------- 1 file changed, 197 insertions(+), 103 deletions(-) (limited to 'lib/swp/table/swp-table.tsx') diff --git a/lib/swp/table/swp-table.tsx b/lib/swp/table/swp-table.tsx index fb3a504e..8ae90bdd 100644 --- a/lib/swp/table/swp-table.tsx +++ b/lib/swp/table/swp-table.tsx @@ -17,6 +17,13 @@ import { TableRow, } from "@/components/ui/table"; import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, +} from "@/components/ui/dialog"; import { Loader2 } from "lucide-react"; import { swpDocumentColumns, swpRevisionColumns, swpFileColumns, type RevisionRow, type FileRow } from "./swp-table-columns"; import { fetchDocumentRevisions, fetchRevisionFiles, type SwpDocumentWithStats } from "../actions"; @@ -43,6 +50,8 @@ export function SwpTable({ const [fileData, setFileData] = useState>({}); const [loadingRevisions, setLoadingRevisions] = useState>(new Set()); const [loadingFiles, setLoadingFiles] = useState>(new Set()); + const [dialogOpen, setDialogOpen] = useState(false); + const [selectedDocument, setSelectedDocument] = useState(null); const table = useReactTable({ data: initialData, @@ -104,10 +113,26 @@ export function SwpTable({ } }; - // 문서 행 확장 핸들러 - const handleDocumentExpand = (docNo: string, isExpanded: boolean) => { - if (isExpanded) { - loadRevisions(docNo); + // 문서 클릭 핸들러 - Dialog 열기 + const handleDocumentClick = async (document: SwpDocumentWithStats) => { + setSelectedDocument(document); + setDialogOpen(true); + + // 리비전 데이터 로드 + if (!revisionData[document.DOC_NO]) { + await loadRevisions(document.DOC_NO); + } + }; + + // 모든 리비전의 파일을 로드 + const loadAllFiles = async (docNo: string) => { + const revisions = revisionData[docNo]; + if (!revisions) return; + + for (const revision of revisions) { + if (!fileData[revision.id]) { + await loadFiles(revision.id); + } } }; @@ -145,10 +170,8 @@ export function SwpTable({ {cell.column.id === "expander" ? (
{ - row.toggleExpanded(); - handleDocumentExpand(row.original.DOC_NO, row.getIsExpanded()); - }} + onClick={() => handleDocumentClick(row.original)} + className="cursor-pointer" > {flexRender( cell.column.columnDef.cell, @@ -161,31 +184,6 @@ export function SwpTable({ ))} - - {/* 리비전 행들 (확장 시) */} - {row.getIsExpanded() && ( - - - {loadingRevisions.has(row.original.DOC_NO) ? ( -
- - 리비전 로딩 중... -
- ) : revisionData[row.original.DOC_NO]?.length ? ( - - ) : ( -
- 리비전 없음 -
- )} -
-
- )} )) ) : ( @@ -227,28 +225,95 @@ export function SwpTable({
+ + {/* 문서 상세 Dialog */} + + + + 문서 상세 + {selectedDocument && ( + + {selectedDocument.DOC_NO} - {selectedDocument.DOC_TITLE} + + )} + + + {selectedDocument && ( +
+ {/* 문서 정보 */} +
+
+ 프로젝트: +
{selectedDocument.PROJ_NO}
+ {selectedDocument.PROJ_NM && ( +
{selectedDocument.PROJ_NM}
+ )} +
+
+ 패키지: +
{selectedDocument.PKG_NO || "-"}
+
+
+ 업체: +
{selectedDocument.CPY_NM || "-"}
+ {selectedDocument.VNDR_CD && ( +
{selectedDocument.VNDR_CD}
+ )} +
+
+ 최신 리비전: +
{selectedDocument.LTST_REV_NO || "-"}
+
+
+ + {/* 리비전 및 파일 목록 */} + {loadingRevisions.has(selectedDocument.DOC_NO) ? ( +
+ + 리비전 로딩 중... +
+ ) : revisionData[selectedDocument.DOC_NO]?.length ? ( + loadAllFiles(selectedDocument.DOC_NO)} + /> + ) : ( +
+ 리비전 없음 +
+ )} +
+ )} +
+
); } // ============================================================================ -// 리비전 서브 테이블 +// 문서 상세 뷰 (Dialog용) // ============================================================================ -interface RevisionSubTableProps { +interface DocumentDetailViewProps { revisions: RevisionRow[]; fileData: Record; loadingFiles: Set; onLoadFiles: (revisionId: number) => void; + onLoadAllFiles: () => void; } -function RevisionSubTable({ +function DocumentDetailView({ revisions, fileData, loadingFiles, onLoadFiles, -}: RevisionSubTableProps) { + onLoadAllFiles, +}: DocumentDetailViewProps) { const [expandedRevisions, setExpandedRevisions] = useState({}); + const [allExpanded, setAllExpanded] = useState(false); const revisionTable = useReactTable({ data: revisions, @@ -262,80 +327,109 @@ function RevisionSubTable({ getRowCanExpand: () => true, }); - const handleRevisionExpand = (revisionId: number, isExpanded: boolean) => { - if (isExpanded) { - onLoadFiles(revisionId); + const handleExpandAll = () => { + if (allExpanded) { + setExpandedRevisions({}); + } else { + const expanded: ExpandedState = {}; + revisions.forEach((_, index) => { + expanded[index] = true; + }); + setExpandedRevisions(expanded); + onLoadAllFiles(); } + setAllExpanded(!allExpanded); + }; + + const handleRevisionExpand = (revisionId: number) => { + onLoadFiles(revisionId); }; return ( -
- - - {revisionTable.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ))} - - ))} - - - {revisionTable.getRowModel().rows.map((row) => ( - - {/* 리비전 행 */} - - {row.getVisibleCells().map((cell) => ( - - {cell.column.id === "expander" ? ( -
{ - row.toggleExpanded(); - handleRevisionExpand(row.original.id, row.getIsExpanded()); - }} - > - {flexRender( - cell.column.columnDef.cell, - cell.getContext() +
+ {/* 전체 펼치기/접기 버튼 */} +
+ +
+ + {/* 리비전 테이블 */} +
+
+ + {revisionTable.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() )} - - ) : ( - flexRender(cell.column.columnDef.cell, cell.getContext()) - )} - + ))} - - {/* 파일 행들 (확장 시) */} - {row.getIsExpanded() && ( - - - {loadingFiles.has(row.original.id) ? ( -
- - 파일 로딩 중... -
- ) : fileData[row.original.id]?.length ? ( - - ) : ( -
- 파일 없음 -
- )} -
+ ))} +
+ + {revisionTable.getRowModel().rows.map((row) => ( + + {/* 리비전 행 */} + + {row.getVisibleCells().map((cell) => ( + + {cell.column.id === "expander" ? ( +
{ + row.toggleExpanded(); + if (!row.getIsExpanded()) { + handleRevisionExpand(row.original.id); + } + }} + className="cursor-pointer" + > + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} +
+ ) : ( + flexRender(cell.column.columnDef.cell, cell.getContext()) + )} +
+ ))}
- )} -
- ))} -
-
+ + {/* 파일 행들 (확장 시) */} + {row.getIsExpanded() && ( + + + {loadingFiles.has(row.original.id) ? ( +
+ + 파일 로딩 중... +
+ ) : fileData[row.original.id]?.length ? ( + + ) : ( +
+ 파일 없음 +
+ )} +
+
+ )} + + ))} + + +
); } -- cgit v1.2.3