552 lines
17 KiB
Vue
552 lines
17 KiB
Vue
|
|
<script>
|
|||
|
|
import { ref, computed, onMounted } from 'vue'
|
|||
|
|
import { use } from 'echarts/core'
|
|||
|
|
import { CanvasRenderer } from 'echarts/renderers'
|
|||
|
|
import { LineChart } from 'echarts/charts'
|
|||
|
|
import { TitleComponent, TooltipComponent, GridComponent, LegendComponent } from 'echarts/components'
|
|||
|
|
import VChart from 'vue-echarts'
|
|||
|
|
|
|||
|
|
use([CanvasRenderer, LineChart, TitleComponent, TooltipComponent, GridComponent, LegendComponent])
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
name: 'Price',
|
|||
|
|
components: { VChart },
|
|||
|
|
props: {
|
|||
|
|
selectedProvince: {
|
|||
|
|
type: String,
|
|||
|
|
default: ''
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
setup(props) {
|
|||
|
|
const provinceNameMap = {
|
|||
|
|
BJ: '北京市', TJ: '天津市', HE: '河北省', SX: '山西省', NM: '内蒙古自治区',
|
|||
|
|
LN: '辽宁省', JL: '吉林省', HL: '黑龙江省', SH: '上海市', JS: '江苏省',
|
|||
|
|
ZJ: '浙江省', AH: '安徽省', FJ: '福建省', JX: '江西省', SD: '山东省',
|
|||
|
|
HA: '河南省', HB: '湖北省', HN: '湖南省', GD: '广东省', GX: '广西壮族自治区',
|
|||
|
|
HI: '海南省', CQ: '重庆市', SC: '四川省', GZ: '贵州省', YN: '云南省',
|
|||
|
|
XZ: '西藏自治区', SN: '陕西省', GS: '甘肃省', QH: '青海省', NX: '宁夏回族自治区', XJ: '新疆维吾尔自治区'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const provinceName = computed(() => provinceNameMap[props.selectedProvince] || props.selectedProvince || '未知地区')
|
|||
|
|
|
|||
|
|
// 省份基础价(元/斤),用于生成示例数据
|
|||
|
|
const basePriceMap = {
|
|||
|
|
NX: 6.8, BJ: 7.2, TJ: 6.9, HI: 7.0, CQ: 6.7, HE: 6.6, SD: 6.9, HB: 6.8
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 牛品种列表(示例)
|
|||
|
|
const breedListMap = {
|
|||
|
|
default: ['西门塔尔牛', '利木赞牛', '夏洛来牛', '本地黄牛'],
|
|||
|
|
NX: ['西门塔尔牛', '本地黄牛', '海福特牛'],
|
|||
|
|
BJ: ['利木赞牛', '安格斯牛', '夏洛来牛'],
|
|||
|
|
HI: ['本地黄牛', '安格斯牛'],
|
|||
|
|
CQ: ['本地黄牛', '西门塔尔牛']
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const unit = ref('元/个')
|
|||
|
|
const days = ref([])
|
|||
|
|
const priceSeries = ref([])
|
|||
|
|
// 省内各地区牛数据列表
|
|||
|
|
const regionRows = ref([])
|
|||
|
|
const selectedRow = ref(null)
|
|||
|
|
|
|||
|
|
const todayPrice = computed(() => (priceSeries.value[priceSeries.value.length - 1] ?? 0))
|
|||
|
|
const max7d = computed(() => (priceSeries.value.length ? Math.max(...priceSeries.value) : 0))
|
|||
|
|
const min7d = computed(() => (priceSeries.value.length ? Math.min(...priceSeries.value) : 0))
|
|||
|
|
const avg7d = computed(() => {
|
|||
|
|
if (!priceSeries.value.length) return 0
|
|||
|
|
const sum = priceSeries.value.reduce((acc, v) => acc + v, 0)
|
|||
|
|
return +(sum / priceSeries.value.length).toFixed(2)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 当日均价(以省内各地区列表的当日价格求平均;无列表则回退为趋势当日值)
|
|||
|
|
const avgToday = computed(() => {
|
|||
|
|
if (selectedRow.value && selectedRow.value.price) {
|
|||
|
|
return +(selectedRow.value.price).toFixed(2)
|
|||
|
|
}
|
|||
|
|
if (regionRows.value.length) {
|
|||
|
|
const sum = regionRows.value.reduce((acc, r) => acc + (r.price || 0), 0)
|
|||
|
|
return +(sum / regionRows.value.length).toFixed(2)
|
|||
|
|
}
|
|||
|
|
return todayPrice.value
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const breeds = computed(() => breedListMap[props.selectedProvince] || breedListMap.default)
|
|||
|
|
|
|||
|
|
// 日期范围与重量类别筛选
|
|||
|
|
const range = ref(7) // 7/30/60
|
|||
|
|
const weight = ref('normal') // normal/400/500
|
|||
|
|
const setRange = (v) => { range.value = v; genData(selectedRow.value?.id) }
|
|||
|
|
const setWeight = (w) => { weight.value = w; genData(selectedRow.value?.id) }
|
|||
|
|
|
|||
|
|
const isUnknownRegion = (name) => {
|
|||
|
|
const n = (name ?? '').toString()
|
|||
|
|
return n === '未知地区' || n.startsWith('未知地区 ')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const chartOption = computed(() => ({
|
|||
|
|
title: { text: `${provinceName.value} 牛价趋势`, left: 'center', textStyle: { color: '#00d4ff' } },
|
|||
|
|
tooltip: { trigger: 'axis' },
|
|||
|
|
grid: { left: 40, right: 20, top: 60, bottom: 40 },
|
|||
|
|
xAxis: { type: 'category', data: days.value, axisLabel: { color: '#cfefff' }, axisLine: { lineStyle: { color: '#2e6ba8' } } },
|
|||
|
|
yAxis: { type: 'value', axisLabel: { color: '#cfefff' }, splitLine: { lineStyle: { color: 'rgba(0,212,255,0.2)' } } },
|
|||
|
|
series: [{
|
|||
|
|
name: '牛价', type: 'line', smooth: true, data: priceSeries.value,
|
|||
|
|
lineStyle: { color: '#00d4ff', width: 2 },
|
|||
|
|
itemStyle: { color: '#00ffcc' },
|
|||
|
|
areaStyle: { color: 'rgba(0,212,255,0.15)' }
|
|||
|
|
}]
|
|||
|
|
}))
|
|||
|
|
|
|||
|
|
// 生成省内地区牛数据列表(示例,固定为10行)
|
|||
|
|
const genRegionRows = () => {
|
|||
|
|
const today = new Date()
|
|||
|
|
const fmt = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`
|
|||
|
|
const regionTypes = [
|
|||
|
|
'省会城区','市辖区','回族自治县','张北县','市郊区',
|
|||
|
|
'开发区','交易市场','牧区','新区','工业园区'
|
|||
|
|
]
|
|||
|
|
const regions = regionTypes.map(t => `${provinceName.value} ${t}`)
|
|||
|
|
const base = basePriceMap[props.selectedProvince] ?? 6.8
|
|||
|
|
regionRows.value = regions.slice(0, 10).map((r, idx) => {
|
|||
|
|
const d = new Date(today)
|
|||
|
|
const fluct = (Math.sin(idx) * 0.08) + (Math.random() * 0.12 - 0.06)
|
|||
|
|
const breed = (breeds.value[idx % breeds.value.length])
|
|||
|
|
const price = +((base + fluct)).toFixed(2)
|
|||
|
|
const delta = +((Math.random() * 0.6 - 0.3)).toFixed(2)
|
|||
|
|
return {
|
|||
|
|
date: fmt(d),
|
|||
|
|
breed,
|
|||
|
|
region: r,
|
|||
|
|
price,
|
|||
|
|
delta,
|
|||
|
|
up: delta > 0,
|
|||
|
|
id: `${props.selectedProvince}-${idx}`
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
const genData = (regionId = null) => {
|
|||
|
|
// 根据筛选生成最近 N 天日期与价格数据(可按地区与重量微调)
|
|||
|
|
const baseBase = basePriceMap[props.selectedProvince] ?? 6.8
|
|||
|
|
const regionOffset = regionId ? (parseInt(regionId.split('-')[1]) || 0) * 0.03 : 0
|
|||
|
|
const weightOffset = weight.value === '400' ? 0.15 : (weight.value === '500' ? 0.25 : 0)
|
|||
|
|
const base = baseBase + regionOffset + weightOffset
|
|||
|
|
const today = new Date()
|
|||
|
|
const d = []
|
|||
|
|
const p = []
|
|||
|
|
const count = range.value
|
|||
|
|
for (let i = count - 1; i >= 0; i--) {
|
|||
|
|
const dt = new Date(today)
|
|||
|
|
dt.setDate(today.getDate() - i)
|
|||
|
|
d.push(`${dt.getMonth() + 1}-${String(dt.getDate()).padStart(2, '0')}`)
|
|||
|
|
// 价格在基础价附近小幅波动
|
|||
|
|
const fluct = (Math.sin(i) * 0.08) + (Math.random() * 0.12 - 0.06)
|
|||
|
|
p.push(+((base + fluct)).toFixed(2))
|
|||
|
|
}
|
|||
|
|
days.value = d
|
|||
|
|
priceSeries.value = p
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handleRowClick = (row) => {
|
|||
|
|
selectedRow.value = row
|
|||
|
|
genData(row?.id)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const yesterdayDelta = computed(() => {
|
|||
|
|
if (!priceSeries.value.length || priceSeries.value.length < 2) return 0
|
|||
|
|
const n = priceSeries.value.length
|
|||
|
|
return +(priceSeries.value[n - 1] - priceSeries.value[n - 2]).toFixed(2)
|
|||
|
|
})
|
|||
|
|
const trendText = computed(() => {
|
|||
|
|
const d = yesterdayDelta.value
|
|||
|
|
if (Math.abs(d) < 0.01) return '平稳'
|
|||
|
|
return d > 0 ? '上涨' : '下跌'
|
|||
|
|
})
|
|||
|
|
const trendSymbol = computed(() => {
|
|||
|
|
const d = yesterdayDelta.value
|
|||
|
|
if (Math.abs(d) < 0.01) return '-'
|
|||
|
|
return d > 0 ? '↑' : '↓'
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
onMounted(() => {
|
|||
|
|
genRegionRows()
|
|||
|
|
genData()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return { unit, provinceName, breeds, todayPrice, max7d, min7d, avg7d, avgToday, days, priceSeries, chartOption, regionRows, selectedRow, handleRowClick, isUnknownRegion, range, weight, setRange, setWeight, yesterdayDelta, trendText, trendSymbol }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<template>
|
|||
|
|
<div class="price-page">
|
|||
|
|
<div class="price-header">
|
|||
|
|
<h2><span :class="{ highlight: isUnknownRegion(provinceName) }">{{ provinceName }}</span> 牛价行情</h2>
|
|||
|
|
<!-- <div class="unit">单位:<span>{{ unit }}</span></div> -->
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="price-content">
|
|||
|
|
<section class="left-info">
|
|||
|
|
<div class="card region-card">
|
|||
|
|
<div class="panel-header">
|
|||
|
|
<div class="diamond-icon"></div>
|
|||
|
|
<h3>省内各地区牛数据列表</h3>
|
|||
|
|
</div>
|
|||
|
|
<div class="region-table">
|
|||
|
|
<div class="table-header">
|
|||
|
|
<div class="th">时间</div>
|
|||
|
|
<div class="th">地区</div>
|
|||
|
|
<div class="th">品类</div>
|
|||
|
|
<div class="th">价格({{ unit }})</div>
|
|||
|
|
<div class="th">涨跌</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="table-body">
|
|||
|
|
<div class="table-row" v-for="row in regionRows" :key="row.id" @click="handleRowClick(row)" :class="{ active: selectedRow && selectedRow.id === row.id }">
|
|||
|
|
<div class="td">{{ row.date }}</div>
|
|||
|
|
<div class="td">{{ row.region }}</div>
|
|||
|
|
<div class="td">{{ row.breed }}</div>
|
|||
|
|
<div class="td">{{ row.price.toFixed(2) }}{{ unit }}</div>
|
|||
|
|
<div class="td">
|
|||
|
|
<span :class="row.delta === 0 ? 'change-zero' : (row.up ? 'change-up' : 'change-down')">
|
|||
|
|
{{ row.delta.toFixed(2) }}{{ unit }}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="right-stats">
|
|||
|
|
<div class="card detail-card">
|
|||
|
|
<div class="panel-header">
|
|||
|
|
<div class="diamond-icon"></div>
|
|||
|
|
<h3>
|
|||
|
|
<span :class="{ highlight: isUnknownRegion(selectedRow ? selectedRow.region : provinceName) }">
|
|||
|
|
{{ (selectedRow ? selectedRow.region : provinceName) }}
|
|||
|
|
</span>
|
|||
|
|
价格详情
|
|||
|
|
</h3>
|
|||
|
|
</div>
|
|||
|
|
<div class="detail-content">
|
|||
|
|
<div class="today-price-line">
|
|||
|
|
<div class="labels">
|
|||
|
|
<span class="label">今日批发均价</span>
|
|||
|
|
<span class="compare">相比昨日 <span :class="yesterdayDelta === 0 ? 'change-zero' : (yesterdayDelta > 0 ? 'change-up' : 'change-down')">{{ trendText }} {{ yesterdayDelta.toFixed(2) }}</span> <span class="symbol">{{ trendSymbol }}</span></span>
|
|||
|
|
</div>
|
|||
|
|
<div class="price-display">
|
|||
|
|
<span class="currency">¥</span>
|
|||
|
|
<span class="value">{{ avgToday.toFixed(2) }}</span>
|
|||
|
|
<span class="unit">{{ unit }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="filters">
|
|||
|
|
<div class="weight-group">
|
|||
|
|
<button :class="['filter-btn', { active: weight === 'normal' }]" @click="setWeight('normal')">通货</button>
|
|||
|
|
<button :class="['filter-btn', { active: weight === '400' }]" @click="setWeight('400')">400斤</button>
|
|||
|
|
<button :class="['filter-btn', { active: weight === '500' }]" @click="setWeight('500')">500斤</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="range-group">
|
|||
|
|
<button :class="['filter-btn', { active: range === 7 }]" @click="setRange(7)">近7天</button>
|
|||
|
|
<button :class="['filter-btn', { active: range === 30 }]" @click="setRange(30)">近30天</button>
|
|||
|
|
<button :class="['filter-btn', { active: range === 60 }]" @click="setRange(60)">近60天</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<v-chart class="trend-chart" :option="chartOption" autoresize />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.price-page {
|
|||
|
|
width: 100%;
|
|||
|
|
height: calc(100vh - 80px);
|
|||
|
|
padding: 16px 24px;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 16px;
|
|||
|
|
background: #011819; /* 与预警监测页背景一致 */
|
|||
|
|
position: relative;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.price-page::before {
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
top: 0; left: 0; right: 0; bottom: 0;
|
|||
|
|
background:
|
|||
|
|
rgba(0, 212, 255, 0.05),
|
|||
|
|
rgba(0, 212, 255, 0.03),
|
|||
|
|
rgba(0, 212, 255, 0.02);
|
|||
|
|
pointer-events: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.price-page > * { position: relative; z-index: 1; }
|
|||
|
|
|
|||
|
|
.price-header {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: center;
|
|||
|
|
align-items: center;
|
|||
|
|
background: rgba(255,255,255,0.06);
|
|||
|
|
border: 1px solid rgba(0,212,255,0.25);
|
|||
|
|
padding: 10px 16px;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.price-header h2 {
|
|||
|
|
font-size: 18px;
|
|||
|
|
color: #eaf7ff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.unit span {
|
|||
|
|
color: #00ffcc;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.price-content {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: 1.4fr 1.6fr; /* 加宽左侧列表区域 */
|
|||
|
|
gap: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.card {
|
|||
|
|
background: rgba(7, 59, 68, 0.15); /* 参考预警监测 .panel 背景 */
|
|||
|
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
|||
|
|
border-radius: 12px;
|
|||
|
|
padding: 16px 18px;
|
|||
|
|
backdrop-filter: blur(10px);
|
|||
|
|
position: relative;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.card::before {
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
height: 2px;
|
|||
|
|
background: #00d4ff;
|
|||
|
|
opacity: 0.6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.card-title {
|
|||
|
|
color: #bfe9ff;
|
|||
|
|
font-size: 14px;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 统一标题为预警监测页风格 */
|
|||
|
|
.panel-header {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 10px;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
border-bottom: 1px solid rgba(0, 212, 255, 0.2);
|
|||
|
|
padding-bottom: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.panel-header h3 {
|
|||
|
|
color: #ffffff;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 700;
|
|||
|
|
margin: 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.highlight { color: #00d4ff; }
|
|||
|
|
|
|||
|
|
.diamond-icon {
|
|||
|
|
width: 12px;
|
|||
|
|
height: 12px;
|
|||
|
|
background: #00d4ff;
|
|||
|
|
transform: rotate(45deg);
|
|||
|
|
box-shadow: 0 0 10px rgba(0, 212, 255, 0.5);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.breed-list {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 8px;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.breed-item {
|
|||
|
|
background: rgba(0,212,255,0.12);
|
|||
|
|
border: 1px solid rgba(0,212,255,0.35);
|
|||
|
|
color: #eaf7ff;
|
|||
|
|
font-size: 12px;
|
|||
|
|
padding: 6px 10px;
|
|||
|
|
border-radius: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.price-today .value {
|
|||
|
|
color: #00ffcc;
|
|||
|
|
font-size: 26px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
margin-right: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.price-today .unit {
|
|||
|
|
color: #cfefff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.right-stats {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.detail-card {
|
|||
|
|
background: rgba(255,255,255,0.06);
|
|||
|
|
border: 1px solid rgba(0,212,255,0.25);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 10px 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.detail-content {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.today-price-line {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: flex-end;
|
|||
|
|
gap: 12px;
|
|||
|
|
}
|
|||
|
|
.today-price-line .labels { color: #cfefff; font-size: 14px; }
|
|||
|
|
.today-price-line .price-display { display: flex; align-items: baseline; gap: 6px; }
|
|||
|
|
.today-price-line .currency { color: #ff7a28; font-size: 22px; font-weight: 700; }
|
|||
|
|
.today-price-line .value { color: #ff7a28; font-size: 32px; font-weight: 800; }
|
|||
|
|
.today-price-line .unit { color: #ff7a28; font-size: 14px; font-weight: 600; }
|
|||
|
|
.today-price-line .symbol { color: #cfefff; margin-left: 6px; }
|
|||
|
|
|
|||
|
|
.filters { display: flex; justify-content: space-between; align-items: center; }
|
|||
|
|
.filter-btn {
|
|||
|
|
background: rgba(255,255,255,0.06);
|
|||
|
|
border: 1px solid rgba(0,212,255,0.35);
|
|||
|
|
color: #eaf7ff;
|
|||
|
|
font-size: 13px;
|
|||
|
|
padding: 6px 12px;
|
|||
|
|
border-radius: 20px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: all 0.2s ease;
|
|||
|
|
margin-right: 8px;
|
|||
|
|
}
|
|||
|
|
.filter-btn.active { background: rgba(0,212,255,0.2); border-color: #00d4ff; color: #ffffff; }
|
|||
|
|
.filter-btn:hover { background: rgba(0,212,255,0.12); }
|
|||
|
|
.weight-group, .range-group { display: flex; align-items: center; }
|
|||
|
|
|
|||
|
|
.region-table {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-header, .table-row {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: 1fr 1.6fr 1.2fr 1fr 1fr; /* 时间略窄,地区更宽,价格与涨跌等宽 */
|
|||
|
|
gap: 10px;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-header {
|
|||
|
|
padding: 8px 0;
|
|||
|
|
border-bottom: 1px solid rgba(0, 212, 255, 0.2);
|
|||
|
|
color: #ffffff;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-body {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-row {
|
|||
|
|
padding: 18px 0; /* 增加上下内边距,提高行高 */
|
|||
|
|
min-height: 60px; /* 提高最小高度,列表更舒展 */
|
|||
|
|
border-bottom: 1px solid rgba(255,255,255,0.08);
|
|||
|
|
color: #eaf7ff;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: background-color 0.2s ease, box-shadow 0.2s ease, border-left-color 0.2s ease;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-row:nth-child(even) { background: rgba(0, 212, 255, 0.05); }
|
|||
|
|
.table-row:nth-child(odd) { background: rgba(255, 255, 255, 0.02); }
|
|||
|
|
|
|||
|
|
.table-row:hover {
|
|||
|
|
background: rgba(0, 212, 255, 0.12);
|
|||
|
|
border-left: 2px solid #00d4ff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-row.active {
|
|||
|
|
background: rgba(0, 212, 255, 0.22);
|
|||
|
|
border-left: 3px solid #00d4ff;
|
|||
|
|
box-shadow: inset 0 0 12px rgba(0, 212, 255, 0.35), 0 0 8px rgba(0, 212, 255, 0.25);
|
|||
|
|
color: #ffffff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-row.active .td {
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 涨跌颜色(左侧列表也复用) */
|
|||
|
|
.change-up { color: #00e676; font-weight: 600; }
|
|||
|
|
.change-down { color: #ff5252; font-weight: 600; }
|
|||
|
|
|
|||
|
|
.th { font-size: 14px; }
|
|||
|
|
.td { font-size: 14px; }
|
|||
|
|
|
|||
|
|
/* 仅将左侧“省内各地区牛数据列表”模块文字居中 */
|
|||
|
|
.region-card .card-title { text-align: center; }
|
|||
|
|
.region-card .region-table { text-align: center; }
|
|||
|
|
.region-card .th, .region-card .td { text-align: center; }
|
|||
|
|
|
|||
|
|
.td .main { color: #eaf7ff; }
|
|||
|
|
.td .sub { color: #9ec7d9; font-size: 12px; margin-top: 2px; }
|
|||
|
|
|
|||
|
|
.change-zero { color: #b9cdd8; }
|
|||
|
|
|
|||
|
|
.stats-grid {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: repeat(4, 1fr);
|
|||
|
|
gap: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stat-item {
|
|||
|
|
background: rgba(255,255,255,0.06);
|
|||
|
|
border: 1px solid rgba(0,212,255,0.25);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 10px;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stat-item .label { color: #cfefff; font-size: 13px; }
|
|||
|
|
.stat-item .value { color: #eaffff; font-size: 22px; font-weight: bold; }
|
|||
|
|
.stat-item .unit { color: #9ed7ff; font-size: 12px; }
|
|||
|
|
|
|||
|
|
.trend-chart { width: 100%; height: 320px; }
|
|||
|
|
|
|||
|
|
@media (max-width: 1366px) {
|
|||
|
|
.trend-chart { height: 280px; }
|
|||
|
|
.table-header, .table-row { grid-template-columns: 0.9fr 1.3fr 1fr 0.9fr 0.9fr; }
|
|||
|
|
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@media (max-width: 768px) {
|
|||
|
|
.price-content { grid-template-columns: 1fr; }
|
|||
|
|
.table-header, .table-row { grid-template-columns: 1fr 1.2fr 1fr 0.9fr 0.9fr; }
|
|||
|
|
.stats-grid { grid-template-columns: 1fr; }
|
|||
|
|
.th, .td { font-size: 13px; }
|
|||
|
|
}
|
|||
|
|
</style>
|