107 lines
3.5 KiB
TypeScript
107 lines
3.5 KiB
TypeScript
/**
|
|
* Flashcard 相關工具函數
|
|
* 統一管理詞卡相關的顯示和處理邏輯
|
|
*/
|
|
|
|
// 詞性簡寫轉換
|
|
export const getPartOfSpeechDisplay = (partOfSpeech: string): string => {
|
|
const shortMap: {[key: string]: string} = {
|
|
'noun': 'n.',
|
|
'verb': 'v.',
|
|
'adjective': 'adj.',
|
|
'adverb': 'adv.',
|
|
'pronoun': 'pron.',
|
|
'conjunction': 'conj.',
|
|
'preposition': 'prep.',
|
|
'interjection': 'int.',
|
|
'idiom': 'idiom'
|
|
}
|
|
|
|
// 處理複合詞性 (如 "preposition/adverb")
|
|
if (partOfSpeech?.includes('/')) {
|
|
return partOfSpeech.split('/').map(p => shortMap[p.trim()] || p.trim()).join('/')
|
|
}
|
|
|
|
return shortMap[partOfSpeech] || partOfSpeech || ''
|
|
}
|
|
|
|
// CEFR等級顏色獲取
|
|
export const getCEFRColor = (level: string): string => {
|
|
switch (level) {
|
|
case 'A1': return 'bg-green-100 text-green-700 border-green-200'
|
|
case 'A2': return 'bg-blue-100 text-blue-700 border-blue-200'
|
|
case 'B1': return 'bg-yellow-100 text-yellow-700 border-yellow-200'
|
|
case 'B2': return 'bg-orange-100 text-orange-700 border-orange-200'
|
|
case 'C1': return 'bg-red-100 text-red-700 border-red-200'
|
|
case 'C2': return 'bg-purple-100 text-purple-700 border-purple-200'
|
|
default: return 'bg-gray-100 text-gray-700 border-gray-200'
|
|
}
|
|
}
|
|
|
|
// 熟練度等級顏色獲取
|
|
export const getMasteryColor = (level: number): string => {
|
|
if (level >= 90) return 'bg-green-100 text-green-800'
|
|
if (level >= 70) return 'bg-yellow-100 text-yellow-800'
|
|
if (level >= 50) return 'bg-orange-100 text-orange-800'
|
|
return 'bg-red-100 text-red-800'
|
|
}
|
|
|
|
// 熟練度等級文字
|
|
export const getMasteryText = (level: number): string => {
|
|
if (level >= 90) return '精通'
|
|
if (level >= 70) return '熟悉'
|
|
if (level >= 50) return '理解'
|
|
return '學習中'
|
|
}
|
|
|
|
// 下次複習時間格式化
|
|
export const formatNextReviewDate = (dateString: string): string => {
|
|
const reviewDate = new Date(dateString)
|
|
const now = new Date()
|
|
const diffInDays = Math.ceil((reviewDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
|
|
|
|
if (diffInDays < 0) return '需要複習'
|
|
if (diffInDays === 0) return '今天'
|
|
if (diffInDays === 1) return '明天'
|
|
return `${diffInDays}天後`
|
|
}
|
|
|
|
// 詞卡創建時間格式化
|
|
export const formatCreatedDate = (dateString: string): string => {
|
|
return new Date(dateString).toLocaleDateString('zh-TW')
|
|
}
|
|
|
|
// 獲取例句圖片URL (統一邏輯)
|
|
export const getFlashcardImageUrl = (flashcard: any): string | null => {
|
|
// 優先使用 primaryImageUrl
|
|
if (flashcard.primaryImageUrl) {
|
|
return flashcard.primaryImageUrl
|
|
}
|
|
|
|
// 然後檢查 exampleImages 陣列
|
|
if (flashcard.exampleImages && flashcard.exampleImages.length > 0) {
|
|
const primaryImage = flashcard.exampleImages.find((img: any) => img.isPrimary)
|
|
if (primaryImage) return primaryImage.imageUrl
|
|
return flashcard.exampleImages[0].imageUrl
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
// 詞卡統計計算
|
|
export const calculateFlashcardStats = (flashcards: any[]) => {
|
|
const total = flashcards.length
|
|
const mastered = flashcards.filter(card => card.masteryLevel >= 80).length
|
|
const learning = flashcards.filter(card => card.masteryLevel >= 40 && card.masteryLevel < 80).length
|
|
const new_cards = flashcards.filter(card => card.masteryLevel < 40).length
|
|
const favorites = flashcards.filter(card => card.isFavorite).length
|
|
|
|
return {
|
|
total,
|
|
mastered,
|
|
learning,
|
|
new: new_cards,
|
|
favorites,
|
|
masteryPercentage: total > 0 ? Math.round((mastered / total) * 100) : 0
|
|
}
|
|
} |