diff --git a/src/components/OrderBook.vue b/src/components/OrderBook.vue index 6410947..1a0c259 100644 --- a/src/components/OrderBook.vue +++ b/src/components/OrderBook.vue @@ -114,16 +114,22 @@ const bids = ref([ setInterval(() => { // Update random ask price and shares const randomAskIndex = Math.floor(Math.random() * asks.value.length) - asks.value[randomAskIndex] = { - ...asks.value[randomAskIndex], - shares: Math.max(0, asks.value[randomAskIndex].shares + Math.floor(Math.random() * 100) - 50), + const askItem = asks.value[randomAskIndex] + if (askItem) { + asks.value[randomAskIndex] = { + price: askItem.price, + shares: Math.max(0, askItem.shares + Math.floor(Math.random() * 100) - 50), + } } // Update random bid price and shares const randomBidIndex = Math.floor(Math.random() * bids.value.length) - bids.value[randomBidIndex] = { - ...bids.value[randomBidIndex], - shares: Math.max(0, bids.value[randomBidIndex].shares + Math.floor(Math.random() * 100) - 50), + const bidItem = bids.value[randomBidIndex] + if (bidItem) { + bids.value[randomBidIndex] = { + price: bidItem.price, + shares: Math.max(0, bidItem.shares + Math.floor(Math.random() * 100) - 50), + } } // Update last price diff --git a/src/views/TradeDetail.vue b/src/views/TradeDetail.vue index 5371cb0..88c1839 100644 --- a/src/views/TradeDetail.vue +++ b/src/views/TradeDetail.vue @@ -45,6 +45,66 @@ + + + + + Comments + Top Holders + Activity + + + + No comments yet. + + + Top holders will appear here. + + + + + + + Live + + + + + + + + + {{ item.user }} + {{ item.action }} + + {{ item.amount }} {{ item.side }} + + at {{ item.price }} + ({{ item.total }}) + + + {{ formatTimeAgo(item.time) }} + + mdi-open-in-new + + + + + + + @@ -105,6 +165,55 @@ const resolutionDate = computed(() => { return s ? s.replace(/,?\s*\d{4}$/, '').trim() || 'Mar 31' : 'Mar 31' }) +// Comments / Top Holders / Activity +const detailTab = ref('activity') +const activityMinAmount = ref('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([ + { 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 timeRanges = [ @@ -706,4 +815,189 @@ onUnmounted(() => { 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; +}