diff options
Diffstat (limited to 'lib/basic-contract/vendor-table/survey-conditional.ts')
| -rw-r--r-- | lib/basic-contract/vendor-table/survey-conditional.ts | 180 |
1 files changed, 28 insertions, 152 deletions
diff --git a/lib/basic-contract/vendor-table/survey-conditional.ts b/lib/basic-contract/vendor-table/survey-conditional.ts index 71c2c1ff..686cc4ba 100644 --- a/lib/basic-contract/vendor-table/survey-conditional.ts +++ b/lib/basic-contract/vendor-table/survey-conditional.ts @@ -131,6 +131,22 @@ public getIncompleteReason(question: SurveyQuestion, surveyAnswers: Record<numbe return true; } + private isValidFile(file: any): boolean { + if (!file || typeof file !== 'object') return false; + + // 브라우저 File 객체 체크 (새로 업로드한 파일) + if (file.name || file.size || file.type) return true; + + // 서버 파일 메타데이터 체크 (기존 파일) + if (file.filename || file.originalName || file.id || file.mimeType) return true; + + return false; + } + + private hasValidFiles(files: any[]): boolean { + return files && files.length > 0 && files.every(file => this.isValidFile(file)); + } + private isQuestionCompleteEnhanced(question: SurveyQuestion, surveyAnswers: Record<number, any>): boolean { const answer = surveyAnswers[question.id]; @@ -157,60 +173,50 @@ public getIncompleteReason(question: SurveyQuestion, surveyAnswers: Record<numbe const hasOtherText = answer.answerValue === 'OTHER' ? (answer.otherText && answer.otherText.trim() !== '') : true; - // 4️⃣ files 체크 (실제 파일이 있는 경우) - const hasValidFiles = answer.files && answer.files.length > 0 && - answer.files.every((file: any) => file && typeof file === 'object' && - (file.name || file.size || file.type)); // 빈 객체 {} 제외 + // 4️⃣ files 체크 (브라우저 File 객체와 서버 파일 메타데이터 모두 처리) - 수정된 부분 + const hasValidFilesResult = this.hasValidFiles(answer.files || []); console.log(`📊 Q${question.questionNumber} 완료 조건 체크:`, { hasAnswerValue, hasDetailText, hasOtherText, - hasValidFiles, + hasValidFiles: hasValidFilesResult, questionType: question.questionType, hasDetailTextRequired: question.hasDetailText, hasFileUploadRequired: question.hasFileUpload || question.questionType === 'FILE' }); - // 🎯 질문 타입별 완료 조건 + // 질문 타입별 완료 조건은 동일하지만 hasValidFilesResult 변수 사용 switch (question.questionType) { case 'RADIO': case 'DROPDOWN': - // 선택형: answerValue가 있고, OTHER인 경우 otherText도 필요 const isSelectComplete = hasAnswerValue && hasOtherText; - // detailText가 필요한 경우 추가 체크 if (question.hasDetailText && isSelectComplete) { return hasDetailText; } - // 파일 업로드가 필요한 경우 추가 체크 if ((question.hasFileUpload || question.questionType === 'FILE') && isSelectComplete) { - return hasValidFiles; + return hasValidFilesResult; // 수정된 부분 } return isSelectComplete; case 'TEXTAREA': - // 텍스트 영역: detailText 또는 answerValue 중 하나라도 있으면 됨 return hasDetailText || hasAnswerValue; case 'FILE': - // 파일 업로드: 유효한 파일이 있어야 함 - return hasValidFiles; + return hasValidFilesResult; // 수정된 부분 default: - // 기본: answerValue, detailText, 파일 중 하나라도 있으면 완료 - let isComplete = hasAnswerValue || hasDetailText || hasValidFiles; + let isComplete = hasAnswerValue || hasDetailText || hasValidFilesResult; // 수정된 부분 - // detailText가 필수인 경우 if (question.hasDetailText) { isComplete = isComplete && hasDetailText; } - // 파일 업로드가 필수인 경우 if (question.hasFileUpload) { - isComplete = isComplete && hasValidFiles; + isComplete = isComplete && hasValidFilesResult; // 수정된 부분 } return isComplete; @@ -303,17 +309,7 @@ private getCompletionDetailsEnhanced(question: SurveyQuestion, answer: any): any // 🎯 현재 답변 상태에 따라 표시되는 질문들 계산 const visibleQuestions = this.getVisibleQuestions(surveyAnswers); - console.log('🔍 표시되는 모든 질문들의 상세 정보:', visibleQuestions.map(q => ({ - id: q.id, - questionNumber: q.questionNumber, - questionText: q.questionText?.substring(0, 30) + '...', - isRequired: q.isRequired, - parentQuestionId: q.parentQuestionId, - conditionalValue: q.conditionalValue, - isConditional: !!q.parentQuestionId, - hasAnswer: !!surveyAnswers[q.id]?.answerValue, - answerValue: surveyAnswers[q.id]?.answerValue - }))); + // 🚨 중요: 트리거된 조건부 질문들을 필수로 처리 const requiredQuestions = visibleQuestions.filter(q => { @@ -334,26 +330,6 @@ private getCompletionDetailsEnhanced(question: SurveyQuestion, answer: any): any return false; }); - console.log('📊 필수 질문 필터링 결과:', { - 전체질문수: this.questions.length, - 표시되는질문수: visibleQuestions.length, - 원래필수질문: visibleQuestions.filter(q => q.isRequired).length, - 트리거된조건부질문: visibleQuestions.filter(q => { - if (!q.parentQuestionId || !q.conditionalValue) return false; - const parentAnswer = surveyAnswers[q.parentQuestionId]; - return parentAnswer?.answerValue === q.conditionalValue; - }).length, - 최종필수질문: requiredQuestions.length, - 현재답변수: Object.keys(surveyAnswers).length, - 필수질문들: requiredQuestions.map(q => ({ - id: q.id, - questionNumber: q.questionNumber, - isRequired: q.isRequired, - isConditional: !!q.parentQuestionId, - hasAnswer: !!surveyAnswers[q.id]?.answerValue, - 처리방식: q.isRequired ? '원래필수' : '트리거됨' - })) - }); const completedQuestionIds: number[] = []; const incompleteQuestionIds: number[] = []; @@ -365,10 +341,7 @@ private getCompletionDetailsEnhanced(question: SurveyQuestion, answer: any): any // 🎯 개선된 완료 체크: 모든 답변 형태를 고려 const isComplete = this.isQuestionCompleteEnhanced(question, surveyAnswers); - - console.log(`📊 Q${question.questionNumber} 완료 상태: ${isComplete}`); - console.log(`📝 Q${question.questionNumber} 답변 내용:`, surveyAnswers[question.id]); - + // 디버깅 정보 수집 debugInfo[question.id] = { questionText: question.questionText, @@ -414,25 +387,6 @@ private getCompletionDetailsEnhanced(question: SurveyQuestion, answer: any): any if (process.env.NODE_ENV === 'development') { (result as any).debugInfo = debugInfo; - // 📋 상세한 진행 상황 로그 - console.log('📋 최종 진행 상황:', { - 총필수질문: requiredQuestions.length, - 완료된질문: completedQuestionIds.length, - 미완료질문: incompleteQuestionIds.length, - 진행률: `${Math.round(progressPercentage)}%`, - 기본질문: visibleQuestions.filter(q => !q.parentQuestionId).length, - 조건부질문: visibleQuestions.filter(q => q.parentQuestionId).length, - 완료된기본질문: completedQuestionIds.filter(id => !visibleQuestions.find(q => q.id === id)?.parentQuestionId).length, - 완료된조건부질문: completedQuestionIds.filter(id => !!visibleQuestions.find(q => q.id === id)?.parentQuestionId).length, - 필수질문상세: requiredQuestions.map(q => ({ - id: q.id, - questionNumber: q.questionNumber, - isRequired: q.isRequired, - isConditional: !!q.parentQuestionId, - isComplete: completedQuestionIds.includes(q.id) - })) - }); - // 🔍 미완료 질문들의 구체적 이유 if (incompleteQuestionIds.length > 0) { console.log('🔍 미완료 질문들:', incompleteQuestionIds.map(id => ({ @@ -446,24 +400,7 @@ private getCompletionDetailsEnhanced(question: SurveyQuestion, answer: any): any // ⚡ 조건부 질문 활성화 및 완료 현황 const conditionalQuestions = visibleQuestions.filter(q => q.parentQuestionId); - if (conditionalQuestions.length > 0) { - console.log('⚡ 조건부 질문 상세 현황:', conditionalQuestions.map(q => ({ - id: q.id, - questionNumber: q.questionNumber, - isRequired: q.isRequired, - parentId: q.parentQuestionId, - condition: q.conditionalValue, - parentAnswer: surveyAnswers[q.parentQuestionId!]?.answerValue, - isTriggered: surveyAnswers[q.parentQuestionId!]?.answerValue === q.conditionalValue, - hasAnswer: !!surveyAnswers[q.id]?.answerValue, - answerValue: surveyAnswers[q.id]?.answerValue, - detailText: surveyAnswers[q.id]?.detailText, - files: surveyAnswers[q.id]?.files, - isComplete: debugInfo[q.id]?.isComplete, - isIncludedInRequired: requiredQuestions.some(rq => rq.id === q.id), - completionDetails: this.getCompletionDetailsEnhanced(q, surveyAnswers[q.id]) - }))); - } + } return result; @@ -606,37 +543,21 @@ getOverallProgressStatus(surveyAnswers: Record<number, any>): { const childQuestion = this.questions.find(q => q.id === childId); if (!childQuestion) return; - console.log(`🔍 자식 질문 ${childId} 체크:`, { - childId, - questionNumber: childQuestion.questionNumber, - conditionalValue: childQuestion.conditionalValue, - newParentValue, - shouldKeep: childQuestion.conditionalValue === newParentValue, - currentAnswer: updatedAnswers[childId]?.answerValue - }); - // 새로운 부모 값이 자식의 조건과 맞지 않으면 자식 답변 삭제 if (childQuestion.conditionalValue !== newParentValue) { - console.log(`🗑️ 자식 질문 Q${childQuestion.questionNumber} 답변 초기화 (조건 불일치)`); delete updatedAnswers[childId]; // 재귀적으로 손자 질문들도 정리 const grandChildAnswers = this.clearAffectedChildAnswers(childId, '', updatedAnswers); Object.assign(updatedAnswers, grandChildAnswers); } else { - console.log(`✅ 자식 질문 Q${childQuestion.questionNumber} 유지 (조건 일치)`); } }); const clearedCount = childQuestionIds.filter(childId => !updatedAnswers[childId]).length; const keptCount = childQuestionIds.filter(childId => !!updatedAnswers[childId]).length; - console.log(`📊 자식 질문 정리 완료:`, { - parentQuestionId, - 총자식질문: childQuestionIds.length, - 초기화된질문: clearedCount, - 유지된질문: keptCount - }); + return updatedAnswers; } @@ -680,21 +601,17 @@ getOverallProgressStatus(surveyAnswers: Record<number, any>): { conditionalValue: question.conditionalValue }; - console.log(`🔍 질문 완료 체크 [Q${question.questionNumber}]:`, logData); if (!question.isRequired) { - console.log(`✅ Q${question.questionNumber}: 선택 질문이므로 완료`); return true; } if (!answer?.answerValue) { - console.log(`❌ Q${question.questionNumber}: 답변이 없음`); return false; } // 1. '기타' 선택 시 추가 입력이 필요한 경우 if (answer.answerValue === 'OTHER' && !answer.otherText?.trim()) { - console.log(`❌ Q${question.questionNumber}: '기타' 선택했지만 상세 내용 없음`); return false; } @@ -702,16 +619,8 @@ getOverallProgressStatus(surveyAnswers: Record<number, any>): { if (question.hasDetailText) { const needsDetailText = ['YES', '네', 'Y', 'true', '1'].includes(answer.answerValue); - console.log(`📝 Q${question.questionNumber} 상세텍스트 체크:`, { - hasDetailText: question.hasDetailText, - answerValue: answer.answerValue, - needsDetailText, - detailText: answer.detailText?.length || 0, - detailTextExists: !!answer.detailText?.trim() - }); if (needsDetailText && !answer.detailText?.trim()) { - console.log(`❌ Q${question.questionNumber}: '${answer.answerValue}' 선택했지만 상세 내용 없음`); return false; } } @@ -720,17 +629,7 @@ getOverallProgressStatus(surveyAnswers: Record<number, any>): { if (question.hasFileUpload || question.questionType === 'FILE') { const needsFileUpload = ['YES', '네', 'Y', 'true', '1'].includes(answer.answerValue); - console.log(`📁 Q${question.questionNumber} 파일업로드 체크:`, { - hasFileUpload: question.hasFileUpload, - questionType: question.questionType, - answerValue: answer.answerValue, - needsFileUpload, - filesCount: answer.files?.length || 0, - hasFiles: !!answer.files && answer.files.length > 0 - }); - if (needsFileUpload && (!answer.files || answer.files.length === 0)) { - console.log(`❌ Q${question.questionNumber}: '${answer.answerValue}' 선택했지만 파일 업로드 없음`); return false; } } @@ -739,50 +638,27 @@ getOverallProgressStatus(surveyAnswers: Record<number, any>): { const childQuestions = this.getChildQuestions(question.id); if (childQuestions.length > 0) { - console.log(`🔗 Q${question.questionNumber} 부모 질문 - 자식 질문들:`, - childQuestions.map(c => ({ - id: c.id, - questionNumber: c.questionNumber, - condition: c.conditionalValue, - required: c.isRequired, - text: c.questionText?.substring(0, 20) + '...' - })) - ); // 현재 답변으로 트리거되는 자식 질문들 찾기 const triggeredChildren = childQuestions.filter(child => child.conditionalValue === answer.answerValue ); - console.log(`🎯 Q${question.questionNumber} 답변 '${answer.answerValue}'로 트리거된 자식들:`, - triggeredChildren.map(c => ({ - id: c.id, - questionNumber: c.questionNumber, - required: c.isRequired, - text: c.questionText?.substring(0, 30) + '...' - })) - ); - // 트리거된 필수 자식 질문들이 모두 완료되었는지 확인 for (const childQuestion of triggeredChildren) { if (childQuestion.isRequired) { - console.log(`🔄 자식 질문 Q${childQuestion.questionNumber} 완료 체크 시작...`); const childComplete = this.isQuestionComplete(childQuestion, surveyAnswers); - console.log(`📊 자식 질문 Q${childQuestion.questionNumber} 완료 상태: ${childComplete}`); if (!childComplete) { - console.log(`❌ 부모 Q${question.questionNumber}의 자식 Q${childQuestion.questionNumber} 미완료`); return false; } } } if (triggeredChildren.filter(c => c.isRequired).length > 0) { - console.log(`✅ Q${question.questionNumber}의 모든 필수 조건부 자식 질문들 완료됨`); } } - console.log(`✅ Q${question.questionNumber} 완료 체크 통과`); return true; } |
