dramaling-vocab-learning/frontend/lib/utils/cefrUtils.ts

122 lines
3.6 KiB
TypeScript

/**
* CEFR (Common European Framework of Reference) 工具函數
* 統一管理 CEFR 等級的轉換和比較邏輯
*/
export const CEFR_LEVELS = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'] as const
export type CEFRLevel = typeof CEFR_LEVELS[number]
/**
* 將 CEFR 字串等級轉換為數字
* @param level CEFR 等級字串 (A1, A2, B1, B2, C1, C2)
* @returns 數字等級 (1-6),無效值返回 0
*/
export const cefrToNumeric = (level: string): number => {
const index = CEFR_LEVELS.indexOf(level as CEFRLevel)
return index === -1 ? 0 : index + 1
}
/**
* 將數字等級轉換為 CEFR 字串
* @param numeric 數字等級 (1-6)
* @returns CEFR 等級字串,無效值返回 'A1'
*/
export const numericToCefr = (numeric: number): CEFRLevel => {
return CEFR_LEVELS[numeric - 1] || 'A1'
}
/**
* 比較兩個 CEFR 等級
* @param level1 第一個等級
* @param level2 第二個等級
* @param operator 比較運算符
* @returns 比較結果
*/
export const compareCEFRLevels = (level1: string, level2: string, operator: '>' | '<' | '==='): boolean => {
const numeric1 = cefrToNumeric(level1)
const numeric2 = cefrToNumeric(level2)
switch (operator) {
case '>': return numeric1 > numeric2
case '<': return numeric1 < numeric2
case '===': return numeric1 === numeric2
default: return false
}
}
/**
* 數字難度等級比較(性能優化版本)
* @param level1 第一個數字等級
* @param level2 第二個數字等級
* @param operator 比較運算符
* @returns 比較結果
*/
export const compareCEFRLevelsNumeric = (level1: number, level2: number, operator: '>' | '<' | '==='): boolean => {
switch (operator) {
case '>': return level1 > level2
case '<': return level1 < level2
case '===': return level1 === level2
default: return false
}
}
/**
* 獲取 CEFR 等級的陣列索引 (0-based)
* @param level CEFR 等級字串
* @returns 陣列索引 (0-5),無效值返回 -1
*/
export const getLevelIndex = (level: string): number => {
return cefrToNumeric(level) - 1
}
/**
* 獲取目標學習範圍
* @param userLevel 用戶當前等級
* @returns 建議學習的等級範圍
*/
export const getTargetLearningRange = (userLevel: string): string => {
const ranges: Record<string, string> = {
'A1': 'A2-B1', 'A2': 'B1-B2', 'B1': 'B2-C1',
'B2': 'C1-C2', 'C1': 'C2', 'C2': 'C2'
}
return ranges[userLevel] || 'A2-B1'
}
/**
* 驗證 CEFR 等級是否有效
* @param level 要驗證的等級字串
* @returns 是否為有效的 CEFR 等級
*/
export const isValidCEFRLevel = (level: string): level is CEFRLevel => {
return CEFR_LEVELS.includes(level as CEFRLevel)
}
/**
* 獲取所有可用的 CEFR 等級
* @returns CEFR 等級陣列的只讀副本
*/
export const getAllCEFRLevels = (): readonly CEFRLevel[] => {
return CEFR_LEVELS
}
/**
* 根據CEFR等級獲取複習類型
* @param userCEFR 用戶CEFR等級
* @param wordCEFR 詞彙CEFR等級
* @returns 推薦的複習類型陣列
*/
export const getReviewTypesByCEFR = (userCEFR: string, wordCEFR: string): string[] => {
const userLevel = cefrToNumeric(userCEFR)
const wordLevel = cefrToNumeric(wordCEFR)
const difficulty = wordLevel - userLevel
if (userCEFR === 'A1') {
return ['flip-memory', 'vocab-choice']
} else if (difficulty < -1) {
return ['sentence-reorder', 'sentence-fill']
} else if (difficulty >= -1 && difficulty <= 1) {
return ['sentence-fill', 'sentence-reorder']
} else {
return ['flip-memory', 'vocab-choice']
}
}