feat: verbessere SRS-Logik zur Bestimmung des nächsten Fälligkeitsdatums für neu erstellte Elemente und erweitere die API-Anfragen für kursweite fällige Items
All checks were successful
Deploy to production / deploy (push) Successful in 2m6s
All checks were successful
Deploy to production / deploy (push) Successful in 2m6s
This commit is contained in:
@@ -191,6 +191,17 @@ export default class VocabService {
|
|||||||
if (existingByKey.has(entry.itemKey)) {
|
if (existingByKey.has(entry.itemKey)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine safe default nextDueAt for newly created items:
|
||||||
|
// - default: next calendar day at 08:00
|
||||||
|
// - ensure at least 24 hours after creation
|
||||||
|
const createdAt = new Date(now);
|
||||||
|
const nextCalendar08 = new Date(createdAt);
|
||||||
|
nextCalendar08.setHours(8, 0, 0, 0);
|
||||||
|
nextCalendar08.setDate(nextCalendar08.getDate() + 1);
|
||||||
|
const min24h = new Date(createdAt.getTime() + 24 * 60 * 60 * 1000);
|
||||||
|
const safeNextDue = nextCalendar08.getTime() < min24h.getTime() ? min24h : nextCalendar08;
|
||||||
|
|
||||||
const created = await VocabSrsItem.create({
|
const created = await VocabSrsItem.create({
|
||||||
userId,
|
userId,
|
||||||
courseId: Number(courseId),
|
courseId: Number(courseId),
|
||||||
@@ -199,7 +210,7 @@ export default class VocabService {
|
|||||||
learning: entry.learning,
|
learning: entry.learning,
|
||||||
reference: entry.reference,
|
reference: entry.reference,
|
||||||
direction: entry.direction,
|
direction: entry.direction,
|
||||||
nextDueAt: now
|
nextDueAt: safeNextDue
|
||||||
});
|
});
|
||||||
createdItems.push(created);
|
createdItems.push(created);
|
||||||
existingByKey.set(entry.itemKey, created);
|
existingByKey.set(entry.itemKey, created);
|
||||||
|
|||||||
@@ -768,10 +768,12 @@ export default {
|
|||||||
let res = null;
|
let res = null;
|
||||||
let courseDueRes = null;
|
let courseDueRes = null;
|
||||||
|
|
||||||
// Wenn SRS-Modus auf Kurs-Ebene, lade kursweite fällige Items (Server liefert totalDueCount)
|
// Wenn SRS-Modus und courseId vorhanden, frage kursweite fällige Items an (Server liefert totalDueCount).
|
||||||
if (this.srsMode && this.openParams.courseId && !this.openParams.lessonId) {
|
// Wir fragen das immer an, auch wenn gerade eine lessonId gesetzt ist, und nutzen es als Fallback
|
||||||
|
// falls kein lesson-spezifischer Pool gefunden wird.
|
||||||
|
if (this.srsMode && this.openParams.courseId) {
|
||||||
try {
|
try {
|
||||||
courseDueRes = await apiClient.get(`/api/vocab/courses/${this.openParams.courseId}/srs/due`, { params: { limit: 100 } });
|
courseDueRes = await apiClient.get(`/api/vocab/courses/${this.openParams.courseId}/srs/due`, { params: { limit: 500 } });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
courseDueRes = null;
|
courseDueRes = null;
|
||||||
}
|
}
|
||||||
@@ -786,6 +788,36 @@ export default {
|
|||||||
lessonId: it.lessonId || null
|
lessonId: it.lessonId || null
|
||||||
})));
|
})));
|
||||||
this.srsServerTotalDue = Number.isFinite(Number(courseDueRes.data?.totalDueCount)) ? Number(courseDueRes.data.totalDueCount) : null;
|
this.srsServerTotalDue = Number.isFinite(Number(courseDueRes.data?.totalDueCount)) ? Number(courseDueRes.data.totalDueCount) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wenn wir eine lessonId haben, versuche zuerst lesson-spezifische Vocabs zu laden.
|
||||||
|
// Falls diese leer sind, und kursweite SRS-Items vorliegen, nutze diese als Fallback.
|
||||||
|
if (this.openParams.lessonId) {
|
||||||
|
try {
|
||||||
|
if (this.allVocabs && this.openParams.courseId) {
|
||||||
|
res = await apiClient.get(`/api/vocab/courses/${this.openParams.courseId}/completed-lesson-vocabs`, {
|
||||||
|
params: { untilLessonId: this.openParams.lessonId }
|
||||||
|
});
|
||||||
|
this.pool = this.normalizePool(res.data?.vocabs || []);
|
||||||
|
} else {
|
||||||
|
res = await apiClient.get(`/api/vocab/lessons/${this.openParams.lessonId}/vocab-pool`);
|
||||||
|
this.pool = this.normalizePool(res.data?.vocabs || []);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res = null;
|
||||||
|
this.pool = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback auf kursweite SRS-Items, falls keine lesson-spezifischen Items vorhanden sind
|
||||||
|
if ((!this.pool || this.pool.length === 0) && courseDueRes && Array.isArray(courseDueRes.data?.items) && courseDueRes.data.items.length > 0) {
|
||||||
|
this.pool = this.normalizePool((courseDueRes.data.items || []).map((it) => ({
|
||||||
|
id: it.itemKey,
|
||||||
|
learning: it.learning,
|
||||||
|
reference: it.reference,
|
||||||
|
lessonId: it.lessonId || null
|
||||||
|
})));
|
||||||
|
this.srsServerTotalDue = Number.isFinite(Number(courseDueRes.data?.totalDueCount)) ? Number(courseDueRes.data.totalDueCount) : null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fallback: lade Lehr- bzw. Kapitel-/Kurs-Vokabeln
|
// Fallback: lade Lehr- bzw. Kapitel-/Kurs-Vokabeln
|
||||||
if (this.openParams.lessonId) {
|
if (this.openParams.lessonId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user