feat(vocab): implement SRS features and enhance vocabulary management
All checks were successful
Deploy to production / deploy (push) Successful in 2m49s

- Added new endpoints in vocabController for retrieving SRS due items and reviewing SRS items, improving spaced repetition support.
- Updated vocabService to handle SRS item creation and scheduling, ensuring effective tracking of vocabulary exposure.
- Enhanced vocabRouter with new routes for SRS functionalities, facilitating user interaction with spaced repetition features.
- Modified VocabPracticeDialog and VocabCourseView to integrate SRS due items, providing users with timely review opportunities.
- Updated translations and UI elements to reflect new SRS features, enhancing user experience and accessibility.
This commit is contained in:
Torsten Schulz (local)
2026-04-17 09:14:30 +02:00
parent 54a77c2e08
commit e2c1147d75
14 changed files with 648 additions and 16 deletions

View File

@@ -15,7 +15,7 @@
<div class="left">
<div class="opts">
<label class="chk">
<input type="checkbox" v-model="allVocabs" @change="reloadPool" />
<input type="checkbox" v-model="allVocabs" :disabled="srsMode" @change="reloadPool" />
{{ $t('socialnetwork.vocab.practice.allVocabs') }}
</label>
<label class="chk">
@@ -116,6 +116,8 @@ export default {
onClose: null,
loading: false,
allVocabs: false,
srsMode: false,
initialPool: null,
simpleMode: false,
pool: [],
@@ -170,13 +172,15 @@ export default {
},
},
methods: {
open({ languageId, chapterId, lessonId, courseId, onClose = null }) {
open({ languageId, chapterId, lessonId, courseId, initialPool = null, srsMode = false, onClose = null }) {
if (this.autoAdvanceTimer) {
clearTimeout(this.autoAdvanceTimer);
this.autoAdvanceTimer = null;
}
this.openParams = { languageId, chapterId, lessonId, courseId };
this.onClose = typeof onClose === 'function' ? onClose : null;
this.srsMode = Boolean(srsMode);
this.initialPool = Array.isArray(initialPool) ? initialPool : null;
this.allVocabs = false;
this.simpleMode = false;
this.correctCount = 0;
@@ -251,7 +255,7 @@ export default {
seen.add(key);
return {
...item,
id: item?.id || item?.key || `${key}|${index}`,
id: item?.id || item?.itemKey || item?.key || `${key}|${index}`,
learning,
reference
};
@@ -298,6 +302,12 @@ export default {
},
async reloadPool() {
if (!this.openParams) return;
if (this.initialPool) {
this.loading = false;
this.pool = this.normalizePool(this.initialPool);
this.next();
return;
}
this.loading = true;
try {
let res;
@@ -423,11 +433,28 @@ export default {
// ignore autoplay issues
}
},
reportSrsReview(isCorrect) {
if (!this.current || !this.openParams?.courseId) {
return;
}
apiClient.post('/api/vocab/srs/review', {
courseId: this.openParams.courseId || this.current.courseId,
lessonId: this.openParams.lessonId || this.current.lessonId || null,
itemKey: this.current.itemKey || null,
learning: this.current.learning,
reference: this.current.reference,
direction: this.direction,
correct: Boolean(isCorrect)
}).catch((error) => {
console.warn('[VocabPracticeDialog] SRS review could not be saved:', error);
});
},
markResult(isCorrect) {
this.answered = true;
this.lastCorrect = isCorrect;
if (isCorrect) this.correctCount += 1;
else this.wrongCount += 1;
this.reportSrsReview(isCorrect);
const id = this.current?.id;
if (!id) return;