summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/basic-contract/viewer/SurveyComponent.tsx263
-rw-r--r--lib/basic-contract/viewer/basic-contract-sign-viewer.tsx4
2 files changed, 225 insertions, 42 deletions
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<SurveyComponentProps> = ({
@@ -53,9 +51,7 @@ export const SurveyComponent: React.FC<SurveyComponentProps> = ({
onSurveyComplete,
onSurveyDataUpdate,
onLoadSurveyTemplate,
- setActiveTab,
- contractFilePath,
- contractFileName
+ setActiveTab
}) => {
const [uploadedFiles, setUploadedFiles] = useState<Record<number, File[]>>({});
const [existingResponse, setExistingResponse] = useState<ExistingResponse | null>(null);
@@ -325,39 +321,232 @@ export const SurveyComponent: React.FC<SurveyComponentProps> = ({
);
}, [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 = `
+<!DOCTYPE html>
+<html lang="ko">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>${surveyTemplate.name}</title>
+ <style>
+ body {
+ font-family: 'Malgun Gothic', '맑은 고딕', Arial, sans-serif;
+ line-height: 1.6;
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+ color: #333;
+ }
+ h1 {
+ color: #1a1a1a;
+ border-bottom: 3px solid #2563eb;
+ padding-bottom: 10px;
+ margin-bottom: 30px;
+ }
+ .question {
+ margin-bottom: 25px;
+ padding: 15px;
+ background-color: #f9fafb;
+ border-left: 4px solid #2563eb;
+ border-radius: 4px;
+ }
+ .question-number {
+ font-weight: bold;
+ color: #2563eb;
+ margin-bottom: 8px;
+ }
+ .question-text {
+ font-size: 16px;
+ font-weight: 600;
+ margin-bottom: 12px;
+ color: #1a1a1a;
+ }
+ .answer {
+ margin-top: 10px;
+ padding: 10px;
+ background-color: #ffffff;
+ border: 1px solid #e5e7eb;
+ border-radius: 4px;
+ }
+ .answer-label {
+ font-weight: 600;
+ color: #4b5563;
+ margin-bottom: 5px;
+ }
+ .answer-value {
+ color: #1f2937;
+ white-space: pre-wrap;
+ }
+ .file-list {
+ margin-top: 8px;
+ padding-left: 20px;
+ }
+ .file-item {
+ color: #2563eb;
+ margin: 4px 0;
+ }
+ .conditional-badge {
+ display: inline-block;
+ background-color: #fef3c7;
+ color: #92400e;
+ padding: 2px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+ margin-left: 8px;
+ }
+ .metadata {
+ margin-top: 30px;
+ padding: 15px;
+ background-color: #f3f4f6;
+ border-radius: 4px;
+ font-size: 14px;
+ color: #6b7280;
+ }
+ </style>
+</head>
+<body>
+ <h1>${surveyTemplate.name}</h1>
+`;
+
+ // 질문과 답변 생성
+ 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 += `
+ <div class="question">
+ <div class="question-number">
+ Q${questionNumber}
+ ${isConditional ? '<span class="conditional-badge">조건부 질문</span>' : ''}
+ ${question.isRequired ? '<span style="color: #dc2626;">*</span>' : ''}
+ </div>
+ <div class="question-text">${question.questionText || ''}</div>
+`;
+
+ if (answerData) {
+ // 답변 값 표시
+ if (answerData.answerValue) {
+ const option = question.options?.find((opt: any) => opt.optionValue === answerData.answerValue);
+ const answerText = option ? option.optionText : answerData.answerValue;
+
+ htmlContent += `
+ <div class="answer">
+ <div class="answer-label">선택한 답변:</div>
+ <div class="answer-value">${answerText}</div>
+ </div>`;
+ }
+
+ // 기타 입력 텍스트
+ if (answerData.otherText) {
+ htmlContent += `
+ <div class="answer">
+ <div class="answer-label">기타 입력:</div>
+ <div class="answer-value">${answerData.otherText}</div>
+ </div>`;
+ }
+
+ // 상세 내용
+ if (answerData.detailText) {
+ htmlContent += `
+ <div class="answer">
+ <div class="answer-label">상세 내용:</div>
+ <div class="answer-value">${answerData.detailText}</div>
+ </div>`;
+ }
+
+ // 첨부 파일
+ const files = answerData.files || [];
+ if (files.length > 0) {
+ htmlContent += `
+ <div class="answer">
+ <div class="answer-label">첨부 파일:</div>
+ <div class="file-list">`;
+
+ files.forEach((file: any) => {
+ const fileName = file.fileName || file.name || '파일';
+ htmlContent += `
+ <div class="file-item">📎 ${fileName}</div>`;
+ });
+
+ htmlContent += `
+ </div>
+ </div>`;
+ }
+ } else {
+ htmlContent += `
+ <div class="answer">
+ <div class="answer-value" style="color: #9ca3af; font-style: italic;">답변 없음</div>
+ </div>`;
+ }
+
+ htmlContent += `
+ </div>`;
+ });
+
+ // 메타데이터 추가
+ const completedDate = existingResponse?.completedAt
+ ? new Date(existingResponse.completedAt).toLocaleString('ko-KR')
+ : new Date().toLocaleString('ko-KR');
+
+ htmlContent += `
+ <div class="metadata">
+ <div><strong>생성일시:</strong> ${completedDate}</div>
+ ${existingResponse ? `<div><strong>상태:</strong> ${existingResponse.status === 'COMPLETED' ? '완료' : '작성중'}</div>` : ''}
+ <div><strong>총 질문 수:</strong> ${questionsToShow.length}개</div>
+ </div>
+</body>
+</html>`;
+
+ // 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<SurveyComponentProps> = ({
</CardTitle>
<div className="flex items-center space-x-3">
- {/* Word 파일 다운로드 버튼 */}
- {contractFilePath && (
- <Button
- variant="outline"
- size="sm"
- onClick={handleDownloadContract}
- className="h-8 text-xs"
- title="계약서 문서 다운로드"
- >
- <Download className="h-3 w-3 mr-1" />
- 문서 다운로드
- </Button>
- )}
+ {/* 설문조사 내용 다운로드 버튼 */}
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleDownloadSurvey}
+ className="h-8 text-xs"
+ title="설문조사 내용 다운로드"
+ >
+ <Download className="h-3 w-3 mr-1" />
+ 설문조사 다운로드
+ </Button>
{/* 컴팩트 진행률 표시 */}
<div className="flex items-center space-x-2">
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}
/>
</div>
@@ -1677,8 +1675,6 @@ export function BasicContractSignViewer({
onSurveyDataUpdate={setSurveyData}
onLoadSurveyTemplate={loadSurveyTemplate}
setActiveTab={setActiveTab}
- contractFilePath={filePath}
- contractFileName={filePath ? filePath.split('/').pop() : undefined}
/>
</div>