From fd4909bba7be8abc1eeab9ae1b4621c66a61604a Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Sun, 23 Nov 2025 16:40:37 +0900 Subject: (김준회) 돌체 재개발 - 1차 (다운로드 오류 수정 필요) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/dolce/dialogs/b4-upload-validation-dialog.tsx | 353 ++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 lib/dolce/dialogs/b4-upload-validation-dialog.tsx (limited to 'lib/dolce/dialogs/b4-upload-validation-dialog.tsx') diff --git a/lib/dolce/dialogs/b4-upload-validation-dialog.tsx b/lib/dolce/dialogs/b4-upload-validation-dialog.tsx new file mode 100644 index 00000000..b274d604 --- /dev/null +++ b/lib/dolce/dialogs/b4-upload-validation-dialog.tsx @@ -0,0 +1,353 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Badge } from "@/components/ui/badge"; +import { CheckCircle2, XCircle, AlertCircle, Upload } from "lucide-react"; + +export interface ParsedFileInfo { + drawingNo: string; + revNo: string; + fileName: string; +} + +export interface FileValidationResult { + file: File; + valid: boolean; + parsed?: ParsedFileInfo; + error?: string; + mappingStatus?: "available" | "not_found"; + drawingName?: string; + registerGroupId?: number; +} + +interface B4UploadValidationDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + validationResults: FileValidationResult[]; + onConfirmUpload: (validFiles: FileValidationResult[]) => void; + isUploading: boolean; +} + +/** + * B4 파일명 검증 함수 + * 형식: [버림] [DrawingNo] [RevNo].[확장자] + * 예시: "testfile GTT-DE-007 R01.pdf" → DrawingNo: "GTT-DE-007", RevNo: "R01" + */ +export function validateB4FileName(fileName: string): { + valid: boolean; + parsed?: ParsedFileInfo; + error?: string; +} { + try { + // 확장자 분리 + const lastDotIndex = fileName.lastIndexOf("."); + if (lastDotIndex === -1) { + return { + valid: false, + error: "파일 확장자가 없습니다", + }; + } + + const extension = fileName.substring(lastDotIndex + 1); + const nameWithoutExt = fileName.substring(0, lastDotIndex); + + // 공백으로 분리 + const parts = nameWithoutExt.split(" ").filter(p => p.trim() !== ""); + + // 최소 3개 파트 필요: [버림], DrawingNo, RevNo + if (parts.length < 3) { + return { + valid: false, + error: `공백이 최소 2개 있어야 합니다 (현재: ${parts.length - 1}개). 형식: [버림] [DrawingNo] [RevNo].[확장자]`, + }; + } + + // 첫 번째 토큰은 버림 + const drawingNo = parts[1]; + const revNo = parts[2]; + + // 필수 항목이 비어있지 않은지 확인 + if (!drawingNo || drawingNo.trim() === "") { + return { + valid: false, + error: "도면번호(DrawingNo)가 비어있습니다", + }; + } + + if (!revNo || revNo.trim() === "") { + return { + valid: false, + error: "리비전 번호(RevNo)가 비어있습니다", + }; + } + + return { + valid: true, + parsed: { + drawingNo: drawingNo.trim(), + revNo: revNo.trim(), + fileName: fileName, + }, + }; + } catch (error) { + return { + valid: false, + error: error instanceof Error ? error.message : "알 수 없는 오류", + }; + } +} + +/** + * B4 업로드 전 파일 검증 다이얼로그 + */ +export function B4UploadValidationDialog({ + open, + onOpenChange, + validationResults, + onConfirmUpload, + isUploading, +}: B4UploadValidationDialogProps) { + const validFiles = validationResults.filter((r) => r.valid && r.mappingStatus === "available"); + const notFoundFiles = validationResults.filter((r) => r.valid && r.mappingStatus === "not_found"); + const invalidFiles = validationResults.filter((r) => !r.valid); + + const handleUpload = () => { + if (validFiles.length > 0) { + onConfirmUpload(validFiles); + } + }; + + const handleCancel = () => { + if (!isUploading) { + onOpenChange(false); + } + }; + + return ( + + + + B4 일괄 업로드 검증 + + 선택한 파일의 파일명 형식과 매핑 가능 여부를 검증합니다 + + + +
+ {/* 요약 통계 */} +
+
+
전체
+
{validationResults.length}
+
+
+
업로드 가능
+
+ {validFiles.length} +
+
+
+
도면 없음
+
+ {notFoundFiles.length} +
+
+
+
형식 오류
+
+ {invalidFiles.length} +
+
+
+ + {/* 경고 메시지 */} + {validFiles.length === 0 && ( + + + + 업로드 가능한 파일이 없습니다. 파일명 형식을 확인하거나 이미 매핑된 파일은 제외해주세요. + + + )} + + {(notFoundFiles.length > 0 || invalidFiles.length > 0) && validFiles.length > 0 && ( + + + + 일부 파일에 문제가 있습니다. 업로드 가능한 {validFiles.length}개 파일만 업로드됩니다. + + + )} + + {/* 파일 목록 */} +
+
+ {/* 업로드 가능 파일 */} + {validFiles.length > 0 && ( +
+

+ + 업로드 가능 ({validFiles.length}개) +

+ {validFiles.map((result, index) => ( +
+
+
+
+ {result.file.name} +
+ {result.parsed && ( +
+ + 도면: {result.parsed.drawingNo} + + + Rev: {result.parsed.revNo} + + {result.drawingName && ( + + {result.drawingName} + + )} +
+ )} +
+ +
+
+ ))} +
+ )} + + {/* 도면을 찾을 수 없는 파일 */} + {notFoundFiles.length > 0 && ( +
+

+ + 도면을 찾을 수 없음 ({notFoundFiles.length}개) +

+ {notFoundFiles.map((result, index) => ( +
+
+
+
+ {result.file.name} +
+
+ ✗ 해당 도면번호가 프로젝트에 등록되어 있지 않습니다 +
+ {result.parsed && ( +
+ + 도면: {result.parsed.drawingNo} + + + Rev: {result.parsed.revNo} + +
+ )} +
+ +
+
+ ))} +
+ )} + + {/* 형식 오류 파일 */} + {invalidFiles.length > 0 && ( +
+

+ + 파일명 형식 오류 ({invalidFiles.length}개) +

+ {invalidFiles.map((result, index) => ( +
+
+
+
+ {result.file.name} +
+ {result.error && ( +
+ ✗ {result.error} +
+ )} +
+ +
+
+ ))} +
+ )} +
+
+ + {/* 형식 안내 */} +
+
+ 📋 올바른 파일명 형식 +
+ + [버림] [DrawingNo] [RevNo].[확장자] + +
+ 예: testfile GTT-DE-007 R01.pdf +
+
+ ※ 첫 번째 단어는 무시되며, 공백으로 구분됩니다 +
+
+ ※ 네 번째 이상의 단어가 있으면 무시됩니다 +
+
+
+ + + + + +
+
+ ); +} + -- cgit v1.2.3