summaryrefslogtreecommitdiff
path: root/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx')
-rw-r--r--lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx556
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