From 30683aee60eedd39893c79773fbae913349a0417 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Tue, 26 Aug 2025 08:23:00 +0000
Subject: (최겸) gtc 레코드 생성 및 기술영업 아이템 import 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../possible-items-toolbar-actions.tsx             | 156 ++++++++++++++++++++-
 1 file changed, 153 insertions(+), 3 deletions(-)

(limited to 'lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx')

diff --git a/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx b/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx
index 192bf614..371f88f9 100644
--- a/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx
+++ b/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx
@@ -2,7 +2,7 @@
 
 import * as React from "react"
 import type { Table } from "@tanstack/react-table"
-import { Plus, Trash2 } from "lucide-react"
+import { Plus, Trash2, Upload, Download } from "lucide-react"
 import { toast } from "sonner"
 
 import { Button } from "@/components/ui/button"
@@ -19,21 +19,33 @@ import {
 } from "@/components/ui/alert-dialog"
 
 import type { TechVendorPossibleItem } from "../validations"
-import { deleteTechVendorPossibleItemsNew } from "../service"
+import {
+  deleteTechVendorPossibleItemsNew,
+  parsePossibleItemsImportFile,
+  importPossibleItemsFromExcel,
+  generatePossibleItemsImportTemplate,
+  generatePossibleItemsErrorExcel,
+  type PossibleItemImportData,
+  type PossibleItemErrorData
+} from "../service"
 
 interface PossibleItemsTableToolbarActionsProps {
   table: Table<TechVendorPossibleItem>
   vendorId: number
   onAdd: () => void // 주석처리
+  onRefresh?: () => void // 데이터 새로고침 콜백
 }
 
 export function PossibleItemsTableToolbarActions({
   table,
   vendorId,
   onAdd, // 주석처리
+  onRefresh,
 }: PossibleItemsTableToolbarActionsProps) {
   const [showDeleteAlert, setShowDeleteAlert] = React.useState(false)
   const [isDeleting, setIsDeleting] = React.useState(false)
+  const [isImporting, setIsImporting] = React.useState(false)
+  const fileInputRef = React.useRef<HTMLInputElement>(null)
 
   const selectedRows = table.getFilteredSelectedRowModel().rows
 
@@ -42,7 +54,7 @@ export function PossibleItemsTableToolbarActions({
     try {
       const ids = selectedRows.map((row) => row.original.id)
       const { error } = await deleteTechVendorPossibleItemsNew(ids, vendorId)
-      
+
       if (error) {
         throw new Error(error)
       }
@@ -50,6 +62,7 @@ export function PossibleItemsTableToolbarActions({
       toast.success(`${ids.length}개의 아이템이 삭제되었습니다`)
       table.resetRowSelection()
       setShowDeleteAlert(false)
+      onRefresh?.() // 데이터 새로고침
     } catch {
       toast.error("아이템 삭제 중 오류가 발생했습니다")
     } finally {
@@ -57,9 +70,146 @@ export function PossibleItemsTableToolbarActions({
     }
   }
 
+  // 템플릿 다운로드 핸들러
+  async function handleTemplateDownload() {
+    try {
+      const templateBlob = await generatePossibleItemsImportTemplate()
+      const url = window.URL.createObjectURL(templateBlob)
+      const link = document.createElement("a")
+      link.href = url
+      link.download = "벤더_possible_items_템플릿.xlsx"
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      window.URL.revokeObjectURL(url)
+      toast.success("템플릿 파일이 다운로드되었습니다")
+    } catch (error) {
+      toast.error("템플릿 다운로드 중 오류가 발생했습니다")
+    }
+  }
+
+  // 파일 선택 핸들러
+  function handleFileSelect() {
+    fileInputRef.current?.click()
+  }
+
+  // Excel 파일 import 핸들러
+  async function handleFileImport(event: React.ChangeEvent<HTMLInputElement>) {
+    const file = event.target.files?.[0]
+    if (!file) return
+
+    // 파일 타입 검증
+    if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.xls')) {
+      toast.error("Excel 파일(.xlsx 또는 .xls)만 업로드 가능합니다")
+      return
+    }
+
+    setIsImporting(true)
+    try {
+      // Excel 파일 파싱
+      const importData: PossibleItemImportData[] = await parsePossibleItemsImportFile(file)
+
+      if (importData.length === 0) {
+        toast.error("업로드할 데이터가 없습니다")
+        return
+      }
+
+      // 데이터 import 실행
+      const result = await importPossibleItemsFromExcel(importData)
+
+      // 결과 메시지 생성
+      const successMessage = `${result.successCount}개의 아이템이 성공적으로 등록되었습니다`
+      const failMessage = result.failedRows.length > 0
+        ? `, ${result.failedRows.length}개의 아이템 등록 실패`
+        : ""
+
+      toast.success(successMessage + failMessage)
+
+      // 실패한 행이 있는 경우 에러 파일 다운로드
+      if (result.failedRows.length > 0) {
+        const errorData: PossibleItemErrorData[] = result.failedRows.map(failedRow => ({
+          vendorEmail: failedRow.vendorEmail,
+          itemCode: failedRow.itemCode,
+          itemType: failedRow.itemType,
+          error: failedRow.error,
+        }))
+
+        const errorBlob = await generatePossibleItemsErrorExcel(errorData)
+        const url = window.URL.createObjectURL(errorBlob)
+        const link = document.createElement("a")
+        link.href = url
+        link.download = "possible_items_import_에러.xlsx"
+        document.body.appendChild(link)
+        link.click()
+        document.body.removeChild(link)
+        window.URL.revokeObjectURL(url)
+
+        toast.error("에러 내역 파일이 다운로드되었습니다")
+      }
+
+      // 파일 입력 초기화
+      if (fileInputRef.current) {
+        fileInputRef.current.value = ""
+      }
+
+      // 데이터 새로고침
+      onRefresh?.()
+
+    } catch (error) {
+      console.error("Import error:", error)
+      toast.error(error instanceof Error ? error.message : "데이터 등록 중 오류가 발생했습니다")
+    } finally {
+      setIsImporting(false)
+    }
+  }
+
   return (
     <>
       <div className="flex items-center gap-2">
+        {/* 템플릿 다운로드 버튼 */}
+        <Tooltip>
+          <TooltipTrigger asChild>
+            <Button
+              variant="outline"
+              size="sm"
+              onClick={handleTemplateDownload}
+            >
+              <Download className="mr-2 h-4 w-4" />
+              템플릿
+            </Button>
+          </TooltipTrigger>
+          <TooltipContent>
+            Excel 템플릿 파일 다운로드
+          </TooltipContent>
+        </Tooltip>
+
+        {/* Excel Import 버튼 */}
+        <Tooltip>
+          <TooltipTrigger asChild>
+            <Button
+              variant="outline"
+              size="sm"
+              onClick={handleFileSelect}
+              disabled={isImporting}
+            >
+              <Upload className="mr-2 h-4 w-4" />
+              {isImporting ? "등록 중..." : "Import"}
+            </Button>
+          </TooltipTrigger>
+          <TooltipContent>
+            Excel 파일로 아이템 일괄 등록
+          </TooltipContent>
+        </Tooltip>
+
+        {/* 숨겨진 파일 입력 */}
+        <input
+          ref={fileInputRef}
+          type="file"
+          accept=".xlsx,.xls"
+          onChange={handleFileImport}
+          className="hidden"
+        />
+
         {/* 아이템 추가 버튼 주석처리 */}
         <Button
           variant="outline"
-- 
cgit v1.2.3

