diff --git a/src/pages/PerformanceDomainPracticePage.tsx b/src/pages/PerformanceDomainPracticePage.tsx index c088551..0198473 100644 --- a/src/pages/PerformanceDomainPracticePage.tsx +++ b/src/pages/PerformanceDomainPracticePage.tsx @@ -1,10 +1,11 @@ -import { useEffect, useMemo, useState, type ReactNode } from 'react' +import { useEffect, useMemo, useState } from 'react' import { motion } from 'framer-motion' import { Link } from 'react-router-dom' import clsx from 'clsx' import { AlertTriangle, BarChart3, + CheckCircle2, GitBranch, GraduationCap, Handshake, @@ -13,6 +14,7 @@ import { Target, Users, Workflow, + XCircle, } from 'lucide-react' import { CelebrationAnimation } from '@/components/practice/CelebrationAnimation' import { @@ -45,16 +47,7 @@ interface AnswerState { isCorrect: boolean } -interface CircularProgressProps { - value: number - total: number - size: number - strokeWidth: number - className?: string - children?: ReactNode -} - -const STORAGE_KEY = 'performance-domain-practice-progress-v2' +const STORAGE_KEY = 'performance-domain-practice-progress-v3' const scopeOptions: Array<{ value: PracticeScope; label: string }> = [ { value: 'all', label: '全部' }, @@ -78,17 +71,6 @@ const iconMap = { PD08: AlertTriangle, } as const -const desktopPositions = [ - 'left-6 top-10', - 'left-1/2 top-1 -translate-x-1/2', - 'right-6 top-10', - 'right-1 top-1/2 -translate-y-[118%]', - 'right-6 bottom-10', - 'left-1/2 bottom-1 -translate-x-1/2', - 'left-6 bottom-10', - 'left-1 top-1/2 translate-y-[18%]', -] as const - function shuffleArray(items: T[]): T[] { const result = [...items] for (let i = result.length - 1; i > 0; i -= 1) { @@ -180,11 +162,10 @@ function getStoredProgress(questions: PracticeQuestion[]): PracticeProgress { const missingIds = filteredIds.filter( (id) => !completedIds.includes(id) && !queue.includes(id) ) - const mergedQueue = [...queue, ...shuffleArray(missingIds)] return { scope, - queue: mergedQueue, + queue: [...queue, ...shuffleArray(missingIds)], completedIds, totalCount: filteredIds.length, correctCount: Math.max(Number(parsed.correctCount) || 0, 0), @@ -196,66 +177,6 @@ function getStoredProgress(questions: PracticeQuestion[]): PracticeProgress { } } -function CircularProgress({ - value, - total, - size, - strokeWidth, - className, - children, -}: CircularProgressProps) { - const clampedTotal = total > 0 ? total : 1 - const ratio = Math.min(Math.max(value / clampedTotal, 0), 1) - const radius = (size - strokeWidth) / 2 - const circumference = 2 * Math.PI * radius - const dashOffset = circumference * (1 - ratio) - - return ( -
- - - - - {children && ( -
- {children} -
- )} -
- ) -} - export default function PerformanceDomainPracticePage() { const questionBank = useMemo(() => buildQuestionBank(), []) const questionMap = useMemo( @@ -280,12 +201,11 @@ export default function PerformanceDomainPracticePage() { ? performanceDomainMap.get(answerState.selectedDomainId) ?? null : null const isFinished = progress.totalCount > 0 && progress.queue.length === 0 - const displayCompletedCount = - progress.completedIds.length + (answerState?.isCorrect ? 1 : 0) - const remainingCount = Math.max(progress.totalCount - displayCompletedCount, 0) + const completedCount = progress.completedIds.length + (answerState?.isCorrect ? 1 : 0) + const remainingCount = Math.max(progress.totalCount - completedCount, 0) const accuracyBase = progress.correctCount + progress.wrongCount - const accuracy = - accuracyBase > 0 ? Math.round((progress.correctCount / accuracyBase) * 100) : 0 + const accuracy = accuracyBase > 0 ? Math.round((progress.correctCount / accuracyBase) * 100) : 0 + const progressPercent = progress.totalCount > 0 ? (completedCount / progress.totalCount) * 100 : 0 useEffect(() => { try { @@ -296,9 +216,7 @@ export default function PerformanceDomainPracticePage() { }, [progress]) useEffect(() => { - if (isFinished) { - setShowCelebration(true) - } + if (isFinished) setShowCelebration(true) }, [isFinished]) const restartPractice = (scope = progress.scope) => { @@ -316,12 +234,10 @@ export default function PerformanceDomainPracticePage() { if (!currentQuestionId) return setAnswerState(null) - setProgress((prev) => { if (prev.queue[0] !== currentQuestionId) return prev const [, ...restQueue] = prev.queue - if (isCorrect) { return { ...prev, @@ -355,7 +271,7 @@ export default function PerformanceDomainPracticePage() { })) } - const renderOptionButton = (domainId: string, className?: string) => { + const renderOptionButton = (domainId: string) => { const domain = performanceDomainMap.get(domainId) if (!domain) return null @@ -371,64 +287,51 @@ export default function PerformanceDomainPracticePage() { handleSelect(domain.id)} disabled={isAnswerShown} className={clsx( - 'w-full rounded-2xl border bg-white/95 px-4 py-3 text-left shadow-sm transition-all backdrop-blur-sm dark:bg-gray-800/95', - 'border-gray-200 hover:border-gray-300 dark:border-gray-700 dark:hover:border-gray-600', - isAnswerShown && 'cursor-default', - !isAnswerShown && 'hover:shadow-md', + 'relative flex min-h-[84px] items-center gap-3 rounded-xl border bg-white p-3 text-left shadow-sm transition-colors dark:bg-gray-800', + 'border-gray-100 hover:border-indigo-200 hover:bg-indigo-50/40 dark:border-gray-700 dark:hover:border-indigo-700 dark:hover:bg-indigo-950/20', + isAnswerShown && 'cursor-default hover:bg-white dark:hover:bg-gray-800', shouldHighlightCorrect && - 'border-emerald-300 bg-emerald-50 dark:border-emerald-700 dark:bg-emerald-950/40', + 'border-emerald-300 bg-emerald-50 dark:border-emerald-700 dark:bg-emerald-950/30', isWrongSelected && - 'border-rose-300 bg-rose-50 dark:border-rose-700 dark:bg-rose-950/40', - className + 'border-rose-300 bg-rose-50 dark:border-rose-700 dark:bg-rose-950/30' )} > -
-
- +
+ +
+
+
+ {domain.name}
-
-
- {domain.name} -
-
- {domain.nameEn} -
+
+ {domain.nameEn}
- {isAnswerShown && ( -
- {isCorrectSelected && ( - - 正确 - - )} - {isWrongSelected && ( - - 你的选择 - - )} - {shouldHighlightCorrect && !isCorrectSelected && ( - - 正确答案 - - )} -
+ {isCorrectSelected && ( + + )} + {isWrongSelected && ( + + )} + {shouldHighlightCorrect && !isCorrectSelected && ( + + 正确 + )} ) } return ( -
+
{showCelebration && ( setShowCelebration(false)} /> )} @@ -436,19 +339,14 @@ export default function PerformanceDomainPracticePage() {
-

- 八大绩效域练习 -

+

八大绩效域练习

根据预期目标和绩效要点,判断对应的绩效域。

@@ -465,89 +363,75 @@ export default function PerformanceDomainPracticePage() {
-
- {scopeOptions.map((option) => { - const isActive = option.value === progress.scope - return ( - - ) - })} -
+
+
+
+ {scopeOptions.map((option) => { + const isActive = option.value === progress.scope + return ( + + ) + })} +
-
-
- 已完成 - - {displayCompletedCount} / {progress.totalCount} - +
+ 已完成 {completedCount}/{progress.totalCount} + 剩余 {remainingCount} + 正确率 {accuracy}% + 错误 {progress.wrongCount} +
-
- 剩余 - - {remainingCount} - -
-
- 正确率 - - {accuracy}% - -
-
- 错误次数 - - {progress.wrongCount} - + +
+
{isFinished ? ( -
+
本轮完成
-

八大绩效域练习已完成

+

八大绩效域练习已完成

共完成 {progress.totalCount} 题,错误 {progress.wrongCount} 次。

-
+
总题数
-
- {progress.totalCount} -
+
{progress.totalCount}
-
+
正确率
-
- {accuracy}% -
+
{accuracy}%
-
+
当前范围
- {scopeOptions.find((option) => option.value === progress.scope)?.label ?? - '全部'} + {scopeOptions.find((option) => option.value === progress.scope)?.label ?? '全部'}
@@ -570,178 +454,71 @@ export default function PerformanceDomainPracticePage() {
) : currentQuestion ? ( -
-
-
- -
-
- {displayCompletedCount} -
-
- / {progress.totalCount} -
-
-
- -
-
- {kindLabelMap[currentQuestion.kind]} -
-
- 剩余 {remainingCount} 题 -
-
+
+
+
+ + {kindLabelMap[currentQuestion.kind]} + + + {completedCount + 1} / {progress.totalCount} +
-
-
-

- {currentQuestion.text} -

-
+
+

+ {currentQuestion.text} +

- {answerState && currentDomain ? (
-
+
+ {answerState.isCorrect ? : } {answerState.isCorrect - ? '回答正确' - : `你选了 ${selectedDomain?.name ?? ''},正确答案是 ${currentDomain.name}`} + ? `正确:${currentDomain.name}` + : `错误:你选了 ${selectedDomain?.name ?? ''}`}
-

- {answerState.isCorrect - ? '这题已答对。' - : '这题已放到后面,稍后会再出现。'} -

+ {!answerState.isCorrect && ( +

+ 正确答案:{currentDomain.name}。这题会放到后面再练。 +

+ )}
-
- -
-
- ) : ( -
- )} - -
- {performanceDomains.map((domain) => renderOptionButton(domain.id))} + +
+ ) : null}
-
+
-
-
- - -
-
- - 已完成 {displayCompletedCount} / {progress.totalCount} - - - {kindLabelMap[currentQuestion.kind]} - -
- -
-
-

- {currentQuestion.text} -

-
-
- - - {answerState && currentDomain ? ( -
-
-
- {answerState.isCorrect - ? '回答正确' - : `你选了 ${selectedDomain?.name ?? ''},正确答案是 ${currentDomain.name}`} -
-

- {answerState.isCorrect - ? '这题已答对。' - : '这题已放到后面,稍后会再出现。'} -

-
-
- -
-
- ) : ( -
- )} - -
- - {performanceDomains.map((domain, index) => ( -
- {renderOptionButton(domain.id)} -
- ))} -
-
+
+ {performanceDomains.map((domain) => renderOptionButton(domain.id))} +
) : null}