feat(vocabLesson): add detailed review section for failed chapter exams
All checks were successful
Deploy to production / deploy (push) Successful in 2m53s

- Introduced a new review section that displays questions, user answers, and correct answers for failed chapter exams.
- Added localization entries for the review section in multiple languages, enhancing user experience and understanding of mistakes.
- Implemented logic to format and present failed exam details, improving feedback for learners.
This commit is contained in:
Torsten Schulz (local)
2026-04-15 14:02:34 +02:00
parent cc791501c9
commit 7b4c9a0b1c
6 changed files with 102 additions and 0 deletions

View File

@@ -957,6 +957,25 @@
target: exerciseTargetScore,
count: exerciseRetryUnlockAttempts
}) }}</p>
<div v-if="chapterExamFailedDetails.length > 0" class="exam-failed-review">
<h4>{{ $t('socialnetwork.vocab.courses.exerciseExamFailedReviewTitle') }}</h4>
<ul>
<li v-for="(item, index) in chapterExamFailedDetails" :key="`failed-${index}-${item.id}`">
<p class="exam-failed-review__question">
<strong>{{ $t('socialnetwork.vocab.courses.exerciseExamFailedQuestionLabel') }} {{ index + 1 }}:</strong>
{{ item.question }}
</p>
<p class="exam-failed-review__answer">
<strong>{{ $t('socialnetwork.vocab.courses.exerciseExamFailedYourAnswerLabel') }}:</strong>
{{ item.userAnswer || $t('socialnetwork.vocab.courses.exerciseExamFailedNoAnswer') }}
</p>
<p class="exam-failed-review__answer">
<strong>{{ $t('socialnetwork.vocab.courses.correctAnswer') }}:</strong>
{{ item.correctAnswer || '—' }}
</p>
</li>
</ul>
</div>
</div>
<div class="dialog-footer">
<button type="button" class="dialog-button dialog-button--primary" @click="closeChapterExamFailedDialog">
@@ -1053,6 +1072,7 @@ export default {
exerciseReinforcementMessage: '',
showChapterExamFailedDialog: false,
chapterExamFailedScore: 0,
chapterExamFailedDetails: [],
/** Index in scrambledChapterExamExercises bei Ein-Frage-Ansicht */
exerciseSequentialIndex: 0,
/** Aus vorherigen Lektionen (MC-Optionen nach Fragentyp Ziel-/Muttersprache) */
@@ -2049,6 +2069,42 @@ export default {
closeChapterExamFailedDialog() {
this.showChapterExamFailedDialog = false;
},
formatExerciseAnswerForReview(exercise, rawAnswer) {
if (rawAnswer === null || rawAnswer === undefined) return '';
const type = this.getExerciseType(exercise);
if (type === 'multiple_choice') {
const options = this.getOptions(exercise);
const idx = Number(rawAnswer);
if (Number.isInteger(idx) && idx >= 0 && idx < options.length) {
return String(options[idx] ?? '');
}
}
if (Array.isArray(rawAnswer)) {
return rawAnswer
.map((v) => String(v || '').trim())
.filter(Boolean)
.join(' | ');
}
return String(rawAnswer || '').trim();
},
buildChapterExamFailedDetails() {
const all = this.effectiveExercises;
if (!Array.isArray(all) || all.length === 0) return [];
const out = [];
all.forEach((exercise) => {
const result = this.exerciseResults[exercise.id];
if (!result || result.correct) return;
const question = String(this.getQuestionText(exercise) || exercise.title || '').trim();
const userAnswerRaw = this.exerciseAnswers[exercise.id];
out.push({
id: exercise.id,
question,
userAnswer: this.formatExerciseAnswerForReview(exercise, userAnswerRaw),
correctAnswer: String(result.correctAnswer || '').trim()
});
});
return out;
},
clearChapterExamAttemptState() {
const all = this.effectiveExercises;
if (!all.length) return;
@@ -2064,6 +2120,7 @@ export default {
this.buildMcRandomizedOptions();
},
handleChapterExamFailed(score) {
this.chapterExamFailedDetails = this.buildChapterExamFailedDetails();
this.exerciseRetryPending = true;
this.exerciseRetryPendingSinceAttempts = this.vocabTrainerTotalAttempts;
this.clearChapterExamAttemptState();
@@ -4234,6 +4291,31 @@ export default {
font-weight: 700;
}
.exam-failed-review {
margin-top: 14px;
padding-top: 12px;
border-top: 1px solid rgba(133, 100, 4, 0.28);
}
.exam-failed-review h4 {
margin: 0 0 8px;
font-size: 0.98rem;
}
.exam-failed-review ul {
margin: 0;
padding-left: 18px;
}
.exam-failed-review li {
margin-bottom: 10px;
}
.exam-failed-review__question,
.exam-failed-review__answer {
margin: 0 0 4px;
}
.exercise-flow-header {
display: flex;
justify-content: space-between;