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/add-detail-drawing-dialog.tsx | 376 ++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 lib/dolce/dialogs/add-detail-drawing-dialog.tsx (limited to 'lib/dolce/dialogs/add-detail-drawing-dialog.tsx') diff --git a/lib/dolce/dialogs/add-detail-drawing-dialog.tsx b/lib/dolce/dialogs/add-detail-drawing-dialog.tsx new file mode 100644 index 00000000..290a226b --- /dev/null +++ b/lib/dolce/dialogs/add-detail-drawing-dialog.tsx @@ -0,0 +1,376 @@ +"use client"; + +import { useState, useCallback } from "react"; +import { useDropzone } from "react-dropzone"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Upload, X, FileIcon, Info } from "lucide-react"; +import { toast } from "sonner"; +import { UnifiedDwgReceiptItem, editDetailDwgReceipt, uploadFilesToDetailDrawing } from "../actions"; +import { v4 as uuidv4 } from "uuid"; + +interface AddDetailDrawingDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + drawing: UnifiedDwgReceiptItem | null; + vendorCode: string; + userId: string; + userName: string; + userEmail: string; + onComplete: () => void; + drawingKind: "B3" | "B4"; // 추가 +} + +// B3 벤더의 선택 옵션 +const B3_DRAWING_USAGE_OPTIONS = [ + { value: "APP", label: "APPROVAL (승인용)" }, + { value: "WOR", label: "WORKING (작업용)" }, +]; + +const B3_REGISTER_KIND_OPTIONS: Record> = { + APP: [ + { value: "APPR", label: "승인용 도면 (Full)", revisionRule: "예: A, B, C 또는 R00, R01, R02" }, + { value: "APPR-P", label: "승인용 도면 (Partial)", revisionRule: "예: A, B, C 또는 R00, R01, R02" }, + ], + WOR: [ + { value: "WORK", label: "작업용 입수도면 (Full)", revisionRule: "예: A, B, C 또는 R00, R01, R02" }, + { value: "WORK-P", label: "작업용 입수도면 (Partial)", revisionRule: "예: A, B, C 또는 R00, R01, R02" }, + ], +}; + +// B4 벤더(GTT)의 선택 옵션 +const B4_DRAWING_USAGE_OPTIONS = [ + { value: "REC", label: "RECEIVE (입수용)" }, +]; + +const B4_REGISTER_KIND_OPTIONS: Record> = { + REC: [ + { value: "RECP", label: "Pre. 도면입수", revisionRule: "예: R00, R01, R02, R03" }, + { value: "RECW", label: "Working 도면입수", revisionRule: "예: R00, R01, R02, R03" }, + ], +}; + +export function AddDetailDrawingDialog({ + open, + onOpenChange, + drawing, + vendorCode, + userId, + userName, + userEmail, + onComplete, + drawingKind, +}: AddDetailDrawingDialogProps) { + const [drawingUsage, setDrawingUsage] = useState(""); + const [registerKind, setRegisterKind] = useState(""); + const [revision, setRevision] = useState(""); + const [files, setFiles] = useState([]); + const [isSubmitting, setIsSubmitting] = useState(false); + + // 파일 드롭 핸들러 + const onDrop = useCallback((acceptedFiles: File[]) => { + setFiles((prev) => [...prev, ...acceptedFiles]); + }, []); + + const { getRootProps, getInputProps, isDragActive } = useDropzone({ + onDrop, + multiple: true, + }); + + // 파일 제거 + const removeFile = (index: number) => { + setFiles((prev) => prev.filter((_, i) => i !== index)); + }; + + // 폼 초기화 + const resetForm = () => { + setDrawingUsage(""); + setRegisterKind(""); + setRevision(""); + setFiles([]); + }; + + // 제출 + const handleSubmit = async () => { + if (!drawing) return; + + // 유효성 검사 + if (!drawingUsage) { + toast.error("도면용도를 선택하세요"); + return; + } + if (!registerKind) { + toast.error("등록종류를 선택하세요"); + return; + } + if (!revision.trim()) { + toast.error("Revision을 입력하세요"); + return; + } + if (files.length === 0) { + toast.error("최소 1개 이상의 파일을 첨부해야 합니다"); + return; + } + + try { + setIsSubmitting(true); + + // 파일 업로드 ID 생성 + const uploadId = uuidv4(); + + // 상세도면 추가 + const result = await editDetailDwgReceipt({ + dwgList: [ + { + Mode: "ADD", + Status: "Draft", + RegisterId: 0, + ProjectNo: drawing.ProjectNo, + Discipline: drawing.Discipline, + DrawingKind: drawing.DrawingKind, + DrawingNo: drawing.DrawingNo, + DrawingName: drawing.DrawingName, + RegisterGroupId: drawing.RegisterGroupId, + RegisterSerialNo: 0, // 자동 증가 + RegisterKind: registerKind, + DrawingRevNo: revision, + Category: "TS", // To SHI (벤더가 SHI에게 제출) + Receiver: null, + Manager: "", + RegisterDesc: "", + UploadId: uploadId, + RegCompanyCode: vendorCode, + }, + ], + userId, + userNm: userName, + vendorCode, + email: userEmail, + }); + + if (result > 0) { + // 파일 업로드 처리 (상세도면 추가 후) + if (files.length > 0) { + toast.info(`${files.length}개 파일 업로드를 진행합니다...`); + + const formData = new FormData(); + formData.append("uploadId", uploadId); + formData.append("userId", userId); + formData.append("fileCount", String(files.length)); + + files.forEach((file, index) => { + formData.append(`file_${index}`, file); + }); + + const uploadResult = await uploadFilesToDetailDrawing(formData); + + if (uploadResult.success) { + toast.success(`상세도면 추가 및 ${uploadResult.uploadedCount}개 파일 업로드 완료`); + } else { + toast.warning(`상세도면은 추가되었으나 파일 업로드 실패: ${uploadResult.error}`); + } + } else { + toast.success("상세도면이 추가되었습니다"); + } + + resetForm(); + onComplete(); + } else { + toast.error("상세도면 추가에 실패했습니다"); + } + } catch (error) { + console.error("상세도면 추가 실패:", error); + toast.error("상세도면 추가 중 오류가 발생했습니다"); + } finally { + setIsSubmitting(false); + } + }; + + const handleCancel = () => { + resetForm(); + onOpenChange(false); + }; + + // DrawingUsage가 변경되면 RegisterKind 초기화 + const handleDrawingUsageChange = (value: string) => { + setDrawingUsage(value); + setRegisterKind(""); + }; + + // 현재 선택 가능한 DrawingUsage 및 RegisterKind 옵션 + const drawingUsageOptions = drawingKind === "B4" ? B4_DRAWING_USAGE_OPTIONS : B3_DRAWING_USAGE_OPTIONS; + const registerKindOptionsMap = drawingKind === "B4" ? B4_REGISTER_KIND_OPTIONS : B3_REGISTER_KIND_OPTIONS; + + const registerKindOptions = drawingUsage + ? registerKindOptionsMap[drawingUsage] || [] + : []; + + // 선택된 RegisterKind의 Revision Rule + const revisionRule = registerKindOptions.find((opt) => opt.value === registerKind)?.revisionRule || ""; + + return ( + + + + 상세도면 추가 + + +
+ {/* 도면 정보 표시 */} + {drawing && ( + + + +
{drawing.DrawingNo}
+
{drawing.DrawingName}
+
+
+ )} + + {/* 도면용도 선택 */} +
+ + +
+ + {/* 등록종류 선택 */} +
+ + + {revisionRule && ( +

+ Revision 입력 형식: {revisionRule} +

+ )} +
+ + {/* Revision 입력 */} +
+ + setRevision(e.target.value)} + placeholder="예: A, B, R00, R01" + disabled={!registerKind} + /> +
+ + {/* 파일 업로드 */} +
+ +
0 ? "py-4" : ""} + `} + > + + {files.length === 0 ? ( +
+ +
+

+ 파일을 드래그하거나 클릭하여 선택 +

+

+ 여러 파일을 한 번에 업로드할 수 있습니다 +

+
+
+ ) : ( +
+

+ {files.length}개 파일 선택됨 +

+

+ 추가로 파일을 드래그하거나 클릭하여 더 추가할 수 있습니다 +

+
+ )} +
+ + {/* 선택된 파일 목록 */} + {files.length > 0 && ( +
+ {files.map((file, index) => ( +
+ + {file.name} + + {(file.size / 1024).toFixed(2)} KB + + +
+ ))} +
+ )} +
+
+ + + + + +
+
+ ); +} + -- cgit v1.2.3