"use client" import * as React from "react" import { type ColumnDef } from "@tanstack/react-table" import { Checkbox } from "@/components/ui/checkbox" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Eye, Edit, MoreHorizontal, FileX } from "lucide-react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { BiddingListItem } from "@/db/schema" import { DataTableRowAction } from "@/types/table" // BiddingListItem에 manager 정보 추가 type BiddingListItemWithManagerCode = BiddingListItem & { bidPicName?: string | null supplyPicName?: string | null } import { biddingStatusLabels, contractTypeLabels, biddingTypeLabels, } from "@/db/schema" import { formatDate } from "@/lib/utils" interface GetColumnsProps { setRowAction: React.Dispatch | null>> } // 상태별 배지 색상 const getStatusBadgeVariant = (status: string) => { switch (status) { case 'bidding_generated': return 'outline' case 'request_for_quotation': case 'received_quotation': return 'secondary' case 'set_target_price': case 'bidding_opened': return 'default' case 'bidding_closed': case 'evaluation_of_bidding': return 'default' case 'vendor_selected': return 'default' case 'bidding_disposal': return 'destructive' default: return 'outline' } } export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef[] { return [ // ═══════════════════════════════════════════════════════════════ // 선택 및 기본 정보 // ═══════════════════════════════════════════════════════════════ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!v)} aria-label="select all" className="translate-y-0.5" /> ), cell: ({ row }) => ( row.toggleSelected(!!v)} aria-label="select row" className="translate-y-0.5" /> ), size: 40, enableSorting: false, enableHiding: false, }, // ░░░ 입찰 No. ░░░ { accessorKey: "biddingNumber", header: ({ column }) => , cell: ({ row }) => (
{row.original.biddingNumber} {row.original.revision > 0 && ( Rev.{row.original.revision} )}
), size: 120, meta: { excelHeader: "입찰 No." }, }, // ░░░ 원입찰번호 ░░░ { accessorKey: "originalBiddingNumber", header: ({ column }) => , cell: ({ row }) => (
{row.original.originalBiddingNumber || '-'}
), size: 120, meta: { excelHeader: "원입찰번호" }, }, // ░░░ 프로젝트명 ░░░ { accessorKey: "projectName", header: ({ column }) => , cell: ({ row }) => (
{row.original.projectName || '-'}
), size: 150, meta: { excelHeader: "프로젝트명" }, }, // ░░░ 입찰명 ░░░ { accessorKey: "title", header: ({ column }) => , cell: ({ row }) => (
), size: 200, meta: { excelHeader: "입찰명" }, }, // ░░░ 계약구분 ░░░ { accessorKey: "contractType", header: ({ column }) => , cell: ({ row }) => ( {contractTypeLabels[row.original.contractType]} ), size: 100, meta: { excelHeader: "계약구분" }, }, // ░░░ 입찰상태 ░░░ { accessorKey: "status", header: ({ column }) => , cell: ({ row }) => ( {biddingStatusLabels[row.original.status]} ), size: 120, meta: { excelHeader: "진행상태" }, }, // ░░░ 입찰유형 ░░░ { accessorKey: "biddingType", header: ({ column }) => , cell: ({ row }) => ( {biddingTypeLabels[row.original.biddingType]} ), size: 100, meta: { excelHeader: "입찰유형" }, }, // ░░░ 통화 ░░░ { accessorKey: "currency", header: ({ column }) => , cell: ({ row }) => ( {row.original.currency} ), size: 60, meta: { excelHeader: "통화" }, }, // ░░░ 예산 ░░░ { accessorKey: "budget", header: ({ column }) => , cell: ({ row }) => ( {row.original.budget} ), size: 120, meta: { excelHeader: "예산" }, }, // ░░░ 내정가 ░░░ { accessorKey: "targetPrice", header: ({ column }) => , cell: ({ row }) => ( {row.original.targetPrice} ), size: 120, meta: { excelHeader: "내정가" }, }, // ░░░ 입찰담당자 ░░░ { accessorKey: "bidPicName", header: ({ column }) => , cell: ({ row }) => { const name = row.original.bidPicName || "-"; return name; }, size: 100, meta: { excelHeader: "입찰담당자" }, }, // ░░░ 입찰등록일 ░░░ { accessorKey: "biddingRegistrationDate", header: ({ column }) => , cell: ({ row }) => ( {formatDate(row.original.biddingRegistrationDate , "KR")} ), size: 100, meta: { excelHeader: "입찰등록일" }, }, { id: "submissionPeriod", header: ({ column }) => , cell: ({ row }) => { const startDate = row.original.submissionStartDate const endDate = row.original.submissionEndDate if (!startDate || !endDate) return - const now = new Date() const isActive = now >= new Date(startDate) && now <= new Date(endDate) const isPast = now > new Date(endDate) return (
{formatDate(startDate, "KR")} ~ {formatDate(endDate, "KR")}
{isActive && ( 진행중 )}
) }, size: 140, meta: { excelHeader: "입찰서제출기간" }, }, // ░░░ 사양설명회 ░░░ { accessorKey: "hasSpecificationMeeting", header: ({ column }) => , cell: ({ row }) => { const hasMeeting = row.original.hasSpecificationMeeting return ( ) }, size: 100, meta: { excelHeader: "사양설명회" }, }, // ░░░ 등록자 ░░░ { accessorKey: "updatedBy", header: ({ column }) => , cell: ({ row }) => ( {row.original.updatedBy || '-'} ), size: 100, meta: { excelHeader: "등록자" }, }, // 등록일시 { accessorKey: "updatedAt", header: ({ column }) => , cell: ({ row }) => ( {formatDate(row.original.updatedAt, "KR")} ), size: 100, meta: { excelHeader: "등록일시" }, }, // ═══════════════════════════════════════════════════════════════ // PR 정보 // ═══════════════════════════════════════════════════════════════ // { // header: "PR 정보", // columns: [ // { // accessorKey: "prNumber", // header: ({ column }) => , // cell: ({ row }) => ( // {row.original.prNumber || '-'} // ), // size: 100, // meta: { excelHeader: "PR No." }, // }, // { // accessorKey: "hasPrDocument", // header: ({ column }) => , // cell: ({ row }) => { // const hasPrDoc = row.original.hasPrDocument // return ( // // ) // }, // size: 80, // meta: { excelHeader: "PR 문서" }, // }, // ] // }, // ░░░ 비고 ░░░ { accessorKey: "remarks", header: ({ column }) => , cell: ({ row }) => (
{row.original.remarks || '-'}
), size: 150, meta: { excelHeader: "비고" }, }, // ═══════════════════════════════════════════════════════════════ // 액션 // ═══════════════════════════════════════════════════════════════ { id: "actions", header: "액션", cell: ({ row }) => ( setRowAction({ row, type: "view" })}> 상세보기 setRowAction({ row, type: "update" })} disabled={['bidding_opened', 'bidding_closed', 'vendor_selected'].includes(row.original.status)} > 수정 {['bidding_opened', 'bidding_closed', 'vendor_selected'].includes(row.original.status) && ( (수정 불가) )} setRowAction({ row, type: "bid_closure" })} disabled={row.original.status !== 'bidding_disposal'} > 폐찰하기 {row.original.status !== 'bidding_disposal' && ( (유찰 시에만 가능) )} {/* setRowAction({ row, type: "copy" })}> 복사 생성 setRowAction({ row, type: "manage_companies" })}> 참여업체 관리 */} ), size: 50, enableSorting: false, enableHiding: false, }, ] }