diff options
Diffstat (limited to 'lib/po/vendor-table/vendor-po-columns.tsx')
| -rw-r--r-- | lib/po/vendor-table/vendor-po-columns.tsx | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/lib/po/vendor-table/vendor-po-columns.tsx b/lib/po/vendor-table/vendor-po-columns.tsx new file mode 100644 index 00000000..1a655b0c --- /dev/null +++ b/lib/po/vendor-table/vendor-po-columns.tsx @@ -0,0 +1,511 @@ +"use client" + +import * as React from "react" +import { type ColumnDef } from "@tanstack/react-table" +import { + FileTextIcon, + MoreHorizontalIcon, + EyeIcon, + PrinterIcon, + FileXIcon, + PlusIcon, + EditIcon +} from "lucide-react" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" +import { Checkbox } from "@/components/ui/checkbox" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" +import { VendorPO, VendorPOActionType } from "./types" + +// 벤더 PO용 행 액션 타입 +type VendorPORowAction = { + row: { original: VendorPO } + type: VendorPOActionType +} + +interface GetVendorColumnsProps { + setRowAction: React.Dispatch<React.SetStateAction<VendorPORowAction | null>> + selectedRows?: number[] + onRowSelect?: (id: number, selected: boolean) => void +} + +export function getVendorColumns({ setRowAction, selectedRows = [], onRowSelect }: GetVendorColumnsProps): ColumnDef<VendorPO>[] { + return [ + // 선택 체크박스 (1개만 선택 가능) + { + id: "select", + header: () => <div className="text-center">선택</div>, + cell: ({ row }) => ( + <div className="flex justify-center"> + <Checkbox + checked={selectedRows.includes(row.original.id)} + onCheckedChange={(checked) => { + if (onRowSelect) { + onRowSelect(row.original.id, !!checked) + } + }} + aria-label="행 선택" + /> + </div> + ), + enableSorting: false, + enableHiding: false, + size: 40, + }, + + // No. (ID) + { + accessorKey: "id", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="No." /> + ), + cell: ({ row }) => { + const id = row.getValue("id") as number + return <div className="text-sm font-mono">{id}</div> + }, + size: 60, + }, + + // PO/계약번호 + { + accessorKey: "contractNo", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="PO/계약번호" /> + ), + cell: ({ row }) => { + const contractNo = row.getValue("contractNo") as string + return ( + <div className="font-medium"> + {contractNo} + </div> + ) + }, + size: 120, + }, + + // Rev. / 품번 (PO 버전) + { + accessorKey: "poVersion", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="Rev. / 품번" /> + ), + cell: ({ row }) => { + const version = row.getValue("poVersion") as number + return <div className="text-sm font-medium">{version || '-'}</div> + }, + size: 80, + }, + + // 계약상태 + { + accessorKey: "contractStatus", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="계약상태" /> + ), + cell: ({ row }) => { + const status = row.getValue("contractStatus") as string + return ( + <Badge variant="outline"> + {status || '-'} + </Badge> + ) + }, + size: 100, + }, + + // 계약종류 + { + accessorKey: "contractType", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="계약종류" /> + ), + cell: ({ row }) => { + const type = row.getValue("contractType") as string + return <Badge variant="outline">{type || '-'}</Badge> + }, + size: 100, + }, + + // 상세품목 (버튼) + { + id: "itemsAction", + header: () => <div className="text-center">상세품목</div>, + cell: ({ row }) => ( + <div className="flex justify-center"> + <Button + variant="outline" + size="sm" + className="h-8 px-2" + onClick={() => setRowAction({ row, type: "view-items" })} + > + <FileTextIcon className="h-3.5 w-3.5 mr-1" /> + 보기 + </Button> + </div> + ), + enableSorting: false, + size: 80, + }, + + // 프로젝트 + { + accessorKey: "projectName", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="프로젝트" /> + ), + cell: ({ row }) => { + const projectName = row.getValue("projectName") as string + return ( + <div className="max-w-[150px] truncate" title={projectName}> + {projectName || '-'} + </div> + ) + }, + size: 150, + }, + + // 계약명/자재내역 + { + accessorKey: "contractName", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="계약명/자재내역" /> + ), + cell: ({ row }) => { + const contractName = row.getValue("contractName") as string + return ( + <div className="max-w-[200px] truncate" title={contractName}> + {contractName || '-'} + </div> + ) + }, + size: 200, + }, + + // PO/계약기간 + { + accessorKey: "contractPeriod", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="PO/계약기간" /> + ), + cell: ({ row }) => { + const period = row.getValue("contractPeriod") as string + return ( + <div className="text-sm whitespace-nowrap"> + {period || '-'} + </div> + ) + }, + size: 150, + }, + + // PO/계약금액 + { + accessorKey: "totalAmount", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="PO/계약금액" /> + ), + cell: ({ row }) => { + const amount = row.getValue("totalAmount") as string | number + return <div className="text-sm text-right font-mono">{amount || '-'}</div> + }, + size: 120, + }, + + // 계약통화 + { + accessorKey: "currency", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="계약통화" /> + ), + cell: ({ row }) => { + const currency = row.getValue("currency") as string + return <div className="text-sm font-mono">{currency || '-'}</div> + }, + size: 80, + }, + + // 지불조건 + { + accessorKey: "paymentTerms", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="지불조건" /> + ), + cell: ({ row }) => { + const terms = row.getValue("paymentTerms") as string + return ( + <div className="max-w-[120px] truncate text-sm" title={terms}> + {terms || '-'} + </div> + ) + }, + size: 120, + }, + + // Tax + { + accessorKey: "tax", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="Tax" /> + ), + cell: ({ row }) => { + const tax = row.getValue("tax") as string + return <div className="text-sm">{tax || '-'}</div> + }, + size: 80, + }, + + // 환율 + { + accessorKey: "exchangeRate", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="환율" /> + ), + cell: ({ row }) => { + const rate = row.getValue("exchangeRate") as string + return <div className="text-sm font-mono">{rate || '-'}</div> + }, + size: 100, + }, + + // 인도조건 + { + accessorKey: "deliveryTerms", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="인도조건" /> + ), + cell: ({ row }) => { + const terms = row.getValue("deliveryTerms") as string + return <div className="text-sm">{terms || '-'}</div> + }, + size: 100, + }, + + // 구매/계약담당 + { + accessorKey: "purchaseManager", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="구매/계약담당" /> + ), + cell: ({ row }) => { + const manager = row.getValue("purchaseManager") as string + return <div className="text-sm">{manager || '-'}</div> + }, + size: 120, + }, + + // PO/계약수신일 + { + accessorKey: "poReceiveDate", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="PO/계약수신일" /> + ), + cell: ({ row }) => { + const date = row.getValue("poReceiveDate") as string + return <div className="text-sm">{date || '-'}</div> + }, + size: 120, + }, + + // 계약체결일 + { + accessorKey: "contractDate", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="계약체결일" /> + ), + cell: ({ row }) => { + const date = row.getValue("contractDate") as string + return <div className="text-sm">{date || '-'}</div> + }, + size: 120, + }, + + // L/C No. + { + accessorKey: "lcNo", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="L/C No." /> + ), + cell: ({ row }) => { + const lcNo = row.getValue("lcNo") as string + return <div className="text-sm">{lcNo || '-'}</div> + }, + size: 120, + }, + + // 납품대금 연동제 대상 + { + accessorKey: "priceIndexTarget", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="납품대금 연동제 대상" /> + ), + cell: ({ row }) => { + const target = row.getValue("priceIndexTarget") as string | boolean + return <div className="text-sm">{target?.toString() || '-'}</div> + }, + size: 140, + }, + + // 연계 PO/계약번호 + { + accessorKey: "linkedContractNo", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="연계 PO/계약번호" /> + ), + cell: ({ row }) => { + const linkedNo = row.getValue("linkedContractNo") as string + return <div className="text-sm">{linkedNo || '-'}</div> + }, + size: 140, + }, + + // 최종수정일 + { + accessorKey: "lastModifiedDate", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="최종수정일" /> + ), + cell: ({ row }) => { + const date = row.getValue("lastModifiedDate") as string + return <div className="text-sm">{date || '-'}</div> + }, + size: 120, + }, + + // 최종수정자 + { + accessorKey: "lastModifiedBy", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="최종수정자" /> + ), + cell: ({ row }) => { + const user = row.getValue("lastModifiedBy") as string + return <div className="text-sm">{user || '-'}</div> + }, + size: 120, + }, + + // 액션 버튼들 + { + id: "actions", + enableHiding: false, + header: () => <div className="text-center">액션</div>, + cell: function Cell({ row }) { + return ( + <div className="flex gap-1"> + {/* 상세품목 버튼 */} + <TooltipProvider> + <Tooltip> + <TooltipTrigger asChild> + <Button + variant="outline" + size="sm" + className="h-8 px-2" + onClick={() => setRowAction({ row, type: "view-items" })} + > + <FileTextIcon className="h-3.5 w-3.5" aria-hidden="true" /> + </Button> + </TooltipTrigger> + <TooltipContent> + 상세품목 보기 + </TooltipContent> + </Tooltip> + </TooltipProvider> + + {/* 드롭다운 메뉴 */} + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="ghost" className="h-8 w-8 p-0"> + <span className="sr-only">Open menu</span> + <MoreHorizontalIcon className="h-4 w-4" /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuLabel>액션</DropdownMenuLabel> + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "view-items" })} + > + <FileTextIcon className="mr-2 h-4 w-4" /> + 상세품목 보기 + </DropdownMenuItem> + <DropdownMenuSeparator /> + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "pcr-create" })} + > + <PlusIcon className="mr-2 h-4 w-4" /> + PCR생성 + </DropdownMenuItem> + + <DropdownMenuSeparator /> + + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "approve" })} + > + 승인 + </DropdownMenuItem> + + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "cancel-approve" })} + > + 승인취소 + </DropdownMenuItem> + + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "reject-contract" })} + className="text-red-600" + > + <FileXIcon className="mr-2 h-4 w-4" /> + 계약거절 + </DropdownMenuItem> + + <DropdownMenuSeparator /> + + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "print-contract" })} + > + <PrinterIcon className="mr-2 h-4 w-4" /> + 계약서출력 + </DropdownMenuItem> + + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "contract-detail" })} + > + <EyeIcon className="mr-2 h-4 w-4" /> + 계약상세 + </DropdownMenuItem> + + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "po-note" })} + > + <EditIcon className="mr-2 h-4 w-4" /> + PO Note + </DropdownMenuItem> + + <DropdownMenuItem + onClick={() => setRowAction({ row, type: "price-index" })} + > + 연동표입력 + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + </div> + ); + }, + size: 120, + minSize: 100, + }, + ] +}
\ No newline at end of file |
