From be5d5ab488ae875e7c56306403aba923e1784021 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Tue, 18 Nov 2025 10:33:51 +0000
Subject: (최겸) 기술영업 첨부파일 결재 등록 및 요구사항 개발
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../table/detail-table/rfq-detail-table.tsx        | 127 +++++++++++++++++++++
 1 file changed, 127 insertions(+)

(limited to 'lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx')

diff --git a/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx b/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx
index 8ce55d56..52758412 100644
--- a/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx
+++ b/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx
@@ -22,6 +22,11 @@ import { TechSalesQuotationAttachmentsSheet, type QuotationAttachment } from "..
 import type { QuotationInfo } from "./rfq-detail-column"
 import { VendorContactSelectionDialog } from "./vendor-contact-selection-dialog"
 import { QuotationContactsViewDialog } from "./quotation-contacts-view-dialog"
+import { ApprovalPreviewDialog } from "@/lib/approval/client"
+import { ApplicationReasonDialog } from "@/lib/rfq-last/vendor/application-reason-dialog"
+import { requestTechSalesRfqSendWithApproval } from "@/lib/techsales-rfq/approval-actions"
+import { mapTechSalesRfqSendToTemplateVariables } from "@/lib/techsales-rfq/approval-handlers"
+import { useSession } from "next-auth/react"
 
 // 기본적인 RFQ 타입 정의
 interface TechSalesRfq {
@@ -48,6 +53,8 @@ interface RfqDetailTablesProps {
 export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps) {
   // console.log("selectedRfq", selectedRfq)
   
+  const session = useSession()
+  
   // 상태 관리
   const [isLoading, setIsLoading] = useState(false)
   const [details, setDetails] = useState<RfqDetailView[]>([])
@@ -89,6 +96,29 @@ export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps
   const [contactsDialogOpen, setContactsDialogOpen] = useState(false)
   const [selectedQuotationForContacts, setSelectedQuotationForContacts] = useState<{ id: number; vendorName?: string } | null>(null)
 
+  // 결재 관련 상태 관리
+  const [showApplicationReasonDialog, setShowApplicationReasonDialog] = useState(false)
+  const [showApprovalPreview, setShowApprovalPreview] = useState(false)
+  const [approvalPreviewData, setApprovalPreviewData] = useState<{
+    vendors: Array<{
+      vendorId: number
+      vendorName: string
+    }>
+    drmAttachments: Array<{
+      fileName?: string | null
+      fileSize?: number | null
+    }>
+    drmAttachmentIds: number[]
+    selectedContacts?: Array<{
+      vendorId: number
+      contactId: number
+      contactEmail: string
+      contactName: string
+    }>
+    templateVariables?: Record<string, string>
+    applicationReason?: string
+  } | null>(null)
+
   // selectedRfq ID 메모이제이션 (객체 참조 변경 방지)
   const selectedRfqId = useMemo(() => selectedRfq?.id, [selectedRfq?.id])
 
@@ -239,6 +269,25 @@ export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps
         selectedContacts: selectedContacts
       });
       
+      // DRM 파일이 있어서 결재가 필요한 경우
+      if (!result.success && result.requiresApproval) {
+        // 결재 데이터 저장
+        setApprovalPreviewData({
+          vendors: selectedRows.map(row => ({
+            vendorId: row.vendorId!,
+            vendorName: row.vendorName || "",
+          })),
+          drmAttachments: result.drmAttachments || [],
+          drmAttachmentIds: result.drmAttachmentIds || [],
+          selectedContacts: selectedContacts,
+        });
+        
+        // 신청사유 입력 다이얼로그 표시
+        setShowApplicationReasonDialog(true);
+        setIsSendingRfq(false);
+        return;
+      }
+      
       if (result.success) {
         toast.success(result.message || `${selectedContacts.length}명의 연락처에게 RFQ가 발송되었습니다.`);
       } else {
@@ -412,6 +461,84 @@ export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps
     setContactsDialogOpen(true)
   }, [])
 
+  // 신청사유 입력 완료 핸들러
+  const handleApplicationReasonConfirm = useCallback(async (reason: string) => {
+    if (!approvalPreviewData) {
+      toast.error("결재 데이터가 없습니다.");
+      return;
+    }
+
+    try {
+      // 템플릿 변수 생성 (신청사유 포함)
+      const templateVariables = await mapTechSalesRfqSendToTemplateVariables({
+        attachments: approvalPreviewData.drmAttachments,
+        vendorNames: approvalPreviewData.vendors.map(v => v.vendorName),
+        applicationReason: reason,
+      });
+
+      // 결재 미리보기 데이터 업데이트
+      setApprovalPreviewData({
+        ...approvalPreviewData,
+        templateVariables,
+        applicationReason: reason,
+      });
+
+      // 신청사유 다이얼로그 닫고 결재 미리보기 열기
+      setShowApplicationReasonDialog(false);
+      setShowApprovalPreview(true);
+    } catch (error) {
+      console.error("템플릿 변수 생성 실패:", error);
+      toast.error("결재 문서 생성에 실패했습니다.");
+    }
+  }, [approvalPreviewData]);
+
+  // 결재 미리보기 확인 핸들러
+  const handleApprovalConfirm = useCallback(async (approvalData: {
+    approvers: string[];
+    title: string;
+    description?: string;
+  }) => {
+    if (!approvalPreviewData || !selectedRfq || !session.data?.user) {
+      toast.error("결재 데이터가 없습니다.");
+      return;
+    }
+
+    if (!session.data.user.epId) {
+      toast.error("Knox EP ID가 필요합니다.");
+      return;
+    }
+
+    try {
+      const result = await requestTechSalesRfqSendWithApproval({
+        rfqId: selectedRfq.id,
+        rfqCode: selectedRfq.rfqCode || undefined,
+        vendorIds: approvalPreviewData.vendors.map(v => v.vendorId),
+        selectedContacts: approvalPreviewData.selectedContacts,
+        drmAttachmentIds: approvalPreviewData.drmAttachmentIds,
+        drmAttachments: approvalPreviewData.drmAttachments,
+        applicationReason: approvalPreviewData.applicationReason || '',
+        currentUser: {
+          id: Number(session.data.user.id),
+          epId: session.data.user.epId || null,
+          name: session.data.user.name || undefined,
+          email: session.data.user.email || undefined,
+        },
+        approvers: approvalData.approvers,
+      });
+
+      if (result.success) {
+        toast.success(result.message);
+        setShowApprovalPreview(false);
+        setApprovalPreviewData(null);
+        setSelectedRows([]);
+        await handleRefreshData();
+      }
+    } catch (error) {
+      console.error("결재 상신 실패:", error);
+      toast.error(error instanceof Error ? error.message : "결재 상신에 실패했습니다.");
+    }
+  }, [approvalPreviewData, selectedRfq, session, handleRefreshData]);
+
   // 칼럼 정의 - unreadMessages 상태 전달 (메모이제이션)
   const columns = useMemo(() =>
     getRfqDetailColumns({
-- 
cgit v1.2.3

