diff --git a/backend/services/vocabService.js b/backend/services/vocabService.js index 8dc01c2..5d55d2d 100644 --- a/backend/services/vocabService.js +++ b/backend/services/vocabService.js @@ -1702,8 +1702,18 @@ export default class VocabService { throw err; } - // Überprüfe Antwort (vereinfachte Logik - kann je nach Übungstyp erweitert werden) - const isCorrect = this._checkAnswer(exercise.answerData, exercise.questionData, userAnswer, exercise.exerciseTypeId); + const originalAnswerData = typeof exercise.answerData === 'string' + ? JSON.parse(exercise.answerData) + : exercise.answerData; + const questionData = typeof exercise.questionData === 'string' + ? JSON.parse(exercise.questionData) + : exercise.questionData; + const effectiveAnswerData = exercise.exerciseTypeId === 2 + ? await this._expandMultipleChoiceAnswerData(exercise, originalAnswerData, questionData) + : originalAnswerData; + + // Überprüfe Antwort + const isCorrect = this._checkAnswer(effectiveAnswerData, questionData, userAnswer, exercise.exerciseTypeId); // Speichere Fortschritt const [progress, created] = await VocabGrammarExerciseProgress.findOrCreate({ @@ -1736,12 +1746,7 @@ export default class VocabService { } // Extrahiere richtige Antwort und Alternativen - const answerData = typeof exercise.answerData === 'string' - ? JSON.parse(exercise.answerData) - : exercise.answerData; - const questionData = typeof exercise.questionData === 'string' - ? JSON.parse(exercise.questionData) - : exercise.questionData; + const answerData = effectiveAnswerData; let correctAnswer = null; let alternatives = []; @@ -1817,6 +1822,86 @@ export default class VocabService { return type ? type.id : null; } + _extractMultipleChoiceIndices(answerData) { + if (!answerData) return []; + if (answerData.correctAnswer !== undefined) { + return Array.isArray(answerData.correctAnswer) + ? answerData.correctAnswer.map(idx => Number(idx)).filter(Number.isInteger) + : [Number(answerData.correctAnswer)].filter(Number.isInteger); + } + if (answerData.correct !== undefined) { + return Array.isArray(answerData.correct) + ? answerData.correct.map(idx => Number(idx)).filter(Number.isInteger) + : [Number(answerData.correct)].filter(Number.isInteger); + } + return []; + } + + _getMultipleChoicePrompt(questionData) { + return this._normalizeTextAnswer( + questionData?.question || questionData?.text || questionData?.prompt || '' + ); + } + + async _expandMultipleChoiceAnswerData(exercise, answerData, questionData) { + const options = Array.isArray(questionData?.options) ? questionData.options : []; + const baseIndices = this._extractMultipleChoiceIndices(answerData); + if (!options.length || !baseIndices.length || !exercise?.lessonId) { + return answerData; + } + + const prompt = this._getMultipleChoicePrompt(questionData); + if (!prompt) { + return answerData; + } + + const optionIndexMap = new Map(); + options.forEach((option, index) => { + const normalizedOption = this._normalizeTextAnswer(option); + if (!normalizedOption) return; + const existing = optionIndexMap.get(normalizedOption) || []; + existing.push(index); + optionIndexMap.set(normalizedOption, existing); + }); + + const lessonExercises = await VocabGrammarExercise.findAll({ + where: { + lessonId: exercise.lessonId, + exerciseTypeId: 2 + }, + attributes: ['id', 'questionData', 'answerData'] + }); + + const expandedIndices = new Set(baseIndices); + lessonExercises.forEach((candidate) => { + const candidateQuestionData = typeof candidate.questionData === 'string' + ? JSON.parse(candidate.questionData) + : candidate.questionData; + const candidatePrompt = this._getMultipleChoicePrompt(candidateQuestionData); + if (candidatePrompt !== prompt) { + return; + } + + const candidateAnswerData = typeof candidate.answerData === 'string' + ? JSON.parse(candidate.answerData) + : candidate.answerData; + const candidateOptions = Array.isArray(candidateQuestionData?.options) ? candidateQuestionData.options : []; + const candidateIndices = this._extractMultipleChoiceIndices(candidateAnswerData); + + candidateIndices.forEach((candidateIndex) => { + const candidateOption = candidateOptions[candidateIndex]; + const normalizedOption = this._normalizeTextAnswer(candidateOption); + const matchingIndices = optionIndexMap.get(normalizedOption) || []; + matchingIndices.forEach((matchingIndex) => expandedIndices.add(matchingIndex)); + }); + }); + + return { + ...answerData, + correctAnswer: Array.from(expandedIndices).sort((a, b) => a - b) + }; + } + _checkAnswer(answerData, questionData, userAnswer, exerciseTypeId) { // Vereinfachte Antwortprüfung - kann je nach Übungstyp erweitert werden if (!answerData || userAnswer === undefined || userAnswer === null) return false;