dramaling-vocab-learning/ReviewRunner組件詳細說明文檔.md

827 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ReviewRunner 組件詳細說明文檔
## 📋 組件概覽
`ReviewRunner` 是複習系統的**核心容器組件**,負責協調 7 種不同的複習模式、管理測驗生命週期、處理答題邏輯,以及控制測驗間的導航流程。
**文件位置**: `/frontend/components/review/ReviewRunner.tsx`
**組件類型**: 容器組件 (Container Component)
**職責範圍**: 業務邏輯 + 狀態管理 + 組件編排
## 🏗️ 組件架構設計
### 架構模式:容器-展示分離
```
ReviewRunner (容器組件)
├── 狀態管理 (4個 Zustand Store)
├── 業務邏輯 (答題處理、導航控制)
├── 組件編排 (動態渲染7種測驗)
└── 智能導航 (SmartNavigationController)
```
**設計哲學**:
- **容器組件**: 處理邏輯和狀態不涉及UI細節
- **展示組件**: 純UI渲染接收 props 和回調
- **關注點分離**: 業務邏輯與UI邏輯完全分離
## 📊 依賴關係分析
### Store 依賴關係
```typescript
// 4個 Zustand Store 的使用
useReviewSessionStore // 當前卡片、錯誤狀態
├── currentCard // 當前複習的詞卡
├── error // 會話錯誤狀態
useTestQueueStore // 測驗佇列管理
├── currentMode // 當前測驗模式
├── testItems // 測驗項目陣列
├── currentTestIndex // 當前測驗索引
├── markTestCompleted // 標記測驗完成
├── goToNextTest // 切換下一個測驗
└── skipCurrentTest // 跳過當前測驗
useTestResultStore // 測驗結果記錄
├── score // 當前分數統計
├── updateScore // 更新分數
└── recordTestResult // 記錄到後端
useReviewUIStore // UI 狀態管理
├── openReportModal // 開啟錯誤報告彈窗
└── openImageModal // 開啟圖片放大彈窗
```
**依賴流程圖**:
```
TestQueueStore (提供測驗項目)
ReviewRunner (協調各Store + 渲染組件)
TestComponent (處理用戶交互)
↓ (答案回調)
ReviewRunner.handleAnswer()
↓ (更新狀態)
TestResultStore + TestQueueStore + 後端API
```
## 🔄 核心方法詳解
### 1. handleAnswer - 答題處理核心邏輯
```typescript
const handleAnswer = useCallback(async (answer: string, confidenceLevel?: number) => {
// 防護性檢查:避免重複提交或無效狀態下提交
if (!currentCard || hasAnswered || isProcessingAnswer) return
setIsProcessingAnswer(true) // 設置處理中狀態
try {
// 第1步答案驗證
const isCorrect = checkAnswer(answer, currentCard, currentMode)
// 第2步本地狀態立即更新
updateScore(isCorrect)
// 第3步異步同步到後端
const success = await recordTestResult({
flashcardId: currentCard.id,
testType: currentMode,
isCorrect,
userAnswer: answer,
confidenceLevel,
responseTimeMs: 2000 // 可以改為實際測量值
})
// 第4步更新測驗佇列狀態
if (success) {
markTestCompleted(currentTestIndex)
setHasAnswered(true) // 啟用"繼續"按鈕
// 第5步答錯處理邏輯 (TODO: 未完全實現)
if (!isCorrect && currentMode !== 'flip-memory') {
console.log('答錯,將重新排入隊列')
// TODO: 實現優先級重排邏輯
}
}
} catch (error) {
console.error('答題處理失敗:', error)
// 錯誤處理:可以顯示錯誤提示或重試機制
} finally {
setIsProcessingAnswer(false) // 解除處理中狀態
}
}, [currentCard, hasAnswered, isProcessingAnswer, currentMode, updateScore, recordTestResult, markTestCompleted, currentTestIndex])
```
**設計特色**
- **防護性檢查**: 避免重複提交和無效狀態
- **樂觀更新**: 本地狀態立即更新,異步同步後端
- **錯誤容錯**: 完整的 try-catch 錯誤處理
- **狀態控制**: `isProcessingAnswer` 防止按鈕重複點擊
### 2. checkAnswer - 答案驗證邏輯
```typescript
const checkAnswer = (answer: string, card: any, mode: string): boolean => {
switch (mode) {
case 'flip-memory':
return true // 翻卡記憶沒有對錯,只有信心等級
case 'vocab-choice':
case 'vocab-listening':
return answer === card.word // 精確匹配詞彙
case 'sentence-fill':
return answer.toLowerCase().trim() === card.word.toLowerCase() // 忽略大小寫
case 'sentence-reorder':
case 'sentence-listening':
return answer.toLowerCase().trim() === card.example.toLowerCase().trim() // 句子匹配
case 'sentence-speaking':
return true // 口說測驗通常算正確 (語音識別待實現)
default:
return false
}
}
```
**演算法特色**
- **模式特化**: 每種測驗類型有專門的驗證邏輯
- **容錯設計**: 忽略大小寫和空格
- **擴展性**: 易於添加新的測驗類型驗證
### 3. generateOptions - 選項生成演算法
```typescript
const generateOptions = (card: any, mode: string): string[] => {
switch (mode) {
case 'vocab-choice':
case 'vocab-listening':
// 詞彙選擇生成3個干擾項 + 1個正確答案
return [card.word, '其他選項1', '其他選項2', '其他選項3']
.sort(() => Math.random() - 0.5) // 隨機排序
case 'sentence-listening':
// 句子聽力生成3個例句干擾項 + 1個正確例句
return [
card.example,
'其他例句選項1',
'其他例句選項2',
'其他例句選項3'
].sort(() => Math.random() - 0.5)
default:
return [] // 其他模式不需要選項
}
}
```
**改進空間** (目前為簡化實現):
- 真實干擾項應基於詞性、CEFR等級、語義相似性生成
- 需要避免過於簡單或過於困難的干擾項
- 可考慮用戶歷史錯誤答案作為干擾項
## 🎛️ 狀態管理流程
### 本地狀態設計
```typescript
interface ReviewRunnerState {
hasAnswered: boolean // 是否已答題(控制導航按鈕顯示)
isProcessingAnswer: boolean // 是否正在處理答案(防重複提交)
}
```
**狀態轉換流程**
```
初始狀態: hasAnswered=false, isProcessingAnswer=false
↓ (用戶答題)
處理中: hasAnswered=false, isProcessingAnswer=true
↓ (處理完成)
已答題: hasAnswered=true, isProcessingAnswer=false
↓ (點擊繼續/跳過)
重置狀態: hasAnswered=false, isProcessingAnswer=false (下一題)
```
### 生命週期管理
```typescript
// 測驗切換時自動重置狀態
useEffect(() => {
setHasAnswered(false)
setIsProcessingAnswer(false)
}, [currentTestIndex, currentMode])
```
**重置觸發條件**
- `currentTestIndex` 改變:切換到新測驗
- `currentMode` 改變:切換測驗類型
- 用戶主動跳過或繼續
## 🎮 動態組件渲染系統
### 組件映射機制
```typescript
// 測驗組件映射表
const TEST_COMPONENTS = {
'flip-memory': FlipMemoryTest,
'vocab-choice': VocabChoiceTest,
'sentence-fill': SentenceFillTest,
'sentence-reorder': SentenceReorderTest,
'vocab-listening': VocabListeningTest,
'sentence-listening': SentenceListeningTest,
'sentence-speaking': SentenceSpeakingTest
} as const
```
**動態渲染邏輯**
```typescript
const renderTestContent = () => {
// 基於 currentMode 動態選擇組件
switch (currentMode) {
case 'flip-memory':
return (
<FlipMemoryTest
{...commonProps} // 共通 props
onConfidenceSubmit={(level) => handleAnswer('', level)} // 特殊處理
disabled={isProcessingAnswer} // 處理中禁用
/>
)
// ... 其他模式
}
}
```
**設計優勢**
- **統一介面**: 所有測驗組件使用相同的 `commonProps`
- **特化處理**: 各測驗的特殊需求通過額外 props 處理
- **類型安全**: TypeScript 確保正確的 props 傳遞
## 🔀 雙重渲染模式
### 模式1真實數據模式 (Production)
```typescript
// 使用真實的 currentCard 數據
if (currentCard) {
const cardData = {
id: currentCard.id,
word: currentCard.word,
definition: currentCard.definition,
// ... 完整詞卡數據
}
return renderTestContent() // 渲染真實測驗
}
```
### 模式2模擬數據模式 (Development/Testing)
```typescript
// 當沒有真實數據時,使用 mockFlashcards
if (!currentCard && testItems.length > 0) {
const currentTest = testItems[currentTestIndex]
const mockCard = mockFlashcards.find(card => card.id === currentTest.cardId)
if (mockCard) {
return renderTestContentWithMockData(mockCard, currentTest.testType, mockOptions)
}
}
```
**雙重模式的價值**
- **開發便利**: 無需後端數據即可測試複習功能
- **錯誤容錯**: 真實數據載入失敗時的降級方案
- **獨立測試**: 前端邏輯可獨立於後端進行測試
## 🎯 導航控制邏輯
### SmartNavigationController 整合
```typescript
<SmartNavigationController
hasAnswered={hasAnswered} // 控制按鈕顯示邏輯
disabled={isProcessingAnswer} // 處理中時禁用按鈕
onSkipCallback={handleSkip} // 跳過處理函數
onContinueCallback={handleContinue} // 繼續處理函數
className="mt-4"
/>
```
**導航邏輯流程**
```
未答題階段: 顯示"跳過"按鈕
↓ (用戶答題)
已答題階段: 顯示"繼續"按鈕
↓ (用戶點擊繼續)
狀態重置: 準備下一題
```
### 跳過和繼續處理
```typescript
// 跳過邏輯
const handleSkip = useCallback(() => {
if (hasAnswered) return // 已答題後不能跳過
skipCurrentTest() // 更新 TestQueue Store
// 重置本地狀態,準備下一題
setHasAnswered(false)
setIsProcessingAnswer(false)
}, [hasAnswered, skipCurrentTest])
// 繼續邏輯
const handleContinue = useCallback(() => {
if (!hasAnswered) return // 未答題不能繼續
goToNextTest() // 切換到下一個測驗
// 重置本地狀態,準備下一題
setHasAnswered(false)
setIsProcessingAnswer(false)
}, [hasAnswered, goToNextTest])
```
## 📈 進度追蹤系統
### ProgressBar 整合
```typescript
{/* 進度條顯示邏輯 */}
{testItems.length > 0 && (
<div className="mb-6">
<ProgressBar
current={currentTestIndex} // 當前進度
total={testItems.length} // 總測驗數
correct={score.correct} // 正確數量
incorrect={score.total - score.correct} // 錯誤數量
skipped={testItems.filter(item => item.isSkipped).length} // 跳過數量
/>
</div>
)}
```
**進度計算邏輯**
- **完成進度**: `currentTestIndex / testItems.length * 100`
- **正確率**: `score.correct / score.total * 100`
- **跳過統計**: 實時統計跳過的測驗數量
## 🧮 測驗組件 Props 設計
### 統一的 commonProps
```typescript
const commonProps = {
cardData, // 標準化的卡片數據
onAnswer: handleAnswer, // 統一的答題回調
onReportError: () => openReportModal(currentCard) // 錯誤報告回調
}
```
### 特化的額外 Props
```typescript
// 翻卡記憶:信心度提交
<FlipMemoryTest
{...commonProps}
onConfidenceSubmit={(level) => handleAnswer('', level)} // 信心度答題
disabled={isProcessingAnswer}
/>
// 選擇題類型:選項陣列
<VocabChoiceTest
{...commonProps}
options={generateOptions(currentCard, currentMode)} // 動態選項生成
disabled={isProcessingAnswer}
/>
// 圖片相關測驗:圖片處理
<SentenceReorderTest
{...commonProps}
exampleImage={cardData.exampleImage} // 圖片數據
onImageClick={openImageModal} // 圖片點擊處理
disabled={isProcessingAnswer}
/>
```
## 🎨 用戶體驗設計
### 載入和錯誤狀態處理
```typescript
// 錯誤狀態顯示
if (error) {
return (
<div className="text-center py-8">
<div className="bg-red-50 border border-red-200 rounded-lg p-6">
<h3 className="text-lg font-semibold text-red-700 mb-2">發生錯誤</h3>
<p className="text-red-600">{error}</p>
</div>
</div>
)
}
// 載入狀態顯示
if (!currentCard) {
return (
<div className="text-center py-8">
<div className="text-gray-500">載入測驗中...</div>
</div>
)
}
```
**UX 設計原則**
- **即時反饋**: 用戶操作立即得到視覺回饋
- **狀態明確**: 清晰區分載入、錯誤、正常狀態
- **防誤操作**: 處理中狀態禁用所有交互
### 視覺層次和佈局
```typescript
return (
<div className={`review-runner ${className}`}>
{/* 第1層進度追蹤 */}
<div className="mb-6">
<ProgressBar {...progressProps} />
</div>
{/* 第2層測驗內容 (主要區域) */}
<div className="mb-6">
{renderTestContent()}
</div>
{/* 第3層導航控制 */}
<div className="border-t pt-6">
<SmartNavigationController {...navigationProps} />
</div>
</div>
)
```
**佈局設計**
- **視覺層次**: 進度→內容→導航,符合用戶視線流
- **間距統一**: 使用 `mb-6` 保持一致間距
- **分隔線**: `border-t` 明確區分導航區域
## ⚡ 性能優化策略
### useCallback 優化
```typescript
// 依賴項精確控制,避免不必要的重新創建
const handleAnswer = useCallback(async (answer: string, confidenceLevel?: number) => {
// 答題邏輯
}, [currentCard, hasAnswered, isProcessingAnswer, currentMode, updateScore, recordTestResult, markTestCompleted, currentTestIndex])
// 依賴項最小化
const handleSkip = useCallback(() => {
// 跳過邏輯
}, [hasAnswered, skipCurrentTest])
```
**優化原則**
- **依賴項精確**: 只包含實際使用的變數
- **穩定引用**: 避免子組件不必要重渲染
- **記憶化**: 複雜函數使用 useCallback
### 條件渲染優化
```typescript
// 避免不必要的組件創建
{testItems.length > 0 && ( // 條件:有測驗項目
<ProgressBar {...props} /> // 才創建進度條
)}
// 提前返回,減少後續計算
if (error) return <ErrorComponent />
if (!currentCard) return <LoadingComponent />
```
## 🔧 技術債務和改進點
### 當前技術債務
1. **generateOptions 實現簡化**
```typescript
// 當前實現:硬編碼假選項
return [card.word, '其他選項1', '其他選項2', '其他選項3']
// 理想實現:智能干擾項生成
const generateIntelligentDistractors = (correctWord: string, allCards: Card[]): string[] => {
const samePOS = allCards.filter(c => c.partOfSpeech === correctWord.partOfSpeech)
const similarCEFR = allCards.filter(c => c.cefr === correctWord.cefr)
const semanticallySimilar = findSemanticallySimilar(correctWord, allCards)
return intelligentlySelect(samePOS, similarCEFR, semanticallySimilar, 3)
}
```
2. **答錯重排邏輯未完整實現**
```typescript
// TODO 部分:需要實現完整的優先級重排
if (!isCorrect && currentMode !== 'flip-memory') {
// 當前:只有 console.log
console.log('答錯,將重新排入隊列')
// 應該實現:
const { reorderByPriority, markTestIncorrect } = useTestQueueStore()
markTestIncorrect(currentTestIndex)
reorderByPriority()
}
```
3. **responseTimeMs 測量缺失**
```typescript
// 當前:硬編碼
responseTimeMs: 2000
// 應該實現:實際測量
const [startTime, setStartTime] = useState<number>()
useEffect(() => {
setStartTime(Date.now()) // 測驗開始時記錄
}, [currentTestIndex])
const actualResponseTime = Date.now() - (startTime || 0)
```
### 建議的改進方向
#### 1. 智能干擾項生成系統
```typescript
interface DistractorGenerationEngine {
// 基於詞性的干擾項
generateByPartOfSpeech(word: string, pos: string): string[]
// 基於CEFR等級的干擾項
generateByCEFRLevel(word: string, level: string): string[]
// 基於語義相似性的干擾項
generateBySemantics(word: string): string[]
// 基於用戶歷史錯誤的干擾項
generateByUserMistakes(word: string, userHistory: ErrorHistory[]): string[]
}
```
#### 2. 完整的答題分析系統
```typescript
interface AnswerAnalyticsEngine {
// 答題時間分析
analyzeResponseTime(startTime: number, endTime: number): ResponseMetrics
// 答錯模式分析
categorizeError(
userAnswer: string,
correctAnswer: string,
testType: ReviewMode
): ErrorCategory
// 學習建議生成
generateLearningAdvice(
errorPattern: ErrorPattern,
userProfile: UserProfile
): LearningAdvice[]
}
```
#### 3. 自適應難度調整
```typescript
interface AdaptiveDifficultyEngine {
// 動態調整測驗難度
adjustDifficulty(
currentPerformance: PerformanceMetrics,
userProfile: UserProfile
): DifficultyAdjustment
// 個性化測驗序列
optimizeTestSequence(
remainingTests: TestItem[],
userStrongWeakPoints: UserAnalytics
): TestItem[]
}
```
## 📊 性能指標和監控
### 關鍵性能指標
**渲染性能**
- **組件切換時間**: 目標 <300ms
- **答題處理時間**: 目標 <500ms
- **狀態更新延遲**: 目標 <100ms
**記憶體使用**
- **組件記憶體**: 每個測驗組件 <5MB
- **狀態記憶體**: 整體 Store 狀態 <10MB
- **清理機制**: 組件卸載時自動清理
**網路性能**
- **答題同步**: 目標 <1秒
- **佇列載入**: 目標 <2秒
- **錯誤重試**: 自動重試 3
### 性能監控實現
```typescript
// 可添加的性能監控邏輯
const usePerformanceMonitoring = () => {
const startTime = useRef<number>()
useEffect(() => {
startTime.current = performance.now()
}, [currentTestIndex])
const recordMetrics = useCallback((action: string) => {
if (startTime.current) {
const duration = performance.now() - startTime.current
console.log(`${action} took ${duration.toFixed(2)}ms`)
// 可以發送到分析服務
analytics.track('test_performance', {
action,
duration,
testType: currentMode,
cardId: currentCard?.id
})
}
}, [currentMode, currentCard])
return { recordMetrics }
}
```
## 🔮 未來擴展可能性
### 1. 實時協作學習
```typescript
interface CollaborativeLearning {
// 多人同時複習
joinSession(sessionId: string): Promise<CollaborativeSession>
// 實時同步進度
syncProgress(progress: ProgressState): Promise<void>
// 互助提示系統
requestHint(testId: string): Promise<PeerHint>
provideHint(testId: string, hint: string): Promise<void>
}
```
### 2. AI輔助學習
```typescript
interface AIAssistedLearning {
// 智能提示系統
generateHint(
testType: ReviewMode,
cardData: ReviewCardData,
userAttempts: Attempt[]
): LearningHint
// 個性化難度
adjustDifficulty(
userPerformance: PerformanceHistory,
targetAccuracy: number
): DifficultyParams
// 學習路徑優化
optimizeLearningPath(
userWeaknesses: WeaknessProfile,
availableTime: number
): OptimizedPath
}
```
### 3. 多模態學習整合
```typescript
interface MultimodalLearning {
// VR/AR 學習環境
enterVRMode(testType: ReviewMode): Promise<VRSession>
// 語音評估整合
enableSpeechAssessment(): Promise<SpeechEvaluator>
// 手寫識別
enableHandwritingRecognition(): Promise<HandwritingEngine>
// 眼動追蹤學習分析
trackLearningAttention(): Promise<AttentionMetrics>
}
```
## 🏆 組件設計優勢
### 架構優勢
1. **模組化設計**: 清晰的職責分離易於維護和擴展
2. **類型安全**: 完整的 TypeScript 類型定義編譯時錯誤檢查
3. **狀態管理**: Zustand 提供高效的跨組件狀態同步
4. **性能優化**: useCallback 和條件渲染減少不必要的重新渲染
5. **錯誤處理**: 完整的錯誤邊界和降級方案
### 開發體驗優勢
1. **開發效率**: 模擬數據模式支援獨立開發
2. **測試友好**: 純函數設計便於單元測試
3. **調試便利**: 詳細的 console.log 和錯誤訊息
4. **擴展性**: 新測驗類型可透過 switch case 輕易添加
### 學習體驗優勢
1. **即時反饋**: 答題結果立即顯示
2. **進度可視**: 詳細的進度追蹤和統計
3. **智能導航**: 根據答題狀態智能顯示操作選項
4. **容錯機制**: 跳過和重試機制避免學習中斷
## 🔧 使用指南和最佳實踐
### 組件使用方式
```typescript
// 在頁面中使用 ReviewRunner
import { ReviewRunner } from '@/components/review/ReviewRunner'
const ReviewPage = () => {
return (
<div className="review-page">
<Navigation />
<div className="max-w-4xl mx-auto px-4 py-8">
<ReviewRunner className="review-content" />
</div>
</div>
)
}
```
### 自定義測驗類型擴展
```typescript
// 1. 創建新的測驗組件
const NewTestType = ({ cardData, onAnswer, disabled }) => {
// 測驗邏輯實現
return <div>新測驗類型UI</div>
}
// 2. 在 ReviewRunner 中添加映射
case 'new-test-type':
return (
<NewTestType
{...commonProps}
disabled={isProcessingAnswer}
// 特化 props
/>
)
// 3. 更新類型定義
export type ReviewMode =
| 'flip-memory'
| 'vocab-choice'
| 'new-test-type' // 新增
```
### Store 狀態訂閱最佳實踐
```typescript
// 精確訂閱,避免不必要重渲染
const currentTest = useTestQueueStore(state =>
state.testItems[state.currentTestIndex]
)
// 避免:訂閱整個 Store
const store = useTestQueueStore() // ❌ 會導致所有變化都重渲染
// 推薦:選擇性訂閱
const { currentMode, currentTestIndex } = useTestQueueStore(state => ({
currentMode: state.currentMode,
currentTestIndex: state.currentTestIndex
})) // ✅ 只有這兩個屬性變化才重渲染
```
## 📋 總結
ReviewRunner 是複習系統的**核心控制中樞**展現了現代 React 應用的最佳實踐
1. **容器-展示分離**: 邏輯與UI完全分離
2. **狀態管理**: 多Store協作職責分明
3. **動態渲染**: 基於狀態的智能組件切換
4. **用戶體驗**: 完整的錯誤處理和載入狀態
5. **性能優化**: useCallback和條件渲染優化
6. **可擴展性**: 新測驗類型易於添加
這個組件是複習功能架構設計的精華體現了**複雜業務邏輯的優雅實現**。
---
*文檔版本: v1.0*
*分析對象: ReviewRunner.tsx (440行)*
*最後更新: 2025-10-02*