11import React , { useState , useEffect , useRef , useMemo } from 'react' ;
2- import { TrendingUp , TrendingDown , Newspaper , Wallet , Activity , AlertTriangle } from 'lucide-react' ;
2+ import { TrendingUp , TrendingDown , Newspaper , Wallet , Activity , AlertTriangle , ChevronDown } from 'lucide-react' ;
33
44// --- Constants & Types ---
55type AssetType = 'OIL' | 'GOLD' | 'WHEAT' | 'MA' | 'CU' | 'RU' | 'TBOND' ;
@@ -126,40 +126,40 @@ const App: React.FC = () => {
126126 return (
127127 < div className = { `app-container ${ viewMode === 'mobile' ? 'force-mobile' : viewMode === 'desktop' ? 'force-desktop' : '' } ` } >
128128 < header className = "header" >
129- < div style = { { display : 'flex' , alignItems : 'center' , gap : '12px' } } >
130- < Activity size = { 32 } color = "#ffd700" />
131- < div >
132- < h1 style = { { margin : 0 , fontSize : '24px' } } > 期货风云</ h1 >
133- < div style = { { display : 'flex' , gap : '8px' , marginTop : '4px' , flexWrap : 'wrap' } } >
134- < a href = "/" style = { { color : '#aaa' , fontSize : '12px' , textDecoration : 'none' , border : '1px solid #444' , padding : '2px 8px' , borderRadius : '4px' } } > 返回首页</ a >
135- < button onClick = { ( ) => setViewMode ( prev => prev === 'mobile' ? 'desktop' : 'mobile' ) } style = { { background : 'none' , border : '1px solid #444' , color : '#ffd700' , fontSize : '12px' , padding : '2px 8px' , borderRadius : '4px' , cursor : 'pointer' } } >
136- 切至{ viewMode === 'mobile' ? '电脑' : '手机' }
137- </ button >
138- < span id = "busuanzi_container_page_pv" style = { { color : '#666' , fontSize : '12px' } } > 访客: < span id = "busuanzi_value_page_pv" > </ span > </ span >
139- </ div >
129+ < div className = "header-left" >
130+ < Activity size = { 24 } color = "#ffd700" />
131+ < h1 style = { { margin : 0 , fontSize : '20px' } } > 期货风云</ h1 >
132+ < div className = "header-actions" >
133+ < a href = "/" className = "small-link" > 返回</ a >
134+ < button onClick = { ( ) => setViewMode ( prev => prev === 'mobile' ? 'desktop' : 'mobile' ) } className = "small-btn" >
135+ { viewMode === 'mobile' ? '电脑' : '手机' }
136+ </ button >
140137 </ div >
141138 </ div >
142139 < div className = "header-stats" >
143- < div style = { { color : '#888' } } > 净资产 : < span style = { { color : equity > 10000 ? '#26a69a' : '#ef5350' , fontWeight : 'bold' } } > ${ equity . toLocaleString ( undefined , { minimumFractionDigits : 2 } ) } </ span > </ div >
144- < div style = { { color : '#888' } } > 余额: < span style = { { color : '#fff' } } > ${ balance . toLocaleString ( undefined , { maximumFractionDigits : 0 } ) } </ span > </ div >
140+ < div className = "stat-line" > 资产 : < span style = { { color : equity > 10000 ? '#26a69a' : '#ef5350' } } > ${ equity . toLocaleString ( undefined , { maximumFractionDigits : 0 } ) } </ span > </ div >
141+ < div className = "stat-line" > 余额: < span > ${ balance . toLocaleString ( undefined , { maximumFractionDigits : 0 } ) } </ span > </ div >
145142 </ div >
146143 </ header >
147144
148145 < div className = "card chart-card" >
149- < div className = "asset-selector" >
150- { ( Object . keys ( ASSET_CONFIG ) as AssetType [ ] ) . map ( asset => (
151- < div key = { asset } className = { `asset-tab ${ activeAsset === asset ? 'active' : '' } ` } onClick = { ( ) => setActiveAsset ( asset ) } >
152- { ASSET_CONFIG [ asset ] . icon } { ASSET_CONFIG [ asset ] . name }
153- </ div >
154- ) ) }
155- </ div >
156- < div style = { { display : 'flex' , justifyContent : 'space-between' , marginBottom : '10px' } } >
157- < div style = { { fontSize : '24px' , fontWeight : 'bold' } } > { prices [ activeAsset ] . toLocaleString ( undefined , { minimumFractionDigits : 2 } ) } </ div >
158- < div className = { prices [ activeAsset ] >= priceHistory [ activeAsset ] [ 0 ] ? 'price-up' : 'price-down' } >
159- { ( ( prices [ activeAsset ] / priceHistory [ activeAsset ] [ 0 ] - 1 ) * 100 ) . toFixed ( 2 ) } %
146+ < div className = "chart-header" >
147+ < div className = "select-wrapper" >
148+ < select value = { activeAsset } onChange = { ( e ) => setActiveAsset ( e . target . value as AssetType ) } className = "styled-select" >
149+ { ( Object . keys ( ASSET_CONFIG ) as AssetType [ ] ) . map ( asset => (
150+ < option key = { asset } value = { asset } > { ASSET_CONFIG [ asset ] . icon } { ASSET_CONFIG [ asset ] . name } </ option >
151+ ) ) }
152+ </ select >
153+ < ChevronDown size = { 14 } className = "select-icon" />
154+ </ div >
155+ < div className = "chart-price-box" >
156+ < span className = "current-price" > { prices [ activeAsset ] . toLocaleString ( undefined , { minimumFractionDigits : 2 } ) } </ span >
157+ < span className = { `price-change ${ prices [ activeAsset ] >= priceHistory [ activeAsset ] [ 0 ] ? 'up' : 'down' } ` } >
158+ { ( ( prices [ activeAsset ] / priceHistory [ activeAsset ] [ 0 ] - 1 ) * 100 ) . toFixed ( 2 ) } %
159+ </ span >
160160 </ div >
161161 </ div >
162- < div className = "chart-container" >
162+ < div className = "chart-container mini-chart " >
163163 < svg width = "100%" height = "100%" viewBox = "0 0 500 300" preserveAspectRatio = "none" >
164164 < polyline fill = "none" stroke = { priceHistory [ activeAsset ] [ priceHistory [ activeAsset ] . length - 1 ] >= priceHistory [ activeAsset ] [ 0 ] ? "#26a69a" : "#ef5350" } strokeWidth = "2"
165165 points = { priceHistory [ activeAsset ] . map ( ( p , i ) => `${ ( i / ( priceHistory [ activeAsset ] . length - 1 ) ) * 500 } ,${ 300 - ( ( p - ( Math . min ( ...priceHistory [ activeAsset ] ) * 0.99 ) ) / ( Math . max ( ...priceHistory [ activeAsset ] ) * 1.01 - Math . min ( ...priceHistory [ activeAsset ] ) * 0.99 ) ) * 300 } ` ) . join ( ' ' ) } />
@@ -168,57 +168,70 @@ const App: React.FC = () => {
168168 </ div >
169169
170170 < div className = "card trading-card" >
171- < div style = { { display : 'flex' , alignItems : 'center' , gap : '10px' , marginBottom : '10px' } } >
172- < Wallet size = { 20 } color = "#ffd700" /> < h3 style = { { margin : 0 } } > 交易 { ASSET_CONFIG [ activeAsset ] . name } </ h3 >
171+ < div className = "trading-header" >
172+ < div className = "trading-title" >
173+ < Wallet size = { 18 } color = "#ffd700" />
174+ < span className = "asset-name" > { ASSET_CONFIG [ activeAsset ] . name } </ span >
175+ </ div >
176+ < div className = "trading-buttons-inline" >
177+ < button className = "mini-btn btn-long" onClick = { ( ) => openPosition ( 1 ) } disabled = { ! ! position } > 做多</ button >
178+ < button className = "mini-btn btn-short" onClick = { ( ) => openPosition ( - 1 ) } disabled = { ! ! position } > 做空</ button >
179+ </ div >
173180 </ div >
174- < div style = { { fontSize : '14px' , color : '#888' , marginBottom : '10px' } } > 杠杆: { LEVERAGE } x | 使用率: { ( utilizationRate * 100 ) . toFixed ( 0 ) } %</ div >
175- < div style = { { display : 'flex' , gap : '5px' , marginBottom : '15px' , flexWrap : 'wrap' } } >
176- { [ 0.1 , 0.3 , 0.5 , 0.8 , 1.0 ] . map ( rate => (
177- < button key = { rate } onClick = { ( ) => setUtilizationRate ( rate ) } style = { { flex : 1 , padding : '6px' , fontSize : '12px' , background : utilizationRate === rate ? '#444' : '#222' , border : utilizationRate === rate ? '1px solid #ffd700' : '1px solid #444' , borderRadius : '4px' , color : '#fff' , cursor : 'pointer' } } > { rate * 100 } %</ button >
178- ) ) }
181+
182+ < div className = "trading-settings" >
183+ < span className = "label" > 杠杆: { LEVERAGE } x</ span >
184+ < div className = "select-wrapper" >
185+ < select value = { utilizationRate } onChange = { ( e ) => setUtilizationRate ( parseFloat ( e . target . value ) ) } className = "styled-select-small" >
186+ { [ 0.1 , 0.3 , 0.5 , 0.8 , 1.0 ] . map ( rate => (
187+ < option key = { rate } value = { rate } > 仓位: { rate * 100 } %</ option >
188+ ) ) }
189+ </ select >
190+ < ChevronDown size = { 12 } className = "select-icon" />
191+ </ div >
179192 </ div >
180- < button className = "btn btn-long" onClick = { ( ) => openPosition ( 1 ) } disabled = { ! ! position } style = { { marginBottom : '10px' } } > 买入 / 做多</ button >
181- < button className = "btn btn-short" onClick = { ( ) => openPosition ( - 1 ) } disabled = { ! ! position } > 卖出 / 做空</ button >
193+
182194 { position && (
183- < div style = { { marginTop : '15px' , padding : '15px' , background : '#222' , borderRadius : '4px' , borderLeft : `4px solid ${ position . direction === 1 ? '#26a69a' : '#ef5350' } ` } } >
184- < div style = { { display : 'flex' , justifyContent : 'space-between' , marginBottom : '5px' } } >
185- < span > { position . direction === 1 ? '做多 ' : '做空 ' } { ASSET_CONFIG [ position . asset ] . name } </ span >
195+ < div className = "active- position" >
196+ < div className = "pos-info" >
197+ < span > { position . direction === 1 ? '多 ' : '空 ' } { ASSET_CONFIG [ position . asset ] . name } </ span >
186198 < span className = { unrealizedPnL >= 0 ? 'price-up' : 'price-down' } > { unrealizedPnL >= 0 ? '+' : '' } { unrealizedPnL . toLocaleString ( undefined , { minimumFractionDigits : 2 } ) } </ span >
187199 </ div >
188- < button className = "btn btn -close" style = { { marginTop : '10px' } } onClick = { closePosition } > 平仓结算 </ button >
200+ < button className = "btn-close-compact" onClick = { closePosition } > 平仓 </ button >
189201 </ div >
190202 ) }
191203 </ div >
192204
193205 < div className = "card news-card" >
194- < div style = { { display : 'flex' , alignItems : 'center' , gap : '10px' , marginBottom : '15px' , color : '#ffd700' } } >
195- < Newspaper size = { 20 } /> < h3 style = { { margin : 0 } } > 实时快讯</ h3 >
206+ < div className = "news-header-mini" >
207+ < Newspaper size = { 16 } /> < span > 快讯</ span >
208+ < span id = "busuanzi_container_page_pv" className = "visitor-count" > 访客: < span id = "busuanzi_value_page_pv" > </ span > </ span >
196209 </ div >
197- < div className = "news-panel" >
198- { news . length === 0 && < div style = { { color : '#555' , textAlign : 'center' } } > 等待行情事件 ...</ div > }
210+ < div className = "news-panel-compact " >
211+ { news . length === 0 && < div className = "news-placeholder" > 等待市场消息 ...</ div > }
199212 { news . map ( item => (
200- < div key = { item . id } className = "news-item" >
201- < span style = { { color : '#888' , marginRight : '8px' } } > [{ new Date ( item . id ) . toLocaleTimeString ( ) } ]</ span >
213+ < div key = { item . id } className = "news-item-mini" >
202214 { item . text }
203215 </ div >
204216 ) ) }
205217 </ div >
206218 </ div >
207219
208- < div className = "card risk-card" >
209- < h3 style = { { margin : '0 0 15px 0' , fontSize : '16px' } } > 实时风控</ h3 >
210- < div style = { { height : '10px' , background : '#333' , borderRadius : '5px' , overflow : 'hidden' } } >
211- < div style = { { height : '100%' , width : `${ Math . min ( 100 , ( currentUtilization / 1.2 ) * 100 ) } %` , background : currentUtilization > 1.0 ? '#ef5350' : '#26a69a' } } />
220+ < div className = "card risk-card-mini" >
221+ < div className = "risk-header" >
222+ < span > 风险: { ( currentUtilization * 100 ) . toFixed ( 1 ) } %</ span >
223+ < div className = "risk-bar-container" >
224+ < div className = "risk-bar" style = { { width : `${ Math . min ( 100 , ( currentUtilization / 1.2 ) * 100 ) } %` , background : currentUtilization > 1.0 ? '#ef5350' : '#26a69a' } } />
225+ </ div >
212226 </ div >
213- < div style = { { fontSize : '12px' , color : '#888' , marginTop : '10px' , textAlign : 'center' } } > 资金使用率: { ( currentUtilization * 100 ) . toFixed ( 1 ) } % / 120%</ div >
214227 </ div >
215228
216229 { isLiquated && (
217230 < div className = "liquidation-overlay" >
218- < AlertTriangle size = { 64 } color = "#ef5350" />
219- < h1 style = { { color : '#ef5350' , fontSize : '48px ' , margin : '20px 0' } } > 爆仓!</ h1 >
220- < p style = { { fontSize : '20px ' , color : '#888' } } > 您的净资产已亏损殆尽 。</ p >
221- < button className = "btn btn-long" style = { { marginTop : '30px ' , padding : '15px 40px ' , width : 'auto' } } onClick = { ( ) => window . location . reload ( ) } > 重新开始职业生涯 </ button >
231+ < AlertTriangle size = { 48 } color = "#ef5350" />
232+ < h1 style = { { color : '#ef5350' , fontSize : '36px ' , margin : '15px 0' } } > 爆仓!</ h1 >
233+ < p style = { { fontSize : '16px ' , color : '#888' } } > 账户净资产已亏损殆尽 。</ p >
234+ < button className = "btn btn-long" style = { { marginTop : '20px ' , padding : '12px 30px ' , width : 'auto' } } onClick = { ( ) => window . location . reload ( ) } > 重新开始 </ button >
222235 </ div >
223236 ) }
224237 </ div >
0 commit comments