diff options
Diffstat (limited to 'lib/swp/table/swp-document-detail-dialog.tsx')
| -rw-r--r-- | lib/swp/table/swp-document-detail-dialog.tsx | 176 |
1 files changed, 90 insertions, 86 deletions
diff --git a/lib/swp/table/swp-document-detail-dialog.tsx b/lib/swp/table/swp-document-detail-dialog.tsx index a87cd0e2..77ef77f7 100644 --- a/lib/swp/table/swp-document-detail-dialog.tsx +++ b/lib/swp/table/swp-document-detail-dialog.tsx @@ -192,85 +192,97 @@ export function SwpDocumentDetailDialog({ } }; - // Revision별로 Activity 그룹핑 (rowspan용) + // Revision별로 Activity 그룹핑 및 정렬 (rowspan용) const groupedActivities = useMemo(() => { + // 1. REV 내림차순, createDate 내림차순으로 정렬 + const sortedActivities = [...activities].sort((a, b) => { + // REV 비교 (내림차순) + const revCompare = b.revNo.localeCompare(a.revNo); + if (revCompare !== 0) return revCompare; + + // 같은 REV 내에서는 createDate 내림차순 + return b.createDate.localeCompare(a.createDate); + }); + + // 2. 그룹핑 const groups: Map<string, ActivityRow[]> = new Map(); - activities.forEach((activity) => { + sortedActivities.forEach((activity) => { const key = `${activity.revNo}|${activity.stage}`; if (!groups.has(key)) { groups.set(key, []); } groups.get(key)!.push(activity); }); + return groups; }, [activities]); return ( <Dialog open={open} onOpenChange={onOpenChange}> - <DialogContent className="max-w-[95vw] max-h-[80vh] overflow-hidden flex flex-col"> + <DialogContent className="max-w-[95vw] h-[90vh] overflow-hidden flex flex-col"> <DialogHeader> - <DialogTitle>문서 리비전 히스토리</DialogTitle> + <DialogTitle className="text-base">문서 리비전 히스토리</DialogTitle> {document && ( - <DialogDescription> + <DialogDescription className="text-xs"> {document.DOC_NO} - {document.DOC_TITLE} </DialogDescription> )} </DialogHeader> {document && ( - <div className="flex-1 flex flex-col space-y-4 overflow-hidden min-h-0"> + <div className="flex-1 flex flex-col space-y-2 overflow-hidden"> {/* 문서 정보 */} - <div className="grid grid-cols-1 md:grid-cols-5 gap-4 p-4 bg-muted/30 rounded-lg"> - <div> - <span className="text-sm font-semibold">프로젝트:</span> - <div className="text-sm">{document.PROJ_NO}</div> + <div className="flex items-center gap-4 px-3 py-2 bg-muted/30 rounded text-xs"> + <div className="flex items-center gap-1"> + <span className="font-semibold">프로젝트:</span> + <span>{document.PROJ_NO}</span> {document.PROJ_NM && ( - <div className="text-xs text-muted-foreground">{document.PROJ_NM}</div> + <span className="text-muted-foreground">({document.PROJ_NM})</span> )} </div> - <div> - <span className="text-sm font-semibold">패키지:</span> - <div className="text-sm">{document.PKG_NO || "-"}</div> + <div className="flex items-center gap-1"> + <span className="font-semibold">패키지:</span> + <span>{document.PKG_NO || "-"}</span> </div> - <div> - <span className="text-sm font-semibold">업체:</span> - <div className="text-sm">{document.CPY_NM || "-"}</div> + <div className="flex items-center gap-1"> + <span className="font-semibold">업체:</span> + <span>{document.CPY_NM || "-"}</span> {document.VNDR_CD && ( - <div className="text-xs text-muted-foreground">{document.VNDR_CD}</div> + <span className="text-muted-foreground">({document.VNDR_CD})</span> )} </div> - <div> - <span className="text-sm font-semibold">최신 리비전:</span> - <div className="text-sm">{document.LTST_REV_NO || "-"}</div> + <div className="flex items-center gap-1"> + <span className="font-semibold">최신 리비전:</span> + <span>{document.LTST_REV_NO || "-"}</span> </div> - <div> - <span className="text-sm font-semibold">총 Activity:</span> - <div className="text-sm">{activities.length}개</div> + <div className="flex items-center gap-1"> + <span className="font-semibold">총 Activity:</span> + <span>{activities.length}개</span> </div> </div> {/* Activity 테이블 */} {isLoading ? ( <div className="flex items-center justify-center p-8"> - <Loader2 className="h-6 w-6 animate-spin" /> - <span className="ml-2">리비전 트리 로딩 중...</span> + <Loader2 className="h-5 w-5 animate-spin" /> + <span className="ml-2 text-sm">리비전 트리 로딩 중...</span> </div> ) : activities.length > 0 ? ( <> {/* Activity 테이블 (위) */} - <div className="flex-1 overflow-auto border rounded-lg min-h-0"> + <div className="h-[40vh] overflow-auto border rounded-lg"> <Table> <TableHeader className="sticky top-0 bg-background z-10"> - <TableRow> - <TableHead className="w-[80px]">Rev</TableHead> - <TableHead className="w-[80px]">Stage</TableHead> - <TableHead className="w-[80px]">IN/OUT</TableHead> - <TableHead className="w-[100px]">Status</TableHead> - <TableHead className="min-w-[150px]">Transmittal No</TableHead> - <TableHead className="min-w-[150px]">Activity No</TableHead> - <TableHead className="min-w-[100px]">Ref Activity</TableHead> - <TableHead className="w-[120px]">Modified</TableHead> - <TableHead className="w-[80px]">By</TableHead> + <TableRow className="text-xs"> + <TableHead className="w-[70px] text-xs h-8">Rev</TableHead> + <TableHead className="w-[70px] text-xs h-8">Stage</TableHead> + <TableHead className="w-[70px] text-xs h-8">IN/OUT</TableHead> + <TableHead className="w-[90px] text-xs h-8">Status</TableHead> + <TableHead className="min-w-[130px] text-xs h-8">Transmittal No</TableHead> + <TableHead className="min-w-[130px] text-xs h-8">Activity No</TableHead> + <TableHead className="min-w-[90px] text-xs h-8">Ref Activity</TableHead> + <TableHead className="w-[100px] text-xs h-8">Modified</TableHead> + <TableHead className="w-[70px] text-xs h-8">By</TableHead> </TableRow> </TableHeader> <TableBody> @@ -280,7 +292,7 @@ export function SwpDocumentDetailDialog({ <TableRow key={activity.actvNo} className={cn( - "cursor-pointer hover:bg-muted/50", + "cursor-pointer hover:bg-muted/50 h-8", selectedActivity?.actvNo === activity.actvNo && "bg-blue-50 hover:bg-blue-100" )} @@ -289,7 +301,7 @@ export function SwpDocumentDetailDialog({ {/* Rev 컬럼 (첫 행만 표시, rowspan) */} {idx === 0 && ( <TableCell - className="font-mono text-sm font-semibold align-top border-r" + className="font-mono text-xs font-semibold align-top border-r py-1" rowSpan={groupActivities.length} > {revNo} @@ -298,45 +310,41 @@ export function SwpDocumentDetailDialog({ {/* Stage 컬럼 (첫 행만 표시, rowspan) */} {idx === 0 && ( <TableCell - className="align-top border-r text-sm" + className="align-top border-r text-xs py-1" rowSpan={groupActivities.length} > {stage} </TableCell> )} - <TableCell> + <TableCell className="py-1"> <Badge variant="outline" - className={ + className={cn( + "text-[10px] h-4 px-1", activity.inOut === "IN" ? "bg-blue-100 text-blue-800" : "bg-green-100 text-green-800" - } + )} > {activity.inOut} </Badge> </TableCell> - <TableCell> - <div className="text-sm"> - <div className="font-medium">{activity.statusName}</div> - <div className="text-xs text-muted-foreground"> - {activity.statusCode} - </div> - </div> + <TableCell className="text-xs py-1"> + <div className="font-medium">{activity.statusName}</div> </TableCell> - <TableCell className="text-sm"> + <TableCell className="text-xs py-1"> {activity.transmittalNo || "-"} </TableCell> - <TableCell className="font-mono text-xs"> + <TableCell className="font-mono text-xs py-1"> {activity.actvNo} </TableCell> - <TableCell className="font-mono text-xs"> + <TableCell className="font-mono text-xs py-1"> {activity.refActivityNo || "-"} </TableCell> - <TableCell className="text-xs"> + <TableCell className="text-xs py-1"> {formatSwpDateShort(activity.createDate)} </TableCell> - <TableCell className="text-xs"> + <TableCell className="text-xs py-1"> {activity.createEmpNo} </TableCell> </TableRow> @@ -347,57 +355,53 @@ export function SwpDocumentDetailDialog({ </div> {/* 파일 목록 (아래) */} - <div className="border rounded-lg overflow-hidden" style={{ height: "250px" }}> - <div className="p-3 bg-muted/50 border-b"> - <h3 className="font-semibold text-sm">파일 목록</h3> + <div className="border rounded-lg overflow-hidden h-[30vh] flex flex-col"> + <div className="px-3 py-1.5 bg-muted/50 border-b flex-shrink-0"> + <h3 className="font-semibold text-xs">파일 목록</h3> {selectedActivity ? ( - <> - <p className="text-xs text-muted-foreground mt-1"> - Activity: {selectedActivity.actvNo} - </p> - <p className="text-xs text-muted-foreground"> - Rev {selectedActivity.revNo} ({selectedActivity.stage}) / {selectedActivity.inOut} - </p> - </> + <p className="text-[10px] text-muted-foreground mt-0.5"> + Activity: {selectedActivity.actvNo} / Rev {selectedActivity.revNo} ({selectedActivity.stage}) / {selectedActivity.inOut} + </p> ) : ( - <p className="text-xs text-muted-foreground mt-1"> + <p className="text-[10px] text-muted-foreground mt-0.5"> Activity를 선택하면 파일 목록이 표시됩니다 </p> )} </div> - <div className="overflow-auto p-3" style={{ height: "calc(250px - 80px)" }}> + <div className="overflow-auto flex-1"> {selectedActivity ? ( isLoadingFiles ? ( <div className="flex items-center justify-center h-full"> - <Loader2 className="h-5 w-5 animate-spin" /> - <span className="ml-2 text-sm">파일 로딩 중...</span> + <Loader2 className="h-4 w-4 animate-spin" /> + <span className="ml-2 text-xs">파일 로딩 중...</span> </div> ) : activityFiles.length > 0 ? ( <Table> - <TableHeader> + <TableHeader className="sticky top-0 bg-background"> <TableRow> - <TableHead className="min-w-[200px]">파일명</TableHead> - <TableHead className="w-[100px]">크기</TableHead> - <TableHead className="w-[120px]">날짜</TableHead> - <TableHead className="w-[100px]">다운로드</TableHead> + <TableHead className="min-w-[200px] text-xs h-8">파일명</TableHead> + <TableHead className="w-[90px] text-xs h-8">크기</TableHead> + <TableHead className="w-[100px] text-xs h-8">날짜</TableHead> + <TableHead className="w-[90px] text-xs h-8">다운로드</TableHead> </TableRow> </TableHeader> <TableBody> {activityFiles.map((file) => ( - <TableRow key={file.FILE_SEQ}> - <TableCell className="font-medium"> + <TableRow key={file.FILE_SEQ} className="h-8"> + <TableCell className="font-medium text-xs py-1"> {file.FILE_NM} </TableCell> - <TableCell className="text-sm text-muted-foreground"> + <TableCell className="text-xs text-muted-foreground py-1"> {file.FILE_SZ ? formatFileSize(file.FILE_SZ) : "-"} </TableCell> - <TableCell className="text-sm text-muted-foreground"> + <TableCell className="text-xs text-muted-foreground py-1"> {file.CRTE_DTM ? formatSwpDateShort(file.CRTE_DTM) : "-"} </TableCell> - <TableCell> + <TableCell className="py-1"> <Button variant="outline" size="sm" + className="h-6 px-2 text-[10px]" onClick={() => handleDownloadFile(file.FILE_NM, document.OWN_DOC_NO || document.DOC_NO)} > <Download className="h-3 w-3 mr-1" /> @@ -409,17 +413,17 @@ export function SwpDocumentDetailDialog({ </TableBody> </Table> ) : ( - <div className="flex items-center justify-center h-full text-sm text-muted-foreground"> + <div className="flex items-center justify-center h-full text-xs text-muted-foreground"> <div className="text-center"> - <AlertCircle className="h-8 w-8 mx-auto mb-2 opacity-50" /> + <AlertCircle className="h-6 w-6 mx-auto mb-1 opacity-50" /> <p>파일이 없습니다</p> </div> </div> ) ) : ( - <div className="flex items-center justify-center h-full text-sm text-muted-foreground"> + <div className="flex items-center justify-center h-full text-xs text-muted-foreground"> <div className="text-center"> - <FileIcon className="h-12 w-12 mx-auto mb-2 opacity-30" /> + <FileIcon className="h-8 w-8 mx-auto mb-1 opacity-30" /> <p>Activity를 선택해주세요</p> </div> </div> @@ -429,8 +433,8 @@ export function SwpDocumentDetailDialog({ </> ) : ( <div className="p-8 text-center text-muted-foreground"> - <AlertCircle className="h-12 w-12 mx-auto mb-2 opacity-50" /> - <p>Activity 정보가 없습니다</p> + <AlertCircle className="h-10 w-10 mx-auto mb-2 opacity-50" /> + <p className="text-sm">Activity 정보가 없습니다</p> </div> )} </div> |
