feat: verbessere initialTotalDue und begrenze tägliche Übungsanzahl auf MAX_DAILY_DUE
All checks were successful
Deploy to production / deploy (push) Successful in 1m59s
All checks were successful
Deploy to production / deploy (push) Successful in 1m59s
This commit is contained in:
@@ -193,14 +193,16 @@ export default class VocabService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine safe default nextDueAt for newly created items:
|
// Determine safe default nextDueAt for newly created items:
|
||||||
// - default: next calendar day at 08:00
|
// - prefer a calendar time (08:00) at least one day after creation
|
||||||
// - ensure at least 24 hours after creation
|
// - ensure at least 48 hours after creation so freshly practiced items
|
||||||
|
// don't immediately appear as due the next day
|
||||||
const createdAt = new Date(now);
|
const createdAt = new Date(now);
|
||||||
const nextCalendar08 = new Date(createdAt);
|
const nextCalendar08 = new Date(createdAt);
|
||||||
nextCalendar08.setHours(8, 0, 0, 0);
|
nextCalendar08.setHours(8, 0, 0, 0);
|
||||||
nextCalendar08.setDate(nextCalendar08.getDate() + 1);
|
// consider the day after tomorrow as earliest calendar slot
|
||||||
const min24h = new Date(createdAt.getTime() + 24 * 60 * 60 * 1000);
|
nextCalendar08.setDate(nextCalendar08.getDate() + 2);
|
||||||
const safeNextDue = nextCalendar08.getTime() < min24h.getTime() ? min24h : nextCalendar08;
|
const min48h = new Date(createdAt.getTime() + 48 * 60 * 60 * 1000);
|
||||||
|
const safeNextDue = nextCalendar08.getTime() < min48h.getTime() ? min48h : nextCalendar08;
|
||||||
|
|
||||||
const created = await VocabSrsItem.create({
|
const created = await VocabSrsItem.create({
|
||||||
userId,
|
userId,
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ const PRACTICE_MIN_EXPOSURES = 3;
|
|||||||
const SRS_SESSION_STORAGE_VERSION = 2;
|
const SRS_SESSION_STORAGE_VERSION = 2;
|
||||||
const HARD_REQUIRED_CONSECUTIVE_CORRECT = 5;
|
const HARD_REQUIRED_CONSECUTIVE_CORRECT = 5;
|
||||||
const SRS_AGAIN_REINSERT_OFFSET = 3;
|
const SRS_AGAIN_REINSERT_OFFSET = 3;
|
||||||
|
const MAX_DAILY_DUE = 50;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'VocabPracticeDialog',
|
name: 'VocabPracticeDialog',
|
||||||
@@ -514,13 +515,14 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.srsSession) {
|
if (!this.srsSession) {
|
||||||
|
const initialTotal = Math.min(MAX_DAILY_DUE, Number.isFinite(Number(this.srsServerTotalDue)) ? Number(this.srsServerTotalDue) : dueIds.length);
|
||||||
this.srsSession = {
|
this.srsSession = {
|
||||||
version: SRS_SESSION_STORAGE_VERSION,
|
version: SRS_SESSION_STORAGE_VERSION,
|
||||||
dateKey: this.getLocalDateKey(),
|
dateKey: this.getLocalDateKey(),
|
||||||
courseId: this.openParams.courseId,
|
courseId: this.openParams.courseId,
|
||||||
// Prefer server-reported total due count when available (shows full-course due count)
|
// For the user's session we cap the number practiced per day to MAX_DAILY_DUE
|
||||||
initialTotalDue: Number.isFinite(Number(this.srsServerTotalDue)) ? Number(this.srsServerTotalDue) : dueIds.length,
|
initialTotalDue: initialTotal,
|
||||||
initialDueIds: dueIds,
|
initialDueIds: dueIds.slice(0, initialTotal),
|
||||||
doneIds: [],
|
doneIds: [],
|
||||||
correctCount: 0,
|
correctCount: 0,
|
||||||
wrongCount: 0,
|
wrongCount: 0,
|
||||||
@@ -536,26 +538,22 @@ export default {
|
|||||||
// If the stored session has an invalid initialTotalDue (e.g. 0), repair it from server/pool data.
|
// If the stored session has an invalid initialTotalDue (e.g. 0), repair it from server/pool data.
|
||||||
if (this.srsSession && (!Number.isFinite(Number(this.srsSession.initialTotalDue)) || Number(this.srsSession.initialTotalDue) <= 0)) {
|
if (this.srsSession && (!Number.isFinite(Number(this.srsSession.initialTotalDue)) || Number(this.srsSession.initialTotalDue) <= 0)) {
|
||||||
const repairedTotal = Number.isFinite(Number(this.srsServerTotalDue)) && Number(this.srsServerTotalDue) > 0 ? Number(this.srsServerTotalDue) : dueIds.length;
|
const repairedTotal = Number.isFinite(Number(this.srsServerTotalDue)) && Number(this.srsServerTotalDue) > 0 ? Number(this.srsServerTotalDue) : dueIds.length;
|
||||||
try { console.debug('[VocabPracticeDialog] repair srsSession.initialTotalDue', { before: this.srsSession.initialTotalDue, repairedTotal }); } catch (_) {}
|
const capped = Math.min(MAX_DAILY_DUE, repairedTotal);
|
||||||
this.srsSession.initialTotalDue = repairedTotal;
|
this.srsSession.initialTotalDue = capped;
|
||||||
this.srsSession.initialDueIds = Array.isArray(this.srsSession.initialDueIds) && this.srsSession.initialDueIds.length ? this.srsSession.initialDueIds : dueIds;
|
this.srsSession.initialDueIds = Array.isArray(this.srsSession.initialDueIds) && this.srsSession.initialDueIds.length ? this.srsSession.initialDueIds.slice(0, capped) : dueIds.slice(0, capped);
|
||||||
try { this.saveSrsSession(); } catch (_) {}
|
try { this.saveSrsSession(); } catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const doneSet = new Set(Array.isArray(this.srsSession.doneIds) ? this.srsSession.doneIds : []);
|
const doneSet = new Set(Array.isArray(this.srsSession.doneIds) ? this.srsSession.doneIds : []);
|
||||||
this.srsQueueIds = dueIds.filter((id) => !doneSet.has(id));
|
this.srsQueueIds = dueIds.filter((id) => !doneSet.has(id));
|
||||||
try {
|
|
||||||
console.debug('[VocabPracticeDialog] initSrsSessionFromPool', { courseId: this.openParams?.courseId, dueIdsLen: dueIds.length, srsQueueLen: this.srsQueueIds.length, stored: !!this.srsSession });
|
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
// Fallback: if SRS mode but queue is empty (e.g. mismatch between stored session and current pool), fall back to pool order
|
// Fallback: if SRS mode but queue is empty (e.g. mismatch between stored session and current pool), fall back to pool order
|
||||||
if (this.srsMode && Array.isArray(this.srsQueueIds) && this.srsQueueIds.length === 0) {
|
if (this.srsMode && Array.isArray(this.srsQueueIds) && this.srsQueueIds.length === 0) {
|
||||||
const fallbackIds = (this.pool || []).map((it) => it.id).filter(Boolean);
|
const fallbackIds = (this.pool || []).map((it) => it.id).filter(Boolean);
|
||||||
if (fallbackIds.length > 0) {
|
if (fallbackIds.length > 0) {
|
||||||
try { console.debug('[VocabPracticeDialog] initSrsSessionFromPool: srsQueueIds empty, falling back to pool ids', { fallbackLen: fallbackIds.length }); } catch (_) {}
|
const limited = fallbackIds.slice(0, MAX_DAILY_DUE);
|
||||||
this.srsQueueIds = fallbackIds;
|
this.srsQueueIds = limited;
|
||||||
// keep initialTotalDue stable if possible
|
// keep initialTotalDue stable if possible
|
||||||
if (!this.srsSession) this.srsSession = { version: SRS_SESSION_STORAGE_VERSION, dateKey: this.getLocalDateKey(), courseId: this.openParams.courseId, initialTotalDue: fallbackIds.length, initialDueIds: fallbackIds, doneIds: [], correctCount: 0, wrongCount: 0 };
|
if (!this.srsSession) this.srsSession = { version: SRS_SESSION_STORAGE_VERSION, dateKey: this.getLocalDateKey(), courseId: this.openParams.courseId, initialTotalDue: limited.length, initialDueIds: limited, doneIds: [], correctCount: 0, wrongCount: 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.saveSrsSession();
|
this.saveSrsSession();
|
||||||
@@ -595,10 +593,6 @@ export default {
|
|||||||
document.addEventListener('keydown', this.handleKeyDown);
|
document.addEventListener('keydown', this.handleKeyDown);
|
||||||
});
|
});
|
||||||
this.loadHardVocabMap();
|
this.loadHardVocabMap();
|
||||||
// Expose instance for temporary debugging in browser console
|
|
||||||
try {
|
|
||||||
window.__vocabPracticeDialog = this;
|
|
||||||
} catch (_) {}
|
|
||||||
this.reloadPool();
|
this.reloadPool();
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
@@ -747,7 +741,6 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const result = mapped.filter(Boolean);
|
const result = mapped.filter(Boolean);
|
||||||
try { console.debug('[VocabPracticeDialog] normalizePool', { inputLen, outLen: result.length, sample: result.slice(0,5) }); } catch (_) {}
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('[VocabPracticeDialog] normalizePool failed', e);
|
console.warn('[VocabPracticeDialog] normalizePool failed', e);
|
||||||
|
|||||||
Reference in New Issue
Block a user