From 7f973de2a814a2040a646161b563c8990b7e2fd2 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 7 Nov 2025 04:43:43 +0000 Subject: (임수민) 기본계약서 서명란 변수 추가 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/basic-contract-template-viewer.tsx | 40 +++++---- .../template/template-editor-wrapper.tsx | 97 ++++++++++++++++++---- 2 files changed, 106 insertions(+), 31 deletions(-) (limited to 'lib/basic-contract') diff --git a/lib/basic-contract/template/basic-contract-template-viewer.tsx b/lib/basic-contract/template/basic-contract-template-viewer.tsx index 018db3a0..52ea4153 100644 --- a/lib/basic-contract/template/basic-contract-template-viewer.tsx +++ b/lib/basic-contract/template/basic-contract-template-viewer.tsx @@ -17,6 +17,7 @@ interface BasicContractTemplateViewerProps { filePath?: string; instance: WebViewerInstance | null; setInstance: Dispatch>; + onSignatureFieldFound?: (searchText: string) => void; // 서명란 발견 시 콜백 } // 서명란 위치 정보 인터페이스 @@ -116,6 +117,7 @@ export function BasicContractTemplateViewer({ filePath, instance, setInstance, + onSignatureFieldFound, }: BasicContractTemplateViewerProps) { const [fileLoading, setFileLoading] = useState(true); const [signatureLocation, setSignatureLocation] = useState(null); @@ -244,6 +246,10 @@ export function BasicContractTemplateViewer({ if (location) { setSignatureLocation(location); console.log("✅ 서명란 위치 발견:", location); + // 서명란 발견 시 부모 컴포넌트에 알림 + if (onSignatureFieldFound) { + onSignatureFieldFound(location.searchText); + } } }, 2000); }; @@ -256,6 +262,10 @@ export function BasicContractTemplateViewer({ const location = await findSignatureFieldLocation(instance); if (location) { setSignatureLocation(location); + // 서명란 발견 시 부모 컴포넌트에 알림 + if (onSignatureFieldFound) { + onSignatureFieldFound(location.searchText); + } } }, 2000); } @@ -326,21 +336,6 @@ export function BasicContractTemplateViewer({ // 기존 SignViewer와 동일한 렌더링 (확대 문제 해결) return (
- {/* 서명란으로 이동 버튼 */} - {signatureLocation && !fileLoading && ( -
- -
- )} -
+ {/* 서명란으로 이동 버튼 - 툴바 아래에 배치 (편집 도구와 겹치지 않도록) */} + {signatureLocation && !fileLoading && ( +
+ +
+ )} + {fileLoading && (
diff --git a/lib/basic-contract/template/template-editor-wrapper.tsx b/lib/basic-contract/template/template-editor-wrapper.tsx index af5d42a8..2c1c7e4d 100644 --- a/lib/basic-contract/template/template-editor-wrapper.tsx +++ b/lib/basic-contract/template/template-editor-wrapper.tsx @@ -18,25 +18,35 @@ interface TemplateEditorWrapperProps { } const getVariablesForTemplate = (templateName: string): string[] => { + let variables: string[] = []; + // 정확한 매치 먼저 확인 if (TEMPLATE_VARIABLES_MAP[templateName as keyof typeof TEMPLATE_VARIABLES_MAP]) { - return [...TEMPLATE_VARIABLES_MAP[templateName as keyof typeof TEMPLATE_VARIABLES_MAP]]; - } - - // GTC가 포함된 경우 확인 - if (templateName.includes("GTC")) { - return [...TEMPLATE_VARIABLES_MAP["GTC"]]; - } - - // 다른 키워드들도 포함 관계로 확인 - for (const [key, variables] of Object.entries(TEMPLATE_VARIABLES_MAP)) { - if (templateName.includes(key)) { - return [...variables]; + variables = [...TEMPLATE_VARIABLES_MAP[templateName as keyof typeof TEMPLATE_VARIABLES_MAP]]; + } else if (templateName.includes("GTC")) { + // GTC가 포함된 경우 확인 + variables = [...TEMPLATE_VARIABLES_MAP["GTC"]]; + } else { + // 다른 키워드들도 포함 관계로 확인 + let found = false; + for (const [key, vars] of Object.entries(TEMPLATE_VARIABLES_MAP)) { + if (templateName.includes(key)) { + variables = [...vars]; + found = true; + break; + } + } + + // 기본값 반환 + if (!found) { + variables = ["company_name", "company_address", "representative_name", "signature_date"]; } } - // 기본값 반환 - return ["company_name", "company_address", "representative_name", "signature_date"]; + // 모든 템플릿에 서명란 변수 추가 (중복 제거) + const signatureVars = ["vendor_signature", "buyer_signature"]; + const allVariables = [...variables, ...signatureVars]; + return [...new Set(allVariables)]; // 중복 제거 }; // 템플릿 이름별 변수 매핑 @@ -67,9 +77,23 @@ const VARIABLE_DESCRIPTION_MAP = { "tax_id": "사업자등록번호", "phone_number": "전화번호", "phone": "전화번호", - "email": "이메일" + "email": "이메일", + "vendor_signature": "협력업체 서명란", + "buyer_signature": "구매자 서명란", + "협력업체_서명란": "협력업체 서명란", + "삼성중공업_서명란": "구매자 서명란" } as const; +// 서명란 텍스트를 변수명으로 변환 +const getSignatureVariableName = (searchText: string): string => { + if (searchText === '협력업체_서명란') { + return 'vendor_signature'; + } else if (searchText === '삼성중공업_서명란') { + return 'buyer_signature'; + } + return searchText; +}; + // 변수 패턴 감지를 위한 정규식 const VARIABLE_PATTERN = /\{\{([^}]+)\}\}/g; @@ -86,6 +110,7 @@ export function TemplateEditorWrapper({ const [documentVariables, setDocumentVariables] = React.useState([]); const [templateName, setTemplateName] = React.useState(""); const [predefinedVariables, setPredefinedVariables] = React.useState([]); + const [signatureVariables, setSignatureVariables] = React.useState([]); // 서명란 변수 // 템플릿 이름 로드 및 변수 설정 React.useEffect(() => { @@ -359,7 +384,7 @@ export function TemplateEditorWrapper({
{/* 변수 도구 */} - {(documentVariables.length > 0 || predefinedVariables.length > 0) && ( + {(documentVariables.length > 0 || predefinedVariables.length > 0 || signatureVariables.length > 0) && (

@@ -388,6 +413,36 @@ export function TemplateEditorWrapper({

)} + {/* 서명란 변수 */} + {signatureVariables.length > 0 && ( +
+

+ 서명란 변수 (클릭하여 복사): +

+ +
+ {signatureVariables.map((variable, index) => ( + + + + + +

{VARIABLE_DESCRIPTION_MAP[variable as keyof typeof VARIABLE_DESCRIPTION_MAP] || variable}

+
+
+ ))} +
+
+
+ )} + {/* 템플릿별 미리 정의된 변수들 */} {predefinedVariables.length > 0 && (
@@ -430,6 +485,16 @@ export function TemplateEditorWrapper({ filePath={filePath} instance={instance} setInstance={setInstance} + onSignatureFieldFound={(searchText) => { + // 서명란 발견 시 변수명으로 변환하여 추가 + const variableName = getSignatureVariableName(searchText); + setSignatureVariables(prev => { + if (!prev.includes(variableName)) { + return [...prev, variableName]; + } + return prev; + }); + }} />
-- cgit v1.2.3