feat(DayProduction, FalukantService, VocabLessonView): enhance vocabulary training and production tracking
All checks were successful
Deploy to production / deploy (push) Successful in 1m51s
All checks were successful
Deploy to production / deploy (push) Successful in 1m51s
- Added a new `completionCount` field to the DayProduction model to track the number of completed productions. - Updated the FalukantService to aggregate completed productions using the new `completionCount` field, improving accuracy in production statistics. - Introduced new vocabulary training features in VocabLessonView, including options to mark vocabulary as difficult and track remaining hard vocabulary, enhancing user engagement and learning effectiveness. - Updated localization files for German and English to support new vocabulary training features, ensuring a consistent user experience across languages.
This commit is contained in:
@@ -23,7 +23,11 @@ DayProduction.init({
|
||||
productionDate: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false,
|
||||
defaultValue: sequelize.literal('CURRENT_DATE')}
|
||||
defaultValue: sequelize.literal('CURRENT_DATE')},
|
||||
completionCount: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 1}
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'DayProduction',
|
||||
|
||||
@@ -2968,7 +2968,9 @@ class FalukantService extends BaseService {
|
||||
|
||||
/**
|
||||
* Zertifikat: abgeschlossene Produktionen über alle Regionen/Niederlassungen.
|
||||
* Es zählt jede abgeschlossene Produktion (ein Datensatz in falukant_log.production).
|
||||
* Es zählt jede abgeschlossene Produktion.
|
||||
* Seit Daemon-Migration über falukant_log.production.completion_count
|
||||
* (aggregierte Zeilen => SUM(completion_count), nicht COUNT(*)).
|
||||
* Filter bei gesetztem countSince wie Daemon (GET_PRODUCTION_CERTIFICATE_INPUT_ROWS):
|
||||
* COALESCE(production_timestamp, production_date::timestamp) >= countSince.
|
||||
*
|
||||
@@ -2983,7 +2985,7 @@ class FalukantService extends BaseService {
|
||||
if (countSince) replacements.countSince = countSince;
|
||||
const rows = await sequelize.query(
|
||||
`
|
||||
SELECT COUNT(*)::int AS cnt
|
||||
SELECT COALESCE(SUM(COALESCE(completion_count, 1)), 0)::int AS cnt
|
||||
FROM falukant_log.production
|
||||
WHERE producer_id = :producerId${sinceClause}
|
||||
`,
|
||||
|
||||
@@ -825,6 +825,13 @@
|
||||
"trainerProgressNewContent": "Neue Inhalte: {current}/{target}",
|
||||
"trainerProgressReview": "Wiederholung: {count}",
|
||||
"trainerProgressMixShare": "Mischanteil: {percent}%",
|
||||
"markVocabHard": "Als schwer markieren",
|
||||
"markVocabHardSaved": "Vokabel als schwer markiert.",
|
||||
"unmarkVocabHard": "Aus Schwerliste entfernen",
|
||||
"unmarkVocabHardSaved": "Vokabel aus der Schwerliste entfernt.",
|
||||
"hardVocabModeActive": "Intensivblock: schwere Vokabeln",
|
||||
"hardVocabRemaining": "Offen bis gefestigt: {count}",
|
||||
"startHardVocabTrainer": "Schwere Vokabeln trainieren ({count})",
|
||||
"unknownExerciseTypeNotice": "Dieser Übungstyp wird in der aktuellen Ansicht noch nicht interaktiv dargestellt.",
|
||||
"unknownExerciseTypeLabel": "Typ: {type}",
|
||||
"lessonReviewHeadlineDone": "Diese Lektion ist in der freien Vertiefung angekommen.",
|
||||
|
||||
@@ -825,6 +825,13 @@
|
||||
"trainerProgressNewContent": "New content: {current}/{target}",
|
||||
"trainerProgressReview": "Review: {count}",
|
||||
"trainerProgressMixShare": "Mixed share: {percent}%",
|
||||
"markVocabHard": "Mark as difficult",
|
||||
"markVocabHardSaved": "Vocabulary marked as difficult.",
|
||||
"unmarkVocabHard": "Remove from difficult list",
|
||||
"unmarkVocabHardSaved": "Vocabulary removed from difficult list.",
|
||||
"hardVocabModeActive": "Intensive block: difficult vocabulary",
|
||||
"hardVocabRemaining": "Remaining until stable: {count}",
|
||||
"startHardVocabTrainer": "Train difficult vocabulary ({count})",
|
||||
"unknownExerciseTypeNotice": "This exercise type is not displayed interactively in the current view yet.",
|
||||
"unknownExerciseTypeLabel": "Type: {type}",
|
||||
"lessonReviewHeadlineDone": "This lesson has reached the free practice stage.",
|
||||
|
||||
@@ -235,6 +235,13 @@
|
||||
<button @click="startVocabTrainer" class="btn-start-trainer">
|
||||
{{ hasPreviousVocab ? $t('socialnetwork.vocab.courses.startLesson') : $t('socialnetwork.vocab.courses.startVocabTrainer') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="hasCrossChapterHardVocab"
|
||||
@click="startHardVocabTrainer"
|
||||
class="btn-start-trainer button-secondary"
|
||||
>
|
||||
{{ $t('socialnetwork.vocab.courses.startHardVocabTrainer', { count: crossChapterHardVocab.length }) }}
|
||||
</button>
|
||||
</template>
|
||||
<p v-else class="vocab-trainer-locked-hint">{{ $t('socialnetwork.vocab.courses.vocabTrainerLockedHint') }}</p>
|
||||
</div>
|
||||
@@ -271,6 +278,10 @@
|
||||
</span>
|
||||
<button @click="stopVocabTrainer" class="btn-stop-trainer">{{ $t('socialnetwork.vocab.courses.stopTrainer') }}</button>
|
||||
</div>
|
||||
<div v-if="vocabTrainerHardMode" class="stats-row trainer-progress-row">
|
||||
<span>{{ $t('socialnetwork.vocab.courses.hardVocabModeActive') }}</span>
|
||||
<span>{{ $t('socialnetwork.vocab.courses.hardVocabRemaining', { count: hardVocabRemainingCount }) }}</span>
|
||||
</div>
|
||||
<div v-if="hasPreviousVocab" class="stats-row trainer-progress-row">
|
||||
<span>{{ $t('socialnetwork.vocab.courses.trainerProgressNewContent', { current: vocabTrainerCurrentAttempts, target: trainerNewFocusTarget }) }}</span>
|
||||
<span>{{ $t('socialnetwork.vocab.courses.trainerProgressReview', { count: vocabTrainerReviewAttempts }) }}</span>
|
||||
@@ -288,6 +299,19 @@
|
||||
{{ $t('socialnetwork.vocab.courses.wrong') }}. {{ $t('socialnetwork.vocab.courses.correctAnswer') }}: {{ currentVocabQuestion.answer }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="vocab-hard-actions">
|
||||
<button type="button" class="btn-switch-mode" @click="markCurrentVocabAsHard">
|
||||
{{ $t('socialnetwork.vocab.courses.markVocabHard') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="isCurrentVocabMarkedHard"
|
||||
type="button"
|
||||
class="btn-switch-mode"
|
||||
@click="unmarkCurrentVocabAsHard"
|
||||
>
|
||||
{{ $t('socialnetwork.vocab.courses.unmarkVocabHard') }}
|
||||
</button>
|
||||
</div>
|
||||
<!-- Multiple Choice Modus -->
|
||||
<div v-if="vocabTrainerMode === 'multiple_choice' && !vocabTrainerAnswered" class="vocab-answer-area multiple-choice">
|
||||
<div class="choice-buttons">
|
||||
@@ -1104,6 +1128,11 @@ export default {
|
||||
vocabTrainerContinueTimer: null,
|
||||
vocabTrainerLastWrongReview: null,
|
||||
vocabTrainerDirection: 'L2R', // L2R: learning->reference, R2L: reference->learning
|
||||
vocabTrainerSessionType: 'lesson', // 'lesson' | 'hard_collection'
|
||||
vocabTrainerHardPool: [],
|
||||
vocabTrainerHardMode: false,
|
||||
vocabTrainerHardMastery: {}, // { [vocabKey]: consecutiveCorrectInHardMode }
|
||||
manualHardVocabMap: {}, // persistente manuell markierte schwere Vokabeln je Lektion
|
||||
isCheckingLessonCompletion: false, // Flag um Endlosschleife zu verhindern
|
||||
isNavigatingToNext: false, // Flag um mehrfache Navigation zu verhindern
|
||||
showNextLessonDialog: false,
|
||||
@@ -1258,6 +1287,45 @@ export default {
|
||||
}
|
||||
return 0.5;
|
||||
},
|
||||
crossChapterHardVocab() {
|
||||
const map = new Map();
|
||||
const pushHard = (entry) => {
|
||||
const learning = String(entry?.learning || '').trim();
|
||||
const reference = String(entry?.reference || '').trim();
|
||||
if (!this.isTrainableLessonVocabPair(learning, reference)) return;
|
||||
const key = `${learning}|${reference}`;
|
||||
const prev = map.get(key) || { learning, reference, wrongCount: 0 };
|
||||
prev.wrongCount += Math.max(1, Number(entry?.wrongCount) || 1);
|
||||
map.set(key, prev);
|
||||
};
|
||||
|
||||
(this.courseProgressList || []).forEach((entry) => {
|
||||
const weak = Array.isArray(entry?.lessonState?.reviewWeakVocab) ? entry.lessonState.reviewWeakVocab : [];
|
||||
const manual = Array.isArray(entry?.lessonState?.manualHardVocab) ? entry.lessonState.manualHardVocab : [];
|
||||
weak.forEach(pushHard);
|
||||
manual.forEach(pushHard);
|
||||
});
|
||||
|
||||
return Array.from(map.values())
|
||||
.sort((a, b) => b.wrongCount - a.wrongCount)
|
||||
.slice(0, 80)
|
||||
.map((v) => ({ learning: v.learning, reference: v.reference }));
|
||||
},
|
||||
hasCrossChapterHardVocab() {
|
||||
return this.crossChapterHardVocab.length > 0;
|
||||
},
|
||||
hardVocabRemainingCount() {
|
||||
const requiredConsecutiveCorrect = 2;
|
||||
return this.vocabTrainerHardPool.filter((vocab) => {
|
||||
const key = this.getVocabKey(vocab);
|
||||
return (Number(this.vocabTrainerHardMastery[key]) || 0) < requiredConsecutiveCorrect;
|
||||
}).length;
|
||||
},
|
||||
isCurrentVocabMarkedHard() {
|
||||
const key = this.currentVocabQuestion?.key || '';
|
||||
if (!key) return false;
|
||||
return Boolean(this.manualHardVocabMap[key]);
|
||||
},
|
||||
canAccessExercises() {
|
||||
if (!this.hasExercises) return false;
|
||||
if (this.exerciseNeedsReinforcement) return false;
|
||||
@@ -1791,6 +1859,11 @@ export default {
|
||||
vocabTrainerRepeatQueue: this.vocabTrainerRepeatQueue,
|
||||
vocabTrainerCurrentAttempts: this.vocabTrainerCurrentAttempts,
|
||||
vocabTrainerReviewAttempts: this.vocabTrainerReviewAttempts,
|
||||
vocabTrainerSessionType: this.vocabTrainerSessionType,
|
||||
vocabTrainerHardPool: this.vocabTrainerHardPool,
|
||||
vocabTrainerHardMode: this.vocabTrainerHardMode,
|
||||
vocabTrainerHardMastery: this.vocabTrainerHardMastery,
|
||||
manualHardVocab: Object.values(this.manualHardVocabMap),
|
||||
exerciseRetryPending: this.exerciseRetryPending,
|
||||
exerciseRetryPendingSinceAttempts: this.exerciseRetryPendingSinceAttempts,
|
||||
exerciseSequentialIndex: this.exerciseSequentialIndex
|
||||
@@ -2104,6 +2177,26 @@ export default {
|
||||
: {};
|
||||
this.vocabTrainerCurrentAttempts = Math.max(0, Number(parsedState.vocabTrainerCurrentAttempts) || 0);
|
||||
this.vocabTrainerReviewAttempts = Math.max(0, Number(parsedState.vocabTrainerReviewAttempts) || 0);
|
||||
this.vocabTrainerSessionType = parsedState.vocabTrainerSessionType === 'hard_collection' ? 'hard_collection' : 'lesson';
|
||||
this.vocabTrainerHardPool = Array.isArray(parsedState.vocabTrainerHardPool) ? parsedState.vocabTrainerHardPool : [];
|
||||
this.vocabTrainerHardMode = Boolean(parsedState.vocabTrainerHardMode);
|
||||
this.vocabTrainerHardMastery = parsedState.vocabTrainerHardMastery && typeof parsedState.vocabTrainerHardMastery === 'object'
|
||||
? parsedState.vocabTrainerHardMastery
|
||||
: {};
|
||||
const savedManualHard = Array.isArray(parsedState.manualHardVocab) ? parsedState.manualHardVocab : [];
|
||||
this.manualHardVocabMap = {};
|
||||
savedManualHard.forEach((entry) => {
|
||||
const learning = String(entry?.learning || '').trim();
|
||||
const reference = String(entry?.reference || '').trim();
|
||||
if (!this.isTrainableLessonVocabPair(learning, reference)) return;
|
||||
const key = `${learning}|${reference}`;
|
||||
this.manualHardVocabMap[key] = {
|
||||
learning,
|
||||
reference,
|
||||
wrongCount: Math.max(1, Number(entry?.wrongCount) || 1),
|
||||
lastWrongAt: String(entry?.lastWrongAt || new Date().toISOString())
|
||||
};
|
||||
});
|
||||
this.exerciseRetryPending = Boolean(parsedState.exerciseRetryPending);
|
||||
this.exerciseRetryPendingSinceAttempts = Math.max(0, Number(parsedState.exerciseRetryPendingSinceAttempts) || 0);
|
||||
const maxIdx = Math.max(0, this.scrambledChapterExamExercises.length - 1);
|
||||
@@ -2657,6 +2750,11 @@ export default {
|
||||
this.vocabTrainerPool = [];
|
||||
this.vocabTrainerMixedPool = [];
|
||||
this.vocabTrainerRepeatQueue = [];
|
||||
this.vocabTrainerHardPool = [];
|
||||
this.vocabTrainerHardMode = false;
|
||||
this.vocabTrainerHardMastery = {};
|
||||
this.manualHardVocabMap = {};
|
||||
this.vocabTrainerSessionType = 'lesson';
|
||||
this.vocabTrainerPhase = 'current';
|
||||
this.vocabTrainerCurrentAttempts = 0;
|
||||
this.vocabTrainerReviewAttempts = 0;
|
||||
@@ -3370,6 +3468,10 @@ export default {
|
||||
this.vocabTrainerStats = {};
|
||||
this.vocabTrainerRepeatQueue = [];
|
||||
this.vocabTrainerLastWrongReview = null;
|
||||
this.vocabTrainerSessionType = 'lesson';
|
||||
this.vocabTrainerHardPool = [];
|
||||
this.vocabTrainerHardMode = false;
|
||||
this.vocabTrainerHardMastery = {};
|
||||
// Bereite Mixed-Pool aus alten Vokabeln vor (ohne Duplikate aus aktueller Lektion)
|
||||
this.vocabTrainerMixedPool = this._buildMixedPool();
|
||||
this.vocabTrainerPhase = 'current';
|
||||
@@ -3392,12 +3494,41 @@ export default {
|
||||
this.vocabTrainerReviewAttempts = 0;
|
||||
this.vocabTrainerMixedPool = [];
|
||||
this.vocabTrainerRepeatQueue = [];
|
||||
this.vocabTrainerHardPool = [];
|
||||
this.vocabTrainerHardMode = false;
|
||||
this.vocabTrainerHardMastery = {};
|
||||
this.vocabTrainerSessionType = 'lesson';
|
||||
this.currentVocabQuestion = null;
|
||||
this.vocabTrainerAnswer = '';
|
||||
this.vocabTrainerSelectedChoice = null;
|
||||
this.vocabTrainerAnswered = false;
|
||||
this.vocabTrainerLastWrongReview = null;
|
||||
},
|
||||
startHardVocabTrainer() {
|
||||
const hardPool = this.crossChapterHardVocab.slice();
|
||||
if (!hardPool.length) return;
|
||||
this.vocabTrainerActive = true;
|
||||
this.vocabTrainerMode = 'multiple_choice';
|
||||
this.vocabTrainerAutoSwitchedToTyping = false;
|
||||
this.vocabTrainerCorrect = 0;
|
||||
this.vocabTrainerWrong = 0;
|
||||
this.vocabTrainerTotalAttempts = 0;
|
||||
this.vocabTrainerCurrentAttempts = 0;
|
||||
this.vocabTrainerReviewAttempts = 0;
|
||||
this.vocabTrainerStats = {};
|
||||
this.vocabTrainerRepeatQueue = [];
|
||||
this.vocabTrainerSessionType = 'hard_collection';
|
||||
this.vocabTrainerHardPool = hardPool;
|
||||
this.vocabTrainerHardMode = true;
|
||||
this.vocabTrainerHardMastery = {};
|
||||
this.vocabTrainerMixedPool = [];
|
||||
this.vocabTrainerPool = hardPool.slice();
|
||||
this.currentVocabQuestion = null;
|
||||
this.vocabTrainerLastWrongReview = null;
|
||||
this.$nextTick(() => {
|
||||
this.nextVocabQuestion();
|
||||
});
|
||||
},
|
||||
/** Erstellt den Mixed-Pool aus vorherigen Lektions-Vokabeln (ohne Duplikate der aktuellen Lektion) */
|
||||
_buildMixedPool() {
|
||||
if (!this.previousVocab || this.previousVocab.length === 0) return [];
|
||||
@@ -3444,6 +3575,50 @@ export default {
|
||||
getVocabKey(vocab) {
|
||||
return `${vocab.learning}|${vocab.reference}`;
|
||||
},
|
||||
markCurrentVocabAsHard() {
|
||||
if (!this.currentVocabQuestion?.vocab) return;
|
||||
const vocab = this.currentVocabQuestion.vocab;
|
||||
const key = this.getVocabKey(vocab);
|
||||
this.manualHardVocabMap[key] = {
|
||||
learning: String(vocab.learning || '').trim(),
|
||||
reference: String(vocab.reference || '').trim(),
|
||||
wrongCount: Math.max(1, Number(this.manualHardVocabMap[key]?.wrongCount) || 1),
|
||||
lastWrongAt: new Date().toISOString()
|
||||
};
|
||||
if (!this.vocabTrainerHardPool.some((entry) => this.getVocabKey(entry) === key)) {
|
||||
this.vocabTrainerHardPool.push(vocab);
|
||||
}
|
||||
if (this.vocabTrainerHardMastery[key] == null) {
|
||||
this.vocabTrainerHardMastery[key] = 0;
|
||||
}
|
||||
this.$root?.$refs?.messageDialog?.open?.('tr:socialnetwork.vocab.courses.markVocabHardSaved');
|
||||
},
|
||||
unmarkCurrentVocabAsHard() {
|
||||
if (!this.currentVocabQuestion?.key) return;
|
||||
const key = this.currentVocabQuestion.key;
|
||||
delete this.manualHardVocabMap[key];
|
||||
this.vocabTrainerHardPool = this.vocabTrainerHardPool.filter((entry) => this.getVocabKey(entry) !== key);
|
||||
delete this.vocabTrainerHardMastery[key];
|
||||
this.$root?.$refs?.messageDialog?.open?.('tr:socialnetwork.vocab.courses.unmarkVocabHardSaved');
|
||||
this.maybeExitHardIntensivePhase();
|
||||
},
|
||||
maybeEnterHardIntensivePhase() {
|
||||
if (this.vocabTrainerSessionType !== 'lesson') return;
|
||||
if (this.vocabTrainerHardMode) return;
|
||||
if (!this.vocabTrainerHardPool.length) return;
|
||||
if (this.vocabTrainerCurrentAttempts < this.trainerNewFocusTarget) return;
|
||||
this.vocabTrainerHardMode = true;
|
||||
},
|
||||
maybeExitHardIntensivePhase() {
|
||||
if (!this.vocabTrainerHardMode) return;
|
||||
if (!this.vocabTrainerHardPool.length) {
|
||||
this.vocabTrainerHardMode = false;
|
||||
return;
|
||||
}
|
||||
if (this.hardVocabRemainingCount <= 0) {
|
||||
this.vocabTrainerHardMode = false;
|
||||
}
|
||||
},
|
||||
getVocabStats(vocab) {
|
||||
const key = this.getVocabKey(vocab);
|
||||
if (!this.vocabTrainerStats[key]) {
|
||||
@@ -3770,6 +3945,68 @@ export default {
|
||||
|
||||
// Prüfe ob Modus-Wechsel nötig ist
|
||||
this.checkVocabModeSwitch();
|
||||
this.maybeEnterHardIntensivePhase();
|
||||
this.maybeExitHardIntensivePhase();
|
||||
|
||||
if (this.vocabTrainerSessionType === 'hard_collection' || this.vocabTrainerHardMode) {
|
||||
const requiredConsecutiveCorrect = 2;
|
||||
const pool = this.vocabTrainerHardPool.filter((vocab) => {
|
||||
const key = this.getVocabKey(vocab);
|
||||
return (Number(this.vocabTrainerHardMastery[key]) || 0) < requiredConsecutiveCorrect;
|
||||
});
|
||||
|
||||
if (!pool.length) {
|
||||
this.vocabTrainerHardMode = false;
|
||||
if (this.vocabTrainerSessionType === 'hard_collection') {
|
||||
this.currentVocabQuestion = null;
|
||||
this.vocabTrainerActive = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const vocab = this.chooseVocabFromPool(pool);
|
||||
if (!vocab) {
|
||||
this.currentVocabQuestion = null;
|
||||
return;
|
||||
}
|
||||
this.vocabTrainerDirection = Math.random() < 0.5 ? 'L2R' : 'R2L';
|
||||
const allTrainerVocabs = pool;
|
||||
const direction = this.vocabTrainerDirection;
|
||||
const prompt = direction === 'L2R' ? vocab.learning : vocab.reference;
|
||||
const acceptableAnswers = this.getEquivalentVocabAnswers(prompt, direction, allTrainerVocabs);
|
||||
this.currentVocabQuestion = {
|
||||
vocab,
|
||||
prompt,
|
||||
answers: acceptableAnswers.length > 0
|
||||
? acceptableAnswers
|
||||
: [direction === 'L2R' ? vocab.reference : vocab.learning],
|
||||
answer: acceptableAnswers.length > 0
|
||||
? acceptableAnswers.join(' / ')
|
||||
: (direction === 'L2R' ? vocab.reference : vocab.learning),
|
||||
key: this.getVocabKey(vocab),
|
||||
source: 'hard'
|
||||
};
|
||||
|
||||
this.vocabTrainerAnswer = '';
|
||||
this.vocabTrainerSelectedChoice = null;
|
||||
this.vocabTrainerAnswered = false;
|
||||
|
||||
if (this.vocabTrainerMode === 'multiple_choice') {
|
||||
this.vocabTrainerChoiceOptions = this.buildChoiceOptions(
|
||||
this.currentVocabQuestion.answers,
|
||||
allTrainerVocabs,
|
||||
this.currentVocabQuestion.prompt,
|
||||
this.vocabTrainerDirection
|
||||
);
|
||||
}
|
||||
|
||||
if (this.vocabTrainerMode === 'typing') {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.vocabInput?.focus?.();
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let questionSource = 'current';
|
||||
let sourcePool = this.trainableLessonVocab;
|
||||
@@ -3969,6 +4206,17 @@ export default {
|
||||
this.vocabTrainerCorrect++;
|
||||
stats.correct++;
|
||||
this.resolveRepeatedVocab(this.currentVocabQuestion.vocab);
|
||||
if (this.currentVocabQuestion.source === 'hard') {
|
||||
const key = this.currentVocabQuestion.key;
|
||||
const nextMastery = Math.max(0, Number(this.vocabTrainerHardMastery[key]) || 0) + 1;
|
||||
this.vocabTrainerHardMastery[key] = nextMastery;
|
||||
// Wenn eine manuell markierte schwierige Vokabel mehrfach korrekt sitzt,
|
||||
// automatisch aus der manuellen Schwerliste entfernen.
|
||||
if (nextMastery >= 2 && this.manualHardVocabMap[key]) {
|
||||
delete this.manualHardVocabMap[key];
|
||||
this.vocabTrainerHardPool = this.vocabTrainerHardPool.filter((entry) => this.getVocabKey(entry) !== key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.vocabTrainerLastWrongReview = {
|
||||
prompt: this.currentVocabQuestion.prompt,
|
||||
@@ -3978,6 +4226,10 @@ export default {
|
||||
this.vocabTrainerWrong++;
|
||||
stats.wrong++;
|
||||
this.queueFailedVocab(this.currentVocabQuestion.vocab);
|
||||
if (this.currentVocabQuestion.source === 'hard') {
|
||||
const key = this.currentVocabQuestion.key;
|
||||
this.vocabTrainerHardMastery[key] = 0;
|
||||
}
|
||||
}
|
||||
this.reportSrsReviewForCurrentQuestion(this.vocabTrainerLastCorrect);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user