diff options
Diffstat (limited to 'lib/rfq-last/table/rfq-table-columns.tsx')
| -rw-r--r-- | lib/rfq-last/table/rfq-table-columns.tsx | 338 |
1 files changed, 337 insertions, 1 deletions
diff --git a/lib/rfq-last/table/rfq-table-columns.tsx b/lib/rfq-last/table/rfq-table-columns.tsx index 62f14579..58c45aa0 100644 --- a/lib/rfq-last/table/rfq-table-columns.tsx +++ b/lib/rfq-last/table/rfq-table-columns.tsx @@ -24,7 +24,7 @@ type NextRouter = ReturnType<typeof useRouter>; interface GetColumnsProps { setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<RfqsLastView> | null>>; - rfqCategory?: "general" | "itb" | "rfq"; + rfqCategory?: "general" | "itb" | "rfq" | "pre_bidding"; router: NextRouter; } @@ -756,6 +756,342 @@ export function getRfqColumns({ } // ═══════════════════════════════════════════════════════════════ + // 사전견적(입찰) 컬럼 정의 + // ═══════════════════════════════════════════════════════════════ + if (rfqCategory === "pre_bidding") { + return [ + // Checkbox + { + id: "select", + header: ({ table }) => ( + <Checkbox + checked={table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && "indeterminate")} + onCheckedChange={(v) => table.toggleAllPageRowsSelected(!!v)} + aria-label="select all" + className="translate-y-0.5" + /> + ), + cell: ({ row }) => ( + <Checkbox + checked={row.getIsSelected()} + onCheckedChange={(v) => row.toggleSelected(!!v)} + aria-label="select row" + className="translate-y-0.5" + /> + ), + size: 40, + enableSorting: false, + enableHiding: false, + }, + + // 견적 No. + { + accessorKey: "rfqCode", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적 No." />, + cell: ({ row }) => ( + <span className="font-mono font-medium">{row.original.rfqCode}</span> + ), + size: 120, + }, + + // 입찰 No. (추가) + { + accessorKey: "biddingNumber", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="입찰 No." />, + cell: ({ row }) => ( + <span className="font-mono font-medium">{row.original.biddingNumber || "-"}</span> + ), + size: 120, + }, + + // 상세 - 수정됨 + { + id: "detail", + header: "상세", + cell: ({ row }) => ( + <Button + variant="ghost" + size="icon" + className="h-8 w-8" + onClick={() => router.push(`/evcp/rfq-last/${row.original.id}`)} + > + <Eye className="h-4 w-4" /> + </Button> + ), + size: 60, + }, + + // 견적상태 + { + accessorKey: "status", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적상태" />, + cell: ({ row }) => ( + <Badge variant={getStatusBadgeVariant(row.original.status)}> + {row.original.status} + </Badge> + ), + size: 120, + }, + + // 프로젝트 (프로젝트명) + { + accessorKey: "projectName", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="프로젝트 (프로젝트명)" />, + cell: ({ row }) => ( + <div className="flex flex-col"> + <span className="font-mono text-xs text-muted-foreground"> + {row.original.projectCode} + </span> + <span className="max-w-[200px] truncate" title={row.original.projectName || ""}> + {row.original.projectName || "-"} + </span> + </div> + ), + size: 220, + }, + + // // 시리즈 + // { + // accessorKey: "series", + // header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="시리즈" />, + // cell: ({ row }) => { + // const series = row.original.series; + // if (!series) return "-"; + // const label = series === "SS" ? "시리즈 통합" : series === "II" ? "품목 통합" : series; + // return <Badge variant="outline">{label}</Badge>; + // }, + // size: 100, + // }, + + // // 선급 + // { + // accessorKey: "classNo", + // header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="선급" />, + // cell: ({ row }) => row.original.classNo || "-", + // size: 80, + // }, + + // 견적명 + { + accessorKey: "rfqTitle", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적명" />, + cell: ({ row }) => ( + <div className="max-w-[200px] truncate" title={row.original.rfqTitle || ""}> + {row.original.rfqTitle || "-"} + </div> + ), + size: 200, + }, + + // 자재그룹 (자재그룹명) + { + accessorKey: "majorItemMaterialDescription", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="자재그룹 (자재그룹명)" />, + cell: ({ row }) => ( + <div className="flex flex-col"> + <span className="font-mono text-xs text-muted-foreground"> + {row.original.majorItemMaterialCategory} + </span> + <span className="max-w-[150px] truncate" title={row.original.majorItemMaterialDescription || ""}> + {row.original.majorItemMaterialDescription || "-"} + </span> + </div> + ), + size: 180, + }, + + // 자재코드 + { + accessorKey: "itemCode", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="자재코드" />, + cell: ({ row }) => ( + <span className="font-mono text-sm">{row.original.itemCode || "-"}</span> + ), + size: 100, + }, + // 자재명 + { + accessorKey: "itemName", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="자재명" />, + cell: ({ row }) => ( + <span className="font-mono text-sm">{row.original.itemName || "-"}</span> + ), + size: 100, + }, + + // 견적 자료 + { + id: "rfqDocument", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적 자료" />, + cell: ({ row }) => ( + <Button + variant="ghost" + size="sm" + onClick={() => setRowAction({ row, type: "attachment" })} + > + <FileText className="h-4 w-4" /> + </Button> + ), + size: 80, + }, + + // 견적품목수 + { + accessorKey: "prItemsCount", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적품목수" />, + cell: ({ row }) => ( + <Button + variant="ghost" + size="sm" + className="font-mono text-sm p-1 h-auto" + onClick={() => setRowAction({ row, type: "items" })} + > + {row.original.prItemsCount || 0} + </Button> + ), + size: 90, + }, + + // 견적생성일 + { + accessorKey: "createdAt", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적생성일" />, + cell: ({ row }) => { + const date = row.original.createdAt; + return date ? format(new Date(date), "yyyy-MM-dd") : "-"; + }, + size: 100, + }, + + // 견적발송일 + { + accessorKey: "rfqSendDate", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적발송일" />, + cell: ({ row }) => { + const date = row.original.rfqSendDate; + return date ? format(new Date(date), "yyyy-MM-dd") : "-"; + }, + size: 100, + }, + + // 견적마감일 + { + accessorKey: "dueDate", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="견적마감일" />, + cell: ({ row }) => { + const date = row.original.dueDate; + if (!date) return "-"; + + const now = new Date(); + const dueDate = new Date(date); + const daysLeft = differenceInDays(dueDate, now); + + // 상태별 스타일과 아이콘 설정 + let statusIcon; + let statusText; + let statusClass; + + if (daysLeft < 0) { + const daysOverdue = Math.abs(daysLeft); + statusIcon = <XCircle className="h-4 w-4" />; + statusText = `${daysOverdue}일 지남`; + statusClass = "text-red-600"; + } else if (daysLeft === 0) { + statusIcon = <AlertTriangle className="h-4 w-4" />; + statusText = "오늘 마감"; + statusClass = "text-orange-600"; + } else if (daysLeft <= 3) { + statusIcon = <AlertCircle className="h-4 w-4" />; + statusText = `${daysLeft}일 남음`; + statusClass = "text-amber-600"; + } else if (daysLeft <= 7) { + statusIcon = <Clock className="h-4 w-4" />; + statusText = `${daysLeft}일 남음`; + statusClass = "text-blue-600"; + } else { + statusIcon = <CheckCircle className="h-4 w-4" />; + statusText = `${daysLeft}일 남음`; + statusClass = "text-green-600"; + } + + return ( + <div className="flex flex-col gap-1"> + <span className="text-sm text-muted-foreground"> + {format(dueDate, "yyyy-MM-dd")} + </span> + <div className={`flex items-center gap-1 ${statusClass}`}> + {statusIcon} + <span className="text-xs font-medium">{statusText}</span> + </div> + </div> + ); + }, + size: 120, + }, + + // 계약기간 (추가) + { + id: "contractPeriod", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="계약기간" />, + cell: ({ row }) => { + const start = row.original.contractStartDate; + const end = row.original.contractEndDate; + + if (!start && !end) return "-"; + + return ( + <div className="flex flex-col text-xs"> + <span>{start ? format(new Date(start), "yyyy-MM-dd") : "미정"}</span> + <span className="text-muted-foreground">~</span> + <span>{end ? format(new Date(end), "yyyy-MM-dd") : "미정"}</span> + </div> + ); + }, + size: 120, + }, + + // 구매담당자 + { + accessorKey: "picUserName", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="구매담당자" />, + cell: ({ row }) => { + const name = row.original.picUserName || row.original.picName || "-"; + const picCode = row.original.picCode || ""; + return name === "-" ? "-" : `${name}(${picCode})`; + }, + size: 100, + }, + + // 최종수정일 + { + accessorKey: "updatedAt", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종수정일" />, + cell: ({ row }) => { + const date = row.original.updatedAt; + return date ? format(new Date(date), "yyyy-MM-dd HH:mm") : "-"; + }, + size: 120, + }, + + // 최종수정자 + { + accessorKey: "updatedByUserName", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종수정자" />, + cell: ({ row }) => row.original.updatedByUserName || "-", + size: 100, + }, + + // 비고 + { + accessorKey: "remark", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="비고" />, + cell: ({ row }) => row.original.remark || "-", + size: 150, + }, + ]; + } + + // ═══════════════════════════════════════════════════════════════ // 일반견적 컬럼 정의 // ═══════════════════════════════════════════════════════════════ if (rfqCategory === "general") { |
