| <template> |
| <div> |
| |
| <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-bottom: 24px;"> |
| <div v-for="card in stats" :key="card.label" class="mk-stat"> |
| <div style="display: flex; justify-content: space-between; align-items: flex-start;"> |
| <div class="mk-stat-icon" :style="{ background: card.gradient, boxShadow: card.shadow }"> |
| <el-icon :size="24"><component :is="card.icon" /></el-icon> |
| </div> |
| <div style="text-align: right;"> |
| <p style="font-size: 12px; color: var(--text-light); font-weight: 500; margin-bottom: 2px;">{{ card.label }}</p> |
| <h4 :style="{ fontSize: '20px', fontWeight: 700, color: card.valueColor || 'var(--text-dark)' }">{{ card.value }}</h4> |
| </div> |
| </div> |
| <hr style="border: none; border-top: 1px solid var(--border); margin: 14px 0 10px;" /> |
| <p style="font-size: 12px; color: var(--text-light);">{{ card.sub }}</p> |
| </div> |
| </div> |
| |
| <div style="display: grid; grid-template-columns: 1.5fr 1fr; gap: 20px;"> |
| |
| <div class="mk-card"> |
| <div style="padding: 16px 20px; display: flex; justify-content: space-between; align-items: center;"> |
| <h6 style="font-size: 15px; font-weight: 700; color: var(--text-dark);">行情概览</h6> |
| <span style="font-size: 12px; color: var(--text-light);">{{ store.filteredQuotes.length }} 个合约</span> |
| </div> |
| <div style="padding: 0 16px 10px;" class="cat-tabs"> |
| <button v-for="cat in store.categoryList" :key="cat.key" :class="['cat-tab', { active: store.selectedCategory === cat.key }]" @click="store.selectedCategory = cat.key">{{ cat.label }}</button> |
| </div> |
| <el-table :data="store.filteredQuotes" style="width: 100%;" size="small" :max-height="380"> |
| <el-table-column label="合约" width="130"> |
| <template #default="{ row }"> |
| <div style="font-weight: 600; font-size: 13px; color: var(--text-dark);">{{ row.name || row.symbol }}</div> |
| <div style="font-size: 10px; color: var(--text-light);">{{ row.exchange }}</div> |
| </template> |
| </el-table-column> |
| <el-table-column label="最新价" width="100"><template #default="{ row }"><span :class="row.change_pct >= 0 ? 'price-up' : 'price-down'" style="font-weight: 700;">{{ row.close?.toFixed(2) }}</span></template></el-table-column> |
| <el-table-column label="涨跌%" width="85"><template #default="{ row }"><span :class="['badge-pill', row.change_pct >= 0 ? 'green' : 'red']">{{ row.change_pct ? (row.change_pct * 100).toFixed(2) + '%' : '-' }}</span></template></el-table-column> |
| <el-table-column label="成交量"><template #default="{ row }"><span style="color: var(--text-body); font-size: 12px;">{{ row.volume?.toLocaleString() }}</span></template></el-table-column> |
| </el-table> |
| </div> |
| |
| <div style="display: flex; flex-direction: column; gap: 20px;"> |
| <div class="mk-card"> |
| <div style="padding: 14px 20px; border-bottom: 1px solid var(--border-light);"><h6 style="font-size: 14px; font-weight: 700; color: var(--text-dark);">持仓概况</h6></div> |
| <div v-if="store.positions.length === 0" style="padding: 40px; text-align: center; color: var(--text-light); font-size: 13px;">暂无持仓</div> |
| <el-table v-else :data="store.positions" style="width: 100%;" size="small" :max-height="180"> |
| <el-table-column prop="symbol" label="合约" width="100" /> |
| <el-table-column label="方向" width="60"><template #default="{ row }"><span :class="['badge-pill', row.side === 'LONG' ? 'green' : 'red']">{{ row.side === 'LONG' ? '多' : '空' }}</span></template></el-table-column> |
| <el-table-column prop="quantity" label="数量" width="50" /> |
| <el-table-column label="盈亏"><template #default="{ row }"><span :class="row.unrealized_pnl >= 0 ? 'price-up' : 'price-down'" style="font-weight: 600;">{{ row.unrealized_pnl?.toFixed(2) }}</span></template></el-table-column> |
| </el-table> |
| </div> |
| <div class="mk-card"> |
| <div style="padding: 14px 20px; border-bottom: 1px solid var(--border-light);"><h6 style="font-size: 14px; font-weight: 700; color: var(--text-dark);">最近成交</h6></div> |
| <div v-if="store.trades.length === 0" style="padding: 40px; text-align: center; color: var(--text-light); font-size: 13px;">暂无成交</div> |
| <el-table v-else :data="store.trades.slice(-5).reverse()" style="width: 100%;" size="small" :max-height="180"> |
| <el-table-column prop="symbol" label="合约" width="100" /> |
| <el-table-column label="方向" width="60"><template #default="{ row }"><span :class="['badge-pill', row.side === 'BUY' ? 'green' : 'red']">{{ row.side === 'BUY' ? '买' : '卖' }}</span></template></el-table-column> |
| <el-table-column label="价格"><template #default="{ row }">{{ row.price?.toFixed(2) }}</template></el-table-column> |
| </el-table> |
| </div> |
| </div> |
| </div> |
| </div> |
| </template> |
| |
| <script setup> |
| import { computed, onMounted } from 'vue' |
| import { useTradingStore } from '../stores/trading' |
| const store = useTradingStore() |
| onMounted(() => { store.fetchQuotes(); store.fetchPositions(); store.fetchTrades(); store.fetchCategories() }) |
| |
| function fmt(n) { return (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) } |
| const stats = computed(() => [ |
| { label: '总资产', value: '¥' + fmt(store.account.total_balance), icon: 'Coin', gradient: 'var(--green-gradient)', shadow: '0 4px 20px 0 rgba(0,0,0,0.14), 0 7px 10px -5px rgba(76,175,80,0.4)', sub: '账户总权益', valueColor: 'var(--text-dark)' }, |
| { label: '可用资金', value: '¥' + fmt(store.account.available_balance), icon: 'Wallet', gradient: 'var(--blue-gradient)', shadow: '0 4px 20px 0 rgba(0,0,0,0.14), 0 7px 10px -5px rgba(25,118,210,0.4)', sub: '可用保证金', valueColor: 'var(--text-dark)' }, |
| { label: '浮动盈亏', value: (store.account.unrealized_pnl >= 0 ? '+' : '') + '¥' + fmt(store.account.unrealized_pnl), icon: 'TrendCharts', gradient: store.account.unrealized_pnl >= 0 ? 'var(--green-gradient)' : 'var(--red-gradient)', shadow: store.account.unrealized_pnl >= 0 ? '0 4px 20px 0 rgba(0,0,0,0.14), 0 7px 10px -5px rgba(76,175,80,0.4)' : '0 4px 20px 0 rgba(0,0,0,0.14), 0 7px 10px -5px rgba(244,67,54,0.4)', sub: '未平仓盈亏', valueColor: store.account.unrealized_pnl >= 0 ? 'var(--green)' : 'var(--red)' }, |
| { label: '已实现盈亏', value: (store.account.realized_pnl >= 0 ? '+' : '') + '¥' + fmt(store.account.realized_pnl), icon: 'DataLine', gradient: 'var(--orange-gradient)', shadow: '0 4px 20px 0 rgba(0,0,0,0.14), 0 7px 10px -5px rgba(251,140,0,0.4)', sub: '已平仓盈亏', valueColor: store.account.realized_pnl >= 0 ? 'var(--green)' : 'var(--red)' }, |
| ]) |
| </script> |
| |