|
|
<template>
|
|
|
<div class="trading-overview-card">
|
|
|
<div class="card-header">
|
|
|
<div class="title-container">
|
|
|
<h2 class="card-title">牦牛实时交易概况</h2>
|
|
|
<div class="title-tibetan">འབྲོག་གཡག་ཉིན་རེའི་ཚོང་འདུས་གནས་སྟངས།</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="overview-content">
|
|
|
<div class="stats-grid">
|
|
|
<div class="stat-item">
|
|
|
<div class="stat-label">
|
|
|
<span class="chinese">今日入场牦牛数</span>
|
|
|
<span class="tibetan">དེ་རིང་ཞུགས་པའི་གཡག་གྲངས།</span>
|
|
|
</div>
|
|
|
<div class="stat-value primary">{{ todayEntryYaks }}</div>
|
|
|
<div class="stat-unit">头</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-item">
|
|
|
<div class="stat-label">
|
|
|
<span class="chinese">已交易牦牛数</span>
|
|
|
<span class="tibetan">ཚོང་བྱས་ཟིན་པའི་གཡག་གྲངས།</span>
|
|
|
</div>
|
|
|
<div class="stat-value success">{{ tradedYaks }}</div>
|
|
|
<div class="stat-unit">头</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-item">
|
|
|
<div class="stat-label">
|
|
|
<span class="chinese">待交易牦牛数</span>
|
|
|
<span class="tibetan">ཚོང་རྒྱུ་བསྡད་པའི་གཡག་གྲངས།</span>
|
|
|
</div>
|
|
|
<div class="stat-value warning">{{ waitingYaks }}</div>
|
|
|
<div class="stat-unit">头</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-item">
|
|
|
<div class="stat-label">
|
|
|
<span class="chinese">卖家人数</span>
|
|
|
<span class="tibetan">ཚོང་པའི་མི་གྲངས།</span>
|
|
|
</div>
|
|
|
<div class="stat-value info">{{ sellerCount }}</div>
|
|
|
<div class="stat-unit">人</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-item">
|
|
|
<div class="stat-label">
|
|
|
<span class="chinese">剩余车位</span>
|
|
|
<span class="tibetan">ལུས་པའི་མོ་ཊ་གནས་སའི་གྲངས།</span>
|
|
|
</div>
|
|
|
<div class="stat-value danger">{{ remainingParkingSpots }}</div>
|
|
|
<div class="stat-unit">个</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import { ref, onMounted, onUnmounted } from 'vue'
|
|
|
|
|
|
// 实时交易概况数据
|
|
|
const todayEntryYaks = ref(0) // 今日入场牦牛数
|
|
|
const tradedYaks = ref(0) // 已交易牦牛数
|
|
|
const waitingYaks = ref(0) // 待交易牦牛数
|
|
|
const sellerCount = ref(0) // 卖家人数
|
|
|
const remainingParkingSpots = ref(0) // 剩余车位
|
|
|
|
|
|
let updateTimer = null
|
|
|
|
|
|
// 加载牦牛实时交易概况数据
|
|
|
const loadTradingOverviewData = async () => {
|
|
|
try {
|
|
|
console.log('正在从JSON文件加载牦牛实时交易概况数据...')
|
|
|
const response = await fetch('/牦牛实时交易概况.json')
|
|
|
if (!response.ok) {
|
|
|
throw new Error(`HTTP error! status: ${response.status}`)
|
|
|
}
|
|
|
const data = await response.json()
|
|
|
|
|
|
if (data.牦牛实时交易概况) {
|
|
|
const overview = data.牦牛实时交易概况
|
|
|
todayEntryYaks.value = overview.todayEntryYaks || 0
|
|
|
tradedYaks.value = overview.tradedYaks || 0
|
|
|
waitingYaks.value = overview.waitingYaks || 0
|
|
|
sellerCount.value = overview.sellerCount || 0
|
|
|
remainingParkingSpots.value = overview.remainingParkingSpots || 0
|
|
|
console.log('成功加载牦牛实时交易概况数据')
|
|
|
} else {
|
|
|
throw new Error('牦牛实时交易概况数据格式不正确')
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('加载牦牛实时交易概况数据失败,使用默认数据:', error)
|
|
|
loadDefaultTradingData()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 加载默认数据(作为备用方案)
|
|
|
const loadDefaultTradingData = () => {
|
|
|
todayEntryYaks.value = 1256
|
|
|
tradedYaks.value = 847
|
|
|
waitingYaks.value = 409
|
|
|
sellerCount.value = 168
|
|
|
remainingParkingSpots.value = 32
|
|
|
}
|
|
|
|
|
|
// 模拟数据更新
|
|
|
const startDataUpdate = () => {
|
|
|
updateTimer = setInterval(() => {
|
|
|
// 随机增加入场牦牛数
|
|
|
const newEntry = Math.floor(Math.random() * 5)
|
|
|
todayEntryYaks.value += newEntry
|
|
|
|
|
|
// 随机交易一些牦牛
|
|
|
const newTrades = Math.floor(Math.random() * 3)
|
|
|
if (waitingYaks.value >= newTrades) {
|
|
|
tradedYaks.value += newTrades
|
|
|
waitingYaks.value -= newTrades
|
|
|
}
|
|
|
|
|
|
// 更新待交易数量(新入场 - 新交易)
|
|
|
waitingYaks.value += (newEntry - newTrades)
|
|
|
if (waitingYaks.value < 0) waitingYaks.value = 0
|
|
|
|
|
|
// 偶尔更新卖家人数和车位
|
|
|
if (Math.random() > 0.7) {
|
|
|
sellerCount.value += Math.floor(Math.random() * 3) - 1 // -1到1的变化
|
|
|
remainingParkingSpots.value += Math.floor(Math.random() * 5) - 2 // -2到2的变化
|
|
|
|
|
|
// 确保数值合理
|
|
|
if (sellerCount.value < 100) sellerCount.value = 100
|
|
|
if (sellerCount.value > 300) sellerCount.value = 300
|
|
|
if (remainingParkingSpots.value < 0) remainingParkingSpots.value = 0
|
|
|
if (remainingParkingSpots.value > 50) remainingParkingSpots.value = 50
|
|
|
}
|
|
|
}, 30000) // 30秒更新一次
|
|
|
}
|
|
|
|
|
|
onMounted(async () => {
|
|
|
await loadTradingOverviewData()
|
|
|
startDataUpdate()
|
|
|
})
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
if (updateTimer) {
|
|
|
clearInterval(updateTimer)
|
|
|
updateTimer = null
|
|
|
}
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.trading-overview-card {
|
|
|
height: 100%;
|
|
|
background: rgba(15, 25, 45, 0.4);
|
|
|
backdrop-filter: blur(20px) saturate(180%);
|
|
|
border-radius: 32px;
|
|
|
padding: 24px;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
box-shadow:
|
|
|
0 16px 64px rgba(0, 0, 0, 0.3),
|
|
|
0 8px 32px rgba(64, 158, 255, 0.1),
|
|
|
inset 0 2px 0 rgba(255, 255, 255, 0.1);
|
|
|
}
|
|
|
|
|
|
.card-header {
|
|
|
margin-bottom: 40px;
|
|
|
}
|
|
|
|
|
|
.title-container {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 32px;
|
|
|
}
|
|
|
|
|
|
.card-title {
|
|
|
font-size: 28px;
|
|
|
font-weight: 700;
|
|
|
background: linear-gradient(135deg, #409EFF 0%, #67C23A 100%);
|
|
|
-webkit-background-clip: text;
|
|
|
-webkit-text-fill-color: transparent;
|
|
|
background-clip: text;
|
|
|
margin: 0;
|
|
|
text-align: left;
|
|
|
}
|
|
|
|
|
|
.title-tibetan {
|
|
|
font-size: 28px;
|
|
|
color: #67C23A;
|
|
|
font-weight: 600;
|
|
|
opacity: 0.8;
|
|
|
}
|
|
|
|
|
|
.overview-content {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
}
|
|
|
|
|
|
.stats-grid {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(5, 1fr);
|
|
|
gap: 20px;
|
|
|
flex: 1;
|
|
|
}
|
|
|
|
|
|
.stat-item {
|
|
|
background: rgba(255, 255, 255, 0.05);
|
|
|
border-radius: 20px;
|
|
|
padding: 24px;
|
|
|
text-align: center;
|
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: center;
|
|
|
min-height: 0;
|
|
|
}
|
|
|
|
|
|
.stat-label {
|
|
|
margin-bottom: 20px;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 8px;
|
|
|
}
|
|
|
|
|
|
.stat-label .chinese {
|
|
|
font-size: 28px;
|
|
|
color: #ffffff;
|
|
|
font-weight: 600;
|
|
|
line-height: 1.2;
|
|
|
}
|
|
|
|
|
|
.stat-label .tibetan {
|
|
|
font-size: 28px;
|
|
|
color: #67C23A;
|
|
|
opacity: 0.8;
|
|
|
line-height: 1.2;
|
|
|
}
|
|
|
|
|
|
.stat-value {
|
|
|
font-size: 64px;
|
|
|
font-weight: 700;
|
|
|
margin-bottom: 8px;
|
|
|
line-height: 1;
|
|
|
}
|
|
|
|
|
|
.stat-value.primary {
|
|
|
color: #409EFF;
|
|
|
}
|
|
|
|
|
|
.stat-value.success {
|
|
|
color: #67C23A;
|
|
|
}
|
|
|
|
|
|
.stat-value.warning {
|
|
|
color: #E6A23C;
|
|
|
}
|
|
|
|
|
|
.stat-value.danger {
|
|
|
color: #F56C6C;
|
|
|
}
|
|
|
|
|
|
.stat-value.info {
|
|
|
color: #17A2B8;
|
|
|
}
|
|
|
|
|
|
.stat-unit {
|
|
|
font-size: 32px;
|
|
|
color: #a0a8b8;
|
|
|
margin-top: 8px;
|
|
|
}
|
|
|
</style> |