This commit is contained in:
aaron 2026-03-29 12:27:25 +08:00
parent ce493b622f
commit 8e025adba9

View File

@ -145,8 +145,81 @@
color: var(--error);
}
/* Real-time Prices */
.price-section {
margin-bottom: 24px;
padding: 16px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: var(--radius-md);
}
.price-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
}
.price-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
}
.price-item .symbol {
font-weight: 600;
color: var(--text-primary);
}
.price-item .price {
font-size: 16px;
font-weight: 700;
color: var(--primary);
}
/* Core Metrics Grid */
.core-metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.core-metric-card {
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 24px;
text-align: center;
}
.core-metric-label {
font-size: 13px;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 8px;
}
.core-metric-value {
font-size: 28px;
font-weight: 700;
color: var(--text-primary);
}
.core-metric-value.positive {
color: var(--success);
}
.core-metric-value.negative {
color: var(--error);
}
@media (max-width: 768px) {
.metrics-grid, .stat-grid, .grade-stats {
.metrics-grid, .stat-grid, .grade-stats, .core-metrics-grid, .price-list {
grid-template-columns: 1fr;
}
}
@ -273,6 +346,17 @@
</div>
</div>
<!-- Real-time Prices -->
<div v-if="Object.keys(latestPrices).length > 0" class="price-section">
<div class="stat-label" style="margin-bottom: 8px;">实时价格</div>
<div class="price-list">
<div class="price-item" v-for="(price, symbol) in latestPrices" :key="symbol">
<span class="symbol">{{ symbol }}</span>
<span class="price">${{ price.toLocaleString() }}</span>
</div>
</div>
</div>
<!-- Tabs -->
<div class="tabs">
<button class="tab" :class="{ active: currentTab === 'positions' }" @click="switchTab('positions')">
@ -284,6 +368,9 @@
<button class="tab" :class="{ active: currentTab === 'history' }" @click="switchTab('history')">
历史订单 ({{ orderHistory.length }})
</button>
<button class="tab" :class="{ active: currentTab === 'stats' }" @click="switchTab('stats')">
详细统计
</button>
</div>
<!-- Content -->
@ -483,6 +570,94 @@
</div>
</div>
</div>
<!-- Detailed Statistics Tab -->
<div v-if="currentTab === 'stats'" class="table-container">
<!-- Core Metrics -->
<div class="core-metrics-grid">
<div class="core-metric-card">
<div class="core-metric-label">累计收益率</div>
<div class="core-metric-value" :class="stats.total_pnl_percent >= 0 ? 'positive' : 'negative'">
{{ stats.total_pnl_percent >= 0 ? '+' : '' }}{{ stats.total_pnl_percent ? stats.total_pnl_percent.toFixed(2) : '0.00' }}%
</div>
</div>
<div class="core-metric-card">
<div class="core-metric-label">总盈亏</div>
<div class="core-metric-value" :class="stats.total_pnl >= 0 ? 'positive' : 'negative'">
{{ stats.total_pnl >= 0 ? '+' : '' }}${{ stats.total_pnl ? stats.total_pnl.toFixed(2) : '0.00' }}
</div>
</div>
<div class="core-metric-card">
<div class="core-metric-label">胜率</div>
<div class="core-metric-value positive">
{{ stats.win_rate ? stats.win_rate.toFixed(1) : '0.0' }}%
</div>
</div>
<div class="core-metric-card">
<div class="core-metric-label">盈亏比</div>
<div class="core-metric-value">
{{ stats.profit_factor === Infinity ? '∞' : (stats.profit_factor ? stats.profit_factor.toFixed(2) : '0.00') }}
</div>
</div>
</div>
<!-- Grade Stats -->
<div class="grade-stats" style="margin-top: 24px;">
<div class="grade-card">
<div class="grade-card-header">
<span class="grade-card-title">交易详情</span>
</div>
<div class="grade-card-stats">
<div class="grade-stat-row">
<span class="grade-stat-label">总交易数</span>
<span class="grade-stat-value">{{ stats.total_trades || 0 }}</span>
</div>
<div class="grade-stat-row">
<span class="grade-stat-label">盈利交易</span>
<span class="grade-stat-value positive">{{ stats.winning_trades || 0 }}</span>
</div>
<div class="grade-stat-row">
<span class="grade-stat-label">亏损交易</span>
<span class="grade-stat-value negative">{{ stats.losing_trades || 0 }}</span>
</div>
<div class="grade-stat-row">
<span class="grade-stat-label">最佳交易</span>
<span class="grade-stat-value positive">{{ stats.best_trade ? stats.best_trade.toFixed(2) : '0.00' }}%</span>
</div>
<div class="grade-stat-row">
<span class="grade-stat-label">最差交易</span>
<span class="grade-stat-value negative">{{ stats.worst_trade ? stats.worst_trade.toFixed(2) : '0.00' }}%</span>
</div>
</div>
</div>
<div class="grade-card">
<div class="grade-card-header">
<span class="grade-card-title">收益分析</span>
</div>
<div class="grade-card-stats">
<div class="grade-stat-row">
<span class="grade-stat-label">平均盈利</span>
<span class="grade-stat-value positive">${{ stats.average_win ? stats.average_win.toFixed(2) : '0.00' }}</span>
</div>
<div class="grade-stat-row">
<span class="grade-stat-label">平均亏损</span>
<span class="grade-stat-value negative">${{ stats.average_loss ? stats.average_loss.toFixed(2) : '0.00' }}</span>
</div>
<div class="grade-stat-row">
<span class="grade-stat-label">最大回撤</span>
<span class="grade-stat-value negative">{{ stats.max_drawdown ? stats.max_drawdown.toFixed(2) : '0.00' }}%</span>
</div>
<div class="grade-stat-row">
<span class="grade-stat-label">收益率</span>
<span class="grade-stat-value" :class="stats.return_percent >= 0 ? 'positive' : 'negative'">
{{ stats.return_percent >= 0 ? '+' : '' }}{{ stats.return_percent ? stats.return_percent.toFixed(2) : '0.00' }}%
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -534,7 +709,9 @@
showAdminMenu: false,
adminPassword: '223388',
titleClickCount: 0,
titleClickTimer: null
titleClickTimer: null,
refreshInterval: null,
latestPrices: {}
};
},
computed: {
@ -571,6 +748,18 @@
}
},
async silentRefresh() {
try {
await Promise.all([
this.fetchAccountStatus(),
this.fetchStatistics(),
this.fetchOrders()
]);
} catch (e) {
console.error('静默刷新失败:', e);
}
},
async fetchAccountStatus() {
try {
const response = await axios.get('/api/trading/account');
@ -599,6 +788,10 @@
console.log('API Response:', response.data);
if (response.data.success) {
this.orders = response.data.orders || [];
// 获取实时价格
if (response.data.latest_prices) {
this.latestPrices = response.data.latest_prices;
}
console.log('Orders loaded:', this.orders.length);
console.log('Orders data:', this.orders);
console.log('Open positions:', this.orders.filter(o => o.status === 'open'));
@ -768,12 +961,22 @@
mounted() {
this.refreshData();
// 每3秒自动刷新静默刷新不显示 loading
this.refreshInterval = setInterval(() => {
this.silentRefresh();
}, 3000);
// 点击外部关闭管理菜单
document.addEventListener('click', (e) => {
if (this.showAdminMenu && !e.target.closest('.admin-dropdown')) {
this.showAdminMenu = false;
}
});
},
beforeUnmount() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
}
}
}).mount('#app');
</script>