diff options
Diffstat (limited to 'lib/evaluation/table/evaluation-columns.tsx')
| -rw-r--r-- | lib/evaluation/table/evaluation-columns.tsx | 341 |
1 files changed, 232 insertions, 109 deletions
diff --git a/lib/evaluation/table/evaluation-columns.tsx b/lib/evaluation/table/evaluation-columns.tsx index 821e8182..10aa7704 100644 --- a/lib/evaluation/table/evaluation-columns.tsx +++ b/lib/evaluation/table/evaluation-columns.tsx @@ -144,14 +144,14 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): }, // ░░░ 평가기간 ░░░ - { - accessorKey: "evaluationPeriod", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가기간" />, - cell: ({ row }) => ( - <Badge variant="outline">{row.getValue("evaluationPeriod")}</Badge> - ), - size: 100, - }, + // { + // accessorKey: "evaluationPeriod", + // header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가기간" />, + // cell: ({ row }) => ( + // <Badge variant="outline">{row.getValue("evaluationPeriod")}</Badge> + // ), + // size: 100, + // }, // ░░░ 구분 ░░░ { @@ -202,12 +202,113 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): }, ] }, + + { + accessorKey: "finalScore", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="확정점수" />, + cell: ({ row }) => { + const finalScore = row.getValue<number>("finalScore"); + return finalScore ? ( + <span className="font-bold text-green-600">{finalScore.toFixed(1)}</span> + ) : ( + <span className="text-muted-foreground">-</span> + ); + }, + size: 90, + }, + { + accessorKey: "finalGrade", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="확정등급" />, + cell: ({ row }) => { + const finalGrade = row.getValue<string>("finalGrade"); + return finalGrade ? ( + <Badge variant={getGradeBadgeVariant(finalGrade)} className="bg-green-600"> + {finalGrade} + </Badge> + ) : ( + <span className="text-muted-foreground">-</span> + ); + }, + size: 90, + }, + + // ═══════════════════════════════════════════════════════════════ + // 진행 현황 + // ═══════════════════════════════════════════════════════════════ + { + header: "평가자 진행 현황", + columns: [ + { + accessorKey: "status", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="진행상태" />, + cell: ({ row }) => { + const status = row.getValue<string>("status"); + return ( + <Badge variant={getStatusBadgeVariant(status)}> + {getStatusLabel(status)} + </Badge> + ); + }, + size: 100, + }, + + { + id: "reviewProgress", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="리뷰진행" />, + cell: ({ row }) => { + const totalReviewers = row.original.totalReviewers || 0; + const completedReviewers = row.original.completedReviewers || 0; + + return getProgressBadge(completedReviewers, totalReviewers); + }, + size: 120, + }, + + { + accessorKey: "reviewCompletedAt", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="검토완료일" />, + cell: ({ row }) => { + const completedAt = row.getValue<Date>("reviewCompletedAt"); + return completedAt ? ( + <span className="text-sm"> + {new Intl.DateTimeFormat("ko-KR", { + month: "2-digit", + day: "2-digit", + }).format(new Date(completedAt))} + </span> + ) : ( + <span className="text-muted-foreground">-</span> + ); + }, + size: 100, + }, + + { + accessorKey: "finalizedAt", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="확정일" />, + cell: ({ row }) => { + const finalizedAt = row.getValue<Date>("finalizedAt"); + return finalizedAt ? ( + <span className="text-sm font-medium"> + {new Intl.DateTimeFormat("ko-KR", { + month: "2-digit", + day: "2-digit", + }).format(new Date(finalizedAt))} + </span> + ) : ( + <span className="text-muted-foreground">-</span> + ); + }, + size: 80, + }, + ] + }, // ═══════════════════════════════════════════════════════════════ // 제출 현황 // ═══════════════════════════════════════════════════════════════ { - header: "제출 현황", + header: "협력업체 제출 현황", columns: [ { accessorKey: "documentsSubmitted", @@ -266,6 +367,8 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): ] }, + + // ═══════════════════════════════════════════════════════════════ // 평가 점수 // ═══════════════════════════════════════════════════════════════ @@ -273,12 +376,12 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): header: "평가 점수", columns: [ { - accessorKey: "totalScore", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="총점" />, + accessorKey: "processScore", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="공정" />, cell: ({ row }) => { - const score = row.getValue<number>("totalScore"); + const score = row.getValue("processScore"); return score ? ( - <span className="font-medium">{score.toFixed(1)}</span> + <span className="font-medium">{Number(score).toFixed(1)}</span> ) : ( <span className="text-muted-foreground">-</span> ); @@ -287,156 +390,176 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): }, { - accessorKey: "evaluationGrade", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="등급" />, + accessorKey: "priceScore", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="가격" />, cell: ({ row }) => { - const grade = row.getValue<string>("evaluationGrade"); - return grade ? ( - <Badge variant={getGradeBadgeVariant(grade)}>{grade}</Badge> + const score = row.getValue("priceScore"); + return score ? ( + <span className="font-medium">{Number(score).toFixed(1)}</span> ) : ( <span className="text-muted-foreground">-</span> ); }, - size: 60, + size: 80, }, - + { - accessorKey: "finalScore", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종점수" />, + accessorKey: "deliveryScore", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="납기" />, cell: ({ row }) => { - const finalScore = row.getValue<number>("finalScore"); - return finalScore ? ( - <span className="font-bold text-green-600">{finalScore.toFixed(1)}</span> + const score = row.getValue("deliveryScore"); + return score ? ( + <span className="font-medium">{Number(score).toFixed(1)}</span> ) : ( <span className="text-muted-foreground">-</span> ); }, - size: 90, + size: 80, + }, + + { + accessorKey: "selfEvaluationScore", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="자율평가" />, + cell: ({ row }) => { + const score = row.getValue("selfEvaluationScore"); + return score ? ( + <span className="font-medium">{Number(score).toFixed(1)}</span> + ) : ( + <span className="text-muted-foreground">-</span> + ); + }, + size: 80, }, + // ✅ 합계 - 4개 점수의 합으로 계산 { - accessorKey: "finalGrade", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종등급" />, + id: "totalScore", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="합계" />, cell: ({ row }) => { - const finalGrade = row.getValue<string>("finalGrade"); - return finalGrade ? ( - <Badge variant={getGradeBadgeVariant(finalGrade)} className="bg-green-600"> - {finalGrade} - </Badge> + const processScore = Number(row.getValue("processScore") || 0); + const priceScore = Number(row.getValue("priceScore") || 0); + const deliveryScore = Number(row.getValue("deliveryScore") || 0); + const selfEvaluationScore = Number(row.getValue("selfEvaluationScore") || 0); + + const total = processScore + priceScore + deliveryScore + selfEvaluationScore; + + return total > 0 ? ( + <span className="font-medium bg-blue-50 px-2 py-1 rounded"> + {total.toFixed(1)} + </span> ) : ( <span className="text-muted-foreground">-</span> ); }, - size: 90, + size: 80, }, - ] - }, - // ═══════════════════════════════════════════════════════════════ - // 진행 현황 - // ═══════════════════════════════════════════════════════════════ - { - header: "진행 현황", - columns: [ { - accessorKey: "status", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="진행상태" />, + accessorKey: "participationBonus", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="참여도(가점)" />, cell: ({ row }) => { - const status = row.getValue<string>("status"); - return ( - <Badge variant={getStatusBadgeVariant(status)}> - {getStatusLabel(status)} - </Badge> + const score = row.getValue("participationBonus"); + return score ? ( + <span className="font-medium text-green-600">+{Number(score).toFixed(1)}</span> + ) : ( + <span className="text-muted-foreground">-</span> ); }, size: 100, }, { - id: "reviewProgress", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="리뷰진행" />, + accessorKey: "qualityDeduction", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="품질(감점)" />, cell: ({ row }) => { - const totalReviewers = row.original.totalReviewers || 0; - const completedReviewers = row.original.completedReviewers || 0; - - return getProgressBadge(completedReviewers, totalReviewers); + const score = row.getValue("qualityDeduction"); + return score ? ( + <span className="font-medium text-red-600">-{Number(score).toFixed(1)}</span> + ) : ( + <span className="text-muted-foreground">-</span> + ); }, - size: 120, + size: 100, }, + // ✅ 새로운 평가점수 컬럼 추가 { - accessorKey: "reviewCompletedAt", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="검토완료일" />, + id: "evaluationScore", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가점수" />, cell: ({ row }) => { - const completedAt = row.getValue<Date>("reviewCompletedAt"); - return completedAt ? ( - <span className="text-sm"> - {new Intl.DateTimeFormat("ko-KR", { - month: "2-digit", - day: "2-digit", - }).format(new Date(completedAt))} + const processScore = Number(row.getValue("processScore") || 0); + const priceScore = Number(row.getValue("priceScore") || 0); + const deliveryScore = Number(row.getValue("deliveryScore") || 0); + const selfEvaluationScore = Number(row.getValue("selfEvaluationScore") || 0); + const participationBonus = Number(row.getValue("participationBonus") || 0); + const qualityDeduction = Number(row.getValue("qualityDeduction") || 0); + + const totalScore = processScore + priceScore + deliveryScore + selfEvaluationScore; + const evaluationScore = totalScore + participationBonus - qualityDeduction; + + return totalScore > 0 ? ( + <span className="font-bold text-blue-600 bg-blue-50 px-2 py-1 rounded"> + {evaluationScore.toFixed(1)} </span> ) : ( <span className="text-muted-foreground">-</span> ); }, - size: 100, + size: 90, }, { - accessorKey: "finalizedAt", - header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="확정일" />, + accessorKey: "evaluationGrade", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가등급" />, cell: ({ row }) => { - const finalizedAt = row.getValue<Date>("finalizedAt"); - return finalizedAt ? ( - <span className="text-sm font-medium"> - {new Intl.DateTimeFormat("ko-KR", { - month: "2-digit", - day: "2-digit", - }).format(new Date(finalizedAt))} - </span> + const grade = row.getValue<string>("evaluationGrade"); + return grade ? ( + <Badge variant={getGradeBadgeVariant(grade)}>{grade}</Badge> ) : ( <span className="text-muted-foreground">-</span> ); }, size: 80, }, + ] }, + + // ░░░ Actions ░░░ - { - id: "actions", - enableHiding: false, - size: 40, - minSize: 40, - cell: ({ row }) => { - return ( - <div className="flex items-center gap-1"> - <Button - variant="ghost" - size="icon" - className="size-8" - onClick={() => setRowAction({ row, type: "view" })} - aria-label="상세보기" - title="상세보기" - > - <Eye className="size-4" /> - </Button> - - <Button - variant="ghost" - size="icon" - className="size-8" - onClick={() => setRowAction({ row, type: "update" })} - aria-label="수정" - title="수정" - > - <Pencil className="size-4" /> - </Button> - </div> - ); - }, - }, + // { + // id: "actions", + // enableHiding: false, + // size: 40, + // minSize: 40, + // cell: ({ row }) => { + // return ( + // <div className="flex items-center gap-1"> + // <Button + // variant="ghost" + // size="icon" + // className="size-8" + // onClick={() => setRowAction({ row, type: "view" })} + // aria-label="상세보기" + // title="상세보기" + // > + // <Eye className="size-4" /> + // </Button> + + // <Button + // variant="ghost" + // size="icon" + // className="size-8" + // onClick={() => setRowAction({ row, type: "update" })} + // aria-label="수정" + // title="수정" + // > + // <Pencil className="size-4" /> + // </Button> + // </div> + // ); + // }, + // }, ]; }
\ No newline at end of file |
