summaryrefslogtreecommitdiff
path: root/lib/po/vendor-table/vendor-po-columns.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/po/vendor-table/vendor-po-columns.tsx')
-rw-r--r--lib/po/vendor-table/vendor-po-columns.tsx511
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