Enhance Bisaya course content creation: Update SQL query to include owner user ID and improve exercise handling logic. Implement checks for existing exercises and placeholder replacements for review lessons, ensuring better management of lesson content and user feedback.

This commit is contained in:
Torsten Schulz (local)
2026-02-02 09:58:35 +01:00
parent 640cdcf671
commit ce34bae16a
3 changed files with 188 additions and 52 deletions

View File

@@ -24,7 +24,7 @@
class="tab-button"
>
{{ $t('socialnetwork.vocab.courses.exercises') }}
<span v-if="hasExercises" class="exercise-count">({{ lesson?.grammarExercises?.length || 0 }})</span>
<span v-if="hasExercises" class="exercise-count">({{ effectiveExercises?.length || 0 }})</span>
</button>
</div>
@@ -160,11 +160,11 @@
</div>
</div>
<!-- Übungen-Tab -->
<!-- Übungen-Tab (Kapitel-Prüfung) -->
<div v-if="activeTab === 'exercises'" class="grammar-exercises">
<div v-if="lesson && lesson.grammarExercises && lesson.grammarExercises.length > 0">
<div v-if="lesson && effectiveExercises && effectiveExercises.length > 0">
<h3>{{ $t('socialnetwork.vocab.courses.grammarExercises') }}</h3>
<div v-for="exercise in lesson.grammarExercises" :key="exercise.id" class="exercise-item">
<div v-for="exercise in effectiveExercises" :key="exercise.id" class="exercise-item">
<h4>{{ exercise.title }}</h4>
<p v-if="exercise.instruction" class="exercise-instruction">{{ exercise.instruction }}</p>
@@ -351,7 +351,7 @@
</div>
</div>
</div>
<div v-else-if="lesson && (!lesson.grammarExercises || lesson.grammarExercises.length === 0)">
<div v-else-if="lesson && (!effectiveExercises || effectiveExercises.length === 0)">
<p>{{ $t('socialnetwork.vocab.courses.noExercises') }}</p>
</div>
</div>
@@ -465,22 +465,33 @@ export default {
computed: {
...mapGetters(['user']),
hasExercises() {
if (!this.lesson) return false;
if (!this.lesson.grammarExercises) return false;
if (!Array.isArray(this.lesson.grammarExercises)) return false;
return this.lesson.grammarExercises.length > 0;
const exercises = this.effectiveExercises;
return exercises && Array.isArray(exercises) && exercises.length > 0;
},
/** Für Wiederholungslektionen: Übungen aus vorherigen Lektionen (Kapitelprüfung). Sonst: eigene Grammatik-Übungen. */
effectiveExercises() {
if (!this.lesson) return [];
const isReview = this.lesson.lessonType === 'review' || this.lesson.lessonType === 'vocab_review';
if (isReview && this.lesson.reviewVocabExercises && Array.isArray(this.lesson.reviewVocabExercises) && this.lesson.reviewVocabExercises.length > 0) {
return this.lesson.reviewVocabExercises;
}
if (this.lesson.grammarExercises && Array.isArray(this.lesson.grammarExercises)) {
return this.lesson.grammarExercises;
}
return [];
},
grammarExplanations() {
// Extrahiere Grammatik-Erklärungen aus den Übungen
try {
if (!this.lesson || !this.lesson.grammarExercises || !Array.isArray(this.lesson.grammarExercises)) {
const exercises = this.effectiveExercises;
if (!exercises || !Array.isArray(exercises) || exercises.length === 0) {
return [];
}
const explanations = [];
const seen = new Set();
this.lesson.grammarExercises.forEach(exercise => {
exercises.forEach(exercise => {
if (exercise.explanation && !seen.has(exercise.explanation)) {
seen.add(exercise.explanation);
explanations.push({
@@ -499,24 +510,14 @@ export default {
importantVocab() {
// Extrahiere wichtige Begriffe aus den Übungen
try {
// Bei Wiederholungslektionen: Verwende Vokabeln aus vorherigen Lektionen
if (this.lesson && (this.lesson.lessonType === 'review' || this.lesson.lessonType === 'vocab_review')) {
if (this.lesson.reviewVocabExercises && Array.isArray(this.lesson.reviewVocabExercises)) {
console.log('[importantVocab] Wiederholungslektion - verwende reviewVocabExercises:', this.lesson.reviewVocabExercises.length);
return this._extractVocabFromExercises(this.lesson.reviewVocabExercises);
} else {
console.log('[importantVocab] Wiederholungslektion aber keine reviewVocabExercises vorhanden');
return [];
}
}
// Normale Lektion: Verwende Übungen aus der aktuellen Lektion
if (!this.lesson || !this.lesson.grammarExercises || !Array.isArray(this.lesson.grammarExercises)) {
// Bei Wiederholungslektionen: Verwende Vokabeln aus vorherigen Lektionen (effectiveExercises = reviewVocabExercises)
// Normale Lektion: Verwende effectiveExercises (grammarExercises)
const exercises = this.effectiveExercises;
if (!exercises || !Array.isArray(exercises) || exercises.length === 0) {
console.log('[importantVocab] Keine Übungen vorhanden');
return [];
}
return this._extractVocabFromExercises(this.lesson.grammarExercises);
return this._extractVocabFromExercises(exercises);
} catch (e) {
console.error('Fehler in importantVocab computed property:', e);
return [];
@@ -706,19 +707,17 @@ export default {
const res = await apiClient.get(`/api/vocab/lessons/${this.lessonId}`);
this.lesson = res.data;
console.log('[VocabLessonView] Geladene Lektion:', this.lesson?.id, this.lesson?.title);
console.log('[VocabLessonView] Übungen:', this.lesson?.grammarExercises?.length || 0);
// Initialisiere Übungen aus der Lektion oder lade sie separat
if (this.lesson && this.lesson.id) {
if (this.lesson.grammarExercises && this.lesson.grammarExercises.length > 0) {
// Übungen sind bereits in der Lektion enthalten
console.log('[VocabLessonView] Übungen bereits in Lektion enthalten:', this.lesson.grammarExercises.length);
this.initializeExercises(this.lesson.grammarExercises);
// Initialisiere mit effectiveExercises (für Review: reviewVocabExercises, sonst: grammarExercises)
this.$nextTick(async () => {
const exercises = this.effectiveExercises;
if (exercises && exercises.length > 0) {
console.log('[VocabLessonView] Übungen für Kapitel-Prüfung:', exercises.length);
this.initializeExercises(exercises);
} else {
// Lade Übungen separat (Fallback)
console.log('[VocabLessonView] Lade Übungen separat...');
await this.loadGrammarExercises();
}
}
});
console.log('[VocabLessonView] loadLesson abgeschlossen');
} catch (e) {
console.error('[VocabLessonView] Fehler beim Laden der Lektion:', e);
@@ -826,7 +825,7 @@ export default {
},
async checkAnswer(exerciseId) {
try {
const exercise = this.lesson.grammarExercises.find(e => e.id === exerciseId);
const exercise = this.effectiveExercises.find(e => e.id === exerciseId);
if (!exercise) return;
const exerciseType = this.getExerciseType(exercise);
@@ -869,13 +868,12 @@ export default {
return;
}
// Prüfe ob alle Übungen korrekt beantwortet wurden
if (!this.lesson || !this.lesson.grammarExercises) {
// Prüfe ob alle Übungen korrekt beantwortet wurden (effectiveExercises = Kapitel-Prüfung)
const allExercises = this.effectiveExercises;
if (!this.lesson || !allExercises || allExercises.length === 0) {
console.log('[VocabLessonView] checkLessonCompletion übersprungen - keine Lektion/Übungen');
return;
}
const allExercises = this.lesson.grammarExercises;
if (allExercises.length === 0) {
console.log('[VocabLessonView] checkLessonCompletion übersprungen - keine Übungen');
return;
@@ -1261,7 +1259,7 @@ export default {
return !!this.activeRecognition[exerciseId];
},
startReadingAloud(exerciseId) {
const exercise = this.lesson.grammarExercises.find(e => e.id === exerciseId);
const exercise = this.effectiveExercises.find(e => e.id === exerciseId);
if (!exercise) return;
const qData = this.getQuestionData(exercise);
@@ -1273,7 +1271,7 @@ export default {
this.stopRecognition(exerciseId);
},
startSpeakingFromMemory(exerciseId) {
const exercise = this.lesson.grammarExercises.find(e => e.id === exerciseId);
const exercise = this.effectiveExercises.find(e => e.id === exerciseId);
if (!exercise) return;
const qData = this.getQuestionData(exercise);