init
This commit is contained in:
85
server/src/services/review.service.js
Normal file
85
server/src/services/review.service.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import { ReviewLog } from '../models/ReviewLog.js';
|
||||
import { StudyItem } from '../models/StudyItem.js';
|
||||
import { getDaysDiff, getSRSDate } from '../utils/dateUtils.js';
|
||||
|
||||
export const processReview = async (user, subjectId, success) => {
|
||||
if (!user.stats) user.stats = { totalReviews: 0, correctReviews: 0, currentStreak: 0, maxStreak: 0 };
|
||||
user.stats.totalReviews += 1;
|
||||
if (success) user.stats.correctReviews += 1;
|
||||
|
||||
const todayStr = new Date().toISOString().split('T')[0];
|
||||
const lastStudyStr = user.stats.lastStudyDate;
|
||||
|
||||
if (lastStudyStr !== todayStr) {
|
||||
if (!lastStudyStr) {
|
||||
user.stats.currentStreak = 1;
|
||||
} else {
|
||||
const diff = getDaysDiff(lastStudyStr, todayStr);
|
||||
if (diff === 1) {
|
||||
user.stats.currentStreak += 1;
|
||||
} else if (diff > 1) {
|
||||
const lastFreeze = user.stats.lastFreezeDate ? new Date(user.stats.lastFreezeDate) : null;
|
||||
let daysSinceFreeze = 999;
|
||||
if (lastFreeze) daysSinceFreeze = getDaysDiff(lastFreeze.toISOString().split('T')[0], todayStr);
|
||||
|
||||
const canUseShield = daysSinceFreeze >= 7;
|
||||
|
||||
if (canUseShield && diff === 2) {
|
||||
console.log(`User ${user._id} saved by Zen Shield!`);
|
||||
user.stats.lastFreezeDate = new Date();
|
||||
user.stats.currentStreak += 1;
|
||||
} else {
|
||||
user.stats.currentStreak = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
user.stats.lastStudyDate = todayStr;
|
||||
if (user.stats.currentStreak > user.stats.maxStreak) user.stats.maxStreak = user.stats.currentStreak;
|
||||
}
|
||||
await user.save();
|
||||
|
||||
await ReviewLog.findOneAndUpdate(
|
||||
{ userId: user._id, date: todayStr },
|
||||
{ $inc: { count: 1 } },
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
|
||||
const item = await StudyItem.findOne({ userId: user._id, wkSubjectId: subjectId });
|
||||
if (!item) throw new Error('Item not found');
|
||||
|
||||
if (!item.stats) item.stats = { correct: 0, total: 0 };
|
||||
item.stats.total += 1;
|
||||
if (success) item.stats.correct += 1;
|
||||
|
||||
if (success) {
|
||||
const nextLevel = Math.min(item.srsLevel + 1, 10);
|
||||
item.srsLevel = nextLevel;
|
||||
item.nextReview = getSRSDate(nextLevel);
|
||||
} else {
|
||||
item.srsLevel = Math.max(1, item.srsLevel - 1);
|
||||
item.nextReview = Date.now();
|
||||
}
|
||||
|
||||
await item.save();
|
||||
return { nextReview: item.nextReview, srsLevel: item.srsLevel };
|
||||
};
|
||||
|
||||
export const getQueue = async (user, limit = 100, sortMode) => {
|
||||
const query = {
|
||||
userId: user._id,
|
||||
srsLevel: { $lt: 10, $gt: 0 },
|
||||
nextReview: { $lte: new Date() }
|
||||
};
|
||||
|
||||
let dueItems;
|
||||
if (sortMode === 'priority') {
|
||||
dueItems = await StudyItem.find(query).sort({ srsLevel: 1, level: 1 }).limit(limit);
|
||||
} else {
|
||||
dueItems = await StudyItem.find(query).limit(limit);
|
||||
for (let i = dueItems.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[dueItems[i], dueItems[j]] = [dueItems[j], dueItems[i]];
|
||||
}
|
||||
}
|
||||
return dueItems;
|
||||
};
|
||||
Reference in New Issue
Block a user