From 088431a6572d87f7ee287252a4357e6c332d04f7 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 20 Nov 2025 07:16:17 +0000 Subject: (임수민) 준법설문조사 다운로드 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/basic-contract/viewer/SurveyComponent.tsx | 263 ++++++++++++++++++--- .../viewer/basic-contract-sign-viewer.tsx | 4 - 2 files changed, 225 insertions(+), 42 deletions(-) (limited to 'lib') diff --git a/lib/basic-contract/viewer/SurveyComponent.tsx b/lib/basic-contract/viewer/SurveyComponent.tsx index 950519ad..e67b8790 100644 --- a/lib/basic-contract/viewer/SurveyComponent.tsx +++ b/lib/basic-contract/viewer/SurveyComponent.tsx @@ -40,8 +40,6 @@ interface SurveyComponentProps { onSurveyDataUpdate: (data: any) => void; onLoadSurveyTemplate: () => void; setActiveTab: (tab: string) => void; - contractFilePath?: string; // 계약서 파일 경로 추가 - contractFileName?: string; // 계약서 파일 이름 추가 } export const SurveyComponent: React.FC = ({ @@ -53,9 +51,7 @@ export const SurveyComponent: React.FC = ({ onSurveyComplete, onSurveyDataUpdate, onLoadSurveyTemplate, - setActiveTab, - contractFilePath, - contractFileName + setActiveTab }) => { const [uploadedFiles, setUploadedFiles] = useState>({}); const [existingResponse, setExistingResponse] = useState(null); @@ -325,39 +321,232 @@ export const SurveyComponent: React.FC = ({ ); }, [control, visibleQuestions]); - // 계약서 다운로드 핸들러 - const handleDownloadContract = useCallback(async () => { - if (!contractFilePath) { - toast.error("다운로드할 파일이 없습니다."); + // 설문조사 내용 다운로드 핸들러 + const handleDownloadSurvey = useCallback(async () => { + if (!surveyTemplate) { + toast.error("설문조사 템플릿이 없습니다."); return; } try { - // 파일 경로를 API 경로로 변환 - const normalizedPath = contractFilePath.startsWith('/') - ? contractFilePath.substring(1) - : contractFilePath; - const encodedPath = normalizedPath.split('/').map(part => encodeURIComponent(part)).join('/'); - const apiFilePath = `/api/files/${encodedPath}`; + const currentValues = getValues(); + + // 설문조사 응답이 없으면 경고 + const hasAnswers = Object.keys(currentValues).some(key => { + const value = currentValues[key]; + return value?.answerValue || value?.detailText || (value?.files && value?.files.length > 0); + }); - // 파일 경로에서 실제 파일명 추출 - const actualFileName = contractFileName || contractFilePath.split('/').pop() || '계약서.pdf'; + if (!hasAnswers && !existingResponse) { + toast.error("다운로드할 설문조사 내용이 없습니다."); + return; + } - // 다운로드 링크 생성 및 클릭 + // HTML 생성 + let htmlContent = ` + + + + + + ${surveyTemplate.name} + + + +

${surveyTemplate.name}

+`; + + // 질문과 답변 생성 + const questionsToShow = visibleQuestions.length > 0 ? visibleQuestions : surveyTemplate.questions; + + questionsToShow.forEach((question: any) => { + const fieldName = `${question.id}`; + const answerData = currentValues[fieldName] || + (existingResponse?.answers.find(a => a.questionId === question.id)); + + // 답변이 없으면 스킵 (조건부 질문일 수 있음) + if (!answerData && !existingResponse) { + return; + } + + const isConditional = !!question.parentQuestionId; + const questionNumber = question.questionNumber || question.id; + + htmlContent += ` +
+
+ Q${questionNumber} + ${isConditional ? '조건부 질문' : ''} + ${question.isRequired ? '*' : ''} +
+
${question.questionText || ''}
+`; + + if (answerData) { + // 답변 값 표시 + if (answerData.answerValue) { + const option = question.options?.find((opt: any) => opt.optionValue === answerData.answerValue); + const answerText = option ? option.optionText : answerData.answerValue; + + htmlContent += ` +
+
선택한 답변:
+
${answerText}
+
`; + } + + // 기타 입력 텍스트 + if (answerData.otherText) { + htmlContent += ` +
+
기타 입력:
+
${answerData.otherText}
+
`; + } + + // 상세 내용 + if (answerData.detailText) { + htmlContent += ` +
+
상세 내용:
+
${answerData.detailText}
+
`; + } + + // 첨부 파일 + const files = answerData.files || []; + if (files.length > 0) { + htmlContent += ` +
+
첨부 파일:
+
`; + + files.forEach((file: any) => { + const fileName = file.fileName || file.name || '파일'; + htmlContent += ` +
📎 ${fileName}
`; + }); + + htmlContent += ` +
+
`; + } + } else { + htmlContent += ` +
+
답변 없음
+
`; + } + + htmlContent += ` +
`; + }); + + // 메타데이터 추가 + const completedDate = existingResponse?.completedAt + ? new Date(existingResponse.completedAt).toLocaleString('ko-KR') + : new Date().toLocaleString('ko-KR'); + + htmlContent += ` + + +`; + + // Blob 생성 및 다운로드 + const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' }); + const url = URL.createObjectURL(blob); const link = document.createElement('a'); - link.href = apiFilePath; - link.download = actualFileName; - link.target = '_blank'; + link.href = url; + link.download = `${surveyTemplate.name}_${new Date().toISOString().split('T')[0]}.html`; document.body.appendChild(link); link.click(); document.body.removeChild(link); + URL.revokeObjectURL(url); - toast.success("파일 다운로드가 시작되었습니다."); + toast.success("설문조사 내용이 다운로드되었습니다."); } catch (error) { - console.error("파일 다운로드 실패:", error); - toast.error("파일 다운로드에 실패했습니다."); + console.error("설문조사 다운로드 실패:", error); + toast.error("설문조사 다운로드에 실패했습니다."); } - }, [contractFilePath, contractFileName]); + }, [surveyTemplate, getValues, visibleQuestions, existingResponse]); // 설문조사 완료 핸들러 const handleSurveyComplete = useCallback(async () => { @@ -581,19 +770,17 @@ export const SurveyComponent: React.FC = ({
- {/* Word 파일 다운로드 버튼 */} - {contractFilePath && ( - - )} + {/* 설문조사 내용 다운로드 버튼 */} + {/* 컴팩트 진행률 표시 */}
diff --git a/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx b/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx index 7401a32c..f21eac38 100644 --- a/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx +++ b/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx @@ -1448,8 +1448,6 @@ export function BasicContractSignViewer({ onSurveyDataUpdate={setSurveyData} onLoadSurveyTemplate={loadSurveyTemplate} setActiveTab={setActiveTab} - contractFilePath={filePath} - contractFileName={filePath ? filePath.split('/').pop() : undefined} />
@@ -1677,8 +1675,6 @@ export function BasicContractSignViewer({ onSurveyDataUpdate={setSurveyData} onLoadSurveyTemplate={loadSurveyTemplate} setActiveTab={setActiveTab} - contractFilePath={filePath} - contractFileName={filePath ? filePath.split('/').pop() : undefined} />
-- cgit v1.2.3