File size: 7,047 Bytes
590a501 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | <template>
<div>
<!-- Stat Cards row -->
<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;">
<!-- Market overview -->
<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>
<!-- Right panels -->
<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>
|