11import React , { useState , useEffect , useRef , useMemo } from 'react' ;
2- import { TrendingUp , TrendingDown , Newspaper , Wallet , Activity , AlertTriangle , ChevronDown , Cloud , User , LogOut } from 'lucide-react' ;
2+ import { TrendingUp , TrendingDown , Newspaper , Wallet , Activity , AlertTriangle , ChevronDown , Cloud , User , LogOut , Trophy } from 'lucide-react' ;
33
44// --- Constants & Config ---
55const API_BASE = 'https://emails-pharmacy-sunrise-outline.trycloudflare.com/api' ;
@@ -29,6 +29,7 @@ const NEWS_POOL = [
2929] ;
3030
3131const App : React . FC = ( ) => {
32+ // --- States ---
3233 const [ balance , setBalance ] = useState ( 10000 ) ;
3334 const [ viewMode , setViewMode ] = useState < ViewMode > ( 'auto' ) ;
3435 const [ activeAsset , setActiveAsset ] = useState < AssetType > ( 'OIL' ) ;
@@ -44,13 +45,17 @@ const App: React.FC = () => {
4445 Object . fromEntries ( Object . entries ( ASSET_CONFIG ) . map ( ( [ k , v ] ) => [ k , [ v . basePrice ] ] ) ) as any
4546 ) ;
4647
48+ // --- Auth & Leaderboard States ---
4749 const [ user , setUser ] = useState < { username : string , token : string } | null > ( null ) ;
4850 const [ showAuthModal , setShowAuthModal ] = useState ( false ) ;
51+ const [ showLeaderboard , setShowLeaderboard ] = useState ( false ) ;
52+ const [ leaderboardData , setLeaderboardData ] = useState < any [ ] > ( [ ] ) ;
4953 const [ authForm , setAuthForm ] = useState ( { username : '' , password : '' , isLogin : true } ) ;
5054 const [ authMsg , setAuthMsg ] = useState ( '' ) ;
5155
5256 const activeImpactsRef = useRef < Record < AssetType , number > > ( { OIL : 0 , GOLD : 0 , WHEAT : 0 , MA : 0 , CU : 0 , RU : 0 , TBOND : 0 } ) ;
5357
58+ // --- Logic ---
5459 useEffect ( ( ) => {
5560 const saved = localStorage . getItem ( 'cc_user' ) ;
5661 if ( saved ) {
@@ -72,6 +77,17 @@ const App: React.FC = () => {
7277 } catch ( e ) { console . error ( 'Profile fetch failed' ) ; }
7378 } ;
7479
80+ const fetchLeaderboard = async ( ) => {
81+ try {
82+ const res = await fetch ( `${ API_BASE } /user/leaderboard` ) ;
83+ if ( res . ok ) {
84+ const data = await res . json ( ) ;
85+ setLeaderboardData ( data ) ;
86+ setShowLeaderboard ( true ) ;
87+ }
88+ } catch ( e ) { console . error ( 'Leaderboard fetch failed' ) ; }
89+ } ;
90+
7591 const handleAuth = async ( ) => {
7692 setAuthMsg ( '请求中...' ) ;
7793 const path = authForm . isLogin ? '/auth/login' : '/auth/register' ;
@@ -187,6 +203,7 @@ const App: React.FC = () => {
187203 ) : (
188204 < button onClick = { ( ) => setShowAuthModal ( true ) } className = "small-btn" style = { { color : '#ffd700' } } > < Cloud size = { 12 } /> 存档</ button >
189205 ) }
206+ < button onClick = { fetchLeaderboard } className = "small-btn" style = { { color : '#ffd700' } } > < Trophy size = { 12 } /> 榜单</ button >
190207 </ div >
191208 </ div >
192209 < div className = "header-stats" >
@@ -270,6 +287,36 @@ const App: React.FC = () => {
270287 </ div >
271288 </ div >
272289
290+ { /* --- Leaderboard Modal --- */ }
291+ { showLeaderboard && (
292+ < div className = "auth-overlay" >
293+ < div className = "auth-card" style = { { maxWidth : '400px' } } >
294+ < h3 style = { { color : '#ffd700' , marginBottom : '15px' } } > < Trophy size = { 20 } style = { { verticalAlign : 'middle' , marginRight : '8px' } } /> 财富排行榜 (前十)</ h3 >
295+ < div style = { { maxHeight : '300px' , overflowY : 'auto' , marginBottom : '20px' } } >
296+ < table style = { { width : '100%' , borderCollapse : 'collapse' , fontSize : '14px' } } >
297+ < thead >
298+ < tr style = { { borderBottom : '1px solid #444' , color : '#888' } } >
299+ < th style = { { padding : '8px' , textAlign : 'left' } } > 排名</ th >
300+ < th style = { { padding : '8px' , textAlign : 'left' } } > 玩家</ th >
301+ < th style = { { padding : '8px' , textAlign : 'right' } } > 净资产</ th >
302+ </ tr >
303+ </ thead >
304+ < tbody >
305+ { leaderboardData . map ( ( row , i ) => (
306+ < tr key = { i } style = { { borderBottom : '1px solid #222' } } >
307+ < td style = { { padding : '10px 8px' } } > { i + 1 } </ td >
308+ < td style = { { padding : '10px 8px' , fontWeight : 'bold' } } > { row . username } </ td >
309+ < td style = { { padding : '10px 8px' , textAlign : 'right' , color : '#26a69a' } } > ${ row . balance . toLocaleString ( undefined , { maximumFractionDigits : 0 } ) } </ td >
310+ </ tr >
311+ ) ) }
312+ </ tbody >
313+ </ table >
314+ </ div >
315+ < button className = "btn btn-long" onClick = { ( ) => setShowLeaderboard ( false ) } > 关闭</ button >
316+ </ div >
317+ </ div >
318+ ) }
319+
273320 { showAuthModal && (
274321 < div className = "auth-overlay" >
275322 < div className = "auth-card" >
0 commit comments