import React, { useState, useEffect } from "react"; import { useSearchParams, useNavigate } from "react-router-dom"; import { Button, message, Typography } from "antd"; import { ArrowLeftOutlined } from "@ant-design/icons"; import type { Question, AnswerResult } from "../types/question"; import * as questionApi from "../api/question"; import QuestionProgress from "../components/QuestionProgress"; import QuestionCard from "../components/QuestionCard"; import CompletionSummary from "../components/CompletionSummary"; import styles from "./Question.module.less"; const { Title } = Typography; const QuestionPage: React.FC = () => { const [searchParams] = useSearchParams(); const navigate = useNavigate(); const [currentQuestion, setCurrentQuestion] = useState(null); const [selectedAnswer, setSelectedAnswer] = useState(""); const [showResult, setShowResult] = useState(false); const [answerResult, setAnswerResult] = useState(null); const [loading, setLoading] = useState(false); const [autoNextLoading, setAutoNextLoading] = useState(false); const [allQuestions, setAllQuestions] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); // 答题统计 const [correctCount, setCorrectCount] = useState(0); const [wrongCount, setWrongCount] = useState(0); const [showSummary, setShowSummary] = useState(false); // 从localStorage恢复答题进度 const getStorageKey = () => { const type = searchParams.get("type"); const mode = searchParams.get("mode"); return `question_progress_${type || mode || "default"}`; }; // 保存答题进度 const saveProgress = (index: number, correct: number, wrong: number) => { const key = getStorageKey(); localStorage.setItem( key, JSON.stringify({ currentIndex: index, correctCount: correct, wrongCount: wrong, timestamp: Date.now(), }) ); }; // 恢复答题进度 const loadProgress = () => { const key = getStorageKey(); const saved = localStorage.getItem(key); if (saved) { try { const progress = JSON.parse(saved); setCurrentIndex(progress.currentIndex || 0); setCorrectCount(progress.correctCount || 0); setWrongCount(progress.wrongCount || 0); return progress.currentIndex || 0; } catch (e) { console.error("恢复进度失败", e); } } return 0; }; // 加载随机题目 const loadRandomQuestion = async () => { setLoading(true); try { // 检查是否是错题练习模式 const mode = searchParams.get("mode"); const res = mode === "wrong" ? await questionApi.getRandomWrongQuestion() : await questionApi.getRandomQuestion(); if (res.success && res.data) { setCurrentQuestion(res.data); setSelectedAnswer(res.data.type === "multiple-selection" ? [] : ""); setShowResult(false); setAnswerResult(null); } } catch (error: any) { if (error.response?.status === 401) { message.error("请先登录"); } else if (error.response?.status === 404) { message.error("暂无错题"); } else { message.error("加载题目失败"); } } finally { setLoading(false); } }; // 加载题目列表(从第一题开始) const loadQuestions = async (type?: string) => { setLoading(true); try { const res = await questionApi.getQuestions({ type }); if (res.success && res.data) { setAllQuestions(res.data); // 恢复答题进度 const savedIndex = loadProgress(); const startIndex = savedIndex < res.data.length ? savedIndex : 0; if (res.data.length > 0) { setCurrentQuestion(res.data[startIndex]); setCurrentIndex(startIndex); setSelectedAnswer( res.data[startIndex].type === "multiple-selection" ? [] : "" ); setShowResult(false); setAnswerResult(null); } } } catch (error) { message.error("加载题目列表失败"); } finally { setLoading(false); } }; // 提交答案 const handleSubmit = async () => { if (!currentQuestion) return; // 检查是否选择了答案 if (currentQuestion.type === "multiple-selection") { if ((selectedAnswer as string[]).length === 0) { message.warning("请选择答案"); return; } } else if (currentQuestion.type === "fill-in-blank") { const answers = selectedAnswer as string[]; if (answers.length === 0 || answers.some((a) => !a || a.trim() === "")) { message.warning("请填写所有空格"); return; } } else { if ( !selectedAnswer || (typeof selectedAnswer === "string" && selectedAnswer.trim() === "") ) { message.warning("请填写答案"); return; } } setLoading(true); try { // 处理判断题答案:将字符串 "true"/"false" 转换为布尔值 let answerToSubmit: string | string[] | boolean = selectedAnswer; if (currentQuestion.type === "true-false" && typeof selectedAnswer === "string") { answerToSubmit = selectedAnswer === "true"; } const res = await questionApi.submitAnswer({ question_id: currentQuestion.id, answer: answerToSubmit, }); if (res.success && res.data) { setAnswerResult(res.data); setShowResult(true); // 更新统计 if (res.data.correct) { const newCorrect = correctCount + 1; setCorrectCount(newCorrect); saveProgress(currentIndex, newCorrect, wrongCount); } else { const newWrong = wrongCount + 1; setWrongCount(newWrong); saveProgress(currentIndex, correctCount, newWrong); } // 如果答案正确,1秒后自动进入下一题 if (res.data.correct) { setAutoNextLoading(true); setTimeout(() => { setAutoNextLoading(false); handleNext(); }, 1000); } } } catch (error) { message.error("提交失败"); } finally { setLoading(false); } }; // 下一题 const handleNext = () => { if (allQuestions.length > 0) { // 检查是否完成所有题目 if (currentIndex + 1 >= allQuestions.length) { // 显示统计摘要 setShowSummary(true); // 清除进度 localStorage.removeItem(getStorageKey()); return; } const nextIndex = currentIndex + 1; setCurrentIndex(nextIndex); setCurrentQuestion(allQuestions[nextIndex]); setSelectedAnswer( allQuestions[nextIndex].type === "multiple-selection" ? [] : "" ); setShowResult(false); setAnswerResult(null); // 保存进度 saveProgress(nextIndex, correctCount, wrongCount); // 滚动到页面顶部 window.scrollTo({ top: 0, behavior: 'smooth' }); } }; // 初始化 useEffect(() => { const typeParam = searchParams.get("type"); const mode = searchParams.get("mode"); // 错题练习模式 if (mode === "wrong") { loadRandomQuestion(); return; } // 普通练习模式 - 从第一题开始 loadQuestions(typeParam || undefined); }, [searchParams]); // 重试处理 const handleRetry = () => { setShowSummary(false); setCurrentIndex(0); setCorrectCount(0); setWrongCount(0); localStorage.removeItem(getStorageKey()); const typeParam = searchParams.get("type"); loadQuestions(typeParam || undefined); }; return (
{/* 固定顶栏:包含导航和进度 */}
{/* 头部导航 */}
AnKao 刷题
正确 {correctCount}
错误 {wrongCount}
{/* 进度条 */}
{/* 主内容区 */}
{/* 题目卡片 */} {currentQuestion && ( )}
{/* 完成统计摘要 */} { setShowSummary(false); navigate("/"); }} onRetry={handleRetry} />
); }; export default QuestionPage;