From aa86729f9a2ab95346a2851e3837de1c367aae17 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 20 Jun 2025 11:37:31 +0000
Subject: (대표님) 20250620 작업사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../table/evaluation-targets-columns.tsx           | 459 +++++++++++++++------
 1 file changed, 322 insertions(+), 137 deletions(-)

(limited to 'lib/evaluation-target-list/table/evaluation-targets-columns.tsx')

diff --git a/lib/evaluation-target-list/table/evaluation-targets-columns.tsx b/lib/evaluation-target-list/table/evaluation-targets-columns.tsx
index b1e19434..93807ef9 100644
--- a/lib/evaluation-target-list/table/evaluation-targets-columns.tsx
+++ b/lib/evaluation-target-list/table/evaluation-targets-columns.tsx
@@ -7,6 +7,11 @@ import { Button } from "@/components/ui/button";
 import { Pencil, Eye, MessageSquare, Check, X } from "lucide-react";
 import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header";
 import { EvaluationTargetWithDepartments } from "@/db/schema";
+import { EditEvaluationTargetSheet } from "./update-evaluation-target";
+
+interface GetColumnsProps {
+  setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<EvaluationTargetWithDepartments> | null>>;
+}
 
 // 상태별 색상 매핑
 const getStatusBadgeVariant = (status: string) => {
@@ -36,8 +41,8 @@ const getConsensusBadge = (consensusStatus: boolean | null) => {
 // 구분 배지
 const getDivisionBadge = (division: string) => {
   return (
-    <Badge variant={division === "OCEAN" ? "default" : "secondary"}>
-      {division === "OCEAN" ? "해양" : "조선"}
+    <Badge variant={division === "PLANT" ? "default" : "secondary"}>
+      {division === "PLANT" ? "해양" : "조선"}
     </Badge>
   );
 };
@@ -46,7 +51,7 @@ const getDivisionBadge = (division: string) => {
 const getMaterialTypeBadge = (materialType: string) => {
   const typeMap = {
     EQUIPMENT: "기자재",
-    BULK: "벌크", 
+    BULK: "벌크",
     EQUIPMENT_BULK: "기자재/벌크"
   };
   return <Badge variant="outline">{typeMap[materialType] || materialType}</Badge>;
@@ -61,8 +66,23 @@ const getDomesticForeignBadge = (domesticForeign: string) => {
   );
 };
 
-export function getEvaluationTargetsColumns(): ColumnDef<EvaluationTargetWithDepartments>[] {
+// 평가 상태 배지
+const getApprovalBadge = (isApproved: boolean | null) => {
+  if (isApproved === null) {
+    return <Badge variant="outline" className="text-xs">대기중</Badge>;
+  }
+  if (isApproved === true) {
+    return <Badge variant="default" className="bg-green-600 text-xs">승인</Badge>;
+  }
+  return <Badge variant="destructive" className="text-xs">거부</Badge>;
+};
+
+export function getEvaluationTargetsColumns({setRowAction}:GetColumnsProps): ColumnDef<EvaluationTargetWithDepartments>[] {
   return [
+    // ═══════════════════════════════════════════════════════════════
+    // 기본 정보
+    // ═══════════════════════════════════════════════════════════════
+
     // Checkbox 
     {
       id: "select",
@@ -102,46 +122,6 @@ export function getEvaluationTargetsColumns(): ColumnDef<EvaluationTargetWithDep
       cell: ({ row }) => getDivisionBadge(row.getValue("division")),
       size: 80,
     },
-
-    // ░░░ 벤더 코드 ░░░
-    {
-      accessorKey: "vendorCode",
-      header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="벤더 코드" />,
-      cell: ({ row }) => (
-        <span className="font-mono text-sm">{row.getValue("vendorCode")}</span>
-      ),
-      size: 120,
-    },
-
-    // ░░░ 벤더명 ░░░
-    {
-      accessorKey: "vendorName",
-      header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="벤더명" />,
-      cell: ({ row }) => (
-        <div className="truncate max-w-[200px]" title={row.getValue<string>("vendorName")!}>
-          {row.getValue("vendorName") as string}
-        </div>
-      ),
-      size: 200,
-    },
-
-    // ░░░ 내외자 ░░░
-    {
-      accessorKey: "domesticForeign",
-      header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="내외자" />,
-      cell: ({ row }) => getDomesticForeignBadge(row.getValue("domesticForeign")),
-      size: 80,
-    },
-
-    // ░░░ 자재구분 ░░░
-    {
-      accessorKey: "materialType",
-      header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="자재구분" />,
-      cell: ({ row }) => getMaterialTypeBadge(row.getValue("materialType")),
-      size: 120,
-    },
-
-    // ░░░ 상태 ░░░
     {
       accessorKey: "status",
       header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="상태" />,
@@ -161,6 +141,54 @@ export function getEvaluationTargetsColumns(): ColumnDef<EvaluationTargetWithDep
       size: 100,
     },
 
+    // ░░░ 벤더 코드 ░░░
+
+    {
+      header: "협력업체 정보",
+      columns: [
+        {
+          accessorKey: "vendorCode",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="벤더 코드" />,
+          cell: ({ row }) => (
+            <span className="font-mono text-sm">{row.getValue("vendorCode")}</span>
+          ),
+          size: 120,
+        },
+
+        // ░░░ 벤더명 ░░░
+        {
+          accessorKey: "vendorName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="벤더명" />,
+          cell: ({ row }) => (
+            <div className="truncate max-w-[200px]" title={row.getValue<string>("vendorName")!}>
+              {row.getValue("vendorName") as string}
+            </div>
+          ),
+          size: 200,
+        },
+
+        // ░░░ 내외자 ░░░
+        {
+          accessorKey: "domesticForeign",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="내외자" />,
+          cell: ({ row }) => getDomesticForeignBadge(row.getValue("domesticForeign")),
+          size: 80,
+        },
+
+      ]
+    },
+
+    // ░░░ 자재구분 ░░░
+    {
+      accessorKey: "materialType",
+      header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="자재구분" />,
+      cell: ({ row }) => getMaterialTypeBadge(row.getValue("materialType")),
+      size: 120,
+    },
+
+    // ░░░ 상태 ░░░
+
+
     // ░░░ 의견 일치 여부 ░░░
     {
       accessorKey: "consensusStatus",
@@ -169,56 +197,235 @@ export function getEvaluationTargetsColumns(): ColumnDef<EvaluationTargetWithDep
       size: 100,
     },
 
-    // ░░░ 담당자 현황 ░░░
+    // ═══════════════════════════════════════════════════════════════
+    // 주문 부서 그룹
+    // ═══════════════════════════════════════════════════════════════
     {
-      id: "reviewers",
-      header: "담당자 현황",
-      cell: ({ row }) => {
-        const reviewers = row.original.reviewers || [];
-        const totalReviewers = reviewers.length;
-        const completedReviews = reviewers.filter(r => r.review?.isApproved !== null).length;
-        const approvedReviews = reviewers.filter(r => r.review?.isApproved === true).length;
-        
-        return (
-          <div className="flex items-center gap-2">
-            <div className="text-xs">
-              <span className="text-green-600 font-medium">{approvedReviews}</span>
-              <span className="text-muted-foreground">/{completedReviews}</span>
-              <span className="text-muted-foreground">/{totalReviewers}</span>
-            </div>
-            {totalReviewers > 0 && (
-              <div className="flex gap-1">
-                {reviewers.slice(0, 3).map((reviewer, idx) => (
-                  <div
-                    key={idx}
-                    className={`w-2 h-2 rounded-full ${
-                      reviewer.review?.isApproved === true
-                        ? "bg-green-500"
-                        : reviewer.review?.isApproved === false
-                        ? "bg-red-500"
-                        : "bg-gray-300"
-                    }`}
-                    title={`${reviewer.departmentCode}: ${
-                      reviewer.review?.isApproved === true
-                        ? "승인"
-                        : reviewer.review?.isApproved === false
-                        ? "거부"
-                        : "대기중"
-                    }`}
-                  />
-                ))}
-                {totalReviewers > 3 && (
-                  <span className="text-xs text-muted-foreground">+{totalReviewers - 3}</span>
-                )}
+      header: "발주 평가 담당자",
+      columns: [
+        {
+          accessorKey: "orderDepartmentName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="부서명" />,
+          cell: ({ row }) => {
+            const departmentName = row.getValue<string>("orderDepartmentName");
+            return departmentName ? (
+              <div className="truncate max-w-[120px]" title={departmentName}>
+                {departmentName}
               </div>
-            )}
-          </div>
-        );
-      },
-      size: 120,
-      enableSorting: false,
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 120,
+        },
+        {
+          accessorKey: "orderReviewerName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="담당자" />,
+          cell: ({ row }) => {
+            const reviewerName = row.getValue<string>("orderReviewerName");
+            return reviewerName ? (
+              <div className="truncate max-w-[100px]" title={reviewerName}>
+                {reviewerName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 100,
+        },
+        {
+          accessorKey: "orderIsApproved",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가" />,
+          cell: ({ row }) => getApprovalBadge(row.getValue("orderIsApproved")),
+          size: 80,
+        },
+      ],
+    },
+
+    // ═══════════════════════════════════════════════════════════════
+    // 조달 부서 그룹
+    // ═══════════════════════════════════════════════════════════════
+    {
+      header: "조달 평가 담당자",
+      columns: [
+        {
+          accessorKey: "procurementDepartmentName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="부서명" />,
+          cell: ({ row }) => {
+            const departmentName = row.getValue<string>("procurementDepartmentName");
+            return departmentName ? (
+              <div className="truncate max-w-[120px]" title={departmentName}>
+                {departmentName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 120,
+        },
+        {
+          accessorKey: "procurementReviewerName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="담당자" />,
+          cell: ({ row }) => {
+            const reviewerName = row.getValue<string>("procurementReviewerName");
+            return reviewerName ? (
+              <div className="truncate max-w-[100px]" title={reviewerName}>
+                {reviewerName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 100,
+        },
+        {
+          accessorKey: "procurementIsApproved",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가" />,
+          cell: ({ row }) => getApprovalBadge(row.getValue("procurementIsApproved")),
+          size: 80,
+        },
+      ],
     },
 
+    // ═══════════════════════════════════════════════════════════════
+    // 품질 부서 그룹
+    // ═══════════════════════════════════════════════════════════════
+    {
+      header: "품질 평가 담당자",
+      columns: [
+        {
+          accessorKey: "qualityDepartmentName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="부서명" />,
+          cell: ({ row }) => {
+            const departmentName = row.getValue<string>("qualityDepartmentName");
+            return departmentName ? (
+              <div className="truncate max-w-[120px]" title={departmentName}>
+                {departmentName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 120,
+        },
+        {
+          accessorKey: "qualityReviewerName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="담당자" />,
+          cell: ({ row }) => {
+            const reviewerName = row.getValue<string>("qualityReviewerName");
+            return reviewerName ? (
+              <div className="truncate max-w-[100px]" title={reviewerName}>
+                {reviewerName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 100,
+        },
+        {
+          accessorKey: "qualityIsApproved",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가" />,
+          cell: ({ row }) => getApprovalBadge(row.getValue("qualityIsApproved")),
+          size: 80,
+        },
+      ],
+    },
+
+    // ═══════════════════════════════════════════════════════════════
+    // 설계 부서 그룹
+    // ═══════════════════════════════════════════════════════════════
+    {
+      header: "설계 평가 담당자",
+      columns: [
+        {
+          accessorKey: "designDepartmentName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="부서명" />,
+          cell: ({ row }) => {
+            const departmentName = row.getValue<string>("designDepartmentName");
+            return departmentName ? (
+              <div className="truncate max-w-[120px]" title={departmentName}>
+                {departmentName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 120,
+        },
+        {
+          accessorKey: "designReviewerName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="담당자" />,
+          cell: ({ row }) => {
+            const reviewerName = row.getValue<string>("designReviewerName");
+            return reviewerName ? (
+              <div className="truncate max-w-[100px]" title={reviewerName}>
+                {reviewerName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 100,
+        },
+        {
+          accessorKey: "designIsApproved",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가" />,
+          cell: ({ row }) => getApprovalBadge(row.getValue("designIsApproved")),
+          size: 80,
+        },
+      ],
+    },
+
+    // ═══════════════════════════════════════════════════════════════
+    // CS 부서 그룹
+    // ═══════════════════════════════════════════════════════════════
+    {
+      header: "CS 평가 담당자",
+      columns: [
+        {
+          accessorKey: "csDepartmentName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="부서명" />,
+          cell: ({ row }) => {
+            const departmentName = row.getValue<string>("csDepartmentName");
+            return departmentName ? (
+              <div className="truncate max-w-[120px]" title={departmentName}>
+                {departmentName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 120,
+        },
+        {
+          accessorKey: "csReviewerName",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="담당자" />,
+          cell: ({ row }) => {
+            const reviewerName = row.getValue<string>("csReviewerName");
+            return reviewerName ? (
+              <div className="truncate max-w-[100px]" title={reviewerName}>
+                {reviewerName}
+              </div>
+            ) : (
+              <span className="text-muted-foreground">-</span>
+            );
+          },
+          size: 100,
+        },
+        {
+          accessorKey: "csIsApproved",
+          header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가" />,
+          cell: ({ row }) => getApprovalBadge(row.getValue("csIsApproved")),
+          size: 80,
+        },
+      ],
+    },
+
+    // ═══════════════════════════════════════════════════════════════
+    // 관리 정보
+    // ═══════════════════════════════════════════════════════════════
+
     // ░░░ 관리자 의견 ░░░
     {
       accessorKey: "adminComment",
@@ -274,69 +481,47 @@ export function getEvaluationTargetsColumns(): ColumnDef<EvaluationTargetWithDep
       size: 100,
     },
 
+    // ░░░ 생성일 ░░░
+    {
+      accessorKey: "createdAt",
+      header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="생성일" />,
+      cell: ({ row }) => {
+        const createdAt = row.getValue<Date>("createdAt");
+        return createdAt ? (
+          <span className="text-sm">
+            {new Intl.DateTimeFormat("ko-KR", {
+              year: "numeric",
+              month: "2-digit",
+              day: "2-digit",
+            }).format(new Date(createdAt))}
+          </span>
+        ) : (
+          <span className="text-muted-foreground">-</span>
+        );
+      },
+      size: 100,
+    },
+
     // ░░░ Actions ░░░
     {
       id: "actions",
       enableHiding: false,
-      size: 120,
-      minSize: 120,
+      size: 40,
+      minSize: 40,
       cell: ({ row }) => {
-        const record = row.original;
-        const [openDetail, setOpenDetail] = React.useState(false);
-        const [openEdit, setOpenEdit] = React.useState(false);
-        const [openRequest, setOpenRequest] = React.useState(false);
-
-        return (
+             return (
           <div className="flex items-center gap-1">
             <Button
               variant="ghost"
               size="icon"
               className="size-8"
-              onClick={() => setOpenDetail(true)}
-              aria-label="상세보기"
-              title="상세보기"
-            >
-              <Eye className="size-4" />
-            </Button>
-            
-            <Button
-              variant="ghost"
-              size="icon"
-              className="size-8"
-              onClick={() => setOpenEdit(true)}
+              onClick={() => setRowAction({ row, type: "update" })}
               aria-label="수정"
               title="수정"
             >
               <Pencil className="size-4" />
             </Button>
 
-            <Button
-              variant="ghost"
-              size="icon"
-              className="size-8"
-              onClick={() => setOpenRequest(true)}
-              aria-label="의견요청"
-              title="의견요청"
-            >
-              <MessageSquare className="size-4" />
-            </Button>
-
-            {/* TODO: 실제 다이얼로그 컴포넌트들로 교체 */}
-            {openDetail && (
-              <div onClick={() => setOpenDetail(false)}>
-                {/* <EvaluationTargetDetailDialog /> */}
-              </div>
-            )}
-            {openEdit && (
-              <div onClick={() => setOpenEdit(false)}>
-                {/* <EditEvaluationTargetDialog /> */}
-              </div>
-            )}
-            {openRequest && (
-              <div onClick={() => setOpenRequest(false)}>
-                {/* <RequestReviewDialog /> */}
-              </div>
-            )}
           </div>
         );
       },
-- 
cgit v1.2.3

