"use client" import * as React from "react" import { type DataTableRowAction } from "@/types/table" import { type ColumnDef } from "@tanstack/react-table" import { Ellipsis, Eye, Calendar, AlertTriangle, CheckCircle2, Clock, FileText } from "lucide-react" import { formatDate, cn } from "@/lib/utils" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { Progress } from "@/components/ui/progress" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { useRouter } from "next/navigation" import { RfqDashboardView } from "@/db/schema" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" type NextRouter = ReturnType; interface GetRFQColumnsProps { setRowAction: React.Dispatch | null>>; router: NextRouter; } // 상태에 따른 Badge 변형 결정 함수 function getStatusBadge(status: string) { switch (status) { case "DRAFT": return { variant: "outline" as const, label: "초안" }; case "Doc. Received": return { variant: "secondary" as const, label: "문서접수" }; case "PIC Assigned": return { variant: "secondary" as const, label: "담당자배정" }; case "Doc. Confirmed": return { variant: "default" as const, label: "문서확정" }; case "Init. RFQ Sent": return { variant: "default" as const, label: "초기RFQ발송" }; case "Init. RFQ Answered": return { variant: "default" as const, label: "초기RFQ회신" }; case "TBE started": return { variant: "secondary" as const, label: "TBE시작" }; case "TBE finished": return { variant: "secondary" as const, label: "TBE완료" }; case "Final RFQ Sent": return { variant: "default" as const, label: "최종RFQ발송" }; case "Quotation Received": return { variant: "default" as const, label: "견적접수" }; case "Vendor Selected": return { variant: "success" as const, label: "업체선정" }; default: return { variant: "outline" as const, label: status }; } } function getProgressBadge(progress: number) { if (progress >= 100) { return { variant: "success" as const, label: "완료" }; } else if (progress >= 70) { return { variant: "default" as const, label: "진행중" }; } else if (progress >= 30) { return { variant: "secondary" as const, label: "초기진행" }; } else { return { variant: "outline" as const, label: "시작" }; } } function getUrgencyLevel(daysToDeadline: number): "high" | "medium" | "low" { if (daysToDeadline <= 3) return "high"; if (daysToDeadline <= 7) return "medium"; return "low"; } export function getRFQColumns({ setRowAction, router }: GetRFQColumnsProps): ColumnDef[] { // Select 컬럼 const selectColumn: ColumnDef = { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" className="translate-y-0.5" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" className="translate-y-0.5" /> ), size: 40, enableSorting: false, enableHiding: false, }; // RFQ 코드 컬럼 const rfqCodeColumn: ColumnDef = { accessorKey: "rfqCode", header: ({ column }) => ( ), cell: ({ row }) => (
{row.getValue("rfqCode")} {row.original.description && ( {row.original.description} )}
), }; // 프로젝트 정보 컬럼 const projectColumn: ColumnDef = { accessorKey: "projectName", header: ({ column }) => ( ), cell: ({ row }) => { const projectName = row.original.projectName; const projectCode = row.original.projectCode; if (!projectName) { return -; } return (
{projectName}
{projectCode && {projectCode}}
); }, }; // 패키지 정보 컬럼 const packageColumn: ColumnDef = { accessorKey: "packageNo", header: ({ column }) => ( ), cell: ({ row }) => { const packageNo = row.original.packageNo; const packageName = row.original.packageName; if (!packageNo) { return -; } return (
{packageNo} {packageName && ( {packageName} )}
); }, }; const updatedColumn: ColumnDef = { accessorKey: "updatedBy", header: ({ column }) => ( ), cell: ({ row }) => { const updatedByName = row.original.updatedByName; const updatedByEmail = row.original.updatedByEmail; if (!updatedByName) { return -; } return (
{updatedByName} {updatedByEmail && ( {updatedByEmail} )}
); }, }; // 상태 컬럼 const statusColumn: ColumnDef = { accessorKey: "status", header: ({ column }) => ( ), cell: ({ row }) => { const statusBadge = getStatusBadge(row.original.status); return {statusBadge.label}; }, filterFn: (row, id, value) => { return value.includes(row.getValue(id)); }, }; // 진행률 컬럼 const progressColumn: ColumnDef = { accessorKey: "overallProgress", header: ({ column }) => ( ), cell: ({ row }) => { const progress = row.original.overallProgress; const progressBadge = getProgressBadge(progress); return (
{progress}% {progressBadge.label}
); }, }; // 마감일 컬럼 const dueDateColumn: ColumnDef = { accessorKey: "dueDate", header: ({ column }) => ( ), cell: ({ row }) => { const dueDate = row.original.dueDate; const daysToDeadline = row.original.daysToDeadline; const urgencyLevel = getUrgencyLevel(daysToDeadline); if (!dueDate) { return -; } return (
{formatDate(dueDate, 'KR')}
{urgencyLevel === "high" && ( )} {urgencyLevel === "medium" && ( )} {urgencyLevel === "low" && ( )} {daysToDeadline > 0 ? `${daysToDeadline}일 남음` : daysToDeadline === 0 ? "오늘 마감" : `${Math.abs(daysToDeadline)}일 지남`}
); }, }; // 담당자 컬럼 const picColumn: ColumnDef = { accessorKey: "picName", header: ({ column }) => ( ), cell: ({ row }) => { const picName = row.original.picName; return picName ? ( {picName} ) : ( 미배정 ); }, }; const engPicColumn: ColumnDef = { accessorKey: "engPicName", header: ({ column }) => ( ), cell: ({ row }) => { const picName = row.original.engPicName; return picName ? ( {picName} ) : ( 미배정 ); }, }; const pjtCompanyColumn: ColumnDef = { accessorKey: "projectCompany", header: ({ column }) => ( ), cell: ({ row }) => { const projectCompany = row.original.projectCompany; return projectCompany ? ( {projectCompany} ) : ( - ); }, }; const pjtFlagColumn: ColumnDef = { accessorKey: "projectFlag", header: ({ column }) => ( ), cell: ({ row }) => { const projectFlag = row.original.projectFlag; return projectFlag ? ( {projectFlag} ) : ( - ); }, }; const pjtSiteColumn: ColumnDef = { accessorKey: "projectSite", header: ({ column }) => ( ), cell: ({ row }) => { const projectSite = row.original.projectSite; return projectSite ? ( {projectSite} ) : ( - ); }, }; const remarkColumn: ColumnDef = { accessorKey: "remark", header: ({ column }) => ( ), cell: ({ row }) => { const remark = row.original.remark; return remark ? ( {remark} ) : ( - ); }, }; // 첨부파일 수 컬럼 const attachmentColumn: ColumnDef = { accessorKey: "totalAttachments", header: ({ column }) => ( ), cell: ({ row }) => { const count = row.original.totalAttachments; return (
{count}
); }, }; // 벤더 현황 컬럼 const vendorStatusColumn: ColumnDef = { accessorKey: "initialVendorCount", header: ({ column }) => ( ), cell: ({ row }) => { const initial = row.original.initialVendorCount; const final = row.original.finalVendorCount; const initialRate = row.original.initialResponseRate; const finalRate = row.original.finalResponseRate; return (
초기: {initial}개사 ({Number(initialRate).toFixed(0)}%)
최종: {final}개사 ({Number(finalRate).toFixed(0)}%)
); }, }; // 생성일 컬럼 const createdAtColumn: ColumnDef = { accessorKey: "createdAt", header: ({ column }) => ( ), cell: ({ row }) => { const dateVal = row.original.createdAt as Date; return formatDate(dateVal, 'KR'); }, }; const updatedAtColumn: ColumnDef = { accessorKey: "updatedAt", header: ({ column }) => ( ), cell: ({ row }) => { const dateVal = row.original.updatedAt as Date; return formatDate(dateVal, 'KR'); }, }; // Actions 컬럼 const actionsColumn: ColumnDef = { id: "detail", header: ({ column }) => ( ), // enableHiding: false, cell: function Cell({ row }) { const rfq = row.original; const detailUrl = `/evcp/b-rfq/${rfq.rfqId}/initial`; return ( ); }, size: 40, }; return [ selectColumn, rfqCodeColumn, projectColumn, packageColumn, statusColumn, picColumn, progressColumn, dueDateColumn, actionsColumn, engPicColumn, pjtCompanyColumn, pjtFlagColumn, pjtSiteColumn, attachmentColumn, vendorStatusColumn, createdAtColumn, updatedAtColumn, updatedColumn, remarkColumn ]; }