summaryrefslogtreecommitdiff
path: root/lib/swp/table/swp-table-columns.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-10-29 15:59:04 +0900
committerjoonhoekim <26rote@gmail.com>2025-10-29 15:59:04 +0900
commit2ecdac866c19abea0b5389708fcdf5b3889c969a (patch)
treee02a02cfa0890691fb28a7df3a96ef495b3d4b79 /lib/swp/table/swp-table-columns.tsx
parent2fc9e5492e220041ba322d9a1479feb7803228cf (diff)
(김준회) SWP 파일 업로드 취소 기능 추가, 업로드 파일명 검증로직에서 파일명 비필수로 변경
Diffstat (limited to 'lib/swp/table/swp-table-columns.tsx')
-rw-r--r--lib/swp/table/swp-table-columns.tsx353
1 files changed, 18 insertions, 335 deletions
diff --git a/lib/swp/table/swp-table-columns.tsx b/lib/swp/table/swp-table-columns.tsx
index 9aecea96..e6abd2a0 100644
--- a/lib/swp/table/swp-table-columns.tsx
+++ b/lib/swp/table/swp-table-columns.tsx
@@ -2,43 +2,26 @@
import { ColumnDef } from "@tanstack/react-table";
import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import { ChevronDown, ChevronRight, FileIcon, Download, Loader2 } from "lucide-react";
-import { formatDistanceToNow } from "date-fns";
-import { ko } from "date-fns/locale";
-import type { SwpDocumentWithStats } from "../actions";
-import { useState } from "react";
-import { toast } from "sonner";
+import type { DocumentListItem } from "@/lib/swp/document-service";
-export const swpDocumentColumns: ColumnDef<SwpDocumentWithStats>[] = [
+export const swpDocumentColumns: ColumnDef<DocumentListItem>[] = [
{
id: "expander",
header: () => null,
- cell: () => {
- return (
- <Button
- variant="ghost"
- size="sm"
- className="h-8 w-8 p-0"
- >
- <ChevronRight className="h-4 w-4" />
- </Button>
- );
- },
+ cell: () => null,
size: 50,
},
{
accessorKey: "LTST_ACTV_STAT",
- header: "상태 (최신 액티비티)",
+ header: "상태",
cell: ({ row }) => {
const status = row.original.LTST_ACTV_STAT;
if (!status) return "-";
- // 상태에 따른 색상 설정 (필요에 따라 조정 가능)
const color =
- status === "Complete" ? "bg-green-100 text-green-800" :
- status === "In Progress" ? "bg-blue-100 text-blue-800" :
- status === "Pending" ? "bg-yellow-100 text-yellow-800" :
+ status.includes("Complete") ? "bg-green-100 text-green-800" :
+ status.includes("Progress") ? "bg-blue-100 text-blue-800" :
+ status.includes("Pending") || status.includes("Ready") ? "bg-yellow-100 text-yellow-800" :
"bg-gray-100 text-gray-800";
return (
@@ -47,7 +30,7 @@ export const swpDocumentColumns: ColumnDef<SwpDocumentWithStats>[] = [
</Badge>
);
},
- size: 100,
+ size: 120,
},
{
accessorKey: "DOC_NO",
@@ -61,7 +44,7 @@ export const swpDocumentColumns: ColumnDef<SwpDocumentWithStats>[] = [
accessorKey: "DOC_TITLE",
header: "문서제목",
cell: ({ row }) => (
- <div className="max-w-md" title={row.original.DOC_TITLE}>
+ <div className="max-w-md truncate" title={row.original.DOC_TITLE}>
{row.original.DOC_TITLE}
</div>
),
@@ -74,7 +57,7 @@ export const swpDocumentColumns: ColumnDef<SwpDocumentWithStats>[] = [
<div>
<div className="font-medium">{row.original.PROJ_NO}</div>
{row.original.PROJ_NM && (
- <div className="text-xs text-muted-foreground max-w-[150px]">
+ <div className="text-xs text-muted-foreground max-w-[150px] truncate">
{row.original.PROJ_NM}
</div>
)}
@@ -127,325 +110,25 @@ export const swpDocumentColumns: ColumnDef<SwpDocumentWithStats>[] = [
},
{
accessorKey: "LTST_REV_NO",
- header: "마지막 REV NO",
+ header: "최신 REV",
cell: ({ row }) => row.original.LTST_REV_NO || "-",
size: 80,
},
{
id: "stats",
- header: "REV/파일",
+ header: "파일",
cell: ({ row }) => (
<div className="text-center">
<div className="text-sm font-medium">
- {row.original.revision_count} / {row.original.file_count}
+ {row.original.fileCount}개
</div>
+ {row.original.standbyFileCount > 0 && (
+ <div className="text-xs text-yellow-600">
+ 대기중 {row.original.standbyFileCount}
+ </div>
+ )}
</div>
),
size: 100,
},
- {
- accessorKey: "last_synced_at",
- header: "동기화",
- cell: ({ row }) => (
- <div className="text-xs text-muted-foreground">
- {formatDistanceToNow(new Date(row.original.last_synced_at), {
- addSuffix: true,
- locale: ko,
- })}
- </div>
- ),
- size: 100,
- },
-];
-
-// ============================================================================
-// 리비전 컬럼 (서브 테이블용)
-// ============================================================================
-
-export interface RevisionRow {
- id: number;
- DOC_NO: string;
- REV_NO: string;
- STAGE: string;
- ACTV_NO: string | null;
- OFDC_NO: string | null;
- sync_status: "synced" | "pending" | "error";
- last_synced_at: Date;
- file_count: number;
-}
-
-export const swpRevisionColumns: ColumnDef<RevisionRow>[] = [
- {
- id: "expander",
- header: () => null,
- cell: ({ row }) => {
- return row.getCanExpand() ? (
- <Button
- variant="ghost"
- size="sm"
- className="h-8 w-8 p-0 ml-8"
- >
- {row.getIsExpanded() ? (
- <ChevronDown className="h-4 w-4" />
- ) : (
- <ChevronRight className="h-4 w-4" />
- )}
- </Button>
- ) : null;
- },
- size: 100,
- },
- {
- accessorKey: "REV_NO",
- header: "리비전",
- cell: ({ row }) => (
- <Badge variant="secondary" className="font-mono">
- REV {row.original.REV_NO}
- </Badge>
- ),
- size: 100,
- },
- {
- accessorKey: "STAGE",
- header: "스테이지",
- cell: ({ row }) => {
- const stage = row.original.STAGE;
- const color =
- stage === "IFC" ? "bg-green-100 text-green-800" :
- stage === "IFA" ? "bg-blue-100 text-blue-800" :
- "bg-gray-100 text-gray-800";
-
- return (
- <Badge variant="outline" className={color}>
- {stage}
- </Badge>
- );
- },
- size: 100,
- },
- {
- accessorKey: "OFDC_NO",
- header: "OFDC 번호",
- cell: ({ row }) => (
- <div className="font-mono text-sm">{row.original.OFDC_NO || "-"}</div>
- ),
- size: 200,
- },
- {
- accessorKey: "ACTV_NO",
- header: "Activity",
- cell: ({ row }) => (
- <div className="font-mono text-xs text-muted-foreground">
- {row.original.ACTV_NO || "-"}
- </div>
- ),
- size: 250,
- },
- {
- id: "file_count",
- header: "파일 수",
- cell: ({ row }) => (
- <div className="flex items-center gap-2">
- <FileIcon className="h-4 w-4 text-muted-foreground" />
- <span className="font-medium">{row.original.file_count}</span>
- </div>
- ),
- size: 100,
- },
- {
- accessorKey: "last_synced_at",
- header: "동기화",
- cell: ({ row }) => (
- <div className="text-xs text-muted-foreground">
- {formatDistanceToNow(new Date(row.original.last_synced_at), {
- addSuffix: true,
- locale: ko,
- })}
- </div>
- ),
- size: 100,
- },
-];
-
-// ============================================================================
-// 파일 컬럼 (서브 서브 테이블용)
-// ============================================================================
-
-export interface FileRow {
- id: number;
- FILE_NM: string;
- FILE_SEQ: string;
- FILE_SZ: string | null;
- FLD_PATH: string | null;
- STAT: string | null;
- STAT_NM: string | null;
- sync_status: "synced" | "pending" | "error";
- created_at: Date;
-}
-
-export const swpFileColumns: ColumnDef<FileRow>[] = [
- {
- id: "spacer",
- header: () => null,
- cell: () => <div className="w-16" />,
- size: 150,
- },
- {
- accessorKey: "FILE_SEQ",
- header: "순서",
- cell: ({ row }) => (
- <Badge variant="outline" className="font-mono">
- #{row.original.FILE_SEQ}
- </Badge>
- ),
- size: 80,
- },
- {
- accessorKey: "FILE_NM",
- header: "파일명",
- cell: ({ row }) => (
- <div className="flex items-center gap-2">
- <FileIcon className="h-4 w-4 text-blue-500" />
- <span className="font-mono text-sm">{row.original.FILE_NM}</span>
- </div>
- ),
- size: 400,
- },
- {
- accessorKey: "FILE_SZ",
- header: "크기",
- cell: ({ row }) => {
- const size = row.original.FILE_SZ;
- if (!size) return "-";
-
- const bytes = parseInt(size, 10);
- if (isNaN(bytes)) return size;
-
- const kb = bytes / 1024;
- const mb = kb / 1024;
-
- return mb >= 1
- ? `${mb.toFixed(2)} MB`
- : `${kb.toFixed(2)} KB`;
- },
- size: 100,
- },
- {
- accessorKey: "STAT_NM",
- header: "상태",
- cell: ({ row }) => {
- const status = row.original.STAT_NM;
- if (!status) return "-";
-
- const color = status === "Complete"
- ? "bg-green-100 text-green-800"
- : "bg-gray-100 text-gray-800";
-
- return (
- <Badge variant="outline" className={color}>
- {status}
- </Badge>
- );
- },
- size: 100,
- },
- {
- accessorKey: "FLD_PATH",
- header: "경로",
- cell: ({ row }) => (
- <div className="font-mono text-xs text-muted-foreground truncate max-w-[200px]" title={row.original.FLD_PATH || ""}>
- {row.original.FLD_PATH || "-"}
- </div>
- ),
- size: 200,
- },
- {
- accessorKey: "created_at",
- header: "생성일",
- cell: ({ row }) => (
- <div className="text-xs text-muted-foreground">
- {formatDistanceToNow(new Date(row.original.created_at), {
- addSuffix: true,
- locale: ko,
- })}
- </div>
- ),
- size: 100,
- },
- {
- id: "actions",
- header: "작업",
- cell: ({ row }) => (
- <DownloadButton fileId={row.original.id} fileName={row.original.FILE_NM} />
- ),
- size: 120,
- },
];
-
-// ============================================================================
-// 다운로드 버튼 컴포넌트: 임시 구성. Download.aspx 동작 안해서 일단 네트워크드라이브 사용하도록 처리
-// ============================================================================
-
-interface DownloadButtonProps {
- fileId: number;
- fileName: string;
-}
-
-function DownloadButton({ fileId, fileName }: DownloadButtonProps) {
- const [isDownloading, setIsDownloading] = useState(false);
-
- const handleDownload = async () => {
- try {
- setIsDownloading(true);
-
- // API Route 호출 (바이너리 직접 전송)
- const response = await fetch(`/api/swp/download/${fileId}`);
-
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ error: "다운로드 실패" }));
- toast.error(errorData.error || "파일 다운로드 실패");
- return;
- }
-
- // Blob 생성 및 다운로드
- const blob = await response.blob();
- const url = window.URL.createObjectURL(blob);
- const link = document.createElement("a");
- link.href = url;
- link.download = fileName;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- window.URL.revokeObjectURL(url);
-
- toast.success(`파일 다운로드 완료: ${fileName}`);
- } catch (error) {
- console.error("다운로드 오류:", error);
- toast.error("파일 다운로드 중 오류가 발생했습니다.");
- } finally {
- setIsDownloading(false);
- }
- };
-
- return (
- <Button
- variant="outline"
- size="sm"
- onClick={handleDownload}
- disabled={isDownloading}
- >
- {isDownloading ? (
- <>
- <Loader2 className="h-4 w-4 mr-1 animate-spin" />
- 다운로드 중...
- </>
- ) : (
- <>
- <Download className="h-4 w-4 mr-1" />
- 다운로드
- </>
- )}
- </Button>
- );
-}
-