You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
livestock-trading/src/components/YakTradingData.vue

313 lines
6.9 KiB

<template>
<BaseCard title="交易所牦牛成交数据">
<div class="time-selector">
<div class="selector-buttons">
<button
v-for="period in timePeriods"
:key="period.value"
:class="['period-btn', { active: selectedPeriod === period.value }]"
@click="changePeriod(period.value)"
>
{{ period.label }}
</button>
</div>
</div>
<div ref="chartRef" class="chart"></div>
</BaseCard>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
import * as echarts from 'echarts'
import BaseCard from './BaseCard.vue'
const chartRef = ref(null)
let chartInstance = null
const selectedPeriod = ref('day')
const timePeriods = [
{ label: '日', value: 'day' },
{ label: '周', value: 'week' },
{ label: '月', value: 'month' }
]
// 生成时间标签
const generateTimeLabels = (period) => {
const now = new Date()
const labels = []
if (period === 'day') {
// 过去6天
for (let i = 5; i >= 0; i--) {
const date = new Date(now)
date.setDate(date.getDate() - i)
labels.push(`${date.getMonth() + 1}/${date.getDate()}`)
}
} else if (period === 'week') {
// 过去6周
for (let i = 5; i >= 0; i--) {
const date = new Date(now)
date.setDate(date.getDate() - i * 7)
const weekStart = new Date(date)
const weekEnd = new Date(date)
weekEnd.setDate(weekEnd.getDate() + 6)
labels.push(`${weekStart.getMonth() + 1}/${weekStart.getDate()}-${weekEnd.getMonth() + 1}/${weekEnd.getDate()}`)
}
} else if (period === 'month') {
// 过去6个月
for (let i = 5; i >= 0; i--) {
const date = new Date(now)
date.setMonth(date.getMonth() - i)
labels.push(`${date.getFullYear()}/${date.getMonth() + 1}`)
}
}
return labels
}
// 生成模拟数据
const generateMockData = (period) => {
const baseTrading = period === 'day' ? 150 : period === 'week' ? 800 : 3500
const baseOrders = period === 'day' ? 45 : period === 'week' ? 280 : 1200
const tradingData = []
const orderData = []
for (let i = 0; i < 6; i++) {
const tradingVariation = Math.floor(Math.random() * 200) - 100
const orderVariation = Math.floor(Math.random() * 60) - 30
tradingData.push(baseTrading + tradingVariation)
orderData.push(baseOrders + orderVariation)
}
return { tradingData, orderData }
}
const initChart = () => {
if (!chartRef.value) return
chartInstance = echarts.init(chartRef.value)
updateChart()
}
const updateChart = () => {
if (!chartInstance) return
const timeLabels = generateTimeLabels(selectedPeriod.value)
const { tradingData, orderData } = generateMockData(selectedPeriod.value)
const option = {
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: '#409EFF',
textStyle: {
color: '#fff',
fontSize: 12
},
formatter: function(params) {
let result = `${params[0].axisValue}<br/>`
params.forEach(param => {
const unit = param.seriesName === '牦牛交易数量' ? '头' : '单'
result += `${param.marker}${param.seriesName}: ${param.value}${unit}<br/>`
})
return result
}
},
grid: {
left: '8%',
right: '8%',
bottom: '15%',
top: '20%'
},
legend: {
data: ['牦牛交易数量', '成交订单数量'],
textStyle: {
color: '#a0a8b8',
fontSize: 11
},
top: '8%'
},
xAxis: {
type: 'category',
data: timeLabels,
axisLine: {
lineStyle: {
color: '#4a5568'
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#a0a8b8',
fontSize: 10,
rotate: selectedPeriod.value === 'week' ? 45 : 0
}
},
yAxis: [
{
type: 'value',
name: '交易数量(头)',
position: 'left',
splitLine: {
lineStyle: {
color: '#2d3748',
type: 'dashed'
}
},
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#a0a8b8',
fontSize: 10
},
nameTextStyle: {
color: '#a0a8b8',
fontSize: 10
}
},
{
type: 'value',
name: '订单数量(单)',
position: 'right',
splitLine: {
show: false
},
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#a0a8b8',
fontSize: 10
},
nameTextStyle: {
color: '#a0a8b8',
fontSize: 10
}
}
],
series: [
{
name: '牦牛交易数量',
type: 'line',
yAxisIndex: 0,
data: tradingData,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
color: '#409EFF',
width: 3
},
itemStyle: {
color: '#409EFF',
borderColor: '#fff',
borderWidth: 2
},
// areaStyle: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// { offset: 0, color: 'rgba(64, 158, 255, 0.3)' },
// { offset: 1, color: 'rgba(64, 158, 255, 0.05)' }
// ])
// }
},
{
name: '成交订单数量',
type: 'line',
yAxisIndex: 1,
data: orderData,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
color: '#67C23A',
width: 3
},
itemStyle: {
color: '#67C23A',
borderColor: '#fff',
borderWidth: 2
},
// areaStyle: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// { offset: 0, color: 'rgba(103, 194, 58, 0.2)' },
// { offset: 1, color: 'rgba(103, 194, 58, 0.05)' }
// ])
// }
}
]
}
chartInstance.setOption(option, true)
}
const changePeriod = (period) => {
selectedPeriod.value = period
}
// 监听时间周期变化
watch(selectedPeriod, () => {
updateChart()
})
onMounted(() => {
initChart()
window.addEventListener('resize', () => {
chartInstance?.resize()
})
})
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose()
}
})
</script>
<style scoped>
.time-selector {
padding: 0 20px 15px;
}
.selector-buttons {
display: flex;
gap: 8px;
justify-content: center;
}
.period-btn {
padding: 6px 16px;
border: 1px solid #4a5568;
background: transparent;
color: #a0a8b8;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.3s ease;
}
.period-btn:hover {
border-color: #409EFF;
color: #409EFF;
}
.period-btn.active {
border-color: #409EFF;
background: #409EFF;
color: #fff;
}
.chart {
width: 100%;
height: calc(100% - 60px);
}
</style>