diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-23 16:40:37 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-23 16:40:37 +0900 |
| commit | fd4909bba7be8abc1eeab9ae1b4621c66a61604a (patch) | |
| tree | d375995611de80b55b344b1c536c5a760f06ccb6 /lib/dolce/table | |
| parent | a2e0785c8749c4d3766ecf3b70edfb7c2fe4df20 (diff) | |
(김준회) 돌체 재개발 - 1차 (다운로드 오류 수정 필요)
Diffstat (limited to 'lib/dolce/table')
| -rw-r--r-- | lib/dolce/table/detail-drawing-columns.tsx | 80 | ||||
| -rw-r--r-- | lib/dolce/table/drawing-list-columns.tsx | 87 | ||||
| -rw-r--r-- | lib/dolce/table/drawing-list-table.tsx | 144 | ||||
| -rw-r--r-- | lib/dolce/table/file-list-columns.tsx | 70 | ||||
| -rw-r--r-- | lib/dolce/table/gtt-drawing-list-columns.tsx | 166 |
5 files changed, 547 insertions, 0 deletions
diff --git a/lib/dolce/table/detail-drawing-columns.tsx b/lib/dolce/table/detail-drawing-columns.tsx new file mode 100644 index 00000000..7f519179 --- /dev/null +++ b/lib/dolce/table/detail-drawing-columns.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { ColumnDef } from "@tanstack/react-table"; +import { DetailDwgReceiptItem } from "../actions"; + +export const detailDrawingColumns: ColumnDef<DetailDwgReceiptItem>[] = [ + { + accessorKey: "RegisterSerialNo", + header: "일련번호", + minSize: 80, + cell: ({ row }) => { + return <div className="text-center">{row.getValue("RegisterSerialNo")}</div>; + }, + }, + { + accessorKey: "DrawingRevNo", + header: "Revision", + minSize: 100, + cell: ({ row }) => { + return <div className="font-medium">{row.getValue("DrawingRevNo")}</div>; + }, + }, + { + accessorKey: "Status", + header: "상태", + minSize: 120, + cell: ({ row }) => { + return <div className="text-center">{row.getValue("Status")}</div>; + }, + }, + { + accessorKey: "CategoryENM", + header: "카테고리", + minSize: 120, + cell: ({ row }) => { + const categoryENM = row.getValue("CategoryENM") as string; + const categoryNM = row.original.CategoryNM; + return <div>{categoryENM || categoryNM}</div>; + }, + }, + { + accessorKey: "DrawingUsageENM", + header: "도면용도", + minSize: 100, + cell: ({ row }) => { + const usageENM = row.getValue("DrawingUsageENM") as string | null; + const usageNM = row.original.DrawingUsageNM; + return <div>{usageENM || usageNM}</div>; + }, + }, + { + accessorKey: "RegisterKindENM", + header: "등록종류", + minSize: 180, + cell: ({ row }) => { + const kindENM = row.getValue("RegisterKindENM") as string | null; + const kindNM = row.original.RegisterKindNM; + return <div>{kindENM || kindNM}</div>; + }, + }, + { + accessorKey: "CreateUserNM", + header: "생성자", + minSize: 150, + cell: ({ row }) => { + const userENM = row.original.CreateUserENM; + const userNM = row.getValue("CreateUserNM") as string; + return <div>{userENM || userNM}</div>; + }, + }, + { + accessorKey: "CreateDt", + header: "생성일시", + minSize: 200, + cell: ({ row }) => { + return <div className="text-sm text-muted-foreground">{row.getValue("CreateDt")}</div>; + }, + }, +]; + diff --git a/lib/dolce/table/drawing-list-columns.tsx b/lib/dolce/table/drawing-list-columns.tsx new file mode 100644 index 00000000..0e18266d --- /dev/null +++ b/lib/dolce/table/drawing-list-columns.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { ColumnDef } from "@tanstack/react-table"; +import { DwgReceiptItem } from "../actions"; + +export const drawingListColumns: ColumnDef<DwgReceiptItem>[] = [ + { + accessorKey: "DrawingNo", + header: "도면번호", + minSize: 200, + cell: ({ row }) => { + return <div className="font-medium">{row.getValue("DrawingNo")}</div>; + }, + }, + { + accessorKey: "DrawingName", + header: "도면명", + minSize: 400, + cell: ({ row }) => { + return <div>{row.getValue("DrawingName")}</div>; + }, + }, + { + accessorKey: "Discipline", + header: "설계공종", + minSize: 80, + }, + { + accessorKey: "Manager", + header: "담당자명", + minSize: 200, + cell: ({ row }) => { + const managerENM = row.original.ManagerENM; + const manager = row.getValue("Manager"); + return <div>{managerENM || manager}</div>; + }, + }, + { + accessorKey: "AppDwg_PlanDate", + header: "승인도면 예정일", + minSize: 140, + cell: ({ row }) => { + const date = row.getValue("AppDwg_PlanDate") as string; + if (!date || date.length !== 8) return null; + return `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`; + }, + }, + { + accessorKey: "AppDwg_ResultDate", + header: "승인도면 결과일", + minSize: 140, + cell: ({ row }) => { + const date = row.getValue("AppDwg_ResultDate") as string; + if (!date || date.length !== 8) return null; + return `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`; + }, + }, + { + accessorKey: "WorDwg_PlanDate", + header: "작업도면 예정일", + minSize: 140, + cell: ({ row }) => { + const date = row.getValue("WorDwg_PlanDate") as string; + if (!date || date.length !== 8) return null; + return `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`; + }, + }, + { + accessorKey: "WorDwg_ResultDate", + header: "작업도면 결과일", + minSize: 140, + cell: ({ row }) => { + const date = row.getValue("WorDwg_ResultDate") as string; + if (!date || date.length !== 8) return null; + return `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`; + }, + }, + { + accessorKey: "CreateDt", + header: "생성일시", + minSize: 200, + cell: ({ row }) => { + return <div className="text-sm text-muted-foreground">{row.getValue("CreateDt")}</div>; + }, + }, +]; + diff --git a/lib/dolce/table/drawing-list-table.tsx b/lib/dolce/table/drawing-list-table.tsx new file mode 100644 index 00000000..cc01f8ba --- /dev/null +++ b/lib/dolce/table/drawing-list-table.tsx @@ -0,0 +1,144 @@ +"use client"; + +import { + ColumnDef, + flexRender, + getCoreRowModel, + useReactTable, + getSortedRowModel, + SortingState, +} from "@tanstack/react-table"; +import { useState } from "react"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { ArrowUpDown, ArrowUp, ArrowDown } from "lucide-react"; + +interface DrawingListTableProps<TData, TValue> { + columns: ColumnDef<TData, TValue>[]; + data: TData[]; + onRowClick?: (row: TData) => void; + selectedRow?: TData; + getRowId?: (row: TData) => string; +} + +export function DrawingListTable<TData, TValue>({ + columns, + data, + onRowClick, + selectedRow, + getRowId, +}: DrawingListTableProps<TData, TValue>) { + const [sorting, setSorting] = useState<SortingState>([]); + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + onSortingChange: setSorting, + state: { + sorting, + }, + }); + + // 행이 선택되었는지 확인하는 함수 + const isRowSelected = (row: TData): boolean => { + if (!selectedRow || !getRowId) return false; + return getRowId(row) === getRowId(selectedRow); + }; + + return ( + <div className="rounded-md border overflow-x-auto max-w-full max-h-[600px] overflow-y-auto"> + <Table className="min-w-max"> + <TableHeader className="sticky top-0 z-10 bg-background"> + {table.getHeaderGroups().map((headerGroup) => ( + <TableRow key={headerGroup.id}> + {headerGroup.headers.map((header) => { + const isSorted = header.column.getIsSorted(); + const canSort = header.column.getCanSort(); + + return ( + <TableHead + key={header.id} + style={{ minWidth: header.column.columnDef.minSize }} + className="bg-background" + > + {header.isPlaceholder ? null : ( + <div + className={`flex items-center gap-2 ${ + canSort ? "cursor-pointer select-none hover:text-primary" : "" + }`} + onClick={ + canSort + ? header.column.getToggleSortingHandler() + : undefined + } + > + {flexRender( + header.column.columnDef.header, + header.getContext() + )} + {canSort && ( + <span className="text-muted-foreground"> + {isSorted === "asc" ? ( + <ArrowUp className="h-4 w-4" /> + ) : isSorted === "desc" ? ( + <ArrowDown className="h-4 w-4" /> + ) : ( + <ArrowUpDown className="h-4 w-4 opacity-50" /> + )} + </span> + )} + </div> + )} + </TableHead> + ); + })} + </TableRow> + ))} + </TableHeader> + <TableBody> + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => { + const isSelected = isRowSelected(row.original); + return ( + <TableRow + key={row.id} + data-state={row.getIsSelected() && "selected"} + onClick={() => onRowClick?.(row.original)} + className={`cursor-pointer transition-colors ${ + isSelected + ? "bg-accent hover:bg-accent" + : "hover:bg-muted/50" + }`} + > + {row.getVisibleCells().map((cell) => ( + <TableCell + key={cell.id} + style={{ minWidth: cell.column.columnDef.minSize }} + > + {flexRender(cell.column.columnDef.cell, cell.getContext())} + </TableCell> + ))} + </TableRow> + ); + }) + ) : ( + <TableRow> + <TableCell colSpan={columns.length} className="h-24 text-center"> + 데이터가 없습니다. + </TableCell> + </TableRow> + )} + </TableBody> + </Table> + </div> + ); +} + diff --git a/lib/dolce/table/file-list-columns.tsx b/lib/dolce/table/file-list-columns.tsx new file mode 100644 index 00000000..f703d56d --- /dev/null +++ b/lib/dolce/table/file-list-columns.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { ColumnDef } from "@tanstack/react-table"; +import { FileInfoItem } from "../actions"; +import { Button } from "@/components/ui/button"; +import { Download } from "lucide-react"; + +interface FileListColumnsProps { + onDownload: (file: FileInfoItem) => void; +} + +export const createFileListColumns = ({ + onDownload, +}: FileListColumnsProps): ColumnDef<FileInfoItem>[] => [ + { + accessorKey: "FileSeq", + header: "순번", + minSize: 80, + cell: ({ row }) => { + return <div className="text-center">{row.getValue("FileSeq")}</div>; + }, + }, + { + accessorKey: "FileName", + header: "파일명", + minSize: 300, + cell: ({ row }) => { + return <div className="font-medium">{row.getValue("FileName")}</div>; + }, + }, + { + accessorKey: "FileSize", + header: "파일크기", + minSize: 100, + cell: ({ row }) => { + const size = parseInt(row.getValue("FileSize") as string); + if (isNaN(size) || size === 0) return "-"; + + if (size < 1024) return `${size} B`; + if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`; + return `${(size / (1024 * 1024)).toFixed(2)} MB`; + }, + }, + { + accessorKey: "CreateDt", + header: "생성일시", + minSize: 200, + cell: ({ row }) => { + return <div className="text-sm text-muted-foreground">{row.getValue("CreateDt")}</div>; + }, + }, + { + id: "actions", + header: "다운로드", + minSize: 120, + cell: ({ row }) => { + return ( + <Button + variant="outline" + size="sm" + onClick={() => onDownload(row.original)} + > + <Download className="h-4 w-4 mr-2" /> + 다운로드 + </Button> + ); + }, + }, +]; + diff --git a/lib/dolce/table/gtt-drawing-list-columns.tsx b/lib/dolce/table/gtt-drawing-list-columns.tsx new file mode 100644 index 00000000..2ff2d7e2 --- /dev/null +++ b/lib/dolce/table/gtt-drawing-list-columns.tsx @@ -0,0 +1,166 @@ +"use client"; + +import { ColumnDef } from "@tanstack/react-table"; +import { GttDwgReceiptItem } from "../actions"; + +// 날짜 포맷 헬퍼 +function formatDate(dateStr: string | null): string | null { + if (!dateStr || dateStr.length !== 8) return null; + return `${dateStr.substring(0, 4)}-${dateStr.substring(4, 6)}-${dateStr.substring(6, 8)}`; +} + +// Document Type 필터 +export type DocumentType = "ALL" | "GTT_DELIVERABLES" | "SHI_INPUT"; + +interface GttDrawingListColumnsOptions { + documentType: DocumentType; +} + +export function createGttDrawingListColumns({ + documentType, +}: GttDrawingListColumnsOptions): ColumnDef<GttDwgReceiptItem>[] { + const baseColumns: ColumnDef<GttDwgReceiptItem>[] = [ + { + accessorKey: "DrawingNo", + header: "도면번호", + minSize: 200, + cell: ({ row }) => { + return <div className="font-medium">{row.getValue("DrawingNo")}</div>; + }, + }, + { + accessorKey: "DrawingName", + header: "도면명", + minSize: 400, + cell: ({ row }) => { + return <div>{row.getValue("DrawingName")}</div>; + }, + }, + { + accessorKey: "Discipline", + header: "설계공종", + minSize: 80, + }, + { + accessorKey: "Manager", + header: "담당자명", + minSize: 200, + cell: ({ row }) => { + const managerENM = row.original.ManagerENM; + const manager = row.getValue("Manager"); + return <div>{managerENM || manager}</div>; + }, + }, + { + accessorKey: "DrawingMoveGbn", + header: "구분", + minSize: 120, + }, + ]; + + // Document Type에 따른 날짜 컬럼 + const dateColumns: ColumnDef<GttDwgReceiptItem>[] = []; + + // ALL: 모든 컬럼 표시 + if (documentType === "ALL") { + dateColumns.push( + { + accessorKey: "GTTInput_PlanDate", + header: "GTT Input 예정일", + minSize: 150, + cell: ({ row }) => formatDate(row.getValue("GTTInput_PlanDate")), + }, + { + accessorKey: "GTTInput_ResultDate", + header: "GTT Input 결과일", + minSize: 150, + cell: ({ row }) => formatDate(row.getValue("GTTInput_ResultDate")), + }, + { + accessorKey: "GTTPreDwg_PlanDate", + header: "GTT Pre 예정일", + minSize: 140, + cell: ({ row }) => formatDate(row.getValue("GTTPreDwg_PlanDate")), + }, + { + accessorKey: "GTTPreDwg_ResultDate", + header: "GTT Pre 결과일", + minSize: 140, + cell: ({ row }) => formatDate(row.getValue("GTTPreDwg_ResultDate")), + }, + { + accessorKey: "GTTWorkingDwg_PlanDate", + header: "GTT Working 예정일", + minSize: 160, + cell: ({ row }) => formatDate(row.getValue("GTTWorkingDwg_PlanDate")), + }, + { + accessorKey: "GTTWorkingDwg_ResultDate", + header: "GTT Working 결과일", + minSize: 160, + cell: ({ row }) => formatDate(row.getValue("GTTWorkingDwg_ResultDate")), + } + ); + } + // SHI_INPUT: 도면제출 (GTTInput만) + else if (documentType === "SHI_INPUT") { + dateColumns.push( + { + accessorKey: "GTTInput_PlanDate", + header: "Input 예정일", + minSize: 120, + cell: ({ row }) => formatDate(row.getValue("GTTInput_PlanDate")), + }, + { + accessorKey: "GTTInput_ResultDate", + header: "Input 결과일", + minSize: 120, + cell: ({ row }) => formatDate(row.getValue("GTTInput_ResultDate")), + } + ); + } + // GTT_DELIVERABLES: 도면입수 (Pre, Working) + else if (documentType === "GTT_DELIVERABLES") { + dateColumns.push( + { + accessorKey: "GTTPreDwg_PlanDate", + header: "Pre 예정일", + minSize: 120, + cell: ({ row }) => formatDate(row.getValue("GTTPreDwg_PlanDate")), + }, + { + accessorKey: "GTTPreDwg_ResultDate", + header: "Pre 결과일", + minSize: 120, + cell: ({ row }) => formatDate(row.getValue("GTTPreDwg_ResultDate")), + }, + { + accessorKey: "GTTWorkingDwg_PlanDate", + header: "Working 예정일", + minSize: 130, + cell: ({ row }) => formatDate(row.getValue("GTTWorkingDwg_PlanDate")), + }, + { + accessorKey: "GTTWorkingDwg_ResultDate", + header: "Working 결과일", + minSize: 130, + cell: ({ row }) => formatDate(row.getValue("GTTWorkingDwg_ResultDate")), + } + ); + } + + // 생성일시 컬럼 + const endColumns: ColumnDef<GttDwgReceiptItem>[] = [ + { + accessorKey: "CreateDt", + header: "생성일시", + minSize: 200, + cell: ({ row }) => { + return <div className="text-sm text-muted-foreground">{row.getValue("CreateDt")}</div>; + }, + }, + ]; + + return [...baseColumns, ...dateColumns, ...endColumns]; +} + |
