154 lines
6.3 KiB
TypeScript
154 lines
6.3 KiB
TypeScript
import { TestItem } from '@/lib/data/reviewSimpleData'
|
|
|
|
interface SimpleProgressProps {
|
|
currentTestItem?: TestItem
|
|
totalTestItems: number
|
|
completedTestItems: number
|
|
score: { correct: number; total: number }
|
|
testItems?: TestItem[] // 用於顯示測驗項目統計
|
|
}
|
|
|
|
export function SimpleProgress({ currentTestItem, totalTestItems, completedTestItems, score, testItems }: SimpleProgressProps) {
|
|
const progress = (completedTestItems / totalTestItems) * 100
|
|
const accuracy = score.total > 0 ? Math.round((score.correct / score.total) * 100) : 0
|
|
|
|
// 測驗項目延遲統計計算
|
|
const delayStats = testItems ? {
|
|
totalSkips: testItems.reduce((sum, item) => sum + item.skipCount, 0),
|
|
totalWrongs: testItems.reduce((sum, item) => sum + item.wrongCount, 0),
|
|
delayedItems: testItems.filter(item => item.skipCount + item.wrongCount > 0).length
|
|
} : null
|
|
|
|
return (
|
|
<div className="mb-8">
|
|
<div className="flex justify-between items-center mb-3">
|
|
<div>
|
|
<span className="text-sm font-medium text-gray-600">線性複習進度</span>
|
|
{currentTestItem && (
|
|
<div className="flex items-center mt-1">
|
|
<span className="text-lg mr-2">
|
|
{currentTestItem.testType === 'flip-card' ? '🔄' : '🎯'}
|
|
</span>
|
|
<span className="text-sm text-gray-500">
|
|
{currentTestItem.testType === 'flip-card' ? '翻卡記憶' : '詞彙選擇'} • {currentTestItem.cardData.word}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-4 text-sm text-right">
|
|
<span className="text-gray-600">
|
|
{completedTestItems}/{totalTestItems} 項目
|
|
</span>
|
|
{score.total > 0 && (
|
|
<span className="text-green-600 font-medium">
|
|
準確率 {accuracy}%
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 進度條 */}
|
|
<div className="w-full bg-gray-200 rounded-full h-3">
|
|
<div
|
|
className="bg-blue-500 h-3 rounded-full transition-all duration-300"
|
|
style={{ width: `${progress}%` }}
|
|
/>
|
|
</div>
|
|
|
|
{/* 詳細統計 */}
|
|
<div className="flex justify-center gap-4 mt-3 text-sm">
|
|
{score.total > 0 && (
|
|
<>
|
|
<div className="flex items-center gap-1">
|
|
<span className="w-2 h-2 bg-green-500 rounded-full"></span>
|
|
<span className="text-green-700">答對 {score.correct}</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<span className="w-2 h-2 bg-red-500 rounded-full"></span>
|
|
<span className="text-red-700">答錯 {score.total - score.correct}</span>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{/* 延遲統計 */}
|
|
{delayStats && (delayStats.totalSkips > 0 || delayStats.totalWrongs > 0) && (
|
|
<>
|
|
{score.total > 0 && <span className="text-gray-400">|</span>}
|
|
<div className="flex items-center gap-1">
|
|
<span className="w-2 h-2 bg-yellow-500 rounded-full"></span>
|
|
<span className="text-yellow-700">跳過次數 {delayStats.totalSkips}</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<span className="w-2 h-2 bg-blue-500 rounded-full"></span>
|
|
<span className="text-blue-700">跳過卡片 {delayStats.delayedItems}</span>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* 測驗項目順序可視化 */}
|
|
{testItems && currentTestItem && (
|
|
<div className="mt-4">
|
|
<div className="bg-white/50 rounded-lg p-3">
|
|
<p className="text-sm text-gray-600 mb-2">測驗項目序列 (線性流程):</p>
|
|
<div className="flex flex-wrap gap-2">
|
|
{testItems.slice(0, 12).map((item) => {
|
|
const isCompleted = item.isCompleted
|
|
const isCurrent = item.id === currentTestItem?.id
|
|
const delayScore = item.skipCount + item.wrongCount
|
|
|
|
// 狀態顏色
|
|
let itemStyle = ''
|
|
let statusText = ''
|
|
|
|
if (isCompleted) {
|
|
itemStyle = 'bg-green-100 text-green-700 border-green-300'
|
|
statusText = '✓'
|
|
} else if (delayScore > 0) {
|
|
if (item.skipCount > 0 && item.wrongCount > 0) {
|
|
itemStyle = 'bg-red-100 text-red-700 border-red-300'
|
|
statusText = `${item.skipCount}+${item.wrongCount}`
|
|
} else if (item.skipCount > 0) {
|
|
itemStyle = 'bg-yellow-100 text-yellow-700 border-yellow-300'
|
|
statusText = `跳${item.skipCount}`
|
|
} else {
|
|
itemStyle = 'bg-orange-100 text-orange-700 border-orange-300'
|
|
statusText = `錯${item.wrongCount}`
|
|
}
|
|
} else {
|
|
itemStyle = 'bg-gray-100 text-gray-600 border-gray-300'
|
|
statusText = ''
|
|
}
|
|
|
|
return (
|
|
<div
|
|
key={item.id}
|
|
className={`px-3 py-2 rounded-lg border text-sm font-medium ${itemStyle}`}
|
|
>
|
|
<div className="flex items-center gap-1">
|
|
<span className="text-xs">
|
|
{item.testType === 'flip-card' ? '🔄' : '🎯'}
|
|
</span>
|
|
<span>{item.cardData.word}</span>
|
|
{statusText && (
|
|
<span className="text-xs">({statusText})</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
})}
|
|
{testItems.length > 12 && (
|
|
<div className="px-3 py-2 text-sm text-gray-500">
|
|
...還有 {testItems.length - 12} 個項目
|
|
</div>
|
|
)}
|
|
</div>
|
|
<p className="text-xs text-gray-500 mt-2 text-right">
|
|
🟢完成、🟡跳過、🟠答錯、🔴多次&答錯、⚪待進行
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
} |