From c228a89c2834ee63b209bad608837c39643f350e Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 28 Jul 2025 11:44:16 +0000 Subject: (대표님) 의존성 docx 추가, basicContract API, gtc(계약일반조건), 벤더평가 esg 평가데이터 내보내기 개선, S-EDP 피드백 대응(CLS_ID, ITEM NO 등) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/gtc-clauses-table-columns.tsx | 283 +++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 lib/gtc-contract/gtc-clauses/table/gtc-clauses-table-columns.tsx (limited to 'lib/gtc-contract/gtc-clauses/table/gtc-clauses-table-columns.tsx') diff --git a/lib/gtc-contract/gtc-clauses/table/gtc-clauses-table-columns.tsx b/lib/gtc-contract/gtc-clauses/table/gtc-clauses-table-columns.tsx new file mode 100644 index 00000000..29efeb9c --- /dev/null +++ b/lib/gtc-contract/gtc-clauses/table/gtc-clauses-table-columns.tsx @@ -0,0 +1,283 @@ +"use client" + +import * as React from "react" +import { type DataTableRowAction } from "@/types/table" +import { type ColumnDef } from "@tanstack/react-table" +import { Ellipsis, Edit, Trash2, Plus, Copy } from "lucide-react" +import { cn, compareItemNumber, formatDate } from "@/lib/utils" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { Checkbox } from "@/components/ui/checkbox" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" +import { toast } from "sonner" +import { useSession } from "next-auth/react" +import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" +import { type GtcClauseTreeView } from "@/db/schema/gtc" + +interface GetColumnsProps { + setRowAction: React.Dispatch | null>> + documentId: number +} + +export function getColumns({ setRowAction, documentId }: GetColumnsProps): ColumnDef[] { + // 1) select + const selectColumn: ColumnDef = { + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!v)} + aria-label="Select all" + className="translate-y-0.5" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!v)} + aria-label="Select row" + className="translate-y-0.5" + /> + ), + size: 40, + enableSorting: false, + enableHiding: false, + } + + // 2) 조항 정보 + const clauseInfoColumns: ColumnDef[] = [ + { + accessorKey: "itemNumber", + header: ({ column }) => , + cell: ({ row }) => { + const itemNumber = row.getValue("itemNumber") as string + const depth = row.original.depth + const childrenCount = row.original.childrenCount + return ( +
+
+ {itemNumber} + {childrenCount > 0 && ( + + + + + {childrenCount} + + + +

{childrenCount}개의 하위 조항

+
+
+
+ )} +
+
+ ) + }, + size: 100, + enableResizing: true, + sortingFn: (rowA, rowB, colId) => + compareItemNumber(rowA.getValue(colId), rowB.getValue(colId)), + meta: { excelHeader: "채번" }, + }, + { + accessorKey: "category", + header: ({ column }) => , + cell: ({ row }) => { + const category = row.getValue("category") as string + return category ? ( + {category} + ) : ( + - + ) + }, + size: 100, + enableResizing: true, + meta: { excelHeader: "분류" }, + }, + { + accessorKey: "subtitle", + header: ({ column }) => , + cell: ({ row }) => { + const subtitle = row.getValue("subtitle") as string + const depth = row.original.depth + return ( +
+ = 2 && "text-sm text-muted-foreground", + )} + title={subtitle} + > + {subtitle} + +
+ ) + }, + size: 150, + enableResizing: true, + meta: { excelHeader: "소제목" }, + }, + { + accessorKey: "content", + header: ({ column }) => , + cell: ({ row }) => { + const content = row.getValue("content") as string | null + if (!content) { + return ( +
+ 그룹핑 조항 + 상세내용 없음 +
+ ) + } + const truncated = content.length > 100 ? `${content.substring(0, 100)}...` : content + return ( + + + +
+

{content}

+
+
+ +

{content}

+
+
+
+ ) + }, + size: 200, + maxSize: 500, + enableResizing: true, + meta: { excelHeader: "상세항목" }, + }, + ] + + // 3) 등록/수정 정보 + const auditColumns: ColumnDef[] = [ + { + accessorKey: "createdAt", + header: ({ column }) => , + cell: ({ row }) => { + const date = row.getValue("createdAt") as Date + return date ? formatDate(date, "KR") : "-" + }, + size: 120, + enableResizing: true, + meta: { excelHeader: "작성일" }, + }, + { + accessorKey: "createdByName", + header: ({ column }) => , + cell: ({ row }) => { + const v = row.getValue("createdByName") as string + return v ? {v} : - + }, + size: 80, + enableResizing: true, + meta: { excelHeader: "작성자" }, + }, + { + accessorKey: "updatedAt", + header: ({ column }) => , + cell: ({ row }) => { + const date = row.getValue("updatedAt") as Date + return {date ? formatDate(date, "KR") : "-"} + }, + size: 120, + enableResizing: true, + meta: { excelHeader: "수정일" }, + }, + { + accessorKey: "updatedByName", + header: ({ column }) => , + cell: ({ row }) => { + const v = row.getValue("updatedByName") as string + return v ? {v} : - + }, + size: 80, + enableResizing: true, + meta: { excelHeader: "수정자" }, + }, + ] + + // 4) actions + const actionsColumn: ColumnDef = { + id: "actions", + enableHiding: false, + cell: function Cell({ row }) { + const { data: session } = useSession() + const gtcClause = row.original + const currentUserId = React.useMemo( + () => (session?.user?.id ? Number(session.user.id) : null), + [session], + ) + + const handleEdit = () => setRowAction({ row, type: "update" }) + const handleDelete = () => setRowAction({ row, type: "delete" }) + const handleAddSubClause = () => setRowAction({ row, type: "addSubClause" }) + const handleDuplicate = () => setRowAction({ row, type: "duplicate" }) + + return ( + + + + + + + + 편집 + + + + 하위 조항 추가 + + + + 복제 + + + + + 삭제 + ⌘⌫ + + + + ) + }, + size: 40, + maxSize: 40, + } + + // 🔹 그룹 헤더 제거: 평탄화된 컬럼 배열 반환 + return [ + selectColumn, + ...clauseInfoColumns, + ...auditColumns, + actionsColumn, + ] +} \ No newline at end of file -- cgit v1.2.3