修改接口

This commit is contained in:
2025-11-28 17:31:33 +08:00
parent b0b0a4061c
commit 37ab6a4b06
3 changed files with 306 additions and 61 deletions

View File

@@ -171,7 +171,7 @@ body {
} }
.dashboard-header { .dashboard-header {
height: 80px; height: 100px;
background: rgba(12, 20, 38, 0.9); background: rgba(12, 20, 38, 0.9);
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -5,14 +5,14 @@
<!-- 全国牛单价排行榜 --> <!-- 全国牛单价排行榜 -->
<div class="panel price-ranking-panel"> <div class="panel price-ranking-panel">
<div class="panel-header"> <div class="panel-header">
<h3>全国牛单价排行榜/</h3> <h3>全国牛单价排行榜/</h3>
</div> </div>
<div class="price-table"> <div class="price-table">
<div class="price-table-header"> <div class="price-table-header">
<div>序号</div> <div>序号</div>
<div>省份</div> <div>省份</div>
<div>品种</div> <div>品种</div>
<div>单价(/)</div> <div>单价(/)</div>
</div> </div>
<div v-for="(row, idx) in nationalPriceTableSortedRows" :key="row.id" class="price-table-row"> <div v-for="(row, idx) in nationalPriceTableSortedRows" :key="row.id" class="price-table-row">
<div>{{ idx + 1 }}</div> <div>{{ idx + 1 }}</div>
@@ -47,9 +47,9 @@
autoresize autoresize
/> />
</div> </div>
<div class="data-notes"> <!-- <div class="data-notes">
<div class="data-source">数据来源国家统计/行业估算示例该值为全国牛总存栏量基准</div> <div class="data-source">数据来源国家统计/行业估算示例该值为全国牛总存栏量基准</div>
</div> </div> -->
</div> </div>
</div> </div>
@@ -59,6 +59,11 @@
<!-- 中间地图区域 --> <!-- 中间地图区域 -->
<section class="dashboard-center"> <section class="dashboard-center">
<!-- 自定义无数据提示框 -->
<div v-if="showNoDataToast" class="no-data-toast">
{{ noDataMessage }}
</div>
<!-- 地图容器 --> <!-- 地图容器 -->
<div class="map-container"> <div class="map-container">
<Map3D @province-click="handleProvinceClick" /> <Map3D @province-click="handleProvinceClick" />
@@ -70,21 +75,21 @@
<!-- 品种单价排行榜替换原地区-品种明细 --> <!-- 品种单价排行榜替换原地区-品种明细 -->
<div class="panel price-ranking-panel"> <div class="panel price-ranking-panel">
<div class="panel-header"> <div class="panel-header">
<h3>品种单价排行榜/</h3> <h3>品种单价排行榜/</h3>
<select v-model="rightSelectedBreed" class="breed-selector"> <select v-model="rightSelectedBreed" class="breed-selector">
<option v-for="b in rightBreedOptions" :key="b" :value="b">{{ b }}</option> <option v-for="b in rightBreedOptions" :key="b" :value="b">{{ b }}</option>
</select> </select>
</div> </div>
<div class="species-price-table"> <div class="species-price-table">
<div class="species-price-table-header"> <div class="species-price-table-header">
<div>序号</div>
<div>品种</div> <div>品种</div>
<div>省份</div>
<div>地区</div> <div>地区</div>
<div>单价(/)</div> <div>单价(/)</div>
</div> </div>
<div v-for="(row, idx) in speciesPriceTableSortedRows" :key="row.id" class="species-price-table-row"> <div v-for="(row, idx) in speciesPriceTableSortedRows" :key="row.id" class="species-price-table-row">
<div>{{ idx + 1 }}</div>
<div>{{ row.breed }}</div> <div>{{ row.breed }}</div>
<div>{{ row.province }}</div>
<div>{{ row.region }}</div> <div>{{ row.region }}</div>
<div>{{ formatPrice(row.price) }}</div> <div>{{ formatPrice(row.price) }}</div>
</div> </div>
@@ -92,24 +97,24 @@
</div> </div>
<!-- 全国省份单价排行榜/ --> <!-- 全国省份单价排行榜/ -->
<div class="panel price-ranking-panel"> <div class="panel price-ranking-panel">
<div class="panel-header"> <div class="panel-header">
<h3>全国省份单价排行榜/</h3> <h3>全国省份平均单价排行榜/</h3>
</div>
<div class="echarts-container">
<v-chart
ref="provincePriceRankingChart"
class="province-price-ranking-chart"
:option="nationalProvincePriceRankingOption"
autoresize
/>
</div>
</div> </div>
<div class="echarts-container">
<v-chart
ref="provincePriceRankingChart"
class="province-price-ranking-chart"
:option="nationalProvincePriceRankingOption"
autoresize
/>
</div>
</div>
<!-- 全国牛出栏率模块年度全国出栏总量 --> <!-- 全国牛出栏率模块年度全国出栏总量 -->
<div class="panel livestock-panel"> <div class="panel livestock-panel">
<div class="panel-header"> <div class="panel-header">
<h3>全国牛出栏</h3> <h3>全国牛出栏</h3>
</div> </div>
<div class="echarts-container"> <div class="echarts-container">
<v-chart <v-chart
@@ -128,6 +133,30 @@
</template> </template>
<style scoped> <style scoped>
/* 自定义无数据提示框 */
.no-data-toast {
position: absolute;
top: 15%;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 20, 40, 0.9);
border: 1px solid #00ffff;
box-shadow: 0 0 15px rgba(0, 255, 255, 0.4);
color: #00ffff;
padding: 12px 24px;
border-radius: 4px;
z-index: 9999;
font-size: 16px;
font-weight: bold;
pointer-events: none;
animation: fadeInOut 0.3s ease-in-out;
}
@keyframes fadeInOut {
from { opacity: 0; transform: translate(-50%, -10px); }
to { opacity: 1; transform: translate(-50%, 0); }
}
.dashboard-container { .dashboard-container {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -177,7 +206,7 @@
} }
.province-price-ranking-chart { .province-price-ranking-chart {
width: 100%; width: 100%;
height: 200px; height: 500px;
} }
.price-ranking-panel { .price-ranking-panel {
display: flex; display: flex;
@@ -197,14 +226,13 @@
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
padding: 10px; padding: 10px;
flex: 1; /* 自适应撑满当前面板剩余空间 */ height: 250px; /* 设置固定高度 */
min-height: 0;
overflow-y: auto; overflow-y: auto;
} }
.species-price-table-header, .species-price-table-header,
.species-price-table-row { .species-price-table-row {
display: grid; display: grid;
grid-template-columns: 0.7fr 1.2fr 1.4fr 1.2fr; /* 序号/品种/地区/单价 */ grid-template-columns: 1.2fr 1fr 1fr 1.2fr; /* 品种/省份/地区/单价 */
gap: 12px; gap: 12px;
align-items: center; align-items: center;
font-size: 14px; font-size: 14px;
@@ -256,7 +284,7 @@
} }
.price-bar-track { .price-bar-track {
flex: 1; flex: 1;
height: 18px; height: 12px; /* 条形更细 */
border-radius: 0; border-radius: 0;
background: transparent; /* 去掉背景色,仅保留条形图颜色 */ background: transparent; /* 去掉背景色,仅保留条形图颜色 */
overflow: hidden; overflow: hidden;
@@ -386,6 +414,8 @@
</style> </style>
<script> <script>
import { ref } from 'vue'
import axios from 'axios'
import Map3D from './Map3D.vue' import Map3D from './Map3D.vue'
import { use } from 'echarts/core' import { use } from 'echarts/core'
import { CanvasRenderer, SVGRenderer } from 'echarts/renderers' import { CanvasRenderer, SVGRenderer } from 'echarts/renderers'
@@ -424,13 +454,50 @@ export default {
}, },
emits: ['navigate-to-warning'], emits: ['navigate-to-warning'],
setup(props, { emit }) { setup(props, { emit }) {
const showNoDataToast = ref(false)
const noDataMessage = ref('')
let toastTimer = null
// 处理省份点击事件 // 处理省份点击事件
const handleProvinceClick = (provinceName) => { const handleProvinceClick = async (provinceName) => {
emit('navigate-to-warning', provinceName) try {
console.log('正在请求省份数据:', provinceName);
const res = await axios.get('/api/cattle-data', {
params: { province: provinceName }
})
console.log('省份数据返回:', res.data);
const raw = res.data;
// 兼容直接返回数组或 { data: [] } 的结构
const list = Array.isArray(raw) ? raw : (Array.isArray(raw?.data) ? raw.data : []);
if (list && list.length > 0) {
console.log('数据存在,准备跳转');
emit('navigate-to-warning', provinceName)
} else {
console.warn('该地区无数据');
noDataMessage.value = `该地区暂无数据: ${provinceName}`
showNoDataToast.value = true
if (toastTimer) clearTimeout(toastTimer)
toastTimer = setTimeout(() => {
showNoDataToast.value = false
}, 3000)
}
} catch (error) {
console.error('获取省份数据出错:', error)
noDataMessage.value = `获取数据失败: ${provinceName}`
showNoDataToast.value = true
if (toastTimer) clearTimeout(toastTimer)
toastTimer = setTimeout(() => {
showNoDataToast.value = false
}, 3000)
}
} }
return { return {
handleProvinceClick handleProvinceClick,
showNoDataToast,
noDataMessage
} }
}, },
data() { data() {
@@ -438,7 +505,8 @@ export default {
// 右侧品种单价排行榜下拉选项与选中值 // 右侧品种单价排行榜下拉选项与选中值
rightBreedOptions: ['安格斯','牦牛','黄牛','利木赞牛','鲁西牛','奶牛','肉牛','水牛','西门塔尔牛','夏洛莱牛','杂交牛','牛'], rightBreedOptions: ['安格斯','牦牛','黄牛','利木赞牛','鲁西牛','奶牛','肉牛','水牛','西门塔尔牛','夏洛莱牛','杂交牛','牛'],
rightSelectedBreed: '安格斯', rightSelectedBreed: '安格斯',
// 存栏率视图模式percent 或 count speciesPriceRows: [], // 品种单价排行(接口)
// 存栏率视图模式percent 或 count
livestockViewMode: 'percent', livestockViewMode: 'percent',
// 全国牛总存栏量基准值 // 全国牛总存栏量基准值
livestockBaseline: 100000000, livestockBaseline: 100000000,
@@ -569,19 +637,19 @@ export default {
textStyle: { color: '#ffffff' }, textStyle: { color: '#ffffff' },
formatter: function(params) { formatter: function(params) {
const p = params[0] const p = params[0]
return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value} 万头` return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value}`
} }
}, },
grid: { left: '12%', right: '8%', bottom: '12%', top: '18%' }, grid: { left: '12%', right: '8%', bottom: '12%', top: '18%' },
xAxis: { xAxis: {
type: 'category', type: 'category',
data: ['2020年','2021年','2022年','2023年','2024年'], data: [],
axisLine: { lineStyle: { color: '#00ffff' } }, axisLine: { lineStyle: { color: '#00ffff' } },
axisLabel: { color: '#ffffff', fontSize: 10 } axisLabel: { color: '#ffffff', fontSize: 10 }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
name: '万头', name: '数量',
nameTextStyle: { color: '#00ffff', fontSize: 11 }, nameTextStyle: { color: '#00ffff', fontSize: 11 },
axisLine: { lineStyle: { color: '#00ffff' } }, axisLine: { lineStyle: { color: '#00ffff' } },
axisLabel: { color: '#ffffff', fontSize: 10 }, axisLabel: { color: '#ffffff', fontSize: 10 },
@@ -593,11 +661,11 @@ export default {
smooth: true, smooth: true,
symbol: 'circle', symbol: 'circle',
symbolSize: 4, symbolSize: 4,
data: [4565.45, 4707.43, 4839.91, 5023.48, 5098.70], data: [],
lineStyle: { color: '#00CDCD', width: 2 }, lineStyle: { color: '#00CDCD', width: 2 },
itemStyle: { color: '#00CDCD' }, itemStyle: { color: '#00CDCD' },
areaStyle: { color: 'rgba(0,205,205,0.15)' }, areaStyle: { color: 'rgba(0,205,205,0.15)' },
label: { show: true, position: 'top', color: '#cfefff', fontSize: 10, formatter: '{c} 万头' } label: { show: true, position: 'top', color: '#cfefff', fontSize: 10, formatter: '{c}' }
}] }]
}, },
@@ -612,19 +680,19 @@ export default {
textStyle: { color: '#ffffff' }, textStyle: { color: '#ffffff' },
formatter: function(params) { formatter: function(params) {
const p = params[0] const p = params[0]
return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value} 万头` return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value}`
} }
}, },
grid: { left: '12%', right: '8%', bottom: '12%', top: '18%' }, grid: { left: '12%', right: '8%', bottom: '12%', top: '18%' },
xAxis: { xAxis: {
type: 'category', type: 'category',
data: ['2020年','2021年','2022年','2023年','2024年'], data: [],
axisLine: { lineStyle: { color: '#00ffff' } }, axisLine: { lineStyle: { color: '#00ffff' } },
axisLabel: { color: '#ffffff', fontSize: 10 } axisLabel: { color: '#ffffff', fontSize: 10 }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
name: '万头', name: '数量',
nameTextStyle: { color: '#00ffff', fontSize: 11 }, nameTextStyle: { color: '#00ffff', fontSize: 11 },
axisLine: { lineStyle: { color: '#00ffff' } }, axisLine: { lineStyle: { color: '#00ffff' } },
axisLabel: { color: '#ffffff', fontSize: 10 }, axisLabel: { color: '#ffffff', fontSize: 10 },
@@ -633,10 +701,10 @@ export default {
series: [{ series: [{
name: '全国牛存栏总量', name: '全国牛存栏总量',
type: 'bar', type: 'bar',
data: [ 9562, 9817, 10215, 10508, 10046], data: [],
barWidth: '40%', barWidth: '40%',
itemStyle: { color: '#00CDCD' }, itemStyle: { color: '#00CDCD' },
label: { show: true, position: 'top', color: '#cfefff', fontSize: 10, formatter: '{c} 万头' } label: { show: true, position: 'top', color: '#cfefff', fontSize: 10, formatter: '{c}' }
}] }]
}, },
@@ -657,6 +725,9 @@ export default {
{ id: 10, province: '河南省', breed: '西门塔尔牛', price: 16800 } { id: 10, province: '河南省', breed: '西门塔尔牛', price: 16800 }
], ],
// 全国省份平均单价数据源(专用于右侧省份排行图表)
nationalProvinceAverageRows: [],
// 全国牛单价排行榜配置(单位:元/头) // 全国牛单价排行榜配置(单位:元/头)
nationalPriceRankingOption: { nationalPriceRankingOption: {
backgroundColor: 'transparent', backgroundColor: 'transparent',
@@ -882,9 +953,7 @@ export default {
} catch (e) { } catch (e) {
return String(this.nationalLivestockCount || 0) return String(this.nationalLivestockCount || 0)
} }
} },
},
computed: {
totalLivestock() { totalLivestock() {
// 以数据源计算总存栏量(万头) // 以数据源计算总存栏量(万头)
return this.livestockSpeciesData.reduce((sum, s) => sum + Math.round(s.count / 10000), 0) return this.livestockSpeciesData.reduce((sum, s) => sum + Math.round(s.count / 10000), 0)
@@ -897,12 +966,14 @@ export default {
}, },
// 品种单价排行榜(右侧)基于地区-品种明细,按价格升序 // 品种单价排行榜(右侧)基于地区-品种明细,按价格升序
speciesPriceTableSortedRows() { speciesPriceTableSortedRows() {
let rows = Array.isArray(this.detailRows) ? this.detailRows.map(r => ({ let rows = (Array.isArray(this.speciesPriceRows) && this.speciesPriceRows.length > 0)
id: r.id, ? this.speciesPriceRows
breed: r.breed, : (Array.isArray(this.detailRows) ? this.detailRows.map(r => ({
region: r.region, id: r.id,
price: r.price breed: r.breed,
})) : [] region: r.region,
price: r.price
})) : [])
// 下拉选择生效:按包含关系过滤(处理“安格斯”匹配“安格斯牛”等) // 下拉选择生效:按包含关系过滤(处理“安格斯”匹配“安格斯牛”等)
if (this.rightSelectedBreed) { if (this.rightSelectedBreed) {
rows = rows.filter(x => String(x.breed || '').includes(this.rightSelectedBreed)) rows = rows.filter(x => String(x.breed || '').includes(this.rightSelectedBreed))
@@ -910,12 +981,14 @@ export default {
rows.sort((a, b) => a.price - b.price) rows.sort((a, b) => a.price - b.price)
return rows return rows
}, },
// 全国省份单价排行榜(右侧图表): nationalPriceTableRows 为数据源,按单价升序 // 全国省份平均单价排行榜(右侧图表):优先使用 nationalProvinceAverageRows否则回退 nationalPriceTableRows
nationalProvincePriceRankingOption() { nationalProvincePriceRankingOption() {
const rows = Array.isArray(this.nationalPriceTableRows) ? [...this.nationalPriceTableRows] : [] const base = (Array.isArray(this.nationalProvinceAverageRows) && this.nationalProvinceAverageRows.length > 0)
rows.sort((a, b) => a.price - b.price) ? [...this.nationalProvinceAverageRows]
const yCategories = rows.map(r => r.province) : (Array.isArray(this.nationalPriceTableRows) ? [...this.nationalPriceTableRows] : [])
const prices = rows.map(r => r.price) base.sort((a, b) => a.price - b.price)
const yCategories = base.map(r => r.province)
const prices = base.map(r => r.price)
return { return {
backgroundColor: 'transparent', backgroundColor: 'transparent',
tooltip: { tooltip: {
@@ -927,13 +1000,13 @@ export default {
textStyle: { color: '#ffffff' }, textStyle: { color: '#ffffff' },
formatter: function(params) { formatter: function(params) {
const p = params[0] const p = params[0]
return `${p.axisValue}<br/>${p.seriesName}: ${p.value} 元/` return `${p.axisValue}<br/>${p.seriesName}: ${p.value} 元/`
} }
}, },
grid: { left: '0%', right: '10%', bottom: '10%', top: '10%', containLabel: true }, grid: { left: '0%', right: '10%', bottom: '5%', top: '5%', containLabel: true },
xAxis: { xAxis: {
type: 'value', type: 'value',
name: '单价(元/', name: '单价(元/',
nameTextStyle: { color: '#00ffff', fontSize: 11 }, nameTextStyle: { color: '#00ffff', fontSize: 11 },
axisLine: { lineStyle: { color: '#00ffff' } }, axisLine: { lineStyle: { color: '#00ffff' } },
axisLabel: { color: '#ffffff', fontSize: 10 }, axisLabel: { color: '#ffffff', fontSize: 10 },
@@ -949,10 +1022,21 @@ export default {
name: '省份单价', name: '省份单价',
type: 'bar', type: 'bar',
data: prices, data: prices,
barWidth: '45%', barWidth: '42%',
barCategoryGap: '28%',
itemStyle: { color: '#4e73df' }, itemStyle: { color: '#4e73df' },
label: { show: true, position: 'right', color: '#cfefff', fontSize: 10, formatter: '{c} 元/' } label: { show: true, position: 'right', color: '#cfefff', fontSize: 10, formatter: '{c} 元/' }
}] }],
dataZoom: [
{
type: 'inside',
yAxisIndex: 0,
startValue: 0,
endValue: yCategories.length - 1,
zoomLock: true,
filterMode: 'empty'
}
]
} }
}, },
// 单价条形图需要的最大值(用于计算宽度百分比) // 单价条形图需要的最大值(用于计算宽度百分比)
@@ -968,6 +1052,16 @@ export default {
return rows return rows
} }
}, },
watch: {
rightSelectedBreed: {
handler(breed) {
if (breed) {
this.fetchSpeciesPriceRanking(breed)
}
},
immediate: true
}
},
methods: { methods: {
// 格式化价格显示(千分位) // 格式化价格显示(千分位)
formatPrice(value) { formatPrice(value) {
@@ -985,6 +1079,63 @@ export default {
const percent = 5 + Math.pow(ratio, 0.6) * 95 const percent = 5 + Math.pow(ratio, 0.6) * 95
return { width: `${percent.toFixed(2)}%` } return { width: `${percent.toFixed(2)}%` }
}, },
// 拉取全国牛单价排行榜数据并填充表格/图表字段type/省份province/单价price
async fetchNationalPriceRanking() {
const url = '/api/cattle-data'
try {
const res = await fetch(url)
const raw = await res.json()
const list = Array.isArray(raw) ? raw : (Array.isArray(raw?.data) ? raw.data : [])
const rows = list.map((item, idx) => ({
id: item.id ?? idx + 1,
province: item.province ?? item.provinceName ?? '',
breed: item.type ?? item.breed ?? '',
price: Number(item.price)
})).filter(r => r.province && r.breed && Number.isFinite(r.price))
// 更新数据源(驱动左侧表格与右侧省份排行图表)
this.nationalPriceTableRows = rows
} catch (e) {
console.warn('获取全国牛单价排行榜失败:', e)
}
},
// 拉取品种单价排行榜数据
async fetchSpeciesPriceRanking(breed) {
const url = `/api/cattle-data?type=${breed}`
try {
const res = await fetch(url)
const raw = await res.json()
const list = Array.isArray(raw) ? raw : (Array.isArray(raw?.data) ? raw.data : [])
const rows = list.map((item, idx) => ({
id: item.id ?? idx + 1,
province: item.province ?? '',
region: item.location ?? '',
breed: item.type ?? item.breed ?? '',
price: Number(item.price)
})).filter(r => r.province && r.region && r.breed && Number.isFinite(r.price))
this.speciesPriceRows = rows
} catch (e) {
console.warn(`获取品种 ${breed} 单价排行失败:`, e)
}
},
// 拉取全国省份平均单价排行榜数据字段province/provincePrice
async fetchNationalProvinceAverages() {
const url = '/api/cattle-data/provinces'
try {
const res = await fetch(url)
const raw = await res.json()
const list = Array.isArray(raw) ? raw : (Array.isArray(raw?.data) ? raw.data : [])
const rows = list.map((item, idx) => ({
id: item.id ?? idx + 1,
province: item.province ?? item.provinceName ?? '',
price: Number(item.provincePrice)
})).filter(r => r.province && Number.isFinite(r.price))
this.nationalProvinceAverageRows = rows
} catch (e) {
console.warn('获取全国省份平均单价失败:', e)
}
},
// 构建环形图(占比) // 构建环形图(占比)
buildLivestockPieOption() { buildLivestockPieOption() {
const baseline = this.livestockBaseline const baseline = this.livestockBaseline
@@ -1027,6 +1178,85 @@ export default {
}] }]
} }
}, },
// 通过接口更新全国存栏/出栏年度数据以2023年为例
async fetchNationalInventorySlaughter() {
// 通过 Vite 代理避免浏览器 CORS使用相对路径
const url = '/api/cattle-data/national'
try {
const res = await fetch(url)
const raw = await res.json()
// 接口可能返回 { code, data: {...} } 或直接返回对象,统一取 payload
const payload = raw && typeof raw === 'object' && raw.data ? raw.data : raw
// 固定横轴为 2023/2024/2025纵轴填充数值单位万头缺失则为 null
const years = ['2023年', '2024年', '2025年']
const readNumber = (obj, key) => {
if (!obj) return null
const v = obj[key]
const n = typeof v === 'string' ? Number(v) : (typeof v === 'number' ? v : null)
return Number.isFinite(n) ? n : null
}
const inventoryValues = [
readNumber(payload, 'nationalInventory23th') ?? readNumber(payload, 'nationalInventory23'),
readNumber(payload, 'nationalInventory24th') ?? readNumber(payload, 'nationalInventory24'),
readNumber(payload, 'nationalInventory25th') ?? readNumber(payload, 'nationalInventory25')
]
const slaughterValues = [
readNumber(payload, 'nationalSlaughter23th') ?? readNumber(payload, 'nationalSlaughter23'),
readNumber(payload, 'nationalSlaughter24th') ?? readNumber(payload, 'nationalSlaughter24'),
readNumber(payload, 'nationalSlaughter25th') ?? readNumber(payload, 'nationalSlaughter25')
]
// 更新“全国牛存栏量”
this.nationalLivestockYearOption.xAxis.data = years
this.nationalLivestockYearOption.series[0].data = inventoryValues
this.nationalLivestockYearOption.yAxis.name = '数量(万头)'
this.nationalLivestockYearOption.series[0].label = { ...this.nationalLivestockYearOption.series[0].label, formatter: '{c} 万头' }
this.nationalLivestockYearOption.tooltip.formatter = function(params) {
const p = params[0]
return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value} 万头`
}
this.nationalLivestockYearOption = { ...this.nationalLivestockYearOption }
// 更新“全国牛出栏量”
this.nationalSlaughterYearOption.xAxis.data = years
this.nationalSlaughterYearOption.series[0].data = slaughterValues
this.nationalSlaughterYearOption.yAxis.name = '数量(万头)'
this.nationalSlaughterYearOption.series[0].label = { ...this.nationalSlaughterYearOption.series[0].label, formatter: '{c} 万头' }
this.nationalSlaughterYearOption.tooltip.formatter = function(params) {
const p = params[0]
return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value} 万头`
}
this.nationalSlaughterYearOption = { ...this.nationalSlaughterYearOption }
} catch (e) {
console.warn('获取全国存栏/出栏接口数据失败:', e)
}
},
// 更新“全国牛存栏量年度柱状图”指定年份的值(单位:万头)
updateLivestockYearValue(year, valueWan) {
const yearLabel = `${year}`
const x = this.nationalLivestockYearOption.xAxis.data || []
const idx = x.indexOf(yearLabel)
if (idx >= 0) {
const arr = this.nationalLivestockYearOption.series[0].data || []
arr[idx] = Number(valueWan)
// 触发响应式更新
this.nationalLivestockYearOption = { ...this.nationalLivestockYearOption }
}
},
// 更新“全国牛出栏量年度折线图”指定年份的值(单位:万头)
updateSlaughterYearValue(year, valueWan) {
const yearLabel = `${year}`
const x = this.nationalSlaughterYearOption.xAxis.data || []
const idx = x.indexOf(yearLabel)
if (idx >= 0) {
const arr = this.nationalSlaughterYearOption.series[0].data || []
arr[idx] = Number(valueWan)
// 触发响应式更新
this.nationalSlaughterYearOption = { ...this.nationalSlaughterYearOption }
}
},
// 构建柱状图(数量) // 构建柱状图(数量)
buildLivestockBarOption() { buildLivestockBarOption() {
const species = this.livestockSpeciesData const species = this.livestockSpeciesData
@@ -1221,6 +1451,12 @@ export default {
this.refreshLivestockOption() this.refreshLivestockOption()
this.refreshSlaughterOption() this.refreshSlaughterOption()
this.validateSlaughterData() this.validateSlaughterData()
// 拉取全国存栏/出栏年度数据并更新图表
this.fetchNationalInventorySlaughter()
// 拉取全国牛单价排行榜数据
this.fetchNationalPriceRanking()
// 拉取全国省份平均单价排行榜数据
this.fetchNationalProvinceAverages()
} }
} }
</script> </script>

View File

@@ -10,6 +10,15 @@ export default defineConfig({
vue(), vue(),
vueDevTools(), vueDevTools(),
], ],
server: {
proxy: {
'/api': {
target: 'https://ad.yunmainiu.com',
changeOrigin: true,
secure: false,
},
},
},
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)) '@': fileURLToPath(new URL('./src', import.meta.url))