From 02b1cf005cf3e1df64183d20ba42930eb2767a9f Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 21 Aug 2025 06:57:36 +0000 Subject: (대표님, 최겸) 설계메뉴추가, 작업사항 업데이트 설계메뉴 - 문서관리 설계메뉴 - 벤더 데이터 gtc 메뉴 업데이트 정보시스템 - 메뉴리스트 및 정보 업데이트 파일 라우트 업데이트 엑셀임포트 개선 기본계약 개선 벤더 가입과정 변경 및 개선 벤더 기본정보 - pq 돌체 오류 수정 및 개선 벤더 로그인 과정 이메일 오류 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edit-investigation-dialog.tsx | 124 ++++++++++++++++++++- lib/pq/pq-review-table-new/site-visit-dialog.tsx | 16 ++- lib/pq/service.ts | 57 +++++++++- 3 files changed, 193 insertions(+), 4 deletions(-) (limited to 'lib/pq') diff --git a/lib/pq/pq-review-table-new/edit-investigation-dialog.tsx b/lib/pq/pq-review-table-new/edit-investigation-dialog.tsx index 7fd1c3f8..c5470e47 100644 --- a/lib/pq/pq-review-table-new/edit-investigation-dialog.tsx +++ b/lib/pq/pq-review-table-new/edit-investigation-dialog.tsx @@ -40,6 +40,9 @@ import { PopoverTrigger, } from "@/components/ui/popover" import { z } from "zod" +import { getInvestigationAttachments, deleteInvestigationAttachment } from "../service" +import { downloadFile } from "@/lib/file-download" +import { Download } from "lucide-react" // Validation schema for editing investigation const editInvestigationSchema = z.object({ @@ -74,6 +77,8 @@ export function EditInvestigationDialog({ }: EditInvestigationDialogProps) { const [isPending, startTransition] = React.useTransition() const [selectedFiles, setSelectedFiles] = React.useState([]) + const [existingAttachments, setExistingAttachments] = React.useState([]) + const [loadingAttachments, setLoadingAttachments] = React.useState(false) const fileInputRef = React.useRef(null) const form = useForm({ @@ -96,9 +101,67 @@ export function EditInvestigationDialog({ attachments: [], }) setSelectedFiles([]) + + // 기존 첨부파일 로드 + loadExistingAttachments(investigation.id) } }, [investigation, form]) + // 기존 첨부파일 로드 함수 + const loadExistingAttachments = async (investigationId: number) => { + setLoadingAttachments(true) + try { + const result = await getInvestigationAttachments(investigationId) + if (result.success) { + setExistingAttachments(result.attachments || []) + } else { + toast.error("첨부파일 목록을 불러오는데 실패했습니다.") + } + } catch (error) { + console.error("첨부파일 로드 실패:", error) + toast.error("첨부파일 목록을 불러오는 중 오류가 발생했습니다.") + } finally { + setLoadingAttachments(false) + } + } + + // 첨부파일 삭제 함수 + const handleDeleteAttachment = async (attachmentId: number) => { + if (!investigation) return + + try { + const result = await deleteInvestigationAttachment(attachmentId) + if (result.success) { + toast.success("첨부파일이 삭제되었습니다.") + // 목록 새로고침 + loadExistingAttachments(investigation.id) + } else { + toast.error(result.error || "첨부파일 삭제에 실패했습니다.") + } + } catch (error) { + console.error("첨부파일 삭제 오류:", error) + toast.error("첨부파일 삭제 중 오류가 발생했습니다.") + } + } + + // 첨부파일 다운로드 함수 + const handleDownloadAttachment = async (attachment: any) => { + if (!attachment.filePath || !attachment.fileName) { + toast.error("첨부파일 정보가 올바르지 않습니다.") + return + } + + try { + await downloadFile(attachment.filePath, attachment.fileName, { + showToast: true, + action: 'download' + }) + } catch (error) { + console.error("첨부파일 다운로드 오류:", error) + toast.error("첨부파일 다운로드 중 오류가 발생했습니다.") + } + } + // 파일 선택 핸들러 const handleFileSelect = (event: React.ChangeEvent) => { const files = Array.from(event.target.files || []) @@ -145,7 +208,7 @@ export function EditInvestigationDialog({ return ( - + 실사 정보 수정 @@ -246,6 +309,65 @@ export function EditInvestigationDialog({ 첨부파일
+ {/* 기존 첨부파일 목록 */} + {(existingAttachments.length > 0 || loadingAttachments) && ( +
+
기존 첨부파일
+
+ {loadingAttachments ? ( +
+ + + 첨부파일 로딩 중... + +
+ ) : existingAttachments.length > 0 ? ( + existingAttachments.map((attachment) => ( +
+
+ + {attachment.attachmentType || 'FILE'} + + {attachment.fileName} + + ({attachment.fileSize ? Math.round(attachment.fileSize / 1024) : 0}KB) + +
+
+ + +
+
+ )) + ) : ( +
+ 첨부된 파일이 없습니다. +
+ )} +
+
+ )} + {/* 파일 선택 영역 */}
| null } } @@ -315,7 +315,19 @@ export function SiteVisitDialog({
대상품목
-
{investigation.pqItems || "-"}
+
+ {investigation.pqItems && investigation.pqItems.length > 0 + ? investigation.pqItems.map((item, index) => ( +
+ + {item.itemCode} + + {item.itemName} +
+ )) + : "-" + } +
diff --git a/lib/pq/service.ts b/lib/pq/service.ts index f15790eb..989f8d5c 100644 --- a/lib/pq/service.ts +++ b/lib/pq/service.ts @@ -2710,7 +2710,7 @@ export async function sendInvestigationResultsAction(input: { await tx.insert(vendorRegularRegistrations).values({ vendorId: investigation.vendorId, - status: "audit_pass", // 실사 통과 상태로 시작 + status: "under_review", // 실사 통과 상태로 시작 majorItems: majorItemsJson, registrationRequestDate: new Date().toISOString().split('T')[0], // date 타입으로 변환 remarks: `PQ 실사 통과로 자동 생성 (PQ번호: ${investigation.pqNumber || 'N/A'})`, @@ -3772,6 +3772,61 @@ export async function updateInvestigationDetailsAction(input: { } } +// 구매자체평가 첨부파일 조회 +export async function getInvestigationAttachments(investigationId: number) { + try { + const attachments = await db + .select({ + id: vendorInvestigationAttachments.id, + fileName: vendorInvestigationAttachments.fileName, + originalFileName: vendorInvestigationAttachments.originalFileName, + filePath: vendorInvestigationAttachments.filePath, + fileSize: vendorInvestigationAttachments.fileSize, + mimeType: vendorInvestigationAttachments.mimeType, + attachmentType: vendorInvestigationAttachments.attachmentType, + createdAt: vendorInvestigationAttachments.createdAt, + }) + .from(vendorInvestigationAttachments) + .where(eq(vendorInvestigationAttachments.investigationId, investigationId)) + .orderBy(desc(vendorInvestigationAttachments.createdAt)); + + return { + success: true, + attachments, + }; + } catch (error) { + console.error("첨부파일 조회 오류:", error); + return { + success: false, + error: "첨부파일 조회 중 오류가 발생했습니다.", + attachments: [], + }; + } +} + +// 구매자체평가 첨부파일 삭제 +export async function deleteInvestigationAttachment(attachmentId: number) { + try { + await db + .delete(vendorInvestigationAttachments) + .where(eq(vendorInvestigationAttachments.id, attachmentId)); + + revalidateTag("pq-submissions"); + revalidatePath("/evcp/pq_new"); + + return { + success: true, + message: "첨부파일이 성공적으로 삭제되었습니다.", + }; + } catch (error) { + console.error("첨부파일 삭제 오류:", error); + return { + success: false, + error: "첨부파일 삭제 중 오류가 발생했습니다.", + }; + } +} + export async function autoDeactivateExpiredPQLists() { try { const now = new Date(); -- cgit v1.2.3