新增:交易详情增加成单记录
This commit is contained in:
parent
3688ce656d
commit
b2ac4ec9f3
@ -114,16 +114,22 @@ const bids = ref([
|
|||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
// Update random ask price and shares
|
// Update random ask price and shares
|
||||||
const randomAskIndex = Math.floor(Math.random() * asks.value.length)
|
const randomAskIndex = Math.floor(Math.random() * asks.value.length)
|
||||||
asks.value[randomAskIndex] = {
|
const askItem = asks.value[randomAskIndex]
|
||||||
...asks.value[randomAskIndex],
|
if (askItem) {
|
||||||
shares: Math.max(0, asks.value[randomAskIndex].shares + Math.floor(Math.random() * 100) - 50),
|
asks.value[randomAskIndex] = {
|
||||||
|
price: askItem.price,
|
||||||
|
shares: Math.max(0, askItem.shares + Math.floor(Math.random() * 100) - 50),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update random bid price and shares
|
// Update random bid price and shares
|
||||||
const randomBidIndex = Math.floor(Math.random() * bids.value.length)
|
const randomBidIndex = Math.floor(Math.random() * bids.value.length)
|
||||||
bids.value[randomBidIndex] = {
|
const bidItem = bids.value[randomBidIndex]
|
||||||
...bids.value[randomBidIndex],
|
if (bidItem) {
|
||||||
shares: Math.max(0, bids.value[randomBidIndex].shares + Math.floor(Math.random() * 100) - 50),
|
bids.value[randomBidIndex] = {
|
||||||
|
price: bidItem.price,
|
||||||
|
shares: Math.max(0, bidItem.shares + Math.floor(Math.random() * 100) - 50),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update last price
|
// Update last price
|
||||||
|
|||||||
@ -45,6 +45,66 @@
|
|||||||
<v-card class="order-book-card" elevation="0" rounded="lg" style="margin-top: 32px">
|
<v-card class="order-book-card" elevation="0" rounded="lg" style="margin-top: 32px">
|
||||||
<OrderBook />
|
<OrderBook />
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
|
<!-- Comments / Top Holders / Activity(与左侧图表、订单簿同宽) -->
|
||||||
|
<v-card class="activity-card" elevation="0" rounded="lg">
|
||||||
|
<v-tabs v-model="detailTab" class="detail-tabs" density="comfortable">
|
||||||
|
<v-tab value="comments">Comments</v-tab>
|
||||||
|
<v-tab value="holders">Top Holders</v-tab>
|
||||||
|
<v-tab value="activity">Activity</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
<v-window v-model="detailTab" class="detail-window">
|
||||||
|
<v-window-item value="comments" class="detail-pane">
|
||||||
|
<div class="placeholder-pane">No comments yet.</div>
|
||||||
|
</v-window-item>
|
||||||
|
<v-window-item value="holders" class="detail-pane">
|
||||||
|
<div class="placeholder-pane">Top holders will appear here.</div>
|
||||||
|
</v-window-item>
|
||||||
|
<v-window-item value="activity" class="detail-pane">
|
||||||
|
<div class="activity-toolbar">
|
||||||
|
<v-select
|
||||||
|
v-model="activityMinAmount"
|
||||||
|
:items="minAmountOptions"
|
||||||
|
density="compact"
|
||||||
|
hide-details
|
||||||
|
variant="outlined"
|
||||||
|
label="Min amount"
|
||||||
|
class="min-amount-select"
|
||||||
|
/>
|
||||||
|
<span class="live-badge">
|
||||||
|
<span class="live-dot"></span>
|
||||||
|
Live
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-list">
|
||||||
|
<div
|
||||||
|
v-for="item in filteredActivity"
|
||||||
|
:key="item.id"
|
||||||
|
class="activity-item"
|
||||||
|
>
|
||||||
|
<div class="activity-avatar" :class="item.avatarClass">
|
||||||
|
<img v-if="item.avatarUrl" :src="item.avatarUrl" :alt="item.user" class="avatar-img" />
|
||||||
|
</div>
|
||||||
|
<div class="activity-body">
|
||||||
|
<span class="activity-user">{{ item.user }}</span>
|
||||||
|
<span class="activity-action">{{ item.action }}</span>
|
||||||
|
<span :class="['activity-amount', item.side === 'Yes' ? 'amount-yes' : 'amount-no']">
|
||||||
|
{{ item.amount }} {{ item.side }}
|
||||||
|
</span>
|
||||||
|
<span class="activity-price">at {{ item.price }}</span>
|
||||||
|
<span class="activity-total">({{ item.total }})</span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-meta">
|
||||||
|
<span class="activity-time">{{ formatTimeAgo(item.time) }}</span>
|
||||||
|
<a href="#" class="activity-link" aria-label="View transaction" @click.prevent>
|
||||||
|
<v-icon size="16">mdi-open-in-new</v-icon>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</v-window-item>
|
||||||
|
</v-window>
|
||||||
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 右侧:交易组件(固定宽度) -->
|
<!-- 右侧:交易组件(固定宽度) -->
|
||||||
@ -105,6 +165,55 @@ const resolutionDate = computed(() => {
|
|||||||
return s ? s.replace(/,?\s*\d{4}$/, '').trim() || 'Mar 31' : 'Mar 31'
|
return s ? s.replace(/,?\s*\d{4}$/, '').trim() || 'Mar 31' : 'Mar 31'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Comments / Top Holders / Activity
|
||||||
|
const detailTab = ref('activity')
|
||||||
|
const activityMinAmount = ref<string>('0')
|
||||||
|
const minAmountOptions = [
|
||||||
|
{ title: 'Any', value: '0' },
|
||||||
|
{ title: '$1', value: '1' },
|
||||||
|
{ title: '$10', value: '10' },
|
||||||
|
{ title: '$100', value: '100' },
|
||||||
|
{ title: '$500', value: '500' },
|
||||||
|
]
|
||||||
|
|
||||||
|
interface ActivityItem {
|
||||||
|
id: string
|
||||||
|
user: string
|
||||||
|
avatarClass: string
|
||||||
|
avatarUrl?: string
|
||||||
|
action: 'bought' | 'sold'
|
||||||
|
side: 'Yes' | 'No'
|
||||||
|
amount: number
|
||||||
|
price: string
|
||||||
|
total: string
|
||||||
|
time: number
|
||||||
|
}
|
||||||
|
const activityList = ref<ActivityItem[]>([
|
||||||
|
{ id: 'a1', user: 'Scottp1887', avatarClass: 'avatar-gradient-1', action: 'bought', side: 'Yes', amount: 914, price: '32.8¢', total: '$300', time: Date.now() - 10 * 60 * 1000 },
|
||||||
|
{ id: 'a2', user: 'Outrageous-Budd...', avatarClass: 'avatar-gradient-2', action: 'sold', side: 'No', amount: 20, price: '70.0¢', total: '$14', time: Date.now() - 29 * 60 * 1000 },
|
||||||
|
{ id: 'a3', user: '0xbc7db42d5ea9a...', avatarClass: 'avatar-gradient-3', action: 'bought', side: 'Yes', amount: 5, price: '68.0¢', total: '$3.40', time: Date.now() - 60 * 60 * 1000 },
|
||||||
|
{ id: 'a4', user: 'FINNISH-FEMBOY', avatarClass: 'avatar-gradient-4', action: 'sold', side: 'No', amount: 57, price: '35.0¢', total: '$20', time: Date.now() - 2 * 60 * 60 * 1000 },
|
||||||
|
{ id: 'a5', user: 'CryptoWhale', avatarClass: 'avatar-gradient-1', action: 'bought', side: 'No', amount: 143, price: '28.0¢', total: '$40', time: Date.now() - 3 * 60 * 60 * 1000 },
|
||||||
|
{ id: 'a6', user: 'PolyTrader', avatarClass: 'avatar-gradient-2', action: 'sold', side: 'Yes', amount: 30, price: '72.0¢', total: '$21.60', time: Date.now() - 5 * 60 * 60 * 1000 },
|
||||||
|
])
|
||||||
|
|
||||||
|
const filteredActivity = computed(() => {
|
||||||
|
const min = Number(activityMinAmount.value) || 0
|
||||||
|
return activityList.value.filter((item) => {
|
||||||
|
const totalNum = parseFloat(item.total.replace(/[$,]/g, ''))
|
||||||
|
return totalNum >= min
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function formatTimeAgo(ts: number): string {
|
||||||
|
const sec = Math.floor((Date.now() - ts) / 1000)
|
||||||
|
if (sec < 60) return 'just now'
|
||||||
|
if (sec < 3600) return `${Math.floor(sec / 60)}m ago`
|
||||||
|
if (sec < 86400) return `${Math.floor(sec / 3600)}h ago`
|
||||||
|
if (sec < 604800) return `${Math.floor(sec / 86400)}d ago`
|
||||||
|
return `${Math.floor(sec / 604800)}w ago`
|
||||||
|
}
|
||||||
|
|
||||||
// 时间粒度
|
// 时间粒度
|
||||||
const selectedTimeRange = ref('ALL')
|
const selectedTimeRange = ref('ALL')
|
||||||
const timeRanges = [
|
const timeRanges = [
|
||||||
@ -706,4 +815,189 @@ onUnmounted(() => {
|
|||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Comments / Top Holders / Activity */
|
||||||
|
.activity-card {
|
||||||
|
margin-top: 32px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-tabs {
|
||||||
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-tabs :deep(.v-tab) {
|
||||||
|
text-transform: none;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-window {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-pane {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-pane {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.min-amount-select {
|
||||||
|
max-width: 140px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.min-amount-select :deep(.v-field) {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #dc2626;
|
||||||
|
animation: live-pulse 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes live-pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-gradient-1 {
|
||||||
|
background: linear-gradient(135deg, #10b981 0%, #8b5cf6 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-gradient-2 {
|
||||||
|
background: linear-gradient(135deg, #10b981 0%, #3b82f6 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-gradient-3 {
|
||||||
|
background: linear-gradient(135deg, #f59e0b 0%, #eab308 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-gradient-4 {
|
||||||
|
background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-body {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-user {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #111827;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-action {
|
||||||
|
color: #6b7280;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-amount {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-yes {
|
||||||
|
color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-no {
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-price {
|
||||||
|
color: #6b7280;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-total {
|
||||||
|
color: #6b7280;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-time {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-link {
|
||||||
|
color: #9ca3af;
|
||||||
|
display: inline-flex;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-link:hover {
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user