import { Checkbox } from "@/components/ui/checkbox" import { Button } from "@/components/ui/button" import { Trash2 } from "lucide-react" import { type ColumnDef } from "@tanstack/react-table" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { EditableCell } from "@/components/data-table/editable-cell" // 수정 여부 확인 헬퍼 함수 const getIsModified = (table: any, rowId: string, fieldName: string) => { const pendingChanges = table.options.meta?.getPendingChanges?.() || {} return String(rowId) in pendingChanges && fieldName in pendingChanges[String(rowId)] } // vendor-pool 테이블 메타 타입 (복사본) interface VendorPoolTableMeta { onCellUpdate?: (id: string | number, field: string, newValue: any) => Promise onCellCancel?: (id: string | number, field: string) => void onAction?: (action: string, data?: any) => void onSaveEmptyRow?: (tempId: string) => Promise onCancelEmptyRow?: (tempId: string) => void isEmptyRow?: (id: string) => boolean } // Vendor Pool 데이터 타입 - 스키마 기반 + 테이블용 추가 필드 import type { VendorPool } from "@/db/schema/avl/vendor-pool" import { DisciplineHardcodedSelector } from "@/components/common/discipline-hardcoded" import { MaterialGroupSelectorDialogSingle } from "@/components/common/material/material-group-selector-dialog-single" import type { MaterialSearchItem } from "@/lib/material/material-group-service" import { VendorTierSelector } from "@/components/common/selectors/vendor-tier/vendor-tier-selector" import { VendorSelectorDialogSingle } from "@/components/common/vendor/vendor-selector-dialog-single" import type { VendorSearchItem } from "@/components/common/vendor/vendor-service" import { PlaceOfShippingSelectorDialogSingle } from "@/components/common/selectors/place-of-shipping/place-of-shipping-selector" import { NationSelector, NationCode } from "@/components/common/selectors/nation" export type VendorPoolItem = Omit & { id: string | number // temp-로 시작하는 경우 string, 실제 데이터는 number no: number // 테이블 표시용 순번 selected: boolean // 테이블 선택 상태 registrationDate: string // 표시용 string으로 변환 lastModifiedDate: string // 표시용 string으로 변환 } // 테이블 컬럼 정의 export const columns: ColumnDef[] = [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, enableColumnFilter: false, size: 40, }, { accessorKey: "id", accessorFn: (row) => String(row.id), header: ({ column }) => ( ), cell: ({ row }) => { const id = String(row.original.id) // 빈 행의 경우 신규 표시 if (id.startsWith('temp-')) { return
신규
} // 실제 ID 표시 return
{id}
}, size: 120, }, { accessorKey: "constructionSector", header: ({ column }) => ( 공사부문 *} /> ), cell: ({ row, table }) => { const value = row.getValue("constructionSector") const isEmptyRow = String(row.original.id).startsWith('temp-') const onSave = async (newValue: any) => { const meta = table.options.meta as VendorPoolTableMeta if (meta?.onCellUpdate) { await meta.onCellUpdate(row.original.id, "constructionSector", newValue) } } // 수정 여부 확인 const isModified = getIsModified(table, row.original.id, "constructionSector") return ( ) }, size: 160, }, { accessorKey: "htDivision", header: ({ column }) => ( H/T *} /> ), cell: ({ row, table }) => { const value = row.getValue("htDivision") const isEmptyRow = String(row.original.id).startsWith('temp-') const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "htDivision", newValue) } } // 수정 여부 확인 const isModified = getIsModified(table, row.original.id, "htDivision") return ( ) }, size: 120, }, { accessorKey: "discipline", header: ({ column }) => ( 설계공종 *} /> ), cell: ({ row, table }) => { const discipline = row.original.discipline as string const onDisciplineSelect = async (newDiscipline: string) => { console.log('선택된 설계공종:', newDiscipline) console.log('행 ID:', row.original.id) if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "discipline", newDiscipline) } else { console.error('onCellUpdate가 정의되지 않음') } } return ( ) }, size: 200, }, { accessorKey: "equipBulkDivision", header: ({ column }) => ( ), cell: ({ row, table }) => { const value = row.getValue("equipBulkDivision") const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "equipBulkDivision", newValue) } } return ( ) }, size: 180, }, { // accessorKey: "materialGroupName", id: "materialGroupName", accessorFn: (row) => { if (row.materialGroupCode && row.materialGroupName) { return `${row.materialGroupCode} - ${row.materialGroupName}` } return row.materialGroupName || row.materialGroupCode || "" }, header: ({ column }) => ( 자재그룹 *} /> ), cell: ({ row, table }) => { const materialGroupCode = row.original.materialGroupCode as string const materialGroupName = row.original.materialGroupName as string // 현재 선택된 material 구성 const selectedMaterial: MaterialSearchItem | null = materialGroupCode && materialGroupName ? { materialGroupCode, materialGroupDescription: materialGroupName, displayText: `${materialGroupCode} - ${materialGroupName}` } : null const onMaterialSelect = async (material: MaterialSearchItem | null) => { console.log('선택된 자재그룹:', material) if (material) { // 자재그룹코드와 자재그룹명 필드 모두 업데이트 if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "materialGroupCode", material.materialGroupCode) await table.options.meta.onCellUpdate(row.original.id, "materialGroupName", material.materialGroupDescription) } } else { // 선택 해제 시 빈 값으로 설정 if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "materialGroupCode", "") await table.options.meta.onCellUpdate(row.original.id, "materialGroupName", "") } } } return ( ) }, size: 400, }, { accessorKey: "similarMaterialNamePurchase", header: ({ column }) => ( // 이전에는 컬럼명이 '유사자재명(구매외)' 였음. ), cell: ({ row, table }) => { const value = row.getValue("similarMaterialNamePurchase") const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "similarMaterialNamePurchase", newValue) } } return ( ) }, size: 250, }, { accessorKey: "vendorSelector", header: ({ column }) => ( ), cell: ({ row, table }) => { const vendorCode = row.original.vendorCode as string const vendorName = row.original.vendorName as string // 현재 선택된 vendor 구성 const selectedVendor: VendorSearchItem | null = vendorCode && vendorName ? { id: 0, // 실제로는 vendorId가 있어야 하지만 여기서는 임시로 0 사용 vendorName, vendorCode: vendorCode || null, taxId: null, // 사업자번호는 vendor-pool에서 관리하지 않음 status: "ACTIVE", // 임시 값 displayText: vendorName + (vendorCode ? ` (${vendorCode})` : "") } : null const onVendorSelect = async (vendor: VendorSearchItem | null) => { console.log('선택된 협력업체:', vendor) if (vendor) { // 협력업체코드, 협력업체명 필드 업데이트 if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "vendorCode", vendor.vendorCode || "") await table.options.meta.onCellUpdate(row.original.id, "vendorName", vendor.vendorName) } } else { // 선택 해제 시 빈 값으로 설정 if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "vendorCode", "") await table.options.meta.onCellUpdate(row.original.id, "vendorName", "") } } } return ( ) }, enableColumnFilter: false, size: 200, }, { accessorKey: "vendorCode", header: ({ column }) => ( ), cell: ({ row, table }) => { const value = row.getValue("vendorCode") const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "vendorCode", newValue) } } // 수정 여부 확인 const isModified = getIsModified(table, row.original.id, "vendorCode") return ( ) }, size: 200, }, { // accessorKey: "vendorName", id: "vendorName", accessorFn: (row) => { if (row.vendorCode && row.vendorName) { return `${row.vendorCode} - ${row.vendorName}` } return row.vendorName || row.vendorCode || "" }, header: ({ column }) => ( 협력업체 명 *} /> ), cell: ({ row, table }) => { const value = row.original.vendorName // accessorFn을 썼으므로 getValue() 대신 original 참조가 더 안전 const isEmptyRow = String(row.original.id).startsWith('temp-') const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "vendorName", newValue) } } // 수정 여부 확인 const isModified = getIsModified(table, row.original.id, "vendorName") return ( ) }, size: 200, }, { accessorKey: "faTarget", header: "FA대상", cell: ({ row, table }) => { const value = row.getValue("faTarget") as boolean const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "faTarget", newValue) } } // 수정 여부 확인 const isModified = getIsModified(table, row.original.id, "faTarget") return ( ) }, enableSorting: false, size: 120, }, { accessorKey: "tier", header: ({ column }) => ( 등급 *} /> ), cell: ({ row, table }) => { const value = row.original.tier as string const onValueChange = async (newValue: string) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "tier", newValue) } } return ( ) }, size: 150, }, { accessorKey: "headquarterLocation", header: ({ column }) => ( 본사 위치 *} /> ), cell: ({ row, table }) => { const headquarterLocation = row.original.headquarterLocation as string // 현재 선택된 국가명으로부터 국가 코드를 찾기 위해 임시로 null 설정 // 실제로는 국가명에서 국가코드를 역추적해야 하지만, 여기서는 단순화 const selectedNation: NationCode | undefined = undefined const onNationSelect = async (nation: NationCode) => { console.log('선택된 국가:', nation) if (table.options.meta?.onCellUpdate) { // CDNM 값(한국어 국가명)을 저장 await table.options.meta.onCellUpdate(row.original.id, "headquarterLocation", nation.CDNM) } } return ( ) }, size: 220, }, { accessorKey: "manufacturingLocation", header: ({ column }) => ( 제작/선적지 *} /> ), cell: ({ row, table }) => { const manufacturingLocation = row.original.manufacturingLocation as string // 현재 선택된 장소 구성 (description은 알 수 없으므로 null로 설정) const selectedPlace = null // 선택된 장소 표시를 위해 null로 설정 const onPlaceSelect = async (place: { code: string; description: string } | null) => { console.log('선택된 제작/선적지:', place) if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "manufacturingLocation", place?.code || "") } } return ( ) }, size: 200, }, { accessorKey: "avlVendorName", header: ({ column }) => ( AVL 등재업체명 *} /> ), cell: ({ row, table }) => { const value = row.getValue("avlVendorName") const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "avlVendorName", newValue) } } return ( ) }, size: 220, }, { accessorKey: "similarVendorName", header: ({ column }) => ( // 이전에는 컬럼명이 '유사업체명' 였음. ), cell: ({ row, table }) => { const value = row.getValue("similarVendorName") const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "similarVendorName", newValue) } } return ( ) }, size: 280, }, { accessorKey: "isBlacklist", header: "Blacklist", cell: ({ row, table }) => { const value = row.getValue("isBlacklist") as boolean const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "isBlacklist", newValue) } } return ( ) }, enableSorting: false, size: 100, }, { accessorKey: "isBcc", header: "BCC", cell: ({ row, table }) => { const value = row.getValue("isBcc") as boolean const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "isBcc", newValue) } } return ( ) }, enableSorting: false, size: 100, }, { accessorKey: "purchaseOpinion", header: ({ column }) => ( ), cell: ({ row, table }) => { const value = row.getValue("purchaseOpinion") const onSave = async (newValue: any) => { if (table.options.meta?.onCellUpdate) { await table.options.meta.onCellUpdate(row.original.id, "purchaseOpinion", newValue) } } return ( ) }, size: 300, }, { accessorKey: "recentQuoteDate", header: ({ column }) => ( ), cell: ({ row }) => { const value = row.getValue("recentQuoteDate") as string return (
{value || "-"}
) }, size: 200, }, { accessorKey: "recentQuoteNumber", header: ({ column }) => ( ), cell: ({ row }) => { const value = row.getValue("recentQuoteNumber") as string return (
{value || "-"}
) }, size: 200, }, { accessorKey: "recentOrderDate", header: ({ column }) => ( ), cell: ({ row }) => { const value = row.getValue("recentOrderDate") as string return (
{value || "-"}
) }, size: 150, }, { accessorKey: "recentOrderNumber", header: ({ column }) => ( ), cell: ({ row }) => { const value = row.getValue("recentOrderNumber") as string return (
{value || "-"}
) }, size: 200, }, { accessorKey: "registrationDate", header: ({ column }) => ( ), size: 150, }, { accessorKey: "registrant", header: ({ column }) => ( ), cell: ({ row }) => { const value = row.getValue("registrant") as string return
{value || ""}
}, size: 150, }, { accessorKey: "lastModifiedDate", header: ({ column }) => ( ), size: 150, }, { accessorKey: "lastModifier", header: ({ column }) => ( ), cell: ({ row }) => { const value = row.getValue("lastModifier") as string return
{value || ""}
}, size: 150, }, // 액션 그룹 { id: "actions", header: "액션", cell: ({ row, table }) => { const data = row.original const isEmptyRow = (table.options.meta as any)?.isEmptyRow?.(String(data.id)) if (isEmptyRow) { // 빈 행의 경우 저장/취소 버튼 표시 return (
) } // 일반 행의 경우 기존 액션 버튼들 표시 return (
) }, size: 120, enableSorting: false, enableHiding: false, enableColumnFilter: false, }, ]