feat(VocabLessonView): enhance exercise access and vocab trainer experience
- Added conditional access to exercises based on user progress and previous vocab completion. - Introduced visual indicators for exercise availability and review priorities to guide users. - Updated vocab trainer descriptions and button labels to reflect the user's current state and encourage engagement. - Implemented methods to manage exercise unlock conditions and improve user feedback on progress.
This commit is contained in:
@@ -19,8 +19,9 @@
|
||||
{{ $t('socialnetwork.vocab.courses.learn') }}
|
||||
</button>
|
||||
<button
|
||||
:class="{ active: activeTab === 'exercises' }"
|
||||
@click="activeTab = 'exercises'"
|
||||
:class="{ active: activeTab === 'exercises' }"
|
||||
:disabled="!canAccessExercises"
|
||||
@click="openExercisesTab"
|
||||
class="tab-button"
|
||||
>
|
||||
{{ $t('socialnetwork.vocab.courses.exercises') }}
|
||||
@@ -190,10 +191,18 @@
|
||||
<!-- Vokabeltrainer -->
|
||||
<div v-if="importantVocab && importantVocab.length > 0" class="vocab-trainer-section">
|
||||
<h4>{{ $t('socialnetwork.vocab.courses.vocabTrainer') }}</h4>
|
||||
<div v-if="hasPreviousVocab" class="review-priority-note">
|
||||
<strong>Tageswiederholung zuerst</strong>
|
||||
<p>Ältere Vokabeln stehen hier bewusst vor der Kapitel-Prüfung, damit Wiederholung täglich mitläuft.</p>
|
||||
</div>
|
||||
<div v-if="hasExercises && !canAccessExercises" class="exercise-lock-note">
|
||||
<strong>Kapitel-Prüfung noch gesperrt</strong>
|
||||
<p>{{ exerciseUnlockHint }}</p>
|
||||
</div>
|
||||
<div v-if="!vocabTrainerActive" class="vocab-trainer-start">
|
||||
<p>{{ $t('socialnetwork.vocab.courses.vocabTrainerDescription') }}</p>
|
||||
<p>{{ hasPreviousVocab ? 'Starte mit der Wiederholung älterer Vokabeln und arbeite dich dann zur aktuellen Lektion vor.' : $t('socialnetwork.vocab.courses.vocabTrainerDescription') }}</p>
|
||||
<button @click="startVocabTrainer" class="btn-start-trainer">
|
||||
{{ $t('socialnetwork.vocab.courses.startVocabTrainer') }}
|
||||
{{ hasPreviousVocab ? 'Tageswiederholung starten' : $t('socialnetwork.vocab.courses.startVocabTrainer') }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="vocab-trainer-active">
|
||||
@@ -293,8 +302,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Button um zu Übungen zu wechseln -->
|
||||
<div v-if="hasExercises" class="continue-to-exercises">
|
||||
<button @click="activeTab = 'exercises'" class="btn-continue">
|
||||
<div v-if="hasExercises && canAccessExercises" class="continue-to-exercises">
|
||||
<button @click="openExercisesTab" class="btn-continue">
|
||||
{{ $t('socialnetwork.vocab.courses.startExercises') }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -692,6 +701,7 @@ export default {
|
||||
vocabTrainerPhase: 'current', // 'current' = aktuelle Lektion, 'mixed' = gemischt mit alten
|
||||
vocabTrainerMixedPool: [], // Pool aus alten Lektionsvokabeln
|
||||
vocabTrainerMixedAttempts: 0, // Zähler für Mixed-Phase
|
||||
exercisePreparationCompleted: false,
|
||||
currentVocabQuestion: null,
|
||||
vocabTrainerAnswer: '',
|
||||
vocabTrainerSelectedChoice: null,
|
||||
@@ -727,6 +737,20 @@ export default {
|
||||
const exercises = this.effectiveExercises;
|
||||
return exercises && Array.isArray(exercises) && exercises.length > 0;
|
||||
},
|
||||
hasPreviousVocab() {
|
||||
return Array.isArray(this.previousVocab) && this.previousVocab.length > 0;
|
||||
},
|
||||
canAccessExercises() {
|
||||
if (!this.hasExercises) return false;
|
||||
const isReview = this.lesson?.lessonType === 'review' || this.lesson?.lessonType === 'vocab_review';
|
||||
return isReview || this.exercisePreparationCompleted;
|
||||
},
|
||||
exerciseUnlockHint() {
|
||||
if (this.hasPreviousVocab) {
|
||||
return 'Beantworte zuerst einige Wiederholungsfragen aus älteren Lektionen richtig. Danach wird die Kapitel-Prüfung freigeschaltet.';
|
||||
}
|
||||
return 'Arbeite zuerst kurz mit dem Vokabeltrainer der aktuellen Lektion. Danach wird die Kapitel-Prüfung freigeschaltet.';
|
||||
},
|
||||
/** Für Wiederholungslektionen: Übungen aus vorherigen Lektionen (Kapitelprüfung). Sonst: eigene Grammatik-Übungen. */
|
||||
effectiveExercises() {
|
||||
if (!this.lesson) return [];
|
||||
@@ -836,6 +860,40 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openExercisesTab() {
|
||||
if (!this.canAccessExercises) {
|
||||
this.activeTab = 'learn';
|
||||
this.showErrorDialog = true;
|
||||
this.errorMessage = this.exerciseUnlockHint;
|
||||
return;
|
||||
}
|
||||
this.activeTab = 'exercises';
|
||||
},
|
||||
updateExerciseUnlockState() {
|
||||
if (this.exercisePreparationCompleted) {
|
||||
return;
|
||||
}
|
||||
if (!this.hasExercises) {
|
||||
this.exercisePreparationCompleted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const minimumAttempts = this.hasPreviousVocab ? 8 : 6;
|
||||
const successRate = this.vocabTrainerTotalAttempts > 0
|
||||
? (this.vocabTrainerCorrect / this.vocabTrainerTotalAttempts) * 100
|
||||
: 0;
|
||||
|
||||
if (this.hasPreviousVocab) {
|
||||
if (this.vocabTrainerPhase === 'mixed' && this.vocabTrainerTotalAttempts >= minimumAttempts && successRate >= 70) {
|
||||
this.exercisePreparationCompleted = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.vocabTrainerTotalAttempts >= minimumAttempts && successRate >= 70) {
|
||||
this.exercisePreparationCompleted = true;
|
||||
}
|
||||
},
|
||||
_extractVocabFromExercises(exercises) {
|
||||
// Sicherstellen, dass exercises ein Array ist
|
||||
if (!exercises) {
|
||||
@@ -989,6 +1047,11 @@ export default {
|
||||
this.assistantMessages = [];
|
||||
this.assistantInput = '';
|
||||
this.assistantError = '';
|
||||
this.exercisePreparationCompleted = false;
|
||||
this.vocabTrainerActive = false;
|
||||
this.vocabTrainerPool = [];
|
||||
this.vocabTrainerMixedPool = [];
|
||||
this.vocabTrainerPhase = 'current';
|
||||
// Reset Flags
|
||||
this.isCheckingLessonCompletion = false;
|
||||
this.isNavigatingToNext = false;
|
||||
@@ -998,6 +1061,9 @@ export default {
|
||||
if (tabParam === 'learn') {
|
||||
this.activeTab = 'learn';
|
||||
}
|
||||
if (tabParam === 'exercises') {
|
||||
this.activeTab = 'learn';
|
||||
}
|
||||
if (this.$route.query.assistant) {
|
||||
this.activeTab = 'learn';
|
||||
}
|
||||
@@ -1406,10 +1472,13 @@ export default {
|
||||
this.vocabTrainerWrong = 0;
|
||||
this.vocabTrainerTotalAttempts = 0;
|
||||
this.vocabTrainerStats = {};
|
||||
this.vocabTrainerPhase = 'current';
|
||||
this.vocabTrainerMixedAttempts = 0;
|
||||
// Bereite Mixed-Pool aus alten Vokabeln vor (ohne Duplikate aus aktueller Lektion)
|
||||
this.vocabTrainerMixedPool = this._buildMixedPool();
|
||||
this.vocabTrainerPhase = this.vocabTrainerMixedPool.length > 0 ? 'mixed' : 'current';
|
||||
this.vocabTrainerMixedAttempts = 0;
|
||||
this.vocabTrainerPool = this.vocabTrainerPhase === 'mixed'
|
||||
? [...this.vocabTrainerMixedPool]
|
||||
: [...this.importantVocab];
|
||||
debugLog('[VocabLessonView] Mixed-Pool:', this.vocabTrainerMixedPool.length, 'Vokabeln');
|
||||
debugLog('[VocabLessonView] Rufe nextVocabQuestion auf');
|
||||
this.$nextTick(() => {
|
||||
@@ -1451,6 +1520,8 @@ export default {
|
||||
const MC_THRESHOLD = 60; // Multiple Choice Versuche pro Phase
|
||||
const MIXED_LIMIT = 40; // Anzahl gemischter Vokabeln aus alten Lektionen
|
||||
|
||||
this.updateExerciseUnlockState();
|
||||
|
||||
if (this.vocabTrainerPhase === 'current') {
|
||||
// Phase 1: Aktuelle Lektion - nach MC_THRESHOLD Versuchen mit 80% → Wechsel zu Mixed oder Typing
|
||||
if (this.vocabTrainerMode === 'multiple_choice' && this.vocabTrainerTotalAttempts >= MC_THRESHOLD) {
|
||||
@@ -2349,6 +2420,31 @@ export default {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.review-priority-note,
|
||||
.exercise-lock-note {
|
||||
margin-bottom: 12px;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.review-priority-note {
|
||||
background: #eef7ff;
|
||||
border: 1px solid #b9d8ff;
|
||||
color: #234a72;
|
||||
}
|
||||
|
||||
.exercise-lock-note {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffc107;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.review-priority-note strong,
|
||||
.exercise-lock-note strong {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.vocab-trainer-start {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user