94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
// 熟悉度計算工具 - 與後端算法保持一致
|
|
|
|
/**
|
|
* 計算當前熟悉度(考慮記憶衰減)
|
|
* @param baseMastery 基礎熟悉度 (0-100)
|
|
* @param lastReviewDate 最後復習日期 (ISO格式)
|
|
* @returns 當前熟悉度 (0-100)
|
|
*/
|
|
export function calculateCurrentMastery(baseMastery: number, lastReviewDate: string): number {
|
|
const today = new Date();
|
|
const lastDate = new Date(lastReviewDate);
|
|
const daysSince = Math.floor((today.getTime() - lastDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
|
|
if (daysSince <= 0) return baseMastery;
|
|
|
|
// 應用記憶衰減(與後端一致的算法)
|
|
const decayRate = 0.05; // 每天5%衰減
|
|
const maxDecayDays = 30;
|
|
const effectiveDays = Math.min(daysSince, maxDecayDays);
|
|
const decayFactor = Math.pow(1 - decayRate, effectiveDays);
|
|
|
|
return Math.max(0, Math.floor(baseMastery * decayFactor));
|
|
}
|
|
|
|
/**
|
|
* 計算衰減程度
|
|
* @param baseMastery 基礎熟悉度
|
|
* @param currentMastery 當前熟悉度
|
|
* @returns 衰減量
|
|
*/
|
|
export function getDecayAmount(baseMastery: number, currentMastery: number): number {
|
|
return Math.max(0, baseMastery - currentMastery);
|
|
}
|
|
|
|
/**
|
|
* 根據學習者程度和詞彙難度決定可用的複習方式
|
|
* @param userLevel 學習者程度 (1-100)
|
|
* @param wordLevel 詞彙難度 (1-100)
|
|
* @returns 適合的複習題型列表
|
|
*/
|
|
export function getReviewTypesByDifficulty(userLevel: number, wordLevel: number): string[] {
|
|
const difficulty = wordLevel - userLevel;
|
|
|
|
if (userLevel <= 20) {
|
|
// A1學習者 - 統一基礎題型
|
|
return ['flip-memory', 'vocab-choice', 'vocab-listening'];
|
|
} else if (difficulty < -10) {
|
|
// 簡單詞彙 (學習者程度 > 詞彙程度)
|
|
return ['sentence-reorder', 'sentence-fill'];
|
|
} else if (difficulty >= -10 && difficulty <= 10) {
|
|
// 適中詞彙 (學習者程度 ≈ 詞彙程度)
|
|
return ['sentence-fill', 'sentence-reorder', 'sentence-speaking'];
|
|
} else {
|
|
// 困難詞彙 (學習者程度 < 詞彙程度)
|
|
return ['flip-memory', 'vocab-choice'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 檢查是否為A1學習者
|
|
* @param userLevel 學習者程度
|
|
* @returns 是否為A1學習者
|
|
*/
|
|
export function isA1Learner(userLevel: number): boolean {
|
|
return userLevel <= 20;
|
|
}
|
|
|
|
/**
|
|
* 獲取熟悉度等級標籤
|
|
* @param masteryLevel 熟悉度 (0-100)
|
|
* @returns 等級標籤和顏色
|
|
*/
|
|
export function getMasteryLevelInfo(masteryLevel: number): { label: string; color: string; bgColor: string } {
|
|
if (masteryLevel >= 80) {
|
|
return { label: '熟練', color: 'text-green-700', bgColor: 'bg-green-100' };
|
|
} else if (masteryLevel >= 60) {
|
|
return { label: '良好', color: 'text-blue-700', bgColor: 'bg-blue-100' };
|
|
} else if (masteryLevel >= 40) {
|
|
return { label: '一般', color: 'text-yellow-700', bgColor: 'bg-yellow-100' };
|
|
} else {
|
|
return { label: '需加強', color: 'text-red-700', bgColor: 'bg-red-100' };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 計算複習進度百分比
|
|
* @param completed 已完成數量
|
|
* @param total 總數量
|
|
* @returns 進度百分比 (0-100)
|
|
*/
|
|
export function calculateProgress(completed: number, total: number): number {
|
|
if (total === 0) return 0;
|
|
return Math.round((completed / total) * 100);
|
|
} |