From aeaa24a239cf29f7bc98363339ccdbd51a4015f0 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Mon, 3 Nov 2025 16:02:12 +0900
Subject: (김준회) dolce: B4 일괄 업로드 파싱 로직 오류 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ship/bulk-b4-upload-dialog.tsx                 | 122 ++++++++++++---------
 1 file changed, 73 insertions(+), 49 deletions(-)

(limited to 'lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx')

diff --git a/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx b/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
index 52252e14..44f9c801 100644
--- a/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
+++ b/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
@@ -31,7 +31,6 @@ import {
   SelectTrigger,
   SelectValue,
 } from "@/components/ui/select"
-import { ScrollArea } from "@/components/ui/scroll-area"
 import { Badge } from "@/components/ui/badge"
 import {
   Upload,
@@ -48,40 +47,34 @@ import { bulkUploadB4Documents } from "../enhanced-document-service"
 
 // 파일명 파싱 유틸리티
 function parseFileName(fileName: string): { docNumber: string | null; revision: string | null } {
-  // 파일 확장자 제거
-  const nameWithoutExt = fileName.replace(/\.[^.]+$/, "")
-  
-  // revision 패턴 찾기 (R01, r01, REV01, rev01 등)
-  const revisionMatch = nameWithoutExt.match(/[Rr](?:EV)?(\d+)/g)
-  const revision = revisionMatch ? revisionMatch[revisionMatch.length - 1].toUpperCase() : null
-  
-  // revision 제거한 나머지에서 docNumber 찾기
-  let cleanedName = nameWithoutExt
-  if (revision) {
-    // revision과 그 앞의 구분자를 제거
-    const revPattern = new RegExp(`[-_\\s]*${revision.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1")}.*$`, 'i')
-    cleanedName = cleanedName.replace(revPattern, "")
+  // 공백으로 단어 분리 (첫 번째는 파일명으로 무시)
+  const words = fileName.trim().split(/\s+/).filter(word => word.length > 0)
+
+  if (words.length < 2) {
+    return { docNumber: null, revision: null }
   }
-  
-  // docNumber 패턴 찾기 (XX-XX-XX 형태)
-  // 공백이나 언더스코어를 하이픈으로 정규화
-  const normalizedName = cleanedName.replace(/[\s_]+/g, '-')
-  
-  // 2~3자리 코드가 2~3개 연결된 패턴 찾기
-  const docNumberPatterns = [
-    /\b([A-Za-z]{2,3})-([A-Za-z]{2,3})-([A-Za-z0-9]{2,4})\b/,
-    /\b([A-Za-z]{2,3})\s+([A-Za-z]{2,3})\s+([A-Za-z0-9]{2,4})\b/,
-  ]
-  
-  let docNumber: string | null = null
-  for (const pattern of docNumberPatterns) {
-    const match = normalizedName.match(pattern) || cleanedName.match(pattern)
-    if (match) {
-      docNumber = `${match[1]}-${match[2]}-${match[3]}`.toUpperCase()
-      break
-    }
+
+  // 마지막 단어에서 확장자와 리비전을 분리
+  const lastWord = words[words.length - 1]
+  const lastDotIndex = lastWord.lastIndexOf('.')
+
+  let revision: string | null = null
+
+  if (lastDotIndex !== -1) {
+    // 마지막 '.' 기준으로 확장자 앞부분만 사용
+    const beforeExt = lastWord.substring(0, lastDotIndex)
+
+    // revision 패턴 찾기 (R01, r01, REV01, rev01 등)
+    const revisionMatch = beforeExt.match(/[Rr](?:EV)?(\d+)/)
+    revision = revisionMatch ? revisionMatch[0].toUpperCase() : null
   }
-  
+
+  // 문서번호: 첫 번째(파일명)와 마지막(REV.ext)을 제외한 모든 단어들을 '-'로 연결
+  const docWords = words.slice(1, -1) // 첫 번째와 마지막 제외
+  const docNumber = docWords.length > 0
+    ? docWords.join('-').toUpperCase()
+    : null
+
   return { docNumber, revision }
 }
 
@@ -113,6 +106,7 @@ export function BulkB4UploadDialog({
   const [isUploading, setIsUploading] = React.useState(false)
   const [parsedFiles, setParsedFiles] = React.useState<ParsedFile[]>([])
   const [isDragging, setIsDragging] = React.useState(false)
+  const [currentProjectId, setCurrentProjectId] = React.useState<string>("")
   const router = useRouter()
   
   // 프로젝트 ID 추출
@@ -134,19 +128,45 @@ export function BulkB4UploadDialog({
   
   // 파일 선택 시 파싱
   const handleFilesChange = (files: File[]) => {
-    const parsed = files.map(file => {
-      const { docNumber, revision } = parseFileName(file.name)
-      return {
-        file,
-        docNumber,
-        revision,
-        status: docNumber ? 'pending' as const : 'ignored' as const,
-        message: !docNumber ? 'docNumber를 찾을 수 없음' : undefined
-      }
-    })
-    
-    setParsedFiles(parsed)
-    form.setValue("files", files)
+    const currentProject = form.watch("projectId")
+
+    // 프로젝트가 변경되었거나 처음 선택하는 경우
+    if (!currentProject || currentProject !== currentProjectId) {
+      setCurrentProjectId(currentProject)
+      const parsed = files.map(file => {
+        const { docNumber, revision } = parseFileName(file.name)
+        return {
+          file,
+          docNumber,
+          revision,
+          status: docNumber ? 'pending' as const : 'ignored' as const,
+          message: !docNumber ? 'docNumber를 찾을 수 없음' : undefined
+        }
+      })
+      setParsedFiles(parsed)
+      form.setValue("files", files)
+    } else {
+      // 같은 프로젝트에서 파일 추가하는 경우
+      const parsed = files.map(file => {
+        const { docNumber, revision } = parseFileName(file.name)
+        return {
+          file,
+          docNumber,
+          revision,
+          status: docNumber ? 'pending' as const : 'ignored' as const,
+          message: !docNumber ? 'docNumber를 찾을 수 없음' : undefined
+        }
+      })
+
+      // 기존 파일들과 새 파일들을 합침 (중복 파일명은 새 것으로 대체)
+      const existingFileNames = new Set(parsedFiles.map(pf => pf.file.name))
+      const newFiles = parsed.filter(pf => !existingFileNames.has(pf.file.name))
+      const combinedParsed = [...parsedFiles, ...newFiles]
+      const combinedFiles = [...parsedFiles.map(pf => pf.file), ...newFiles.map(pf => pf.file)]
+
+      setParsedFiles(combinedParsed)
+      form.setValue("files", combinedFiles)
+    }
   }
   
   // 파일 제거
@@ -275,6 +295,7 @@ export function BulkB4UploadDialog({
       form.reset()
       setParsedFiles([])
       setIsDragging(false)
+      setCurrentProjectId("")
     }
   }, [open, form])
   
@@ -288,7 +309,10 @@ export function BulkB4UploadDialog({
           <DialogTitle>B4 Document Bulk Upload</DialogTitle>
           <DialogDescription>
             Document numbers and revisions will be automatically extracted from file names.
-            Example: &quot;agadfg de na oc R01.pdf&quot; → Document Number: DE-NA-OC, Revision: R01
+            Format: [filename] [DOC1] [DOC2] ... [DOCN] [REV].[ext]
+            Examples:
+            &quot;testfile TANK ANA R01.pdf&quot; → Document Number: TANK-ANA, Revision: R01
+            &quot;drawing ABC DEF GHI JKL R02.pdf&quot; → Document Number: ABC-DEF-GHI-JKL, Revision: R02
           </DialogDescription>
         </DialogHeader>
         
@@ -378,7 +402,7 @@ export function BulkB4UploadDialog({
                   </div>
                 </div>
                 
-                <ScrollArea className="h-[250px] border rounded-lg p-2">
+                <div className="max-h-[250px] border rounded-lg p-2 overflow-y-auto">
                   <div className="space-y-2">
                     {parsedFiles.map((pf, index) => (
                       <div
@@ -440,7 +464,7 @@ export function BulkB4UploadDialog({
                       </div>
                     ))}
                   </div>
-                </ScrollArea>
+                </div>
               </div>
             )}
             
-- 
cgit v1.2.3

