-
-
-
-
-
-
-
系统设置
-
管理员:{user?.username}
-
-
-
-
+
+
{/* Content */}
-
+
{/* Basic Settings */}
基础设置
diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx
index 6df634a..b773cc1 100644
--- a/frontend/src/pages/Dashboard.jsx
+++ b/frontend/src/pages/Dashboard.jsx
@@ -5,7 +5,7 @@ import React, { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { examAPI, mistakeAPI } from '../api/client'
import { useAuth } from '../context/AuthContext'
-import Layout from '../components/Layout'
+
import {
FolderOpen, XCircle, TrendingUp, BookOpen, ArrowRight, Settings, Shield
} from 'lucide-react'
@@ -58,7 +58,7 @@ export const Dashboard = () => {
}
return (
-
+ <>
{/* Welcome */}
@@ -179,35 +179,8 @@ export const Dashboard = () => {
)}
- {/* Admin Quick Access */}
- {isAdmin && (
-
-
-
-
管理员功能
-
用户管理、系统统计、配置设置
-
-
-
-
-
-
-
- )}
-
+ >
)
}
diff --git a/frontend/src/pages/ExamDetail.jsx b/frontend/src/pages/ExamDetail.jsx
index b4e679b..a175e91 100644
--- a/frontend/src/pages/ExamDetail.jsx
+++ b/frontend/src/pages/ExamDetail.jsx
@@ -4,7 +4,6 @@
import React, { useState, useEffect, useRef } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { examAPI, questionAPI } from '../api/client'
-import Layout from '../components/Layout'
import ParsingProgress from '../components/ParsingProgress'
import {
ArrowLeft, Upload, Play, Loader, FileText, AlertCircle, RefreshCw, ArrowRight
@@ -155,22 +154,18 @@ export const ExamDetail = () => {
if (loading) {
return (
-
-
-
-
-
+
+
+
)
}
if (!exam) {
return (
-
-
-
+
)
}
@@ -180,7 +175,7 @@ export const ExamDetail = () => {
const quizProgress = calculateProgress(exam.current_index, exam.total_questions)
return (
-
+ <>
{/* Back Button */}
)}
-
+ >
)
}
diff --git a/frontend/src/pages/ExamList.jsx b/frontend/src/pages/ExamList.jsx
index d33283b..d25ec40 100644
--- a/frontend/src/pages/ExamList.jsx
+++ b/frontend/src/pages/ExamList.jsx
@@ -4,7 +4,6 @@
import React, { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { examAPI } from '../api/client'
-import Layout from '../components/Layout'
import {
Plus, FolderOpen, Loader, AlertCircle, Trash2, Upload
} from 'lucide-react'
@@ -131,16 +130,14 @@ export const ExamList = () => {
if (loading) {
return (
-
-
-
-
-
+
+
+
)
}
return (
-
+ <>
{/* Header */}
@@ -150,10 +147,11 @@ export const ExamList = () => {
@@ -337,7 +335,7 @@ export const ExamList = () => {
)}
-
+ >
)
}
diff --git a/frontend/src/pages/MistakeList.jsx b/frontend/src/pages/MistakeList.jsx
index 065855b..3f2b90f 100644
--- a/frontend/src/pages/MistakeList.jsx
+++ b/frontend/src/pages/MistakeList.jsx
@@ -4,9 +4,8 @@
import React, { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { mistakeAPI } from '../api/client'
-import Layout from '../components/Layout'
import Pagination from '../components/Pagination'
-import { XCircle, Loader, Trash2, BookOpen, Play } from 'lucide-react'
+import { XCircle, Loader, Trash2, BookOpen, Play, ChevronRight } from 'lucide-react'
import toast from 'react-hot-toast'
import { getQuestionTypeText, formatRelativeTime } from '../utils/helpers'
@@ -62,16 +61,14 @@ export const MistakeList = () => {
if (loading) {
return (
-
-
-
-
-
+
+
+
)
}
return (
-
+ <>
{/* Header */}
@@ -83,10 +80,11 @@ export const MistakeList = () => {
{mistakes.length > 0 && (
)}
@@ -237,7 +235,7 @@ export const MistakeList = () => {
)}
-
+ >
)
}
diff --git a/frontend/src/pages/MistakePlayer.jsx b/frontend/src/pages/MistakePlayer.jsx
index 46be56d..0ab8c19 100644
--- a/frontend/src/pages/MistakePlayer.jsx
+++ b/frontend/src/pages/MistakePlayer.jsx
@@ -4,7 +4,6 @@
import React, { useState, useEffect } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'
import { mistakeAPI, questionAPI } from '../api/client'
-import Layout from '../components/Layout'
import {
ArrowLeft, ArrowRight, Check, X, Loader, Trash2, AlertCircle
} from 'lucide-react'
@@ -13,16 +12,17 @@ import { getQuestionTypeText } from '../utils/helpers'
export const MistakePlayer = () => {
const navigate = useNavigate()
-
const location = useLocation()
const searchParams = new URLSearchParams(location.search)
const mode = searchParams.get('mode') || 'sequential'
+ console.log('MistakePlayer mounted, mode:', mode)
+
const [loading, setLoading] = useState(true)
const [mistake, setMistake] = useState(null)
const [currentIndex, setCurrentIndex] = useState(0)
const [total, setTotal] = useState(0)
- const [randomIds, setRandomIds] = useState([]) // For random mode
+ const [randomMistakes, setRandomMistakes] = useState([]) // Store full mistake objects
const [submitting, setSubmitting] = useState(false)
const [userAnswer, setUserAnswer] = useState('')
@@ -31,7 +31,7 @@ export const MistakePlayer = () => {
useEffect(() => {
loadMistake()
- }, [currentIndex])
+ }, [currentIndex, mode])
const loadMistake = async () => {
try {
@@ -41,49 +41,26 @@ export const MistakePlayer = () => {
if (mode === 'random') {
// Random Mode Logic
- if (randomIds.length === 0) {
- // First load: fetch all mistakes to get IDs
- // Note: fetching up to 1000 for now. For larger datasets, we need a specific API to get just IDs.
+ if (randomMistakes.length === 0) {
+ // First load: fetch all mistakes
const response = await mistakeAPI.getList(0, 1000)
const allMistakes = response.data.mistakes
setTotal(response.data.total)
if (allMistakes.length > 0) {
- // Shuffle IDs
- const ids = allMistakes.map(m => m.id)
- for (let i = ids.length - 1; i > 0; i--) {
+ // Shuffle mistakes
+ const shuffled = [...allMistakes]
+ for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
- [ids[i], ids[j]] = [ids[j], ids[i]];
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
- setRandomIds(ids)
-
- // Get first mistake from shuffled list
- // We need to find the full mistake object from our initial fetch
- // (Since we fetched all, we have it)
- const firstId = ids[0]
- currentMistake = allMistakes.find(m => m.id === firstId)
+ setRandomMistakes(shuffled)
+ currentMistake = shuffled[0]
}
} else {
- // Subsequent loads: use stored random IDs
- // We need to fetch the specific mistake details if we don't have them cached
- // But wait, mistakeAPI.getList is pagination based.
- // We can't easily "get mistake by ID" using getList without knowing its index.
- // However, we have `mistakeAPI.remove` but not `getById`.
- // Actually, the `mistake` object contains the `question`.
- // If we only have the ID, we might need an API to get mistake by ID.
- // But since we fetched ALL mistakes initially (up to 1000), we can just store the whole objects in randomIds?
- // No, that's too much memory if many.
-
- // Let's assume for now we fetched all and stored them in a "cache" or just store the list of objects if < 1000.
- // For simplicity and performance on small datasets:
- // If randomIds contains objects, use them.
-
- // REVISION: Let's just store the full shuffled list of mistakes in state if < 1000.
- // If > 1000, this approach needs backend support for "random fetch".
- // Given the user requirements, let's assume < 1000 for now.
-
- if (currentIndex < randomIds.length) {
- currentMistake = randomIds[currentIndex]
+ // Subsequent loads: use stored mistakes
+ if (currentIndex < randomMistakes.length) {
+ currentMistake = randomMistakes[currentIndex]
}
}
} else {
@@ -101,15 +78,10 @@ export const MistakePlayer = () => {
currentMistake.question.options = ['A. 正确', 'B. 错误']
}
setMistake(currentMistake)
+ console.log('Mistake loaded:', currentMistake)
setResult(null)
setUserAnswer('')
setMultipleAnswers([])
-
- // If we just initialized random mode, update state
- if (mode === 'random' && randomIds.length === 0) {
- // This part is tricky because state updates are async.
- // We handled the initialization above.
- }
} else {
setMistake(null)
}
@@ -118,6 +90,7 @@ export const MistakePlayer = () => {
toast.error('加载错题失败')
} finally {
setLoading(false)
+ console.log('Loading finished')
}
}
@@ -176,8 +149,8 @@ export const MistakePlayer = () => {
// If we remove the last item, we need to go back one step or show empty
if (mode === 'random') {
// Remove from random list
- const newRandomList = randomIds.filter(m => m.id !== mistake.id)
- setRandomIds(newRandomList)
+ const newRandomList = randomMistakes.filter(m => m.id !== mistake.id)
+ setRandomMistakes(newRandomList)
setTotal(newRandomList.length)
if (currentIndex >= newRandomList.length && newRandomList.length > 0) {
@@ -219,35 +192,46 @@ export const MistakePlayer = () => {
if (loading && !mistake) {
return (
-
-
-
-
-
+
+
+
)
}
if (!mistake) {
return (
-
-
-
-
错题本为空
-
-
-
+
+
+
错题本为空
+
+
)
}
const question = mistake.question
+ if (!question) {
+ return (
+
+
+
题目数据缺失
+
+
+ )
+ }
+
return (
-
+ <>
{/* Header */}
@@ -421,7 +405,7 @@ export const MistakePlayer = () => {
)}
-
+ >
)
}
diff --git a/frontend/src/pages/QuestionBank.jsx b/frontend/src/pages/QuestionBank.jsx
index 9140784..12122b7 100644
--- a/frontend/src/pages/QuestionBank.jsx
+++ b/frontend/src/pages/QuestionBank.jsx
@@ -3,7 +3,6 @@
*/
import React, { useState, useEffect } from 'react'
import { questionAPI } from '../api/client'
-import Layout from '../components/Layout'
import Pagination from '../components/Pagination'
import { FileText, Loader, Search } from 'lucide-react'
import toast from 'react-hot-toast'
@@ -44,16 +43,14 @@ export const QuestionBank = () => {
if (loading && questions.length === 0) {
return (
-
-
-
-
-
+
+
+
)
}
return (
-
+ <>
{/* Header */}
@@ -152,7 +149,7 @@ export const QuestionBank = () => {
}}
/>
-
+ >
)
}
diff --git a/frontend/src/pages/QuizPlayer.jsx b/frontend/src/pages/QuizPlayer.jsx
index d7200e4..49df908 100644
--- a/frontend/src/pages/QuizPlayer.jsx
+++ b/frontend/src/pages/QuizPlayer.jsx
@@ -4,7 +4,6 @@
import React, { useState, useEffect } from 'react'
import { useParams, useNavigate, useSearchParams } from 'react-router-dom'
import { examAPI, questionAPI, mistakeAPI } from '../api/client'
-import Layout from '../components/Layout'
import {
ArrowLeft, ArrowRight, Check, X, Loader, BookmarkPlus, BookmarkX, AlertCircle
} from 'lucide-react'
@@ -159,27 +158,23 @@ export const QuizPlayer = () => {
if (loading) {
return (
-
-
-
-
-
+
+
+
)
}
if (!question) {
return (
-
-
-
+
)
}
return (
-
+ <>
{/* Header */}
@@ -212,8 +207,8 @@ export const QuizPlayer = () => {
)}
-
+ >
)
}