332 lines
7.3 KiB
Vue
332 lines
7.3 KiB
Vue
<template>
|
||
<v-container class="wallet-container">
|
||
<!-- 顶部:Portfolio + Profit/Loss 卡片 -->
|
||
<v-row class="wallet-cards">
|
||
<v-col cols="12" md="6">
|
||
<v-card class="wallet-card portfolio-card" elevation="0" rounded="lg">
|
||
<div class="card-header">
|
||
<span class="card-title">
|
||
Portfolio
|
||
<v-icon size="16" class="title-icon">mdi-eye-off-outline</v-icon>
|
||
</span>
|
||
<div class="balance-badge">
|
||
<v-icon size="14">mdi-sack</v-icon>
|
||
<span>${{ portfolioBalance }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="card-value">${{ portfolioBalance }}</div>
|
||
<div class="card-timeframe">Today</div>
|
||
<div class="card-actions">
|
||
<v-btn color="primary" variant="flat" class="action-btn" prepend-icon="mdi-arrow-down">
|
||
Deposit
|
||
</v-btn>
|
||
<v-btn variant="outlined" color="grey" class="action-btn" prepend-icon="mdi-arrow-up">
|
||
Withdraw
|
||
</v-btn>
|
||
</div>
|
||
</v-card>
|
||
</v-col>
|
||
<v-col cols="12" md="6">
|
||
<v-card class="wallet-card pl-card" elevation="0" rounded="lg">
|
||
<div class="card-header">
|
||
<span class="card-title">
|
||
<v-icon size="16" color="success">mdi-triangle-small-up</v-icon>
|
||
Profit/Loss
|
||
</span>
|
||
<div class="pl-tabs">
|
||
<v-btn
|
||
v-for="t in plTimeRanges"
|
||
:key="t"
|
||
:variant="plRange === t ? 'flat' : 'text'"
|
||
:color="plRange === t ? 'primary' : undefined"
|
||
size="small"
|
||
class="pl-tab"
|
||
@click="plRange = t"
|
||
>
|
||
{{ t }}
|
||
</v-btn>
|
||
</div>
|
||
</div>
|
||
<div class="card-value-row">
|
||
<span class="card-value">${{ profitLoss }}</span>
|
||
<v-icon size="18" class="info-icon">mdi-information-outline</v-icon>
|
||
</div>
|
||
<div class="card-timeframe">All-Time</div>
|
||
<div class="polymarket-logo">
|
||
<span class="logo-p">P</span>
|
||
</div>
|
||
<div class="pl-bar">
|
||
<div class="pl-bar-fill" />
|
||
</div>
|
||
</v-card>
|
||
</v-col>
|
||
</v-row>
|
||
|
||
<!-- 下方:Positions / Open orders / History -->
|
||
<div class="wallet-section">
|
||
<v-tabs v-model="activeTab" class="wallet-tabs" density="comfortable">
|
||
<v-tab value="positions">Positions</v-tab>
|
||
<v-tab value="orders">Open orders</v-tab>
|
||
<v-tab value="history">History</v-tab>
|
||
</v-tabs>
|
||
<div class="toolbar">
|
||
<v-text-field
|
||
v-model="search"
|
||
placeholder="Search"
|
||
density="compact"
|
||
hide-details
|
||
variant="outlined"
|
||
rounded
|
||
class="search-field"
|
||
prepend-inner-icon="mdi-magnify"
|
||
/>
|
||
<v-btn variant="outlined" size="small" class="filter-btn">
|
||
<v-icon size="18">mdi-filter</v-icon>
|
||
Current value
|
||
</v-btn>
|
||
</div>
|
||
<v-card class="table-card" elevation="0" rounded="lg">
|
||
<v-table class="positions-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="text-left">MARKET</th>
|
||
<th class="text-left">
|
||
AVG → NOW
|
||
<v-icon size="14" class="th-icon">mdi-information-outline</v-icon>
|
||
</th>
|
||
<th class="text-left">BET</th>
|
||
<th class="text-left">TO WIN</th>
|
||
<th class="text-left">
|
||
VALUE
|
||
<v-icon size="14" class="th-icon">mdi-chevron-down</v-icon>
|
||
</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-if="positions.length === 0">
|
||
<td colspan="5" class="empty-cell">
|
||
No positions found.
|
||
</td>
|
||
</tr>
|
||
<tr v-for="pos in positions" :key="pos.id">
|
||
<td>{{ pos.market }}</td>
|
||
<td>{{ pos.avgNow }}</td>
|
||
<td>{{ pos.bet }}</td>
|
||
<td>{{ pos.toWin }}</td>
|
||
<td>{{ pos.value }}</td>
|
||
</tr>
|
||
</tbody>
|
||
</v-table>
|
||
</v-card>
|
||
</div>
|
||
</v-container>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed } from 'vue'
|
||
import { useUserStore } from '../stores/user'
|
||
|
||
const userStore = useUserStore()
|
||
const portfolioBalance = computed(() => userStore.balance)
|
||
const profitLoss = ref('0.00')
|
||
const plRange = ref('ALL')
|
||
const plTimeRanges = ['1D', '1W', '1M', 'ALL']
|
||
const activeTab = ref('positions')
|
||
const search = ref('')
|
||
const positions = ref<{ id: string; market: string; avgNow: string; bet: string; toWin: string; value: string }[]>([])
|
||
</script>
|
||
|
||
<style scoped>
|
||
.wallet-container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 24px 16px;
|
||
}
|
||
|
||
.wallet-cards {
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.wallet-card {
|
||
padding: 20px;
|
||
border: 1px solid #e5e7eb;
|
||
height: 100%;
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: #374151;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.title-icon {
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.balance-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
font-size: 12px;
|
||
color: #059669;
|
||
background-color: #d1fae5;
|
||
padding: 4px 8px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.card-value {
|
||
font-size: 28px;
|
||
font-weight: 600;
|
||
color: #111827;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.card-value-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.card-value-row .card-value {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.info-icon {
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.card-timeframe {
|
||
font-size: 12px;
|
||
color: #6b7280;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.card-actions {
|
||
display: flex;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.action-btn {
|
||
text-transform: none;
|
||
}
|
||
|
||
.pl-tabs {
|
||
display: flex;
|
||
gap: 4px;
|
||
}
|
||
|
||
.pl-tab {
|
||
min-width: 40px;
|
||
text-transform: none;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.polymarket-logo {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.logo-p {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 28px;
|
||
height: 28px;
|
||
background: linear-gradient(135deg, #1a73e8 0%, #34a853 100%);
|
||
color: white;
|
||
font-weight: 700;
|
||
font-size: 14px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.pl-bar {
|
||
height: 6px;
|
||
background: #e5e7eb;
|
||
border-radius: 3px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.pl-bar-fill {
|
||
height: 100%;
|
||
width: 40%;
|
||
background: linear-gradient(90deg, #93c5fd 0%, #bfdbfe 100%);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.wallet-section {
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.wallet-tabs {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.toolbar {
|
||
display: flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
margin-bottom: 16px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.search-field {
|
||
max-width: 280px;
|
||
}
|
||
|
||
.search-field :deep(.v-field) {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.filter-btn {
|
||
text-transform: none;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.table-card {
|
||
border: 1px solid #e5e7eb;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.positions-table {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.positions-table th {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
color: #6b7280;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.02em;
|
||
padding: 12px 16px;
|
||
}
|
||
|
||
.th-icon {
|
||
vertical-align: middle;
|
||
margin-left: 2px;
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.positions-table td {
|
||
padding: 12px 16px;
|
||
color: #374151;
|
||
}
|
||
|
||
.empty-cell {
|
||
text-align: center;
|
||
color: #6b7280;
|
||
padding: 48px 16px !important;
|
||
font-size: 14px;
|
||
}
|
||
</style>
|