From b5c174429548a53e5c86a13bdbfc61516e5ee345 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Tue, 9 Dec 2025 03:04:05 +0000 Subject: (최겸) 구매 구매자서명 내 삼성중공업 정보 입력 추가 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pq/pq-criteria/add-pq-dialog.tsx | 968 +++++++++++++++++------------------ 1 file changed, 484 insertions(+), 484 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 1752f503..144e5ce4 100644 --- a/lib/pq/pq-criteria/add-pq-dialog.tsx +++ b/lib/pq/pq-criteria/add-pq-dialog.tsx @@ -1,485 +1,485 @@ -"use client" - -import * as React from "react" -import { useForm } from "react-hook-form" -import { zodResolver } from "@hookform/resolvers/zod" -import { z } from "zod" -import { Plus } from "lucide-react" -import { useRouter } from "next/navigation" - -import { - Dialog, - DialogTrigger, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter -} from "@/components/ui/dialog" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Textarea } from "@/components/ui/textarea" -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" - -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({ - code: z.string().min(1, "Code is required"), - checkPoint: z.string().min(1, "Check point is required"), - groupName: z.string().min(1, "Group is required"), - subGroupName: z.string().optional(), - description: z.string().optional(), - remarks: z.string().optional(), - inputFormat: z.string().default("TEXT"), - type: z.string().optional(), -}); - -type CreatePqFormType = z.infer; - -// 그룹 이름 옵션 -export const groupOptions = [ - "GENERAL", - "QMS", - "Warranty", - "HSE+", - "기타", -]; - -// 입력 형식 옵션 -const inputFormatOptions = [ - { value: "TEXT", label: "텍스트" }, - { value: "FILE", label: "파일" }, - { value: "EMAIL", label: "이메일" }, - { value: "PHONE", label: "전화번호" }, - { value: "FAX", label: "팩스번호" }, - { value: "NUMBER", label: "숫자" }, - { value: "NUMBER_WITH_UNIT", label: "숫자+단위" }, - { value: "TEXT_FILE", label: "텍스트 + 파일" }, -]; - -const typeOptions = [ - { value: "내자", label: "내자" }, - { value: "외자", label: "외자" }, - { value: "내외자", label: "내외자" }, -]; - -interface AddPqDialogProps { - pqListId: number; -} - -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() - - // react-hook-form 설정 - const form = useForm({ - resolver: zodResolver(createPqSchema), - defaultValues: { - code: "", - checkPoint: "", - groupName: groupOptions[0], - subGroupName: "", - description: "", - remarks: "", - inputFormat: "TEXT", - type: "내외자", - }, - }) - const formState = form.formState - - async function onSubmit(data: CreatePqFormType) { - try { - setIsSubmitting(true) - - // 서버 액션 호출 - const result = await createPqCriteria(pqListId, { - ...data, - attachments: uploadedFiles, - }) - - if (!result.success) { - toast({ - title: "오류", - description: result.message || "PQ 항목 생성에 실패했습니다", - variant: "destructive", - }) - return - } - - // 성공 시 처리 - toast({ - title: "성공", - description: result.message || "PQ 항목이 성공적으로 생성되었습니다", - }) - - // 모달 닫고 폼 리셋 - form.reset() - setUploadedFiles([]) - setOpen(false) - - // 페이지 새로고침 - router.refresh() - - } catch (error) { - console.error('Error creating PQ criteria:', error) - toast({ - title: "오류", - description: "예상치 못한 오류가 발생했습니다", - variant: "destructive", - }) - } finally { - setIsSubmitting(false) - } - } - - 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 ( - - - - - - - - PQ 항목 생성 - - 새 PQ 항목을 추가합니다. - - - -
- -
- {/* Group Name 필드 */} - ( - - 대분류 * - - - - )} - /> - - {/* Sub Group Name 필드 */} - ( - - 소분류 - - - - - 세부 분류를 위한 서브 그룹명을 입력하세요 (선택사항) - - - - )} - /> - {/* Code 필드 */} - ( - - 일련번호 * - - - - - PQ 항목의 고유 코드를 입력하세요 - - - - )} - /> - {/* Check Point 필드 */} - ( - - PQ 항목 * - - - - - - )} - /> - - {/* 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 필드 */} - ( - - 설명 - -