@@ -20,6 +20,7 @@ import toast from 'react-hot-toast';
2020import api from '../services/api' ;
2121import ProblemCard from '../components/ProblemCard' ;
2222import type { Problem , PaginatedResponse , ProblemStats } from '../types' ;
23+ import { useAuth } from '../context/AuthContext' ;
2324import { useBookmarks } from '../context/BookmarkContext' ;
2425import { useDocumentTitle } from '../hooks/useDocumentTitle' ;
2526
@@ -66,6 +67,9 @@ export default function Problems() {
6667 const [ jumpPage , setJumpPage ] = useState ( '' ) ;
6768 const [ bookmarkFilter , setBookmarkFilter ] = useState ( false ) ;
6869 const { isBookmarked } = useBookmarks ( ) ;
70+ const { user } = useAuth ( ) ;
71+ const [ userStats , setUserStats ] = useState < { accepted : number } | null > ( null ) ;
72+ const totalProblems = stats ?. total ?? 0 ;
6973
7074 const fetchStats = useCallback ( async ( ) => {
7175 try {
@@ -90,6 +94,15 @@ export default function Problems() {
9094 fetchTags ( ) ;
9195 } , [ fetchStats , fetchTags ] ) ;
9296
97+ useEffect ( ( ) => {
98+ if ( ! user ) return ;
99+ api . auth . profile ( ) . then ( ( res : any ) => {
100+ if ( res ?. accepted_count != null ) {
101+ setUserStats ( { accepted : res . accepted_count } ) ;
102+ }
103+ } ) . catch ( ( ) => { } ) ;
104+ } , [ user ] ) ;
105+
93106 const fetchProblems = useCallback ( async ( ) => {
94107 setLoading ( true ) ;
95108 setError ( null ) ;
@@ -256,6 +269,22 @@ export default function Problems() {
256269 </ div >
257270 ) }
258271
272+ { /* Completion Progress */ }
273+ { user && userStats && (
274+ < div className = "card p-4 mb-4" >
275+ < div className = "flex items-center justify-between mb-2" >
276+ < h3 className = "text-sm font-medium text-dark-200" > 答题进度</ h3 >
277+ < span className = "text-xs text-dark-400" > { userStats . accepted } / { totalProblems } 通过</ span >
278+ </ div >
279+ < div className = "h-2 bg-dark-700 rounded-full overflow-hidden" >
280+ < div
281+ className = "h-full bg-gradient-to-r from-primary-500 to-emerald-500 rounded-full transition-all duration-500"
282+ style = { { width : `${ totalProblems > 0 ? Math . min ( 100 , ( userStats . accepted / totalProblems ) * 100 ) : 0 } %` } }
283+ />
284+ </ div >
285+ </ div >
286+ ) }
287+
259288 { /* Filters & Page Size */ }
260289 < div className = "flex flex-wrap items-center gap-4 mb-6" >
261290 < div className = "flex gap-1" >
0 commit comments