11import { useState , useEffect } from 'react' ;
22import { Link } from 'react-router-dom' ;
3- import { User , Mail , Shield , Award , TrendingUp , Loader2 , AlertTriangle , CheckCircle2 , XCircle , Clock , Zap , Lock , Key , CalendarDays } from 'lucide-react' ;
3+ import { User , Mail , Shield , Award , TrendingUp , Loader2 , AlertTriangle , CheckCircle2 , XCircle , Clock , Zap , Lock , Key , CalendarDays , Code } from 'lucide-react' ;
44import { useAuth } from '../context/AuthContext' ;
55import api from '../services/api' ;
66import type { Submission } from '../types' ;
@@ -50,6 +50,7 @@ export default function Profile() {
5050 const [ passwordMessage , setPasswordMessage ] = useState < string | null > ( null ) ;
5151 const [ passwordError , setPasswordError ] = useState < string | null > ( null ) ;
5252 const [ calendarDates , setCalendarDates ] = useState < Set < string > > ( new Set ( ) ) ;
53+ const [ languageStats , setLanguageStats ] = useState < { language : string ; count : number } [ ] > ( [ ] ) ;
5354
5455 useEffect ( ( ) => {
5556 const token = localStorage . getItem ( 'oj_token' ) ;
@@ -60,6 +61,12 @@ export default function Profile() {
6061 setCalendarDates ( new Set ( data . dates || [ ] ) ) ;
6162 } )
6263 . catch ( ( ) => { } ) ;
64+ fetch ( '/api/auth/language-stats' , { headers : { Authorization : `Bearer ${ token } ` } } )
65+ . then ( r => r . json ( ) )
66+ . then ( data => {
67+ setLanguageStats ( data . languages || [ ] ) ;
68+ } )
69+ . catch ( ( ) => { } ) ;
6370 } , [ ] ) ;
6471
6572 useEffect ( ( ) => {
@@ -206,6 +213,32 @@ export default function Profile() {
206213 </ div >
207214 </ div >
208215
216+ { /* Language usage */ }
217+ { languageStats . length > 0 && (
218+ < div className = "card p-6" >
219+ < h3 className = "text-sm font-semibold text-dark-200 mb-3 flex items-center gap-2" >
220+ < Code className = "w-4 h-4 text-blue-400" /> 使用语言统计
221+ </ h3 >
222+ < div className = "space-y-2" >
223+ { languageStats . map ( ( lang : { language : string ; count : number } ) => {
224+ const maxCount = Math . max ( ...languageStats . map ( ( l : any ) => l . count ) ) ;
225+ return (
226+ < div key = { lang . language } className = "flex items-center gap-3" >
227+ < span className = "w-24 text-xs text-dark-400 text-right" > { lang . language || '未知' } </ span >
228+ < div className = "flex-1 h-4 bg-dark-700 rounded-full overflow-hidden" >
229+ < div
230+ className = "h-full bg-primary-500 rounded-full transition-all duration-500"
231+ style = { { width : `${ ( lang . count / maxCount ) * 100 } %` } }
232+ />
233+ </ div >
234+ < span className = "text-xs text-dark-400 w-8" > { lang . count } </ span >
235+ </ div >
236+ ) ;
237+ } ) }
238+ </ div >
239+ </ div >
240+ ) }
241+
209242 < GamificationSection />
210243
211244 { /* Solved calendar */ }
0 commit comments