122 lines
3.6 KiB
TypeScript
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']
|
|
}
|
|
} |