From 2ecdac866c19abea0b5389708fcdf5b3889c969a Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Wed, 29 Oct 2025 15:59:04 +0900 Subject: (김준회) SWP 파일 업로드 취소 기능 추가, 업로드 파일명 검증로직에서 파일명 비필수로 변경 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/swp/table/swp-table-columns.tsx | 353 ++---------------------------------- 1 file changed, 18 insertions(+), 335 deletions(-) (limited to 'lib/swp/table/swp-table-columns.tsx') 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[] = [ +export const swpDocumentColumns: ColumnDef[] = [ { id: "expander", header: () => null, - cell: () => { - return ( - - ); - }, + 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[] = [ ); }, - size: 100, + size: 120, }, { accessorKey: "DOC_NO", @@ -61,7 +44,7 @@ export const swpDocumentColumns: ColumnDef[] = [ accessorKey: "DOC_TITLE", header: "문서제목", cell: ({ row }) => ( -
+
{row.original.DOC_TITLE}
), @@ -74,7 +57,7 @@ export const swpDocumentColumns: ColumnDef[] = [
{row.original.PROJ_NO}
{row.original.PROJ_NM && ( -
+
{row.original.PROJ_NM}
)} @@ -127,325 +110,25 @@ export const swpDocumentColumns: ColumnDef[] = [ }, { 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 }) => (
- {row.original.revision_count} / {row.original.file_count} + {row.original.fileCount}개
+ {row.original.standbyFileCount > 0 && ( +
+ 대기중 {row.original.standbyFileCount} +
+ )}
), size: 100, }, - { - accessorKey: "last_synced_at", - header: "동기화", - cell: ({ row }) => ( -
- {formatDistanceToNow(new Date(row.original.last_synced_at), { - addSuffix: true, - locale: ko, - })} -
- ), - 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[] = [ - { - id: "expander", - header: () => null, - cell: ({ row }) => { - return row.getCanExpand() ? ( - - ) : null; - }, - size: 100, - }, - { - accessorKey: "REV_NO", - header: "리비전", - cell: ({ row }) => ( - - REV {row.original.REV_NO} - - ), - 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 ( - - {stage} - - ); - }, - size: 100, - }, - { - accessorKey: "OFDC_NO", - header: "OFDC 번호", - cell: ({ row }) => ( -
{row.original.OFDC_NO || "-"}
- ), - size: 200, - }, - { - accessorKey: "ACTV_NO", - header: "Activity", - cell: ({ row }) => ( -
- {row.original.ACTV_NO || "-"} -
- ), - size: 250, - }, - { - id: "file_count", - header: "파일 수", - cell: ({ row }) => ( -
- - {row.original.file_count} -
- ), - size: 100, - }, - { - accessorKey: "last_synced_at", - header: "동기화", - cell: ({ row }) => ( -
- {formatDistanceToNow(new Date(row.original.last_synced_at), { - addSuffix: true, - locale: ko, - })} -
- ), - 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[] = [ - { - id: "spacer", - header: () => null, - cell: () =>
, - size: 150, - }, - { - accessorKey: "FILE_SEQ", - header: "순서", - cell: ({ row }) => ( - - #{row.original.FILE_SEQ} - - ), - size: 80, - }, - { - accessorKey: "FILE_NM", - header: "파일명", - cell: ({ row }) => ( -
- - {row.original.FILE_NM} -
- ), - 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 ( - - {status} - - ); - }, - size: 100, - }, - { - accessorKey: "FLD_PATH", - header: "경로", - cell: ({ row }) => ( -
- {row.original.FLD_PATH || "-"} -
- ), - size: 200, - }, - { - accessorKey: "created_at", - header: "생성일", - cell: ({ row }) => ( -
- {formatDistanceToNow(new Date(row.original.created_at), { - addSuffix: true, - locale: ko, - })} -
- ), - size: 100, - }, - { - id: "actions", - header: "작업", - cell: ({ row }) => ( - - ), - 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 ( - - ); -} - -- cgit v1.2.3