diff --git a/backend/services/vocabService.js b/backend/services/vocabService.js index 6e79a1d..81e31af 100644 --- a/backend/services/vocabService.js +++ b/backend/services/vocabService.js @@ -2881,6 +2881,23 @@ export default class VocabService { }); const plainLesson = lesson.get({ plain: true }); + // Normalize exercise types: if question text contains clear gap placeholders, + // ensure the questionData.type is 'gap_fill' so the frontend renders the gap UI. + (plainLesson.grammarExercises || []).forEach((ex) => { + try { + const qData = typeof ex.questionData === 'string' ? JSON.parse(ex.questionData || '{}') : (ex.questionData || {}); + const text = String(qData.text || qData.question || '').trim(); + const hasUnderscoreGap = /_{3,}/.test(text); + const hasBraceGap = /\{\s*gap\s*\}/i.test(text); + const hasParenPlaceholders = /\(\s*_{0,}\s*\)/.test(text); + if ((hasUnderscoreGap || hasBraceGap || hasParenPlaceholders) && qData.type !== 'gap_fill') { + qData.type = 'gap_fill'; + ex.questionData = qData; + } + } catch (err) { + // ignore parse errors + } + }); // Lade Vokabeln aus vorherigen Lektionen (für Wiederholung UND für gemischten Vokabeltrainer) if (plainLesson.lessonNumber > 1) { diff --git a/frontend/src/views/social/VocabLessonView.vue b/frontend/src/views/social/VocabLessonView.vue index 3215fd7..5aaf93d 100644 --- a/frontend/src/views/social/VocabLessonView.vue +++ b/frontend/src/views/social/VocabLessonView.vue @@ -2816,6 +2816,30 @@ export default { } await this.$nextTick(); let exercises = this.effectiveExercises; + // Wenn das Backend eine chapterLexemeTraining-Liste liefert, wandle sie + // in temporäre gap_fill-Übungen um und mische sie in die grammarExercises + try { + if (this.lesson && Array.isArray(this.lesson.chapterLexemeTraining) && this.lesson.chapterLexemeTraining.length) { + const temps = this.lesson.chapterLexemeTraining.map((item, idx) => { + const id = `cht-${this.lesson.id}-${String(item.id)}`; + return { + id, + lessonId: this.lesson.id, + exerciseTypeId: 1, + title: `Kapitel-Vokabel: ${item.learning}`, + instruction: this.$t('socialnetwork.vocab.courses.fillTheBlank') || 'Lückentext', + questionData: { type: 'gap_fill', text: `{gap} (${item.learning})` }, + answerData: { type: 'gap_fill', answers: [item.reference] } + }; + }); + this.lesson.grammarExercises = Array.isArray(this.lesson.grammarExercises) + ? [...this.lesson.grammarExercises, ...temps] + : temps; + exercises = this.effectiveExercises; + } + } catch (err) { + console.warn('[VocabLessonView] Fehler beim Einfügen von chapterLexemeTraining:', err); + } if (!exercises || exercises.length === 0) { debugLog('[VocabLessonView] Lade Übungen separat...'); await this.loadGrammarExercises();