dramaling-vocab-learning/note/智能複習/智能複習系統-前端功能規格書.md

1091 lines
32 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.

# 智能複習系統 - 前端功能規格書 (FFS)
**目標讀者**: 前端開發工程師、UI/UX設計師
**版本**: 1.0
**日期**: 2025-09-25
---
## 🎯 **功能概述**
智能複習系統前端負責呈現動態熟悉度、復習進度追蹤、學習統計等功能,提供直觀的學習體驗。
### **核心特色**
- **實時熟悉度顯示**: 詞彙熟悉度隨時間動態變化
- **智能復習提醒**: 基於算法的個人化復習建議
- **進度可視化**: 清晰的學習進度和統計圖表
- **響應式設計**: 支援各種設備和屏幕尺寸
---
## 🏗️ **組件架構 (基於現有實現)**
### **實際頁面結構**
```
frontend/
├── app/
│ ├── learn/
│ │ └── page.tsx # 🎯 主復習頁面 (已完成7種題型UI)
│ ├── flashcards/
│ │ ├── page.tsx # 詞卡列表頁面 (已完成)
│ │ └── [id]/page.tsx # 詞卡詳細頁面 (已完成)
│ ├── dashboard/page.tsx # 儀表板 (已完成)
│ └── settings/page.tsx # 設定頁面 (已完成)
├── components/
│ ├── Navigation.tsx # 導航組件 (已完成)
│ ├── AudioPlayer.tsx # 音頻播放組件 (已完成)
│ ├── VoiceRecorder.tsx # 音頻錄製組件 (已完成)
│ ├── LearningComplete.tsx # 學習完成組件 (已完成)
│ └── Toast.tsx # 通知組件 (已完成)
├── lib/services/
│ ├── flashcards.ts # 詞卡API服務 (已完成)
│ ├── auth.ts # 認證服務 (已完成)
│ └── imageGeneration.ts # 圖片生成服務 (已完成)
└── contexts/
└── AuthContext.tsx # 認證上下文 (已完成)
```
### **需要新增的智能複習組件**
```
frontend/components/review/ # 🆕 智能複習專用組件
├── ReviewTypeIndicator.tsx # 🆕 題型顯示指示器
├── MasteryIndicator.tsx # 🆕 熟悉度指示器
├── ReviewSchedule.tsx # 🆕 復習排程組件
└── utils/
├── masteryCalculator.ts # 🆕 熟悉度計算工具
├── reviewTypeSelector.ts # 🆕 自動題型選擇邏輯
└── spacedRepetition.ts # 🆕 間隔重複算法整合
frontend/lib/services/
└── review.ts # 🆕 智能複習API服務
frontend/contexts/
└── SpacedRepetitionContext.tsx # 🆕 復習狀態管理
```
---
## 📱 **核心組件設計 (基於現有實現)**
### **1. LearnPage 主複習頁面** (已完成)
#### **實際功能實現**
- ✅ 7種複習模式完整UI實現
- ✅ 手動模式切換 (待改為自動選擇)
- ✅ 進度追蹤和分數統計
- ✅ 完整的答題反饋系統
- ✅ 音頻播放和錄音整合
- ✅ 響應式設計和動畫效果
#### **現有狀態管理**
```typescript
// 基於實際 learn/page.tsx 的狀態結構
interface LearnPageState {
currentCardIndex: number;
isFlipped: boolean;
mode: 'flip-memory' | 'vocab-choice' | 'vocab-listening' |
'sentence-listening' | 'sentence-fill' | 'sentence-reorder' |
'sentence-speaking';
score: { correct: number; total: number };
selectedAnswer: string | null;
showResult: boolean;
fillAnswer: string;
showHint: boolean;
// 例句重組專用狀態
shuffledWords: string[];
arrangedWords: string[];
reorderResult: boolean | null;
// UI狀態
cardHeight: number;
modalImage: string | null;
showReportModal: boolean;
showComplete: boolean;
}
```
#### **需要新增的智能化狀態**
```typescript
interface EnhancedLearnPageState extends LearnPageState {
// 智能複習相關
reviewMode: ReviewType; // 系統自動選擇的題型
userLevel: number; // 學習者程度
currentCard: FlashcardExtended; // 包含複習相關資料的詞卡
isAutoSelecting: boolean; // 系統正在選擇題型
masteryLevel: number; // 當前熟悉度
nextReviewDate: string; // 下次復習日期
}
```
### **2. 現有7種複習題型實現 (已完成UI)**
#### **實際程式碼結構基於 learn/page.tsx**
```typescript
// 現有的7種複習模式 (已完成UI需整合智能邏輯)
type LearnMode =
| 'flip-memory' // ✅ 翻卡記憶 (對應 FlipCardQuestion)
| 'vocab-choice' // ✅ 詞彙選擇 (對應 MultipleChoiceQuestion)
| 'vocab-listening' // ✅ 詞彙聽力 (對應 VocabularyListeningQuestion)
| 'sentence-listening' // ⚠️ 例句聽力 (UI框架完成邏輯開發中)
| 'sentence-fill' // ✅ 例句填空 (對應 FillBlankQuestion)
| 'sentence-reorder' // ✅ 例句重組 (對應 SentenceReconstructionQuestion)
| 'sentence-speaking' // ✅ 例句口說 (對應 SentenceSpeakingQuestion)
// 現有的詞卡資料結構
interface CurrentCardData {
id: number;
word: string;
partOfSpeech: string;
pronunciation: string;
translation: string;
definition: string;
example: string;
exampleTranslation: string;
exampleImage: string;
synonyms: string[];
difficulty: string; // CEFR等級 (A1, B1, B2, C1)
}
```
### **2. MasteryIndicator 組件**
#### **功能需求**
- 視覺化顯示熟悉度百分比
- 區分基礎熟悉度和當前熟悉度
- 衰減狀態提示
#### **設計規格**
```tsx
interface MasteryIndicatorProps {
level: number; // 0-100
isDecaying?: boolean; // 是否正在衰減
showPercentage?: boolean; // 是否顯示百分比數字
size?: 'small' | 'medium' | 'large';
}
export const MasteryIndicator: React.FC<MasteryIndicatorProps> = ({
level,
isDecaying = false,
showPercentage = true,
size = 'medium'
}) => {
const getColor = (level: number, isDecaying: boolean) => {
if (isDecaying) return '#ff9500'; // 橙色表示衰減中
if (level >= 80) return '#34c759'; // 綠色表示熟悉
if (level >= 50) return '#007aff'; // 藍色表示中等
return '#ff3b30'; // 紅色表示需要加強
};
return (
<div className={`mastery-indicator ${size}`}>
<div className="progress-circle">
<svg viewBox="0 0 36 36">
<circle
cx="18" cy="18" r="15.915"
fill="transparent"
stroke="#e5e5e7"
strokeWidth="2"
/>
<circle
cx="18" cy="18" r="15.915"
fill="transparent"
stroke={getColor(level, isDecaying)}
strokeWidth="2"
strokeDasharray={`${level} 100`}
transform="rotate(-90 18 18)"
/>
</svg>
{showPercentage && (
<div className="percentage">
{level}%
{isDecaying && <span className="decay-icon"></span>}
</div>
)}
</div>
<div className="mastery-label">
{level >= 80 ? '熟悉' :
level >= 50 ? '中等' : '需加強'}
</div>
</div>
);
};
```
### **3. ReviewSchedule 組件**
#### **功能需求**
- 顯示今日復習列表
- 按優先級排序(逾期 > 到期 > 提前復習)
- 復習進度追蹤
#### **實現概要**
```tsx
export const ReviewSchedule: React.FC = () => {
const [dueCards, setDueCards] = useState<Flashcard[]>([]);
const [completedCount, setCompletedCount] = useState(0);
useEffect(() => {
loadDueCards();
}, []);
const loadDueCards = async () => {
const response = await reviewApi.getDueFlashcards();
setDueCards(response.data);
};
const handleReviewComplete = (cardId: number) => {
setDueCards(prev => prev.filter(card => card.id !== cardId));
setCompletedCount(prev => prev + 1);
};
// 按優先級排序
const sortedCards = useMemo(() => {
return [...dueCards].sort((a, b) => {
if (a.isOverdue !== b.isOverdue) {
return a.isOverdue ? -1 : 1; // 逾期優先
}
if (a.isOverdue && b.isOverdue) {
return b.overdueDays - a.overdueDays; // 逾期天數多的優先
}
return 0;
});
}, [dueCards]);
return (
<div className="review-schedule">
<div className="progress-header">
<h2>今日復習</h2>
<div className="progress">
{completedCount} / {dueCards.length + completedCount}
</div>
</div>
<div className="card-list">
{sortedCards.map(card => (
<FlashcardItem
key={card.id}
flashcard={card}
onReviewClick={() => startReview(card.id)}
/>
))}
</div>
</div>
);
};
```
### **4. ReviewPage 組件**
#### **功能需求**
- 復習界面(翻卡、選擇題等)
- 信心程度評分 (1-5)
- 復習結果反饋
- 下一張卡片自動載入
---
## 🎓 **複習方式設計**
### **複習題型規劃**
#### **1. 翻卡題 (Flipcard)**
- **操作方式**: 顯示詞彙,學習者自己憑感覺評估記憶情況
- **學習效益**: 對詞彙形成全面的初步印象
- **適用情境**:
- A1學習者的基礎學習
- 困難詞彙(學習者程度 < 詞彙程度的重新熟悉
#### **2. 選擇題 (Multiple Choice)**
- **操作方式**: 給定義選擇正確的詞彙
- **學習效益**: 加深詞彙定義與詞彙之間的連結
- **適用情境**:
- A1學習者的概念建立
- 困難詞彙的定義強化
#### **3. 詞彙聽力題 (Vocabulary Listening)**
- **操作方式**: 播放詞彙發音選擇正確詞彙
- **學習效益**: 加強詞彙的發音記憶
- **限制說明**: 人類短期記憶能力強當次學習時聽力複習由短期記憶驅動可能壓縮發音與詞彙本身的連結效果
- **適用情境**: A1學習者的發音熟悉
#### **4. 例句聽力題 (Sentence Listening)**
- **操作方式**: 播放例句選擇正確例句
- **學習效益**: 強化例句的發音記憶
- **限制說明**: 受短期記憶影響對學習新例句幫助有限
- **適用情境**: 長期複習中的聽力維持
#### **5. 填空題 (Fill in the Blank)**
- **操作方式**: 提供挖空例句學習者填入正確詞彙
- **學習效益**:
- 練習拼字能力
- 加深詞彙與使用情境的連結
- **適用情境**:
- 簡單詞彙學習者程度 > 詞彙程度)
- 適中詞彙(學習者程度 = 詞彙程度)
#### **6. 例句重組題 (Sentence Reconstruction)**
- **操作方式**: 打亂例句單字順序,重新組織成完整句子
- **學習效益**: 快速練習組織句子的能力
- **適用情境**:
- 簡單詞彙的語法練習
- 適中詞彙的句型熟悉
#### **7. 例句口說題 (Sentence Speaking)**
- **操作方式**: 給出例句,學習者朗讀例句
- **學習效益**:
- 練習看圖揣摩情境
- 練習完整句子表達
- 加深例句與情境的連結
- 模仿母語者表達方式
- **適用情境**: 適中詞彙的口語表達練習
### **學習程度適配策略**
#### **A1初學者策略**
```typescript
const A1_REVIEW_TYPES = ['flipcard', 'vocabulary_listening', 'multiple_choice'];
// 統一使用基礎題型,重點建立信心和基本概念
function getA1ReviewType(flashcard: Flashcard): ReviewType {
// 隨機選擇基礎題型,或根據上次表現調整
const weights = {
flipcard: 0.4, // 40% - 主要熟悉方式
multiple_choice: 0.4, // 40% - 概念強化
vocabulary_listening: 0.2 // 20% - 發音熟悉
};
return weightedRandomSelect(A1_REVIEW_TYPES, weights);
}
```
#### **程度適配算法**
```typescript
interface DifficultyMapping {
userLevel: number; // 學習者程度 (1-100)
wordLevel: number; // 詞彙難度 (1-100)
reviewTypes: ReviewType[];
}
function getReviewTypesByDifficulty(userLevel: number, wordLevel: number): ReviewType[] {
const difficulty = wordLevel - userLevel;
if (userLevel <= 20) {
// A1學習者 - 統一基礎題型
return ['flipcard', 'multiple_choice', 'vocabulary_listening'];
} else if (difficulty < -10) {
// 簡單詞彙 (學習者程度 > 詞彙程度)
return ['sentence_reconstruction', 'fill_blank'];
} else if (difficulty >= -10 && difficulty <= 10) {
// 適中詞彙 (學習者程度 ≈ 詞彙程度)
return ['fill_blank', 'sentence_reconstruction', 'sentence_speaking'];
} else {
// 困難詞彙 (學習者程度 < 詞彙程度)
return ['flipcard', 'multiple_choice'];
}
}
```
### **複習題型顯示組件設計**
#### **ReviewTypeIndicator 組件**
```typescript
interface ReviewTypeIndicatorProps {
currentMode: ReviewType;
userLevel: number;
wordLevel: number;
}
export const ReviewTypeIndicator: React.FC<ReviewTypeIndicatorProps> = ({
currentMode,
userLevel,
wordLevel
}) => {
const modeLabels = {
flipcard: '翻卡題',
multiple_choice: '選擇題',
vocabulary_listening: '詞彙聽力',
sentence_listening: '例句聽力',
fill_blank: '填空題',
sentence_reconstruction: '例句重組',
sentence_speaking: '例句口說'
};
const getDifficultyLabel = (userLevel: number, wordLevel: number) => {
const difficulty = wordLevel - userLevel;
if (userLevel <= 20) return 'A1學習者';
if (difficulty < -10) return '簡單詞彙';
if (difficulty >= -10 && difficulty <= 10) return '適中詞彙';
return '困難詞彙';
};
return (
<div className="review-type-indicator">
<div className="current-type">
<span className="type-label">{modeLabels[currentMode]}</span>
<span className="auto-selected">系統智能選擇</span>
</div>
<div className="difficulty-info">
<span className="difficulty-label">
{getDifficultyLabel(userLevel, wordLevel)}適配
</span>
</div>
</div>
);
};
```
#### **更新的狀態管理**
```tsx
interface ReviewState {
currentCard: Flashcard | null;
showAnswer: boolean;
reviewMode: ReviewType; // 系統自動選擇的題型
confidenceLevel: number | null;
userAnswer: string | null;
isCorrect: boolean | null;
isSubmitting: boolean;
currentQuestionData: QuestionData | null;
startTime: number; // 題目開始時間
}
// 移除 availableReviewModes因為用戶不需要選擇
interface QuestionData {
questionType: ReviewType;
options?: string[]; // 選擇題選項
correctAnswer: string; // 正確答案
userLevel: number; // 學習者程度
wordLevel: number; // 詞彙難度
audioUrl?: string; // 聽力題音頻
sentence?: string; // 例句
blankedSentence?: string; // 填空題的挖空句子
scrambledWords?: string[]; // 重組題的打亂單字
}
export const ReviewPage: React.FC = () => {
const [state, setState] = useState<ReviewState>({
currentCard: null,
showAnswer: false,
reviewMode: 'flipcard',
confidenceLevel: null,
userAnswer: null,
isCorrect: null,
isSubmitting: false,
currentQuestionData: null,
startTime: Date.now()
});
useEffect(() => {
loadNextCard();
}, []);
const loadNextCard = async () => {
try {
const response = await reviewApi.getNextReviewCard();
const card = response.data;
// 系統自動選擇最適合的複習模式
const selectedMode = await selectOptimalReviewMode(card);
// 生成對應的題目數據
const questionData = await generateQuestionData(card, selectedMode);
setState(prev => ({
...prev,
currentCard: card,
reviewMode: selectedMode,
currentQuestionData: questionData,
showAnswer: false,
userAnswer: null,
isCorrect: null,
startTime: Date.now()
}));
} catch (error) {
console.error('載入卡片失敗:', error);
}
};
// 新增:系統自動選擇題型的函數
const selectOptimalReviewMode = async (card: Flashcard): Promise<ReviewType> => {
const response = await reviewApi.getOptimalReviewMode(card.id, card.userLevel, card.wordLevel);
return response.data.selectedMode;
};
const handleAnswerSubmit = async (userAnswer: string | boolean) => {
if (!state.currentCard || !state.currentQuestionData) return;
setState(prev => ({ ...prev, isSubmitting: true }));
try {
// 檢查答案正確性
const isCorrect = checkAnswer(userAnswer, state.currentQuestionData);
setState(prev => ({
...prev,
userAnswer: typeof userAnswer === 'string' ? userAnswer : null,
isCorrect,
showAnswer: true
}));
// 提交復習結果
const result = await reviewApi.submitReview(state.currentCard.id, {
isCorrect,
confidenceLevel: state.confidenceLevel,
questionType: state.reviewMode,
userAnswer: typeof userAnswer === 'string' ? userAnswer : null,
timeTaken: Date.now() - state.startTime
});
// 顯示結果反饋
showFeedback(result.data);
} catch (error) {
console.error('復習提交失敗:', error);
} finally {
setState(prev => ({ ...prev, isSubmitting: false }));
}
};
const renderQuestionComponent = () => {
if (!state.currentCard || !state.currentQuestionData) return null;
const commonProps = {
flashcard: state.currentCard,
questionData: state.currentQuestionData,
onAnswerSubmit: handleAnswerSubmit,
isSubmitting: state.isSubmitting,
showResult: state.showAnswer,
isCorrect: state.isCorrect,
userAnswer: state.userAnswer
};
switch (state.reviewMode) {
case 'flipcard':
return <FlipCardQuestion {...commonProps} />;
case 'multiple_choice':
return <MultipleChoiceQuestion {...commonProps} />;
case 'vocabulary_listening':
return <VocabularyListeningQuestion {...commonProps} />;
case 'sentence_listening':
return <SentenceListeningQuestion {...commonProps} />;
case 'fill_blank':
return <FillBlankQuestion {...commonProps} />;
case 'sentence_reconstruction':
return <SentenceReconstructionQuestion {...commonProps} />;
case 'sentence_speaking':
return <SentenceSpeakingQuestion {...commonProps} />;
default:
return <FlipCardQuestion {...commonProps} />;
}
};
return (
<div className="review-page">
{state.currentCard && (
<>
<ReviewTypeIndicator
currentMode={state.reviewMode}
userLevel={state.currentCard.userLevel}
wordLevel={state.currentCard.wordLevel}
/>
{renderQuestionComponent()}
{state.showAnswer && (
<div className="next-card-section">
<button
className="next-btn"
onClick={loadNextCard}
disabled={state.isSubmitting}
>
下一張卡片
</button>
</div>
)}
</>
)}
</div>
);
};
### **現有7種題型UI實現分析**
#### **1. 翻卡記憶 (flip-memory)** 已完成
```typescript
// 基於現有實現 learn/page.tsx lines 412-535
實現特色:
- ✅ 3D翻卡動畫效果 (CSS transform)
- ✅ 動態卡片高度計算 (useLayoutEffect)
- ✅ 前面顯示:詞彙 + 發音 + 音頻播放
- ✅ 背面顯示:定義 + 例句 + 同義詞
- ✅ 自適應響應式設計
- ✅ 錯誤回報功能整合
現有邏輯:點擊翻面,用戶自評熟悉程度
需要整合:信心等級評分 (1-5) + 間隔算法
```
#### **2. 詞彙選擇 (vocab-choice)** ✅ 已完成
```typescript
// 基於現有實現 learn/page.tsx lines 536-647
實現特色:
- 4選項多選題界面
- 選項自動生成邏輯 (避免重複)
- 即時結果反饋 (正確/錯誤高亮)
- 答案解析顯示
- 音頻播放整合
現有邏輯:顯示定義,選擇正確詞彙
需要整合:後端選項生成 + 難度適配
```
#### **3. 例句填空 (sentence-fill)** ✅ 已完成
```typescript
// 基於現有實現 learn/page.tsx lines 649-817
實現特色:
- 動態輸入框 (自適應寬度)
- 例句圖片顯示 + 模態框放大
- 虛線邊框設計美觀
- 大小寫不敏感驗證
- 提示功能 (顯示/隱藏定義)
- Enter鍵快速提交
現有邏輯:挖空例句,用戶填入詞彙
需要整合:後端挖空邏輯 + 拼字評分
```
#### **4. 詞彙聽力 (vocab-listening)** ✅ 已完成
```typescript
// 基於現有實現 learn/page.tsx lines 818-927
實現特色:
- AudioPlayer組件整合
- 2x2網格選項佈局
- 聽力專用UI提示
- 發音展示 + 重複播放
- 選項結果高亮反饋
現有邏輯:播放詞彙發音,選擇正確詞彙
需要整合:音頻檔案管理 + 選項後端生成
```
#### **5. 例句口說 (sentence-speaking)** ✅ 已完成
```typescript
// 基於現有實現 learn/page.tsx lines 928-996
實現特色:
- VoiceRecorder組件完整整合
- 目標例句 + 中文翻譯顯示
- 例句圖片情境提示
- 錄音完成自動處理
- 簡化評分機制
現有邏輯:看圖說例句,錄音提交
需要整合:語音識別評分 + 發音準確度
```
#### **6. 例句重組 (sentence-reorder)** ✅ 已完成
```typescript
// 基於現有實現 learn/page.tsx lines 1064-1228
實現特色:
- 拖放式單字重組界面
- 雙區域設計 (重組區 + 可用單字區)
- 動態單字按鈕 (點擊移動)
- 即時答案檢查邏輯
- 重置功能 + 例句圖片顯示
- 字符串比較驗證 (大小寫不敏感)
現有邏輯:打亂單字,重組成正確例句
需要整合:語法難度評估 + 句型分析
```
#### **7. 例句聽力 (sentence-listening)** ⚠️ 框架完成
```typescript
// 基於現有實現 learn/page.tsx lines 997-1063
實現狀況:
- UI框架和佈局完成
- AudioPlayer整合
- ⚠️ 選項生成邏輯待完成
- ⚠️ 例句音頻檔案管理待完成
現有邏輯:播放例句,選擇正確選項 (開發中)
需要完成:例句選項生成 + 音頻檔案系統
```
### **3. 現有音頻組件整合分析**
#### **AudioPlayer 組件** ✅ 已完成整合
```typescript
// 現有實現已完美整合到各題型中
使用場景:
- 翻卡記憶:詞彙發音播放
- 詞彙聽力:音頻播放按鈕
- 例句聽力:例句音頻播放
- 填空題:提示音頻播放
現有功能:
- 文字轉語音 (TTS)
- 播放控制按鈕
- 載入狀態處理
- 錯誤處理機制
```
#### **VoiceRecorder 組件** ✅ 已完成整合
```typescript
// 完整整合到例句口說題型中
使用特色:
- 麥克風權限處理
- 錄音品質設定
- 即時錄音反饋
- 錄音回放功能
- 目標例句顯示
- 情境圖片輔助
現有Props介面
interface VoiceRecorderProps {
targetText: string; // 目標例句
targetTranslation: string; // 中文翻譯
exampleImage: string; // 情境圖片
instructionText: string; // 指導文字
onRecordingComplete: () => void;
}
```
---
## 🔌 **API 整合 (基於現有架構)**
### **現有服務層 (已完成)**
#### **flashcardsService** (已存在於 `lib/services/flashcards.ts`)
```typescript
// 現有API服務需要擴展智能複習功能
class FlashcardsService {
// ✅ 已完成的基礎功能
async getFlashcards(search?, favoritesOnly?, cefrLevel?, partOfSpeech?, ...): Promise<ApiResponse<FlashcardsResponse>>
async getFlashcard(id: string): Promise<ApiResponse<Flashcard>>
async createFlashcard(data: CreateFlashcardRequest): Promise<ApiResponse<Flashcard>>
async updateFlashcard(id: string, data: Partial<CreateFlashcardRequest>): Promise<ApiResponse<Flashcard>>
async deleteFlashcard(id: string): Promise<ApiResponse<void>>
async toggleFavorite(id: string): Promise<ApiResponse<void>>
// 🆕 需要新增的智能複習方法
async getDueFlashcards(limit = 50): Promise<ApiResponse<Flashcard[]>>
async getNextReviewCard(): Promise<ApiResponse<FlashcardExtended>>
async submitReview(id: string, reviewData: ReviewSubmission): Promise<ApiResponse<ReviewResult>>
async getOptimalReviewMode(cardId: string, userLevel: number, wordLevel: number): Promise<ApiResponse<{selectedMode: ReviewType}>>
async generateQuestionOptions(cardId: string, questionType: ReviewType): Promise<ApiResponse<QuestionData>>
}
```
### **需要新增的智能複習服務**
#### **reviewService.ts** (新增)
```typescript
interface ReviewService {
// 間隔重複算法整合
calculateNextReviewDate(cardId: string, isCorrect: boolean, confidenceLevel?: number): Promise<string>
calculateCurrentMastery(baseMastery: number, lastReviewDate: string): number
// 四情境自動適配
getReviewTypesByDifficulty(userLevel: number, wordLevel: number): ReviewType[]
selectOptimalReviewMode(card: FlashcardExtended, reviewHistory?: ReviewRecord[]): Promise<ReviewType>
// 學習統計和進度
getReviewStatistics(userId: string): Promise<ReviewStats>
getTodayProgress(): Promise<TodayProgress>
// A1學習者保護
isA1Learner(userLevel: number): boolean
getA1ProtectedModes(): ReviewType[]
}
```
### **智能複習邏輯重構方案**
#### **現有狀態 vs 智能化目標**
```typescript
// 現況:手動模式切換
const [mode, setMode] = useState<LearnMode>('flip-memory')
// 目標:系統自動選擇
const [reviewMode, setReviewMode] = useState<ReviewType>()
const [isAutoSelecting, setIsAutoSelecting] = useState(true)
// 重構策略:
// 1. 保留所有現有UI邏輯
// 2. 移除模式切換按鈕組
// 3. 新增 ReviewTypeIndicator 顯示當前題型
// 4. 整合後端自動選擇API
```
#### **智能適配邏輯整合**
```typescript
// 需要新增到現有 learn/page.tsx 的函數
const loadNextCardWithAutoMode = async () => {
try {
// 1. 取得下一張到期詞卡
const cardResponse = await flashcardsService.getNextReviewCard()
if (!cardResponse.success) throw new Error(cardResponse.error)
const card = cardResponse.data
// 2. 系統自動選擇最適合的題型
const modeResponse = await flashcardsService.getOptimalReviewMode(
card.id,
card.userLevel,
card.wordLevel
)
if (!modeResponse.success) throw new Error(modeResponse.error)
const selectedMode = modeResponse.data.selectedMode
// 3. 更新狀態 (無用戶選擇)
setCurrentCard(card)
setMode(selectedMode) // 系統決定的模式
setIsAutoSelecting(false)
// 4. 重置題型專用狀態
resetQuestionStates()
} catch (error) {
console.error('載入複習卡片失敗:', error)
}
}
// 映射系統選擇的題型到現有模式
const mapReviewTypeToMode = (reviewType: ReviewType): LearnMode => {
const mapping = {
'flipcard': 'flip-memory',
'multiple_choice': 'vocab-choice',
'vocabulary_listening': 'vocab-listening',
'sentence_listening': 'sentence-listening',
'fill_blank': 'sentence-fill',
'sentence_reconstruction': 'sentence-reorder',
'sentence_speaking': 'sentence-speaking'
}
return mapping[reviewType] || 'flip-memory'
}
```
```
---
## 🎨 **UI/UX 設計規範**
### **色彩設計**
```css
:root {
/* 熟悉度顏色 */
--mastery-high: #34c759; /* 綠色 80-100% */
--mastery-medium: #007aff; /* 藍色 50-79% */
--mastery-low: #ff3b30; /* 紅色 0-49% */
--mastery-decaying: #ff9500; /* 橙色 衰減中 */
/* 復習狀態顏色 */
--status-due: #007aff; /* 到期 */
--status-overdue: #ff3b30; /* 逾期 */
--status-future: #8e8e93; /* 未到期 */
/* 背景色 */
--bg-primary: #ffffff;
--bg-secondary: #f2f2f7;
--bg-tertiary: #e5e5ea;
}
```
### **響應式設計**
```css
/* 手機端 */
@media (max-width: 768px) {
.flashcard-item {
padding: 12px;
margin: 8px 0;
}
.mastery-indicator.medium {
width: 40px;
height: 40px;
}
}
/* 平板端 */
@media (min-width: 769px) and (max-width: 1024px) {
.card-list {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
}
/* 桌面端 */
@media (min-width: 1025px) {
.card-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
}
```
### **動畫效果**
```css
.mastery-indicator .progress-circle circle {
transition: stroke-dasharray 0.6s ease-in-out;
}
.flashcard-item {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.flashcard-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.decay-icon {
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
```
---
## 📊 **狀態管理**
### **使用 React Context**
```tsx
interface SpacedRepetitionContextValue {
flashcards: Flashcard[];
dueCount: number;
completedToday: number;
refreshFlashcards: () => Promise<void>;
updateFlashcard: (id: number, updates: Partial<Flashcard>) => void;
}
const SpacedRepetitionContext = createContext<SpacedRepetitionContextValue | null>(null);
export const SpacedRepetitionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [flashcards, setFlashcards] = useState<Flashcard[]>([]);
const [dueCount, setDueCount] = useState(0);
const [completedToday, setCompletedToday] = useState(0);
const refreshFlashcards = async () => {
const response = await reviewApi.getAllFlashcards();
setFlashcards(response.data);
// 計算到期數量
const today = new Date().toISOString().split('T')[0];
const due = response.data.filter(card => card.nextReviewDate <= today).length;
setDueCount(due);
};
return (
<SpacedRepetitionContext.Provider value={{
flashcards,
dueCount,
completedToday,
refreshFlashcards,
updateFlashcard
}}>
{children}
</SpacedRepetitionContext.Provider>
);
};
```
---
## 🧪 **測試策略**
### **單元測試**
```javascript
// masteryCalculator.test.js
describe('calculateCurrentMastery', () => {
test('should return base mastery for same day', () => {
const today = new Date().toISOString().split('T')[0];
const result = calculateCurrentMastery(80, today);
expect(result).toBe(80);
});
test('should apply decay for overdue cards', () => {
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
.toISOString().split('T')[0];
const result = calculateCurrentMastery(80, sevenDaysAgo);
expect(result).toBeLessThan(80);
expect(result).toBeGreaterThan(50);
});
});
```
### **整合測試**
- API 呼叫測試
- 組件互動測試
- 狀態更新測試
### **E2E 測試**
- 復習流程測試
- 熟悉度更新測試
- 響應式設計測試
---
## 📋 **智能化重構檢查清單 (基於現有實現)**
### **核心邏輯重構** ⭐ 主要工作
- [ ] **移除手動模式切換** - 刪除7個模式按鈕 (learn/page.tsx lines 337-410)
- [ ] **新增 ReviewTypeIndicator** - 純顯示當前系統選擇的題型
- [ ] **整合自動選擇API** - 替換mock data為真實到期詞卡
- [ ] **四情境適配邏輯** - A1/簡單/適中/困難自動判斷
- [ ] **間隔重複算法** - 整合實時熟悉度計算和下次復習時間
### **API服務擴展**
- [ ] **flashcardsService 擴展** - 新增6個智能複習方法
- [ ] **reviewService 新增** - 專門的複習邏輯服務
- [ ] **masteryCalculator 新增** - 前端熟悉度實時計算
- [ ] **後端API對接** - 確保前後端數據格式一致
### **UI保持和微調**
- [x] **7種題型UI完成** - 現有實現已非常完善
- [x] **音頻功能完成** - AudioPlayer + VoiceRecorder 整合良好
- [x] **響應式設計完成** - 現有設計已適配各種螢幕
- [ ] **新增熟悉度指示器** - 實時顯示當前詞彙熟悉程度
- [ ] **例句聽力補完** - 完成選項邏輯 (目前標記為開發中)
### **狀態管理升級**
- [ ] **擴展現有狀態** - 新增智能複習相關狀態
- [ ] **SpacedRepetitionContext** - 全域復習狀態管理
- [ ] **A1保護邏輯** - 自動限制複雜題型
- [ ] **復習進度追蹤** - 整合間隔重複算法
### **測試和優化**
- [x] **基礎功能測試** - 現有7種題型已運作良好
- [ ] **智能邏輯測試** - 自動選擇和適配算法
- [ ] **A1保護測試** - 確保初學者體驗
- [ ] **性能測試** - API整合後的響應速度
---
## 🚀 **重構時程調整 (大幅縮短)**
**原預估**: 3-4週全新開發
**實際需求**: 1-2週智能化重構
### **Week 1: 核心邏輯重構**
- 移除手動選擇 + 整合自動選擇API
- 新增智能適配邏輯
- 完成例句聽力補完
### **Week 2: 測試和優化**
- API整合測試
- A1保護邏輯驗證
- 性能優化和錯誤處理
**重構優勢**:
- ✅ UI已完成95%,無需重建
- ✅ 音頻功能完整,無需重寫
- ✅ 7種題型邏輯成熟只需API整合