From 8a19a6fa336768d8b6712752c9d713360067ecb0 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 8 Dec 2025 08:45:20 +0000 Subject: (최겸) 구매 피드백 수정, 안전담당자, pq항목 내 첨부, 내외자 구분, 도로명주소 api 반영(운영기준) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pq/pq-criteria/add-pq-dialog.tsx | 145 ++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 3 deletions(-) (limited to 'lib/pq/pq-criteria/add-pq-dialog.tsx') diff --git a/lib/pq/pq-criteria/add-pq-dialog.tsx b/lib/pq/pq-criteria/add-pq-dialog.tsx index 660eb360..1752f503 100644 --- a/lib/pq/pq-criteria/add-pq-dialog.tsx +++ b/lib/pq/pq-criteria/add-pq-dialog.tsx @@ -38,6 +38,10 @@ import { import { useToast } from "@/hooks/use-toast" import { createPqCriteria } from "../service" +import { uploadPqCriteriaFileAction } from "@/lib/pq/service" +import { Dropzone, DropzoneInput, DropzoneZone, DropzoneUploadIcon, DropzoneTitle, DropzoneDescription } from "@/components/ui/dropzone" +import { FileList, FileListHeader, FileListInfo, FileListItem, FileListName, FileListDescription, FileListAction } from "@/components/ui/file-list" +import { X, Loader2 } from "lucide-react" // PQ 생성을 위한 Zod 스키마 정의 const createPqSchema = z.object({ @@ -48,7 +52,7 @@ const createPqSchema = z.object({ description: z.string().optional(), remarks: z.string().optional(), inputFormat: z.string().default("TEXT"), - + type: z.string().optional(), }); type CreatePqFormType = z.infer; @@ -74,6 +78,12 @@ const inputFormatOptions = [ { value: "TEXT_FILE", label: "텍스트 + 파일" }, ]; +const typeOptions = [ + { value: "내자", label: "내자" }, + { value: "외자", label: "외자" }, + { value: "내외자", label: "내외자" }, +]; + interface AddPqDialogProps { pqListId: number; } @@ -81,6 +91,10 @@ interface AddPqDialogProps { export function AddPqDialog({ pqListId }: AddPqDialogProps) { const [open, setOpen] = React.useState(false) const [isSubmitting, setIsSubmitting] = React.useState(false) + const [isUploading, setIsUploading] = React.useState(false) + const [uploadedFiles, setUploadedFiles] = React.useState< + { fileName: string; url: string; size?: number; originalFileName?: string }[] + >([]) const router = useRouter() const { toast } = useToast() @@ -95,7 +109,7 @@ export function AddPqDialog({ pqListId }: AddPqDialogProps) { description: "", remarks: "", inputFormat: "TEXT", - + type: "내외자", }, }) const formState = form.formState @@ -105,7 +119,10 @@ export function AddPqDialog({ pqListId }: AddPqDialogProps) { setIsSubmitting(true) // 서버 액션 호출 - const result = await createPqCriteria(pqListId, data) + const result = await createPqCriteria(pqListId, { + ...data, + attachments: uploadedFiles, + }) if (!result.success) { toast({ @@ -124,6 +141,7 @@ export function AddPqDialog({ pqListId }: AddPqDialogProps) { // 모달 닫고 폼 리셋 form.reset() + setUploadedFiles([]) setOpen(false) // 페이지 새로고침 @@ -144,10 +162,34 @@ export function AddPqDialog({ pqListId }: AddPqDialogProps) { function handleDialogOpenChange(nextOpen: boolean) { if (!nextOpen) { form.reset() + setUploadedFiles([]) } setOpen(nextOpen) } + const handleUpload = async (files: File[]) => { + try { + setIsUploading(true) + for (const file of files) { + const uploaded = await uploadPqCriteriaFileAction(file) + setUploadedFiles((prev) => [...prev, uploaded]) + } + toast({ + title: "업로드 완료", + description: "첨부파일이 업로드되었습니다.", + }) + } catch (error) { + console.error(error) + toast({ + title: "업로드 실패", + description: "첨부파일 업로드 중 오류가 발생했습니다.", + variant: "destructive", + }) + } finally { + setIsUploading(false) + } + } + return ( @@ -253,6 +295,33 @@ export function AddPqDialog({ pqListId }: AddPqDialogProps) { )} /> + {/* Type 필드 */} + ( + + 내/외자 구분 + + 미선택 시 기본값은 내외자입니다. + + + )} + /> + {/* Input Format 필드 */} + {/* 첨부 파일 업로드 */} +
+
+ 첨부 파일 + {isUploading && ( +
+ 업로드 중... +
+ )} +
+ handleUpload(files)} + onDropRejected={() => + toast({ + title: "업로드 실패", + description: "파일 크기/형식을 확인하세요.", + variant: "destructive", + }) + } + disabled={isUploading} + > + {() => ( + + + + + +
+ +
+ 파일을 드래그하거나 클릭하여 업로드 + PDF, 이미지, 문서 (최대 600MB) +
+
+
+ 기준 문서 첨부가 필요한 경우 업로드하세요. +
+ )} +
+ + {uploadedFiles.length > 0 && ( +
+

첨부된 파일 ({uploadedFiles.length})

+ + {uploadedFiles.map((file, idx) => ( + + + + {file.originalFileName || file.fileName} + {file.size && ( + {`${file.size} bytes`} + )} + + + setUploadedFiles((prev) => prev.filter((_, i) => i !== idx)) + } + > + + Remove + + + + ))} + +
+ )} +
+ {/* Description 필드 */}