diff options
Diffstat (limited to 'lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx')
| -rw-r--r-- | lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx b/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx new file mode 100644 index 00000000..1ec0284f --- /dev/null +++ b/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx @@ -0,0 +1,556 @@ +"use client" + +import * as React from "react" +import { type DataTableRowAction } from "@/types/table" +import { type ColumnDef } from "@tanstack/react-table" +import { + Ellipsis, + InfoIcon, + PenToolIcon, + FileTextIcon, + ClipboardListIcon, + CheckIcon, + XIcon, + ClockIcon, + Send, + User, + Calendar +} from "lucide-react" + +import { formatDate, formatCurrency } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { Checkbox } from "@/components/ui/checkbox" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { Badge } from "@/components/ui/badge" +import { useRouter } from "next/navigation" + +import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" +import { ReviewerEvaluationView } from "@/db/schema" + + +type NextRouter = ReturnType<typeof useRouter>; + +interface GetColumnsProps { + setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<ReviewerEvaluationView> | null>> + router: NextRouter; + +} + +/** + * 평가 진행 상태에 따른 배지 스타일 + */ +const getProgressBadge = (isCompleted: boolean, completedAt: Date | null) => { + if (isCompleted && completedAt) { + return { + variant: "default" as const, + icon: <CheckIcon className="h-3 w-3" />, + label: "완료", + className: "bg-green-100 text-green-800 border-green-200" + } + } else { + return { + variant: "secondary" as const, + icon: <ClockIcon className="h-3 w-3" />, + label: "미완료" + } + } +} + +/** + * 정기평가 상태에 따른 배지 스타일 + */ +const getPeriodicStatusBadge = (status: string) => { + switch (status) { + case 'PENDING': + return { + variant: "secondary" as const, + icon: <ClockIcon className="h-3 w-3" />, + label: "대기중" + } + + case 'PENDING_SUBMISSION': + return { + variant: "secondary" as const, + icon: <ClockIcon className="h-3 w-3" />, + label: "업체 제출 대기중" + } + case 'IN_PROGRESS': + return { + variant: "default" as const, + icon: <PenToolIcon className="h-3 w-3" />, + label: "진행중" + } + case 'REVIEW': + return { + variant: "outline" as const, + icon: <ClipboardListIcon className="h-3 w-3" />, + label: "검토중" + } + case 'COMPLETED': + return { + variant: "default" as const, + icon: <CheckIcon className="h-3 w-3" />, + label: "완료", + className: "bg-green-100 text-green-800 border-green-200" + } + default: + return { + variant: "secondary" as const, + icon: null, + label: status + } + } +} + +/** + * 평가 제출 테이블 컬럼 정의 + */ +export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef<ReviewerEvaluationView>[] { + + // ---------------------------------------------------------------- + // 1) select 컬럼 (체크박스) + // ---------------------------------------------------------------- + const selectColumn: ColumnDef<ReviewerEvaluationView> = { + id: "select", + header: ({ table }) => ( + <Checkbox + checked={ + table.getIsAllPageRowsSelected() || + (table.getIsSomePageRowsSelected() && "indeterminate") + } + onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + className="translate-y-0.5" + /> + ), + cell: ({ row }) => ( + <Checkbox + checked={row.getIsSelected()} + onCheckedChange={(value) => row.toggleSelected(!!value)} + aria-label="Select row" + className="translate-y-0.5" + /> + ), + enableSorting: false, + enableHiding: false, + size: 40, + } + + // ---------------------------------------------------------------- + // 2) 기본 정보 컬럼들 + // ---------------------------------------------------------------- + const basicColumns: ColumnDef<ReviewerEvaluationView>[] = [ + { + accessorKey: "evaluationYear", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="평가연도" /> + ), + cell: ({ row }) => ( + <Badge variant="outline"> + {row.getValue("evaluationYear")}년 + </Badge> + ), + size: 80, + }, + + { + id: "vendorInfo", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="협력업체" /> + ), + cell: ({ row }) => { + const vendorName = row.original.vendorName; + const vendorCode = row.original.vendorCode; + const domesticForeign = row.original.domesticForeign; + + return ( + <div className="space-y-1"> + <div className="font-medium">{vendorName}</div> + <div className="text-sm text-muted-foreground"> + {vendorCode} • {domesticForeign === 'DOMESTIC' ? 'D' : 'F'} + </div> + </div> + ); + }, + enableSorting: false, + size: 200, + }, + + + { + id: "materialType", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="자재구분" /> + ), + cell: ({ row }) => { + const materialType = row.original.materialType; + const material = materialType ==="BULK" ? "벌크": materialType ==="EQUIPMENT" ? "기자재" :"기자재/벌크" + + return ( + <div className="space-y-1"> + <div className="font-medium">{material}</div> + + </div> + ); + }, + enableSorting: false, + }, + + { + id: "division", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="division" /> + ), + cell: ({ row }) => { + const division = row.original.division; + const divisionKR = division === "PLANT"?"해양":"조선"; + + return ( + <div className="space-y-1"> + <div className="font-medium">{divisionKR}</div> + + </div> + ); + }, + enableSorting: false, + }, + ] + + // ---------------------------------------------------------------- + // 3) 상태 정보 컬럼들 + // ---------------------------------------------------------------- + const statusColumns: ColumnDef<ReviewerEvaluationView>[] = [ + { + id: "evaluationProgress", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="평가 진행상태" /> + ), + cell: ({ row }) => { + const isCompleted = row.original.isCompleted; + const completedAt = row.original.completedAt; + const badgeInfo = getProgressBadge(isCompleted, completedAt); + + return ( + <div className="space-y-1"> + <Badge + variant={badgeInfo.variant} + className={`flex items-center gap-1 ${badgeInfo.className || ''}`} + > + {badgeInfo.icon} + {badgeInfo.label} + </Badge> + {completedAt && ( + <div className="text-xs text-muted-foreground"> + {formatDate(completedAt,"KR")} + </div> + )} + </div> + ); + }, + size: 130, + }, + + { + id: "periodicStatus", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="정기평가 상태" /> + ), + cell: ({ row }) => { + const status = row.original.periodicStatus; + const badgeInfo = getPeriodicStatusBadge(status); + + return ( + <Badge + variant={badgeInfo.variant} + className={`flex items-center gap-1 ${badgeInfo.className || ''}`} + > + {badgeInfo.icon} + {badgeInfo.label} + </Badge> + ); + }, + size: 120, + }, + + // { + // id: "submissionInfo", + // header: ({ column }) => ( + // <DataTableColumnHeaderSimple column={column} title="제출정보" /> + // ), + // cell: ({ row }) => { + // // const submissionDate = row.original.submittedAt; + // const completedAt = row.original.completedAt; + + // return ( + // <div className="space-y-1"> + // <div className="flex items-center gap-1"> + // <Badge variant={submissionDate ? "default" : "secondary"}> + // {submissionDate ? "제출완료" : "미제출"} + // </Badge> + // </div> + + // {completedAt && ( + // <div className="text-xs text-muted-foreground"> + // 평가완료: {formatDate(completedAt, "KR")} + // </div> + // )} + // {/* {submissionDate && ( + // <div className="text-xs text-muted-foreground"> + // 제출: {formatDate(submissionDate, "KR")} + // </div> + // )} */} + + // </div> + // ); + // }, + // enableSorting: false, + // size: 140, + // }, + ] + + // ---------------------------------------------------------------- + // 4) 점수 및 평가 정보 컬럼들 + // ---------------------------------------------------------------- + const scoreColumns: ColumnDef<ReviewerEvaluationView>[] = [ + { + id: "periodicScores", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="정기평가 점수" /> + ), + cell: ({ row }) => { + const finalScore = row.original.periodicFinalScore; + const finalGrade = row.original.periodicFinalGrade; + const evaluationScore = row.original.periodicEvaluationScore; + const evaluationGrade = row.original.periodicEvaluationGrade; + + return ( + <div className="text-center space-y-1"> + {finalScore && finalGrade ? ( + <div className="space-y-1"> + <div className="font-medium text-blue-600"> + 최종: {parseFloat(finalScore.toString()).toFixed(1)}점 + </div> + <Badge variant="outline">{finalGrade}</Badge> + </div> + ) : evaluationScore && evaluationGrade ? ( + <div className="space-y-1"> + <div className="font-medium"> + {parseFloat(evaluationScore.toString()).toFixed(1)}점 + </div> + <Badge variant="outline">{evaluationGrade}</Badge> + </div> + ) : ( + <span className="text-muted-foreground">미산정</span> + )} + </div> + ); + }, + enableSorting: false, + size: 120, + }, + + ] + + + + // ---------------------------------------------------------------- + // 6) 메타데이터 컬럼들 + // ---------------------------------------------------------------- + const metaColumns: ColumnDef<ReviewerEvaluationView>[] = [ + { + accessorKey: "reviewerEvaluationCreatedAt", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="생성일" /> + ), + cell: ({ row }) => { + const date = row.getValue("reviewerEvaluationCreatedAt") as Date; + return formatDate(date); + }, + size: 140, + }, + { + accessorKey: "reviewerEvaluationUpdatedAt", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="수정일" /> + ), + cell: ({ row }) => { + const date = row.getValue("reviewerEvaluationUpdatedAt") as Date; + return formatDate(date); + }, + size: 140, + }, + ] + + // ---------------------------------------------------------------- + // 7) actions 컬럼 (드롭다운 메뉴) + // ---------------------------------------------------------------- + const actionsColumn: ColumnDef<ReviewerEvaluationView> = { + id: "actions", + header: "작업", + enableHiding: false, + cell: function Cell({ row }) { + const isCompleted = row.original.isCompleted; + const reviewerEvaluationId = row.original.reviewerEvaluationId; + + return ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="ghost" size="icon"> + <Ellipsis className="h-4 w-4" /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuItem + onClick={() => router.push(`/evcp/evaluation-input/${reviewerEvaluationId}`)} + > + {isCompleted ? "완료된 평가보기":"평가 작성하기"} + </DropdownMenuItem> + + </DropdownMenuContent> + </DropdownMenu> + ) + }, + size: 80, + } + + // ---------------------------------------------------------------- + // 8) 최종 컬럼 배열 + // ---------------------------------------------------------------- + return [ + selectColumn, + ...basicColumns, + { + id: "statusInfo", + header: "상태 정보", + columns: statusColumns, + }, + { + id: "scoreInfo", + header: "점수 및 평가", + columns: scoreColumns, + }, + + { + id: "metadata", + header: "메타데이터", + columns: metaColumns, + }, + actionsColumn, + ] +} + +// ---------------------------------------------------------------- +// 9) 컬럼 설정 (필터링용) +// ---------------------------------------------------------------- +export const evaluationSubmissionsColumnsConfig = [ + { + id: "reviewerEvaluationId", + label: "평가 ID", + group: "기본 정보", + type: "text", + excelHeader: "Evaluation ID", + }, + { + id: "vendorName", + label: "협력업체명", + group: "기본 정보", + type: "text", + excelHeader: "Vendor Name", + }, + { + id: "vendorCode", + label: "협력업체 코드", + group: "기본 정보", + type: "text", + excelHeader: "Vendor Code", + }, + { + id: "evaluationYear", + label: "평가연도", + group: "기본 정보", + type: "number", + excelHeader: "Evaluation Year", + }, + { + id: "departmentCode", + label: "부서코드", + group: "기본 정보", + type: "text", + excelHeader: "Department Code", + }, + { + id: "isCompleted", + label: "완료 여부", + group: "상태 정보", + type: "select", + options: [ + { label: "완료", value: "true" }, + { label: "미완료", value: "false" }, + ], + excelHeader: "Is Completed", + }, + { + id: "periodicStatus", + label: "정기평가 상태", + group: "상태 정보", + type: "select", + options: [ + { label: "대기중", value: "PENDING" }, + { label: "진행중", value: "IN_PROGRESS" }, + { label: "검토중", value: "REVIEW" }, + { label: "완료", value: "COMPLETED" }, + ], + excelHeader: "Periodic Status", + }, + { + id: "documentsSubmitted", + label: "문서 제출여부", + group: "상태 정보", + type: "select", + options: [ + { label: "제출완료", value: "true" }, + { label: "미제출", value: "false" }, + ], + excelHeader: "Documents Submitted", + }, + { + id: "periodicFinalScore", + label: "최종점수", + group: "점수 정보", + type: "number", + excelHeader: "Final Score", + }, + { + id: "periodicFinalGrade", + label: "최종등급", + group: "점수 정보", + type: "text", + excelHeader: "Final Grade", + }, + { + id: "reviewerEvaluationCreatedAt", + label: "생성일", + group: "메타데이터", + type: "date", + excelHeader: "Created At", + }, + { + id: "reviewerEvaluationUpdatedAt", + label: "수정일", + group: "메타데이터", + type: "date", + excelHeader: "Updated At", + }, +] as const;
\ No newline at end of file |
