diff options
Diffstat (limited to 'lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx')
| -rw-r--r-- | lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx | 632 |
1 files changed, 325 insertions, 307 deletions
diff --git a/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx index b6f9289f..cd748fd8 100644 --- a/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx +++ b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx @@ -1,307 +1,325 @@ -"use client"
-
-import { type ColumnDef } from "@tanstack/react-table"
-import { Checkbox } from "@/components/ui/checkbox"
-import { Badge } from "@/components/ui/badge"
-import { format } from "date-fns"
-
-import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
-import { VendorRegularRegistration, statusLabels, statusColors } from "@/config/vendorRegularRegistrationsColumnsConfig"
-import { DocumentStatusDialog } from "@/components/vendor-regular-registrations/document-status-dialog"
-import { Button } from "@/components/ui/button"
-import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
-import { Eye, FileText, Ellipsis, Shield, Package } from "lucide-react"
-import { toast } from "sonner"
-import { useState } from "react"
-import { SafetyQualificationUpdateDialog } from "./safety-qualification-update-dialog"
-import { MajorItemsUpdateDialog } from "./major-items-update-dialog"
-
-export function getColumns(): ColumnDef<VendorRegularRegistration>[] {
-
- return [
- {
- id: "select",
- header: ({ table }) => (
- <Checkbox
- checked={
- table.getIsAllPageRowsSelected() ||
- (table.getIsSomePageRowsSelected() && "indeterminate")
- }
- onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
- aria-label="Select all"
- className="translate-y-[2px]"
- />
- ),
- cell: ({ row }) => (
- <Checkbox
- checked={row.getIsSelected()}
- onCheckedChange={(value) => row.toggleSelected(!!value)}
- aria-label="Select row"
- className="translate-y-[2px]"
- />
- ),
- enableSorting: false,
- enableHiding: false,
- },
- {
- accessorKey: "status",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="Status" />
- ),
- cell: ({ row }) => {
- const status = row.getValue("status") as string
- return (
- <Badge
- variant="secondary"
- className={statusColors[status as keyof typeof statusColors]}
- >
- {statusLabels[status as keyof typeof statusLabels] || status}
- </Badge>
- )
- },
- filterFn: (row, id, value) => {
- return Array.isArray(value) && value.includes(row.getValue(id))
- },
- },
- {
- accessorKey: "potentialCode",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="잠재코드" />
- ),
- cell: ({ row }) => row.getValue("potentialCode") || "-",
- },
- {
- accessorKey: "businessNumber",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="사업자번호" />
- ),
- },
- {
- accessorKey: "companyName",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="업체명" />
- ),
- },
- {
- accessorKey: "majorItems",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="주요품목" />
- ),
- cell: ({ row }) => {
- const majorItems = row.getValue("majorItems") as string
- try {
- const items = majorItems ? JSON.parse(majorItems) : []
- if (items.length === 0) return "-"
-
- // 첫 번째 아이템을 itemCode-itemName 형태로 표시
- const firstItem = items[0]
- let displayText = ""
-
- if (typeof firstItem === 'string') {
- displayText = firstItem
- } else if (typeof firstItem === 'object') {
- const code = firstItem.itemCode || firstItem.code || ""
- const name = firstItem.itemName || firstItem.name || firstItem.materialGroupName || ""
- if (code && name) {
- displayText = `${code}-${name}`
- } else {
- displayText = name || code || String(firstItem)
- }
- } else {
- displayText = String(firstItem)
- }
-
- // 나머지 개수 표시
- if (items.length > 1) {
- displayText += ` 외 ${items.length - 1}개`
- }
-
- return displayText
- } catch {
- return majorItems || "-"
- }
- },
- },
- {
- accessorKey: "establishmentDate",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="설립일자" />
- ),
- cell: ({ row }) => {
- const date = row.getValue("establishmentDate") as string
- return date ? format(new Date(date), "yyyy.MM.dd") : "-"
- },
- },
- {
- accessorKey: "representative",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="대표자명" />
- ),
- cell: ({ row }) => row.getValue("representative") || "-",
- },
- {
- id: "documentStatus",
- header: "진행현황",
- cell: ({ row }) => {
- const DocumentStatusCell = () => {
- const [documentDialogOpen, setDocumentDialogOpen] = useState(false)
- const registration = row.original
-
- // 문서 현황 계산 (국가별 요구사항 적용)
- const isForeign = registration.country !== 'KR'
- const requiredDocs = isForeign ? 4 : 3 // 외자: 4개(통장사본 포함), 내자: 3개(통장사본 제외)
- const submittedDocs = Object.values(registration.documentSubmissions).filter(Boolean).length
- const incompleteDocs = requiredDocs - submittedDocs
-
- // 기본계약 현황 계산
- const totalContracts = registration.basicContracts?.length || 0
- const completedContracts = registration.basicContracts?.filter(c => c.status === "VENDOR_SIGNED" || c.status === "COMPLETED").length || 0
- const incompleteContracts = totalContracts - completedContracts
-
- // 안전적격성 평가 현황
- const safetyCompleted = !!registration.safetyQualificationContent
-
- // 추가정보 현황
- const additionalInfoCompleted = registration.additionalInfo
-
- // 전체 미완료 항목 계산
- const totalIncomplete =
- (incompleteDocs > 0 ? 1 : 0) +
- incompleteContracts +
- (!safetyCompleted ? 1 : 0) +
- (!additionalInfoCompleted ? 1 : 0)
-
- const isAllComplete = totalIncomplete === 0
-
- return (
- <>
- <div className="space-y-1">
- <Button
- variant="ghost"
- size="sm"
- onClick={() => setDocumentDialogOpen(true)}
- className="h-auto p-1 text-left justify-start"
- >
- <div className="space-y-0.5">
- {isAllComplete ? (
- <div className="text-xs text-green-600 font-medium">모든 항목 완료</div>
- ) : (
- <div className="text-xs text-orange-600 font-medium">
- 총 {totalIncomplete}건 미완료
- </div>
- )}
- </div>
- </Button>
- </div>
- <DocumentStatusDialog
- open={documentDialogOpen}
- onOpenChange={setDocumentDialogOpen}
- registration={registration}
- isVendorUser={false}
- />
- </>
- )
- }
-
- return <DocumentStatusCell />
- },
- },
- {
- accessorKey: "registrationRequestDate",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="등록요청일" />
- ),
- cell: ({ row }) => {
- const date = row.getValue("registrationRequestDate") as string
- return date ? format(new Date(date), "yyyy.MM.dd") : "-"
- },
- },
- {
- accessorKey: "assignedDepartment",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="담당부서" />
- ),
- cell: ({ row }) => row.getValue("assignedDepartment") || "-",
- },
- {
- accessorKey: "assignedUser",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="담당자" />
- ),
- cell: ({ row }) => row.getValue("assignedUser") || "-",
- },
- {
- accessorKey: "remarks",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="비고" />
- ),
- cell: ({ row }) => row.getValue("remarks") || "-",
- },
- {
- id: "actions",
- cell: ({ row }) => {
- const ActionsDropdownCell = () => {
- const [safetyQualificationSheetOpen, setSafetyQualificationSheetOpen] = useState(false)
- const [majorItemsSheetOpen, setMajorItemsSheetOpen] = useState(false)
- const registration = row.original
-
- return (
- <>
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Button
- aria-label="Open menu"
- variant="ghost"
- className="flex h-8 w-8 p-0 data-[state=open]:bg-muted"
- >
- <Ellipsis className="h-4 w-4" />
- </Button>
- </DropdownMenuTrigger>
- <DropdownMenuContent align="end" className="w-[160px]">
- <DropdownMenuItem
- onClick={() => setSafetyQualificationSheetOpen(true)}
- >
- <Shield className="mr-2 h-4 w-4" />
- 안전적격성 평가
- </DropdownMenuItem>
- <DropdownMenuItem
- onClick={() => setMajorItemsSheetOpen(true)}
- >
- <Package className="mr-2 h-4 w-4" />
- 주요품목 등록
- </DropdownMenuItem>
-
- </DropdownMenuContent>
- </DropdownMenu>
- <SafetyQualificationUpdateDialog
- open={safetyQualificationSheetOpen}
- onOpenChange={setSafetyQualificationSheetOpen}
- registrationId={registration.id}
- vendorName={registration.companyName}
- currentContent={registration.safetyQualificationContent}
- onSuccess={() => {
- // 페이지 새로고침 또는 데이터 리페치
- window.location.reload()
- }}
- />
- <MajorItemsUpdateDialog
- open={majorItemsSheetOpen}
- onOpenChange={setMajorItemsSheetOpen}
- registrationId={registration.id}
- vendorName={registration.companyName}
- currentItems={registration.majorItems}
- onSuccess={() => {
- // 페이지 새로고침 또는 데이터 리페치
- window.location.reload()
- }}
- />
-
- </>
- )
- }
-
- return <ActionsDropdownCell />
- },
- },
- ]
-}
+"use client" + +import { type ColumnDef } from "@tanstack/react-table" +import { Checkbox } from "@/components/ui/checkbox" +import { Badge } from "@/components/ui/badge" +import { format } from "date-fns" + +import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" +import { VendorRegularRegistration, statusLabels, statusColors } from "@/config/vendorRegularRegistrationsColumnsConfig" +import { DocumentStatusDialog } from "@/components/vendor-regular-registrations/document-status-dialog" +import { Button } from "@/components/ui/button" +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" +import { Ellipsis, Shield, Package } from "lucide-react" +import { useState } from "react" +import { SafetyQualificationUpdateDialog } from "./safety-qualification-update-dialog" +import { MajorItemsUpdateDialog } from "./major-items-update-dialog" + +export function getColumns(): ColumnDef<VendorRegularRegistration>[] { + + return [ + { + id: "select", + header: ({ table }) => ( + <Checkbox + checked={ + table.getIsAllPageRowsSelected() || + (table.getIsSomePageRowsSelected() && "indeterminate") + } + onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + className="translate-y-[2px]" + /> + ), + cell: ({ row }) => ( + <Checkbox + checked={row.getIsSelected()} + onCheckedChange={(value) => row.toggleSelected(!!value)} + aria-label="Select row" + className="translate-y-[2px]" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "status", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="Status" /> + ), + cell: ({ row }) => { + const status = row.getValue("status") as string + return ( + <Badge + variant="secondary" + className={statusColors[status as keyof typeof statusColors]} + > + {statusLabels[status as keyof typeof statusLabels] || status} + </Badge> + ) + }, + filterFn: (row, id, value) => { + return Array.isArray(value) && value.includes(row.getValue(id)) + }, + }, + { + accessorKey: "potentialCode", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="잠재코드" /> + ), + cell: ({ row }) => row.getValue("potentialCode") || "-", + }, + { + accessorKey: "businessNumber", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="사업자번호" /> + ), + }, + { + accessorKey: "companyName", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="업체명" /> + ), + }, + { + accessorKey: "majorItems", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="주요품목" /> + ), + cell: ({ row }) => { + const majorItems = row.getValue("majorItems") as string + try { + const items = majorItems ? JSON.parse(majorItems) : [] + if (items.length === 0) return "-" + + // 모든 아이템을 표시 + return ( + <div className="flex flex-wrap gap-1 max-w-md"> + {items.map((item: unknown, index: number) => { + let displayText = "" + + if (typeof item === 'string') { + displayText = item + } else if (typeof item === 'object' && item !== null) { + // materialGroup 형태 처리 + const itemObj = item as Record<string, unknown> + const materialGroupCode = (itemObj.materialGroupCode as string) || "" + const materialGroupDescription = (itemObj.materialGroupDescription as string) || "" + + if (materialGroupCode && materialGroupDescription) { + displayText = `${materialGroupCode} - ${materialGroupDescription}` + } else if (materialGroupDescription) { + displayText = materialGroupDescription + } else if (materialGroupCode) { + displayText = materialGroupCode + } else { + // 알 수 없는 형태 + console.warn("알 수 없는 품목 형식:", item) + displayText = JSON.stringify(item) + } + } else { + displayText = String(item) + } + + return ( + <Badge + key={`${row.original.id}-item-${index}`} + variant="outline" + className="text-xs" + > + {displayText} + </Badge> + ) + })} + </div> + ) + } catch (error) { + // JSON 파싱 실패 시 원본 문자열 표시 + console.error("주요품목 파싱 오류:", error) + return majorItems || "-" + } + }, + }, + { + accessorKey: "establishmentDate", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="설립일자" /> + ), + cell: ({ row }) => { + const date = row.getValue("establishmentDate") as string + return date ? format(new Date(date), "yyyy.MM.dd") : "-" + }, + }, + { + accessorKey: "representative", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="대표자명" /> + ), + cell: ({ row }) => row.getValue("representative") || "-", + }, + { + id: "documentStatus", + header: "진행현황", + cell: ({ row }) => { + const DocumentStatusCell = () => { + const [documentDialogOpen, setDocumentDialogOpen] = useState(false) + const registration = row.original + + // 문서 현황 계산 (국가별 요구사항 적용) + const isForeign = registration.country !== 'KR' + const requiredDocs = isForeign ? 4 : 3 // 외자: 4개(통장사본 포함), 내자: 3개(통장사본 제외) + const submittedDocs = Object.values(registration.documentSubmissions).filter(Boolean).length + const incompleteDocs = requiredDocs - submittedDocs + + // 기본계약 현황 계산 + const totalContracts = registration.basicContracts?.length || 0 + const completedContracts = registration.basicContracts?.filter(c => c.status === "VENDOR_SIGNED" || c.status === "COMPLETED").length || 0 + const incompleteContracts = totalContracts - completedContracts + + // 안전적격성 평가 현황 + const safetyCompleted = !!registration.safetyQualificationContent + + // 추가정보 현황 + const additionalInfoCompleted = registration.additionalInfo + + // 전체 미완료 항목 계산 + const totalIncomplete = + (incompleteDocs > 0 ? 1 : 0) + + incompleteContracts + + (!safetyCompleted ? 1 : 0) + + (!additionalInfoCompleted ? 1 : 0) + + const isAllComplete = totalIncomplete === 0 + + return ( + <> + <div className="space-y-1"> + <Button + variant="ghost" + size="sm" + onClick={() => setDocumentDialogOpen(true)} + className="h-auto p-1 text-left justify-start" + > + <div className="space-y-0.5"> + {isAllComplete ? ( + <div className="text-xs text-green-600 font-medium">모든 항목 완료</div> + ) : ( + <div className="text-xs text-orange-600 font-medium"> + 총 {totalIncomplete}건 미완료 + </div> + )} + </div> + </Button> + </div> + <DocumentStatusDialog + open={documentDialogOpen} + onOpenChange={setDocumentDialogOpen} + registration={registration} + isVendorUser={false} + /> + </> + ) + } + + return <DocumentStatusCell /> + }, + }, + { + accessorKey: "registrationRequestDate", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="등록요청일" /> + ), + cell: ({ row }) => { + const date = row.getValue("registrationRequestDate") as string + return date ? format(new Date(date), "yyyy.MM.dd") : "-" + }, + }, + { + accessorKey: "assignedDepartment", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="담당부서" /> + ), + cell: ({ row }) => row.getValue("assignedDepartment") || "-", + }, + { + accessorKey: "assignedUser", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="담당자" /> + ), + cell: ({ row }) => row.getValue("assignedUser") || "-", + }, + { + accessorKey: "remarks", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="비고" /> + ), + cell: ({ row }) => row.getValue("remarks") || "-", + }, + { + id: "actions", + cell: ({ row }) => { + const ActionsDropdownCell = () => { + const [safetyQualificationSheetOpen, setSafetyQualificationSheetOpen] = useState(false) + const [majorItemsSheetOpen, setMajorItemsSheetOpen] = useState(false) + const registration = row.original + + return ( + <> + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button + aria-label="Open menu" + variant="ghost" + className="flex h-8 w-8 p-0 data-[state=open]:bg-muted" + > + <Ellipsis className="h-4 w-4" /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end" className="w-[160px]"> + <DropdownMenuItem + onClick={() => setSafetyQualificationSheetOpen(true)} + > + <Shield className="mr-2 h-4 w-4" /> + 안전적격성 평가 + </DropdownMenuItem> + <DropdownMenuItem + onClick={() => setMajorItemsSheetOpen(true)} + > + <Package className="mr-2 h-4 w-4" /> + 주요품목 등록 + </DropdownMenuItem> + + </DropdownMenuContent> + </DropdownMenu> + <SafetyQualificationUpdateDialog + open={safetyQualificationSheetOpen} + onOpenChange={setSafetyQualificationSheetOpen} + registrationId={registration.id} + vendorName={registration.companyName} + currentContent={registration.safetyQualificationContent} + onSuccess={() => { + // 페이지 새로고침 또는 데이터 리페치 + window.location.reload() + }} + /> + <MajorItemsUpdateDialog + open={majorItemsSheetOpen} + onOpenChange={setMajorItemsSheetOpen} + registrationId={registration.id} + vendorName={registration.companyName} + currentItems={registration.majorItems} + onSuccess={() => { + // 페이지 새로고침 또는 데이터 리페치 + window.location.reload() + }} + /> + + </> + ) + } + + return <ActionsDropdownCell /> + }, + }, + ] +} |
