From 2b490956c9752c1b756780a3461bc1c37b6fe0a7 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Mon, 15 Sep 2025 18:58:07 +0900
Subject: (김준회) AVL 관리 및 상세 - 기능 구현 1차 + docker compose 내 오류
 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/avl/table/columns-detail.tsx | 516 +++++----------------------------------
 1 file changed, 63 insertions(+), 453 deletions(-)

(limited to 'lib/avl/table/columns-detail.tsx')

diff --git a/lib/avl/table/columns-detail.tsx b/lib/avl/table/columns-detail.tsx
index 204d34f5..84ad9d9a 100644
--- a/lib/avl/table/columns-detail.tsx
+++ b/lib/avl/table/columns-detail.tsx
@@ -1,28 +1,8 @@
 import { Checkbox } from "@/components/ui/checkbox"
 import { Badge } from "@/components/ui/badge"
-import { Button } from "@/components/ui/button"
-import { Edit, Trash2 } from "lucide-react"
-import { type ColumnDef, TableMeta } from "@tanstack/react-table"
+import { type ColumnDef } from "@tanstack/react-table"
 import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
-import { EditableCell } from "@/components/data-table/editable-cell"
 
-// 수정 여부 확인 헬퍼 함수
-const getIsModified = (table: any, rowId: string, fieldName: string) => {
-  const pendingChanges = table.options.meta?.getPendingChanges?.() || {}
-  return String(rowId) in pendingChanges && fieldName in pendingChanges[String(rowId)]
-}
-
-// 테이블 메타 타입 확장
-declare module "@tanstack/react-table" {
-  interface TableMeta<TData> {
-    onCellUpdate?: (id: string, field: keyof TData, newValue: any) => Promise<void>
-    onCellCancel?: (id: string, field: keyof TData) => void
-    onAction?: (action: string, data?: any) => void
-    onSaveEmptyRow?: (tempId: string) => Promise<void>
-    onCancelEmptyRow?: (tempId: string) => void
-    isEmptyRow?: (id: string) => boolean
-  }
-}
 
 // AVL 상세 아이템 타입
 export type AvlDetailItem = {
@@ -89,29 +69,6 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
   {
     header: "기본 정보",
     columns: [
-      {
-        id: "select",
-        header: ({ table }) => (
-          <Checkbox
-            checked={
-              table.getIsAllPageRowsSelected() ||
-              (table.getIsSomePageRowsSelected() && "indeterminate")
-            }
-            onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
-            aria-label="Select all"
-          />
-        ),
-        cell: ({ row }) => (
-          <Checkbox
-            checked={row.getIsSelected()}
-            onCheckedChange={(value) => row.toggleSelected(!!value)}
-            aria-label="Select row"
-          />
-        ),
-        enableSorting: false,
-        enableHiding: false,
-        size: 50,
-      },
       {
         accessorKey: "no",
         header: ({ column }) => (
@@ -124,33 +81,12 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="Equip/Bulk 구분" />
         ),
-        cell: ({ row, table }) => {
+        cell: ({ row }) => {
           const value = row.getValue("equipBulkDivision") as string
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "equipBulkDivision", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "equipBulkDivision")
-
           return (
-            <EditableCell
-              value={value}
-              type="select"
-              onSave={onSave}
-              options={[
-                { label: "EQUIP", value: "EQUIP" },
-                { label: "BULK", value: "BULK" }
-              ]}
-              placeholder="구분 선택"
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
+            <Badge variant="outline">
+              {value || "-"}
+            </Badge>
           )
         },
         size: 120,
@@ -160,31 +96,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="설계공종" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("disciplineName")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "disciplineName", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "disciplineName")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="설계공종 입력"
-              maxLength={50}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("disciplineName") as string
+          return <span>{value || "-"}</span>
         },
         size: 120,
       },
@@ -193,31 +107,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="고객사 AVL 자재명" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("materialNameCustomerSide")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "materialNameCustomerSide", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "materialNameCustomerSide")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="자재명 입력"
-              maxLength={100}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("materialNameCustomerSide") as string
+          return <span>{value || "-"}</span>
         },
         size: 150,
       },
@@ -226,31 +118,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="패키지 정보" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("packageName")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "packageName", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "packageName")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="패키지명 입력"
-              maxLength={100}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("packageName") as string
+          return <span>{value || "-"}</span>
         },
         size: 130,
       },
@@ -259,31 +129,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="자재그룹코드" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("materialGroupCode")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "materialGroupCode", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "materialGroupCode")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="자재그룹코드 입력"
-              maxLength={50}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("materialGroupCode") as string
+          return <span>{value || "-"}</span>
         },
         size: 120,
       },
@@ -292,31 +140,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="자재그룹명" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("materialGroupName")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "materialGroupName", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "materialGroupName")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="자재그룹명 입력"
-              maxLength={100}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("materialGroupName") as string
+          return <span>{value || "-"}</span>
         },
         size: 130,
       },
@@ -325,31 +151,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="협력업체코드" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("vendorCode")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "vendorCode", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "vendorCode")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="협력업체코드 입력"
-              maxLength={50}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("vendorCode") as string
+          return <span>{value || "-"}</span>
         },
         size: 120,
       },
@@ -358,31 +162,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="협력업체명" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("vendorName")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "vendorName", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "vendorName")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="협력업체명 입력"
-              maxLength={100}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("vendorName") as string
+          return <span className="font-medium">{value || "-"}</span>
         },
         size: 140,
       },
@@ -391,31 +173,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="AVL 등재업체명" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("avlVendorName")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "avlVendorName", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "avlVendorName")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="AVL 등재업체명 입력"
-              maxLength={100}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("avlVendorName") as string
+          return <span>{value || "-"}</span>
         },
         size: 140,
       },
@@ -424,34 +184,20 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="등급 (Tier)" />
         ),
-        cell: ({ row, table }) => {
+        cell: ({ row }) => {
           const value = row.getValue("tier") as string
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "tier", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "tier")
-
+          if (!value) return <span>-</span>
+          
+          const tierColor = {
+            "Tier 1": "bg-green-100 text-green-800",
+            "Tier 2": "bg-yellow-100 text-yellow-800", 
+            "Tier 3": "bg-red-100 text-red-800"
+          }[value] || "bg-gray-100 text-gray-800"
+          
           return (
-            <EditableCell
-              value={value}
-              type="select"
-              onSave={onSave}
-              options={[
-                { label: "Tier 1", value: "Tier 1" },
-                { label: "Tier 2", value: "Tier 2" },
-                { label: "Tier 3", value: "Tier 3" }
-              ]}
-              placeholder="등급 선택"
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
+            <Badge className={tierColor}>
+              {value}
+            </Badge>
           )
         },
         size: 100,
@@ -467,28 +213,12 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="FA 대상" />
         ),
-        cell: ({ row, table }) => {
+        cell: ({ row }) => {
           const value = row.getValue("faTarget") as boolean
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "faTarget", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "faTarget")
-
           return (
-            <EditableCell
-              value={value}
-              type="checkbox"
-              onSave={onSave}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
+            <Badge variant={value ? "default" : "secondary"}>
+              {value ? "대상" : "비대상"}
+            </Badge>
           )
         },
         size: 80,
@@ -498,31 +228,9 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
         header: ({ column }) => (
           <DataTableColumnHeaderSimple column={column} title="FA 현황" />
         ),
-        cell: ({ row, table }) => {
-          const value = row.getValue("faStatus")
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "faStatus", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "faStatus")
-
-          return (
-            <EditableCell
-              value={value}
-              type="text"
-              onSave={onSave}
-              placeholder="FA 현황 입력"
-              maxLength={50}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
-            />
-          )
+        cell: ({ row }) => {
+          const value = row.getValue("faStatus") as string
+          return <span>{value || "-"}</span>
         },
         size: 100,
       },
@@ -535,27 +243,13 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
       {
         accessorKey: "shiAvl",
         header: "AVL",
-        cell: ({ row, table }) => {
+        cell: ({ row }) => {
           const value = row.getValue("shiAvl") as boolean
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "shiAvl", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "shiAvl")
-
           return (
-            <EditableCell
-              value={value}
-              type="checkbox"
-              onSave={onSave}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
+            <Checkbox
+              checked={value}
+              disabled
+              aria-label="SHI AVL 등재 여부"
             />
           )
         },
@@ -564,27 +258,13 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
       {
         accessorKey: "shiBlacklist",
         header: "Blacklist",
-        cell: ({ row, table }) => {
+        cell: ({ row }) => {
           const value = row.getValue("shiBlacklist") as boolean
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "shiBlacklist", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "shiBlacklist")
-
           return (
-            <EditableCell
-              value={value}
-              type="checkbox"
-              onSave={onSave}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
+            <Checkbox
+              checked={value}
+              disabled
+              aria-label="SHI Blacklist 등재 여부"
             />
           )
         },
@@ -593,27 +273,13 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
       {
         accessorKey: "shiBcc",
         header: "BCC",
-        cell: ({ row, table }) => {
+        cell: ({ row }) => {
           const value = row.getValue("shiBcc") as boolean
-          const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-          const onSave = async (newValue: any) => {
-            if (table.options.meta?.onCellUpdate) {
-              await table.options.meta.onCellUpdate(row.original.id, "shiBcc", newValue)
-            }
-          }
-
-          const isModified = getIsModified(table, row.original.id, "shiBcc")
-
           return (
-            <EditableCell
-              value={value}
-              type="checkbox"
-              onSave={onSave}
-              autoSave={true}
-              disabled={false}
-              initialEditMode={isEmptyRow}
-              isModified={isModified}
+            <Checkbox
+              checked={value}
+              disabled
+              aria-label="SHI BCC 등재 여부"
             />
           )
         },
@@ -621,60 +287,4 @@ export const columns: ColumnDef<AvlDetailItem>[] = [
       },
     ],
   },
-  // 액션 컬럼
-  {
-    id: "actions",
-    header: "액션",
-    cell: ({ row, table }) => {
-      const isEmptyRow = String(row.original.id).startsWith('temp-')
-
-      return (
-        <div className="flex items-center gap-2">
-          {!isEmptyRow && (
-            <>
-              <Button
-                variant="ghost"
-                size="sm"
-                onClick={() => table.options.meta?.onAction?.('edit', row.original)}
-                className="h-8 w-8 p-0"
-              >
-                <Edit className="h-4 w-4" />
-              </Button>
-              <Button
-                variant="ghost"
-                size="sm"
-                onClick={() => table.options.meta?.onAction?.('delete', row.original)}
-                className="h-8 w-8 p-0 text-destructive hover:text-destructive"
-              >
-                <Trash2 className="h-4 w-4" />
-              </Button>
-            </>
-          )}
-          {isEmptyRow && (
-            <>
-              <Button
-                variant="ghost"
-                size="sm"
-                onClick={() => table.options.meta?.onSaveEmptyRow?.(row.original.id)}
-                className="h-8 w-8 p-0"
-              >
-                저장
-              </Button>
-              <Button
-                variant="ghost"
-                size="sm"
-                onClick={() => table.options.meta?.onCancelEmptyRow?.(row.original.id)}
-                className="h-8 w-8 p-0"
-              >
-                취소
-              </Button>
-            </>
-          )}
-        </div>
-      )
-    },
-    size: 100,
-    enableSorting: false,
-    enableHiding: false,
-  },
 ]
-- 
cgit v1.2.3

