import type { ColumnDef, Row } from "@tanstack/react-table"; import { ClientDataTableColumnHeaderSimple } from "../client-data-table/data-table-column-simple-header"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Ellipsis } from "lucide-react"; import { formatDate } from "@/lib/utils"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { toast } from 'sonner'; /** row 액션 관련 타입 */ export interface DataTableRowAction { row: Row; type: "open" | "edit" | "update"; } /** 컬럼 타입 (필요에 따라 확장) */ export type ColumnType = "STRING" | "NUMBER" | "LIST"; export interface DataTableColumnJSON { key: string; /** 실제 Excel 등에서 구분용으로 쓰이는 label (고정) */ label: string; /** UI 표시용 label (예: 단위를 함께 표시) */ displayLabel?: string; type: ColumnType; options?: string[]; uom?: string; uomId?: string; shi?: boolean; } /** * getColumns 함수에 필요한 props * - TData: 테이블에 표시할 행(Row)의 타입 */ interface GetColumnsProps { columnsJSON: DataTableColumnJSON[]; setRowAction: React.Dispatch< React.SetStateAction | null> >; setReportData: React.Dispatch>; tempCount: number; // 체크박스 선택 관련 props selectedRows?: Record; onRowSelectionChange?: (updater: Record | ((prev: Record) => Record)) => void; editableFieldsMap?: Map; // 새로 추가 } /** * getColumns 함수 * 1) columnsJSON 배열을 순회하면서 accessorKey / header / cell 등을 설정 * 2) 체크박스 컬럼 추가 (showBatchSelection이 true일 때) * 3) 마지막에 "Action" 칼럼(예: update 버튼) 추가 */ export function getColumns({ columnsJSON, setRowAction, setReportData, tempCount, selectedRows = {}, onRowSelectionChange, editableFieldsMap = new Map(), // 새로 추가 }: GetColumnsProps): ColumnDef[] { const columns: ColumnDef[] = []; // (1) 체크박스 컬럼 (항상 표시) const selectColumn: ColumnDef = { id: "select", header: ({ table }) => ( { table.toggleAllPageRowsSelected(!!value); // 모든 행 선택/해제 if (onRowSelectionChange) { const allRowsSelection: Record = {}; table.getRowModel().rows.forEach((row) => { allRowsSelection[row.id] = !!value; }); onRowSelectionChange(allRowsSelection); } }} aria-label="Select all" className="translate-y-[2px]" /> ), cell: ({ row }) => ( { row.toggleSelected(!!value); // 개별 행 선택 상태 업데이트 if (onRowSelectionChange) { onRowSelectionChange(prev => ({ ...prev, [row.id]: !!value })); } }} aria-label="Select row" className="translate-y-[2px]" /> ), enableSorting: false, enableHiding: false, size: 40, }; columns.push(selectColumn); // (2) 기본 컬럼들 const baseColumns: ColumnDef[] = columnsJSON.map((col) => ({ accessorKey: col.key, header: ({ column }) => ( ), meta: { excelHeader: col.label, minWidth: 80, paddingFactor: 1.2, maxWidth: col.key === "TAG_NO" ? 120 : 150, isReadOnly: col.shi === true, }, cell: ({ row }) => { const cellValue = row.getValue(col.key); // 기본 읽기 전용 여부 (shi 속성 기반) let isReadOnly = col.shi === true; // 동적 읽기 전용 여부 계산 if (!isReadOnly && col.key !== 'TAG_NO' && col.key !== 'TAG_DESC') { const tagNo = row.getValue('TAG_NO') as string; if (tagNo && editableFieldsMap.has(tagNo)) { const editableFields = editableFieldsMap.get(tagNo) || []; // 해당 TAG의 편집 가능 필드 목록에 없으면 읽기 전용 isReadOnly = !editableFields.includes(col.key); } else { // TAG_NO가 없거나 editableFieldsMap에 없으면 읽기 전용 isReadOnly = true; } } const readOnlyClass = isReadOnly ? "read-only-cell" : ""; const cellStyle = isReadOnly ? { backgroundColor: '#f5f5f5', color: '#666', cursor: 'not-allowed' } : {}; // 툴팁 메시지 설정 let tooltipMessage = ""; if (isReadOnly) { if (col.shi === true) { tooltipMessage = "SHI 전용 필드입니다"; } else if (col.key === 'TAG_NO' || col.key === 'TAG_DESC') { tooltipMessage = "기본 필드는 수정할 수 없습니다"; } else { tooltipMessage = "이 TAG 클래스에서는 편집할 수 없는 필드입니다"; } } // 데이터 타입별 처리 switch (col.type) { case "NUMBER": return (
{cellValue ? Number(cellValue).toLocaleString() : ""}
); case "LIST": return (
{String(cellValue ?? "")}
); case "STRING": default: return (
{String(cellValue ?? "")}
); } }, })); columns.push(...baseColumns); // (4) 액션 칼럼 - update 버튼 예시 const actionColumn: ColumnDef = { id: "update", header: "", cell: ({ row }) => ( { setRowAction({ row, type: "update" }); }} > Edit { if(tempCount > 0){ const { original } = row; setReportData([original]); } else { toast.error("업로드된 Template File이 없습니다."); } }} > Create Document ), minSize: 50, enablePinning: true, }; columns.push(actionColumn); // (5) 최종 반환 return columns; }