dramaling-vocab-learning/frontend/lib/services/review/reviewService.ts

135 lines
3.9 KiB
TypeScript

import { flashcardsService } from '@/lib/services/flashcards'
import { ExtendedFlashcard, TestItem } from '@/store/useReviewStore'
// 複習會話服務
export class ReviewService {
// 載入到期詞卡
static async loadDueCards(limit = 50): Promise<ExtendedFlashcard[]> {
try {
const result = await flashcardsService.getDueFlashcards(limit)
if (result.success && result.data) {
return result.data
} else {
throw new Error(result.error || '載入詞卡失敗')
}
} catch (error) {
console.error('載入到期詞卡失敗:', error)
throw error
}
}
// 載入已完成的測驗
static async loadCompletedTests(cardIds: string[]): Promise<any[]> {
try {
const result = await flashcardsService.getCompletedTests(cardIds)
if (result.success && result.data) {
return result.data
} else {
console.warn('載入已完成測驗失敗:', result.error)
return []
}
} catch (error) {
console.error('載入已完成測驗異常:', error)
return []
}
}
// 記錄測驗結果
static async recordTestResult(params: {
flashcardId: string
testType: string
isCorrect: boolean
userAnswer?: string
confidenceLevel?: number
responseTimeMs?: number
}): Promise<boolean> {
try {
const result = await flashcardsService.recordTestCompletion({
...params,
responseTimeMs: params.responseTimeMs || 2000
})
if (result.success) {
return true
} else {
console.error('記錄測驗結果失敗:', result.error)
return false
}
} catch (error) {
console.error('記錄測驗結果異常:', error)
return false
}
}
// 生成測驗選項
static async generateTestOptions(
cardId: string,
testType: string,
count = 4
): Promise<string[]> {
try {
// 這裡可以呼叫後端API生成選項
// 或者使用本地邏輯生成
// 暫時使用簡單的佔位符邏輯
return Array.from({ length: count }, (_, i) => `選項 ${i + 1}`)
} catch (error) {
console.error('生成測驗選項失敗:', error)
return []
}
}
// 驗證學習會話完整性
static validateSession(
cards: ExtendedFlashcard[],
testItems: TestItem[]
): { isValid: boolean; errors: string[] } {
const errors: string[] = []
// 檢查詞卡是否存在
if (!cards || cards.length === 0) {
errors.push('沒有可用的詞卡')
}
// 檢查測驗項目
if (!testItems || testItems.length === 0) {
errors.push('沒有可用的測驗項目')
}
// 檢查測驗項目和詞卡的一致性
if (cards && testItems) {
const cardIds = new Set(cards.map(c => c.id))
const testCardIds = new Set(testItems.map(t => t.cardId))
for (const testCardId of testCardIds) {
if (!cardIds.has(testCardId)) {
errors.push(`測驗項目引用了不存在的詞卡: ${testCardId}`)
}
}
}
return {
isValid: errors.length === 0,
errors
}
}
// 計算學習統計
static calculateStats(testItems: TestItem[], score: { correct: number; total: number }) {
const completed = testItems.filter(item => item.isCompleted).length
const total = testItems.length
const progressPercentage = total > 0 ? (completed / total) * 100 : 0
const accuracyPercentage = score.total > 0 ? (score.correct / score.total) * 100 : 0
return {
completed,
total,
remaining: total - completed,
progressPercentage: Math.round(progressPercentage),
accuracyPercentage: Math.round(accuracyPercentage),
estimatedTimeRemaining: Math.max(0, (total - completed) * 30) // 假設每個測驗30秒
}
}
}