Files
gongxue-base/apps/taro/src/pages/student/reports/index.tsx
2026-06-29 13:03:02 +08:00

86 lines
4.0 KiB
TypeScript
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.

import { useEffect, useState } from 'react';
import Taro, { useRouter } from '@tarojs/taro';
import { Button, Text, View } from '@tarojs/components';
import { loadPracticeReports, loadPracticeSessionReport, type PracticeReport } from '@/services/learning';
import '../student.css';
function percent(value?: number) {
return `${Math.round((value || 0) * 100)}%`;
}
export default function StudentReportsPage() {
const router = useRouter();
const practiceSessionId = router.params?.practiceSessionId || '';
const [report, setReport] = useState<PracticeReport | null>(null);
const [reports, setReports] = useState<PracticeReport[]>([]);
const [error, setError] = useState('');
useEffect(() => {
if (practiceSessionId) {
loadPracticeSessionReport(practiceSessionId)
.then(payload => setReport(payload.item || null))
.catch(nextError => setError(nextError instanceof Error ? nextError.message : '报告加载失败'));
return;
}
loadPracticeReports({ limit: 20 })
.then(payload => setReports(payload.items || []))
.catch(nextError => setError(nextError instanceof Error ? nextError.message : '报告列表加载失败'));
}, [practiceSessionId]);
const current = report || reports[0] || null;
return (
<View className='student-page'>
<View className='student-topbar'>
<View className='student-title-block'>
<Text className='student-kicker'>Report</Text>
<Text className='student-title'></Text>
<Text className='student-subtitle'> session </Text>
</View>
<Button className='secondary-button' onClick={() => Taro.navigateBack()}></Button>
</View>
{current ? (
<View className='report-panel'>
<Text className='metric-value'>{String(current.score)} / {String(current.totalScore)}</Text>
<Text className='metric-label'>{current.mode} · {percent(current.accuracy)} · {current.answeredCount}/{current.totalQuestions}</Text>
<View className='grid-two section-block'>
<View className='metric'><Text className='metric-value'>{String(current.correctCount)}</Text><Text className='metric-label'></Text></View>
<View className='metric'><Text className='metric-value'>{String(current.wrongCount)}</Text><Text className='metric-label'></Text></View>
</View>
</View>
) : <View className='empty-state'></View>}
{current?.sectionStats?.length ? (
<View className='section-block'>
<Text className='section-heading'></Text>
<View className='list-stack'>
{current.sectionStats.map((section, index) => (
<View className='list-row' key={String(section.key || index)}>
<Text className='row-main'>{String(section.title || section.key || '分段')}</Text>
<Text className='row-meta'> {String(section.score || 0)} / {String(section.totalScore || 0)} · {String(section.correctCount || 0)} / {String(section.questionCount || 0)}</Text>
</View>
))}
</View>
</View>
) : null}
{!practiceSessionId && reports.length > 1 ? (
<View className='section-block'>
<Text className='section-heading'></Text>
<View className='list-stack'>
{reports.slice(1).map(item => (
<View className='list-row' key={item.id} onClick={() => setReport(item)}>
<Text className='row-main'>{item.mode} · {String(item.score)} / {String(item.totalScore)}</Text>
<Text className='row-meta'> {percent(item.accuracy)} · {item.submittedAt ? item.submittedAt.slice(0, 10) : ''}</Text>
</View>
))}
</View>
</View>
) : null}
{error ? <Text className='error-text'>{error}</Text> : null}
</View>
);
}