summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-03 16:02:12 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-03 16:02:12 +0900
commitaeaa24a239cf29f7bc98363339ccdbd51a4015f0 (patch)
tree30d91c2b54d92d0ed6a9da108ab4e67bc730d35a
parent8688794b0cae0a6bb15d4c1f40a5b2c71e87acb4 (diff)
(김준회) dolce: B4 일괄 업로드 파싱 로직 오류 수정
-rw-r--r--lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx122
1 files changed, 73 insertions, 49 deletions
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>
)}