This commit is contained in:
aaron 2026-02-07 01:18:30 +08:00
parent 161f9feda0
commit cc059b726b

View File

@ -18,13 +18,23 @@
margin: 0 auto; margin: 0 auto;
} }
/* 固定顶部区域 */
.sticky-header {
position: sticky;
top: 0;
z-index: 100;
background: var(--bg-primary);
padding-bottom: 10px;
}
.trading-header { .trading-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 30px; margin-bottom: 20px;
padding-bottom: 20px; padding: 10px 0 20px 0;
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
background: var(--bg-primary);
} }
.trading-title { .trading-title {
@ -57,7 +67,7 @@
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 16px; gap: 16px;
margin-bottom: 30px; margin-bottom: 20px;
} }
.stat-card { .stat-card {
@ -453,56 +463,59 @@
<div id="app"> <div id="app">
<div class="trading-page"> <div class="trading-page">
<div class="trading-container"> <div class="trading-container">
<!-- 头部 --> <!-- 固定顶部区域 -->
<div class="trading-header"> <div class="sticky-header">
<h1 class="trading-title">模拟交易 <span>Paper Trading</span></h1> <!-- 头部 -->
<div style="display: flex; align-items: center; gap: 12px;"> <div class="trading-header">
<div class="monitor-status"> <h1 class="trading-title">模拟交易 <span>Paper Trading</span></h1>
<div class="monitor-dot" :class="{ running: monitorRunning }"></div> <div style="display: flex; align-items: center; gap: 12px;">
<span>{{ monitorRunning ? '监控中' : '未启动' }}</span> <div class="monitor-status">
</div> <div class="monitor-dot" :class="{ running: monitorRunning }"></div>
<button class="refresh-btn" @click="refreshData">刷新数据</button> <span>{{ monitorRunning ? '监控中' : '未启动' }}</span>
<button class="reset-btn" @click="resetData">重置数据</button> </div>
</div> <button class="refresh-btn" @click="manualRefresh">刷新数据</button>
</div> <button class="reset-btn" @click="resetData">重置数据</button>
<!-- 统计卡片 -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">总交易数</div>
<div class="stat-value">{{ stats.total_trades }}</div>
</div>
<div class="stat-card">
<div class="stat-label">胜率</div>
<div class="stat-value">{{ stats.win_rate.toFixed(1) }}%</div>
</div>
<div class="stat-card">
<div class="stat-label">总盈亏</div>
<div class="stat-value" :class="stats.total_pnl >= 0 ? 'positive' : 'negative'">
${{ stats.total_pnl.toFixed(2) }}
</div> </div>
</div> </div>
<div class="stat-card">
<div class="stat-label">盈亏比</div>
<div class="stat-value">{{ stats.profit_factor === Infinity ? '∞' : stats.profit_factor.toFixed(2) }}</div>
</div>
<div class="stat-card">
<div class="stat-label">平均盈利</div>
<div class="stat-value positive">${{ stats.average_win.toFixed(2) }}</div>
</div>
<div class="stat-card">
<div class="stat-label">平均亏损</div>
<div class="stat-value negative">${{ stats.average_loss.toFixed(2) }}</div>
</div>
</div>
<!-- 实时价格 --> <!-- 统计卡片 -->
<div v-if="Object.keys(latestPrices).length > 0" style="margin-bottom: 20px;"> <div class="stats-grid">
<div class="stat-label" style="margin-bottom: 8px;">实时价格</div> <div class="stat-card">
<div class="price-list"> <div class="stat-label">总交易数</div>
<div class="price-item" v-for="(price, symbol) in latestPrices" :key="symbol"> <div class="stat-value">{{ stats.total_trades }}</div>
<span class="symbol">{{ symbol }}</span> </div>
<span class="price">${{ price.toLocaleString() }}</span> <div class="stat-card">
<div class="stat-label">胜率</div>
<div class="stat-value">{{ stats.win_rate.toFixed(1) }}%</div>
</div>
<div class="stat-card">
<div class="stat-label">总盈亏</div>
<div class="stat-value" :class="stats.total_pnl >= 0 ? 'positive' : 'negative'">
${{ stats.total_pnl.toFixed(2) }}
</div>
</div>
<div class="stat-card">
<div class="stat-label">盈亏比</div>
<div class="stat-value">{{ stats.profit_factor === Infinity ? '∞' : stats.profit_factor.toFixed(2) }}</div>
</div>
<div class="stat-card">
<div class="stat-label">平均盈利</div>
<div class="stat-value positive">${{ stats.average_win.toFixed(2) }}</div>
</div>
<div class="stat-card">
<div class="stat-label">平均亏损</div>
<div class="stat-value negative">${{ stats.average_loss.toFixed(2) }}</div>
</div>
</div>
<!-- 实时价格 -->
<div v-if="Object.keys(latestPrices).length > 0" style="margin-bottom: 15px;">
<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>
</div> </div>
</div> </div>
@ -714,7 +727,7 @@
data() { data() {
return { return {
activeTab: 'active', activeTab: 'active',
loading: false, loading: true, // 只在首次加载时为 true
activeOrders: [], activeOrders: [],
historyOrders: [], historyOrders: [],
stats: { stats: {
@ -731,14 +744,15 @@
}, },
monitorRunning: false, monitorRunning: false,
latestPrices: {}, latestPrices: {},
refreshInterval: null refreshInterval: null,
isFirstLoad: true
}; };
}, },
mounted() { mounted() {
this.refreshData(); this.refreshData();
// 每3秒自动刷新实时价格更新 // 每3秒自动刷新静默刷新,不显示 loading
this.refreshInterval = setInterval(() => { this.refreshInterval = setInterval(() => {
this.refreshData(); this.silentRefresh();
}, 3000); }, 3000);
}, },
beforeUnmount() { beforeUnmount() {
@ -747,8 +761,18 @@
} }
}, },
methods: { methods: {
async refreshData() { // 手动刷新(显示 loading
async manualRefresh() {
this.loading = true; this.loading = true;
await this.refreshData();
},
// 静默刷新(不显示 loading
async silentRefresh() {
await this.refreshData();
},
async refreshData() {
try { try {
await Promise.all([ await Promise.all([
this.fetchActiveOrders(), this.fetchActiveOrders(),
@ -760,6 +784,7 @@
console.error('刷新数据失败:', e); console.error('刷新数据失败:', e);
} finally { } finally {
this.loading = false; this.loading = false;
this.isFirstLoad = false;
} }
}, },