feat: 完善AI生成頁面功能與體驗
- 修復詞彙顏色邏輯,實現基於用戶程度的相對難度顯示 - A2用戶看B2詞彙現在正確顯示橘色(挑戰等級),而非固定藍色 - 新增分析結果localStorage持久化,跳頁後保留分析內容 - 添加簡潔的用戶程度指示器,使用經典齒輪圖標 - 程度按鈕靠右對齊,固定灰色主題,清楚導航到設定頁面 提升個人化學習體驗和界面一致性 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2c204c1146
commit
1b6e62de95
|
|
@ -1,12 +1,12 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState, useMemo, useCallback } from 'react'
|
import { useState, useMemo, useCallback, useEffect } from 'react'
|
||||||
import { ProtectedRoute } from '@/components/shared/ProtectedRoute'
|
import { ProtectedRoute } from '@/components/shared/ProtectedRoute'
|
||||||
import { Navigation } from '@/components/shared/Navigation'
|
import { Navigation } from '@/components/shared/Navigation'
|
||||||
import { WordPopup } from '@/components/word/WordPopup'
|
import { WordPopup } from '@/components/word/WordPopup'
|
||||||
import { useToast } from '@/components/shared/Toast'
|
import { useToast } from '@/components/shared/Toast'
|
||||||
import { flashcardsService } from '@/lib/services/flashcards'
|
import { flashcardsService } from '@/lib/services/flashcards'
|
||||||
import { getLevelIndex, getTargetLearningRange } from '@/lib/utils/cefrUtils'
|
import { getLevelIndex } from '@/lib/utils/cefrUtils'
|
||||||
import { useWordAnalysis } from '@/hooks/word/useWordAnalysis'
|
import { useWordAnalysis } from '@/hooks/word/useWordAnalysis'
|
||||||
import { API_CONFIG } from '@/lib/config/api'
|
import { API_CONFIG } from '@/lib/config/api'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
@ -49,8 +49,50 @@ function GenerateContent() {
|
||||||
const [selectedIdiom, setSelectedIdiom] = useState<string | null>(null)
|
const [selectedIdiom, setSelectedIdiom] = useState<string | null>(null)
|
||||||
const [selectedWord, setSelectedWord] = useState<string | null>(null)
|
const [selectedWord, setSelectedWord] = useState<string | null>(null)
|
||||||
|
|
||||||
|
// localStorage 快取函數
|
||||||
|
const saveAnalysisToCache = useCallback((cacheData: any) => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem('generate_analysis_cache', JSON.stringify(cacheData))
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('無法保存分析快取:', error)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const loadAnalysisFromCache = useCallback(() => {
|
||||||
|
try {
|
||||||
|
const cached = localStorage.getItem('generate_analysis_cache')
|
||||||
|
return cached ? JSON.parse(cached) : null
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('無法載入分析快取:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const clearAnalysisCache = useCallback(() => {
|
||||||
|
try {
|
||||||
|
localStorage.removeItem('generate_analysis_cache')
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('無法清除分析快取:', error)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// 組件載入時恢復快取的分析結果
|
||||||
|
useEffect(() => {
|
||||||
|
const cached = loadAnalysisFromCache()
|
||||||
|
if (cached) {
|
||||||
|
setTextInput(cached.textInput || '')
|
||||||
|
setSentenceAnalysis(cached.sentenceAnalysis || null)
|
||||||
|
setSentenceMeaning(cached.sentenceMeaning || '')
|
||||||
|
setGrammarCorrection(cached.grammarCorrection || null)
|
||||||
|
setShowAnalysisView(cached.showAnalysisView || false)
|
||||||
|
console.log('✅ 已恢復快取的分析結果')
|
||||||
|
}
|
||||||
|
}, [loadAnalysisFromCache])
|
||||||
|
|
||||||
// 處理句子分析 - 使用真實API
|
// 處理句子分析 - 使用真實API
|
||||||
const handleAnalyzeSentence = async () => {
|
const handleAnalyzeSentence = async () => {
|
||||||
|
// 清除舊的分析快取
|
||||||
|
clearAnalysisCache()
|
||||||
|
|
||||||
setIsAnalyzing(true)
|
setIsAnalyzing(true)
|
||||||
|
|
||||||
|
|
@ -126,6 +168,29 @@ function GenerateContent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
setShowAnalysisView(true)
|
setShowAnalysisView(true)
|
||||||
|
|
||||||
|
// 保存分析結果到快取
|
||||||
|
const cacheData = {
|
||||||
|
textInput,
|
||||||
|
sentenceAnalysis: analysisData,
|
||||||
|
sentenceMeaning: apiData.sentenceMeaning || '',
|
||||||
|
grammarCorrection: apiData.grammarCorrection ? {
|
||||||
|
hasErrors: apiData.grammarCorrection.hasErrors,
|
||||||
|
originalText: textInput,
|
||||||
|
correctedText: apiData.grammarCorrection.correctedText || textInput,
|
||||||
|
corrections: apiData.grammarCorrection.corrections || [],
|
||||||
|
confidenceScore: apiData.grammarCorrection.confidenceScore || 1.0
|
||||||
|
} : {
|
||||||
|
hasErrors: false,
|
||||||
|
originalText: textInput,
|
||||||
|
correctedText: textInput,
|
||||||
|
corrections: [],
|
||||||
|
confidenceScore: 1.0
|
||||||
|
},
|
||||||
|
showAnalysisView: true
|
||||||
|
}
|
||||||
|
saveAnalysisToCache(cacheData)
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in sentence analysis:', error)
|
console.error('Error in sentence analysis:', error)
|
||||||
setGrammarCorrection({
|
setGrammarCorrection({
|
||||||
|
|
@ -299,32 +364,25 @@ function GenerateContent() {
|
||||||
'🔍 分析句子'
|
'🔍 分析句子'
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
{/* 個人化程度指示器 */}
|
|
||||||
<div className="text-center text-sm text-gray-600 mt-2">
|
|
||||||
{(() => {
|
|
||||||
const userLevel = localStorage.getItem('userEnglishLevel') || 'A2'
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-center gap-2">
|
|
||||||
<span>🎯 您的程度: {userLevel}</span>
|
|
||||||
<span className="text-gray-400">|</span>
|
|
||||||
<span>📈 重點學習範圍: {getTargetLearningRange(userLevel)}</span>
|
|
||||||
<Link
|
|
||||||
href="/settings"
|
|
||||||
className="text-blue-500 hover:text-blue-700 ml-2"
|
|
||||||
>
|
|
||||||
調整 ⚙️
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
/* 重新設計的句子分析視圖 - 簡潔流暢 */
|
/* 重新設計的句子分析視圖 - 簡潔流暢 */
|
||||||
<>
|
<>
|
||||||
|
{/* 用戶程度指示器 */}
|
||||||
|
<div className="flex justify-end mb-6">
|
||||||
|
<Link
|
||||||
|
href="/profile"
|
||||||
|
className="flex items-center gap-2 px-4 py-2 rounded-lg transition-colors hover:shadow-md bg-gray-100 text-gray-700 border border-gray-200"
|
||||||
|
>
|
||||||
|
<span className="text-sm font-medium">你的程度 {userLevel}</span>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth="2">
|
||||||
|
<path d="M12 15a3 3 0 100-6 3 3 0 000 6z"/>
|
||||||
|
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/>
|
||||||
|
</svg>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 語法修正面板 - 如果需要的話 */}
|
{/* 語法修正面板 - 如果需要的話 */}
|
||||||
{grammarCorrection && grammarCorrection.hasErrors && (
|
{grammarCorrection && grammarCorrection.hasErrors && (
|
||||||
<div className="bg-yellow-50 border border-yellow-200 rounded-xl p-6 mb-6">
|
<div className="bg-yellow-50 border border-yellow-200 rounded-xl p-6 mb-6">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue