2025-10-27 17:29:42 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="dashboard-container">
|
|
|
|
|
|
<!-- 左侧面板 -->
|
|
|
|
|
|
<aside class="dashboard-left">
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<!-- 全国牛单价排行榜 -->
|
|
|
|
|
|
<div class="panel price-ranking-panel">
|
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
|
<h3>全国牛单价排行榜(元/头)</h3>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="price-table">
|
|
|
|
|
|
<div class="price-table-header">
|
|
|
|
|
|
<div>序号</div>
|
|
|
|
|
|
<div>省份</div>
|
|
|
|
|
|
<div>品种</div>
|
|
|
|
|
|
<div>单价(元/头)</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-for="(row, idx) in nationalPriceTableSortedRows" :key="row.id" class="price-table-row">
|
|
|
|
|
|
<div>{{ idx + 1 }}</div>
|
|
|
|
|
|
<div>{{ row.province }}</div>
|
|
|
|
|
|
<div>{{ row.breed }}</div>
|
|
|
|
|
|
<div class="price-bar-cell">
|
|
|
|
|
|
<div class="price-bar-track">
|
|
|
|
|
|
<div class="price-bar" :style="getPriceBarStyle(row.price)">
|
|
|
|
|
|
<span class="price-value on-bar">{{ formatPrice(row.price) }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 全国牛存栏量模块 -->
|
2025-11-07 14:04:09 +08:00
|
|
|
|
<div class="panel slaughter-panel">
|
2025-10-27 17:29:42 +08:00
|
|
|
|
<div class="panel-header">
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<h3>全国牛存栏量</h3>
|
2025-10-27 17:29:42 +08:00
|
|
|
|
</div>
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<div class="total-stock">
|
|
|
|
|
|
<div class="total-number">
|
|
|
|
|
|
<!-- <span class="currency">≈</span> -->
|
|
|
|
|
|
<!-- <span class="value">{{ nationalLivestockDisplay }}</span> -->
|
|
|
|
|
|
<!-- <span class="unit">头</span> -->
|
|
|
|
|
|
</div>
|
2025-11-07 14:04:09 +08:00
|
|
|
|
<div class="echarts-container">
|
|
|
|
|
|
<v-chart
|
2025-11-26 17:31:42 +08:00
|
|
|
|
ref="nationalLivestockYearChart"
|
|
|
|
|
|
class="national-livestock-year-chart"
|
|
|
|
|
|
:option="nationalLivestockYearOption"
|
2025-10-27 17:29:42 +08:00
|
|
|
|
autoresize
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
2025-11-07 14:04:09 +08:00
|
|
|
|
<div class="data-notes">
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<div class="data-source">数据来源:国家统计/行业估算(示例)。该值为全国牛总存栏量基准。</div>
|
2025-11-07 14:04:09 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<!-- 已移除:不同品种年度总销售额柱状图模块 -->
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
</aside>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 中间地图区域 -->
|
|
|
|
|
|
<section class="dashboard-center">
|
|
|
|
|
|
<!-- 地图容器 -->
|
|
|
|
|
|
<div class="map-container">
|
2025-11-07 14:04:09 +08:00
|
|
|
|
<Map3D @province-click="handleProvinceClick" />
|
2025-10-27 17:29:42 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧面板 -->
|
|
|
|
|
|
<aside class="dashboard-right">
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<!-- 品种单价排行榜(替换原地区-品种明细) -->
|
|
|
|
|
|
<div class="panel price-ranking-panel">
|
2025-10-27 17:29:42 +08:00
|
|
|
|
<div class="panel-header">
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<h3>品种单价排行榜(元/头)</h3>
|
|
|
|
|
|
<select v-model="rightSelectedBreed" class="breed-selector">
|
|
|
|
|
|
<option v-for="b in rightBreedOptions" :key="b" :value="b">{{ b }}</option>
|
|
|
|
|
|
</select>
|
2025-10-27 17:29:42 +08:00
|
|
|
|
</div>
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<div class="species-price-table">
|
|
|
|
|
|
<div class="species-price-table-header">
|
|
|
|
|
|
<div>序号</div>
|
|
|
|
|
|
<div>品种</div>
|
2025-10-27 17:29:42 +08:00
|
|
|
|
<div>地区</div>
|
|
|
|
|
|
<div>单价(元/头)</div>
|
|
|
|
|
|
</div>
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<div v-for="(row, idx) in speciesPriceTableSortedRows" :key="row.id" class="species-price-table-row">
|
|
|
|
|
|
<div>{{ idx + 1 }}</div>
|
|
|
|
|
|
<div>{{ row.breed }}</div>
|
2025-10-27 17:29:42 +08:00
|
|
|
|
<div>{{ row.region }}</div>
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<div>{{ formatPrice(row.price) }}</div>
|
2025-10-27 17:29:42 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<!-- 全国省份单价排行榜(元/头) -->
|
|
|
|
|
|
<div class="panel price-ranking-panel">
|
2025-10-27 17:29:42 +08:00
|
|
|
|
<div class="panel-header">
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<h3>全国省份单价排行榜(元/头)</h3>
|
2025-10-27 17:29:42 +08:00
|
|
|
|
</div>
|
2025-11-26 17:31:42 +08:00
|
|
|
|
<div class="echarts-container">
|
2025-10-27 17:29:42 +08:00
|
|
|
|
<v-chart
|
2025-11-26 17:31:42 +08:00
|
|
|
|
ref="provincePriceRankingChart"
|
|
|
|
|
|
class="province-price-ranking-chart"
|
|
|
|
|
|
:option="nationalProvincePriceRankingOption"
|
2025-10-27 17:29:42 +08:00
|
|
|
|
autoresize
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-11-26 17:31:42 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 全国牛出栏率模块(年度全国出栏总量) -->
|
|
|
|
|
|
<div class="panel livestock-panel">
|
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
|
<h3>全国牛出栏率</h3>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="echarts-container">
|
|
|
|
|
|
<v-chart
|
|
|
|
|
|
ref="nationalSlaughterYearChart"
|
|
|
|
|
|
class="national-slaughter-year-chart"
|
|
|
|
|
|
:option="nationalSlaughterYearOption"
|
|
|
|
|
|
autoresize
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- <div class="data-notes">
|
|
|
|
|
|
<div class="data-source">全国出栏总量(单位:万头)。数据来源:国家统计/行业估算(示例)。</div>
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
</div>
|
2025-10-27 17:29:42 +08:00
|
|
|
|
</aside>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.dashboard-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 20px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
/* 全国牛存栏量显示样式 */
|
|
|
|
|
|
.total-stock {
|
|
|
|
|
|
padding: 10px 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.total-number {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.total-number .currency {
|
|
|
|
|
|
color: #00ffff;
|
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
}
|
|
|
|
|
|
.total-number .value {
|
|
|
|
|
|
color: #00ffcc;
|
|
|
|
|
|
font-size: 36px;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
}
|
|
|
|
|
|
.total-number .unit {
|
|
|
|
|
|
color: #cfefff;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.national-livestock-year-chart {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 190px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.national-slaughter-year-chart {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 150px;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.national-price-ranking-chart {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 180px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.province-price-ranking-chart {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 200px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-ranking-panel {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-ranking-panel .echarts-container {
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
padding: 0 0 5px 0; /* 左侧去掉内边距,整体更靠左 */
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 品种单价排行榜列表样式(右侧) */
|
|
|
|
|
|
.species-price-table {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
flex: 1; /* 自适应撑满当前面板剩余空间 */
|
|
|
|
|
|
min-height: 0;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.species-price-table-header,
|
|
|
|
|
|
.species-price-table-row {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 0.7fr 1.2fr 1.4fr 1.2fr; /* 序号/品种/地区/单价 */
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.species-price-table-header {
|
|
|
|
|
|
color: #84acf0;
|
|
|
|
|
|
border-bottom: 1px solid rgba(132, 172, 240, 0.2);
|
|
|
|
|
|
padding-bottom: 6px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
.species-price-table-row {
|
|
|
|
|
|
color: #eaf7ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 全国牛单价排行榜表格样式 */
|
|
|
|
|
|
.price-table {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
/* 表格自适应增高,撑满左侧面板剩余空间 */
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-height: 0;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-table-header,
|
|
|
|
|
|
.price-table-row {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 0.6fr 1fr 1.2fr 2fr;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-table-header {
|
|
|
|
|
|
color: #84acf0;
|
|
|
|
|
|
border-bottom: 1px solid rgba(132, 172, 240, 0.2);
|
|
|
|
|
|
padding-bottom: 6px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-table-row {
|
|
|
|
|
|
color: #eaf7ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 单价列条形图样式 */
|
|
|
|
|
|
.price-bar-cell {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-bar-track {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 18px;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
background: transparent; /* 去掉背景色,仅保留条形图颜色 */
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-bar {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
border-radius: 0 0 0 0; /* 去掉左侧圆角,仅保留右侧 */
|
|
|
|
|
|
background: #4e73df; /* 与图二一致的蓝色 */
|
|
|
|
|
|
transition: width 0.3s ease;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-value {
|
|
|
|
|
|
min-width: 86px;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
color: #eaf7ff;
|
|
|
|
|
|
font-variant-numeric: tabular-nums;
|
|
|
|
|
|
}
|
|
|
|
|
|
.price-value.on-bar {
|
|
|
|
|
|
min-width: unset;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
2025-10-27 17:29:42 +08:00
|
|
|
|
.dashboard-center {
|
2025-11-07 14:04:09 +08:00
|
|
|
|
flex: 1; /* 中心区域保持基准宽度 */
|
2025-10-27 17:29:42 +08:00
|
|
|
|
min-width: 300px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: 100vh; /* 确保中间区域占满整个视口高度 */
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
.dashboard-left,
|
2025-10-27 17:29:42 +08:00
|
|
|
|
.dashboard-right {
|
2025-11-07 14:04:09 +08:00
|
|
|
|
flex: 0.6; /* 两侧数据栏进一步缩小至约60%相对权重 */
|
|
|
|
|
|
min-width: 300px; /* 保持最小宽度,避免内容截断 */
|
|
|
|
|
|
max-width: 520px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
/* 左侧数据栏按列布局并占满视口高度 */
|
|
|
|
|
|
.dashboard-left {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
/* 中低分辨率下进一步缩小到70%,保证协调性 */
|
|
|
|
|
|
@media (max-width: 1366px) {
|
|
|
|
|
|
.dashboard-left,
|
|
|
|
|
|
.dashboard-right {
|
|
|
|
|
|
flex: 0.55;
|
|
|
|
|
|
}
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.dashboard-left,
|
|
|
|
|
|
.dashboard-center,
|
|
|
|
|
|
.dashboard-right {
|
|
|
|
|
|
flex: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
|
|
|
|
|
/* 侧边数据栏面板样式,参考预警监测模块 */
|
|
|
|
|
|
.panel {
|
|
|
|
|
|
background: rgba(7, 59, 68, 0.15);
|
|
|
|
|
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
backdrop-filter: blur(10px);
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.panel::before {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
height: 2px;
|
|
|
|
|
|
background: #00d4ff;
|
|
|
|
|
|
opacity: 0.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.panel-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.panel-header h3 {
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.diamond-icon {
|
|
|
|
|
|
width: 12px;
|
|
|
|
|
|
height: 12px;
|
|
|
|
|
|
background: #00d4ff;
|
|
|
|
|
|
transform: rotate(45deg);
|
|
|
|
|
|
box-shadow: 0 0 10px rgba(0, 212, 255, 0.5);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 统一下拉选择样式 */
|
|
|
|
|
|
.region-select,
|
|
|
|
|
|
.breed-selector {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.2);
|
|
|
|
|
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.region-select option,
|
|
|
|
|
|
.breed-selector option {
|
|
|
|
|
|
background: #0c1426;
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
}
|
2025-10-27 17:29:42 +08:00
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import Map3D from './Map3D.vue'
|
|
|
|
|
|
import { use } from 'echarts/core'
|
2025-11-07 14:04:09 +08:00
|
|
|
|
import { CanvasRenderer, SVGRenderer } from 'echarts/renderers'
|
2025-10-27 17:29:42 +08:00
|
|
|
|
import { PieChart, BarChart } from 'echarts/charts'
|
|
|
|
|
|
import {
|
|
|
|
|
|
TitleComponent,
|
|
|
|
|
|
TooltipComponent,
|
|
|
|
|
|
LegendComponent,
|
|
|
|
|
|
GridComponent
|
|
|
|
|
|
} from 'echarts/components'
|
2025-11-07 14:04:09 +08:00
|
|
|
|
import * as echarts from 'echarts'
|
2025-10-27 17:29:42 +08:00
|
|
|
|
import VChart from 'vue-echarts'
|
|
|
|
|
|
|
|
|
|
|
|
use([
|
|
|
|
|
|
CanvasRenderer,
|
2025-11-07 14:04:09 +08:00
|
|
|
|
SVGRenderer,
|
2025-10-27 17:29:42 +08:00
|
|
|
|
PieChart,
|
|
|
|
|
|
BarChart,
|
|
|
|
|
|
TitleComponent,
|
|
|
|
|
|
TooltipComponent,
|
|
|
|
|
|
LegendComponent,
|
|
|
|
|
|
GridComponent
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'Home',
|
|
|
|
|
|
components: {
|
|
|
|
|
|
Map3D,
|
|
|
|
|
|
VChart
|
|
|
|
|
|
},
|
2025-11-07 14:04:09 +08:00
|
|
|
|
props: {
|
|
|
|
|
|
selectedProvince: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
emits: ['navigate-to-warning'],
|
|
|
|
|
|
setup(props, { emit }) {
|
|
|
|
|
|
// 处理省份点击事件
|
|
|
|
|
|
const handleProvinceClick = (provinceName) => {
|
|
|
|
|
|
emit('navigate-to-warning', provinceName)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
handleProvinceClick
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-10-27 17:29:42 +08:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
2025-11-26 17:31:42 +08:00
|
|
|
|
// 右侧品种单价排行榜下拉选项与选中值
|
|
|
|
|
|
rightBreedOptions: ['安格斯','牦牛','黄牛','利木赞牛','鲁西牛','奶牛','肉牛','水牛','西门塔尔牛','夏洛莱牛','杂交牛','牛'],
|
|
|
|
|
|
rightSelectedBreed: '安格斯',
|
2025-11-07 14:04:09 +08:00
|
|
|
|
// 存栏率视图模式:percent 或 count
|
|
|
|
|
|
livestockViewMode: 'percent',
|
|
|
|
|
|
// 全国牛总存栏量基准值
|
|
|
|
|
|
livestockBaseline: 100000000,
|
|
|
|
|
|
// 不同品种默认数据(单位:头)
|
|
|
|
|
|
livestockSpeciesData: [
|
|
|
|
|
|
{ name: '黄牛及改良牛', key: 'yellow', count: 87500000, color: '#00CDCD' },
|
|
|
|
|
|
{ name: '奶牛', key: 'dairy', count: 11000000, color: '#869DB0' },
|
|
|
|
|
|
{ name: '水牛', key: 'buffalo', count: 4750000, color: '#267EEF' },
|
|
|
|
|
|
{ name: '牦牛', key: 'yak', count: 16000000, color: '#42A2E1', globalShare: '>90%', domesticShare: '16%' }
|
|
|
|
|
|
],
|
|
|
|
|
|
// 出栏率统计校验信息
|
|
|
|
|
|
validationMessageSlaughter: '',
|
|
|
|
|
|
// 存栏率选中的地区
|
|
|
|
|
|
selectedRegionStock: '全国',
|
2025-10-27 17:29:42 +08:00
|
|
|
|
// 选中的品种
|
|
|
|
|
|
selectedBreed: '',
|
|
|
|
|
|
|
|
|
|
|
|
// 防疫统计柱状图配置
|
|
|
|
|
|
epidemicChartOption: {
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#ffffff'
|
|
|
|
|
|
},
|
|
|
|
|
|
formatter: '{b}: {c}万头'
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
data: ['口蹄疫防疫', '猪瘟防疫', '其他类型防疫'],
|
|
|
|
|
|
right: '10%',
|
|
|
|
|
|
top: '10%',
|
|
|
|
|
|
orient: 'vertical',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#ffffff',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
|
|
|
|
|
itemWidth: 12,
|
|
|
|
|
|
itemHeight: 8
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '15%',
|
|
|
|
|
|
right: '35%',
|
|
|
|
|
|
bottom: '15%',
|
|
|
|
|
|
top: '15%'
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: ['口蹄疫防疫', '猪瘟防疫', '其他类型防疫'],
|
|
|
|
|
|
axisLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#00ffff'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#ffffff',
|
|
|
|
|
|
fontSize: 10,
|
|
|
|
|
|
rotate: 0,
|
|
|
|
|
|
margin: 10
|
|
|
|
|
|
},
|
|
|
|
|
|
axisTick: {
|
|
|
|
|
|
alignWithLabel: true,
|
|
|
|
|
|
show: true
|
|
|
|
|
|
},
|
|
|
|
|
|
boundaryGap: true
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '头数(万)',
|
|
|
|
|
|
nameTextStyle: {
|
|
|
|
|
|
color: '#00ffff',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#00ffff'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#ffffff',
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
},
|
|
|
|
|
|
splitLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: 'rgba(0, 255, 255, 0.2)'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '防疫统计',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: [
|
|
|
|
|
|
{ value: 32.67, itemStyle: { color: '#00ffff' } },
|
|
|
|
|
|
{ value: 20.3, itemStyle: { color: '#84acf0' } },
|
|
|
|
|
|
{ value: 1.91, itemStyle: { color: '#96ceb4' } }
|
|
|
|
|
|
],
|
|
|
|
|
|
barWidth: '30%',
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: function(params) {
|
|
|
|
|
|
const colors = ['#00ffff', '#84acf0', '#96ceb4'];
|
|
|
|
|
|
return colors[params.dataIndex];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}]
|
|
|
|
|
|
},
|
2025-11-07 14:04:09 +08:00
|
|
|
|
// 出栏率分类数据(单位:头)与颜色(统一主题)
|
|
|
|
|
|
slaughterSpeciesData: [
|
|
|
|
|
|
{ name: '杂交改良牛', key: 'hybrid', count: 43000000, color: '#00CDCD', percent: 85 },
|
|
|
|
|
|
{ name: '奶公犊', key: 'dairy_bull_calf', count: 5000000, color: '#869DB0', percent: 10 },
|
|
|
|
|
|
{ name: '地方品种黄牛', key: 'local_yellow', minCount: 1500000, maxCount: 2000000, color: '#267EEF', minPercent: 3, maxPercent: 4 },
|
|
|
|
|
|
{ name: '其他品种', key: 'others', minCount: 500000, maxCount: 800000, color: '#42A2E1', minPercent: 1, maxPercent: 1.5 }
|
|
|
|
|
|
],
|
|
|
|
|
|
slaughterPieOption: {},
|
|
|
|
|
|
slaughterBarOption: {},
|
2025-11-26 17:31:42 +08:00
|
|
|
|
// 不同品种牛存栏率图表(已改为全国出栏率,此处不再使用)
|
2025-11-07 14:04:09 +08:00
|
|
|
|
livestockPieOption: {},
|
|
|
|
|
|
livestockBarOption: {},
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
// 全国牛出栏总量年度柱状图(单位:万头)
|
|
|
|
|
|
nationalSlaughterYearOption: {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const p = params[0]
|
|
|
|
|
|
return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value} 万头`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: { left: '12%', right: '8%', bottom: '12%', top: '18%' },
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: ['2020年','2021年','2022年','2023年','2024年'],
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 10 }
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '万头',
|
|
|
|
|
|
nameTextStyle: { color: '#00ffff', fontSize: 11 },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 10 },
|
|
|
|
|
|
splitLine: { lineStyle: { color: 'rgba(0,255,255,0.2)' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '全国牛出栏总量',
|
|
|
|
|
|
type: 'line',
|
|
|
|
|
|
smooth: true,
|
|
|
|
|
|
symbol: 'circle',
|
|
|
|
|
|
symbolSize: 4,
|
|
|
|
|
|
data: [4565.45, 4707.43, 4839.91, 5023.48, 5098.70],
|
|
|
|
|
|
lineStyle: { color: '#00CDCD', width: 2 },
|
|
|
|
|
|
itemStyle: { color: '#00CDCD' },
|
|
|
|
|
|
areaStyle: { color: 'rgba(0,205,205,0.15)' },
|
|
|
|
|
|
label: { show: true, position: 'top', color: '#cfefff', fontSize: 10, formatter: '{c} 万头' }
|
|
|
|
|
|
}]
|
|
|
|
|
|
},
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
// 全国牛存栏量年度柱状图(单位:万头)
|
|
|
|
|
|
nationalLivestockYearOption: {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const p = params[0]
|
|
|
|
|
|
return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value} 万头`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: { left: '12%', right: '8%', bottom: '12%', top: '18%' },
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: ['2020年','2021年','2022年','2023年','2024年'],
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 10 }
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '万头',
|
|
|
|
|
|
nameTextStyle: { color: '#00ffff', fontSize: 11 },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 10 },
|
|
|
|
|
|
splitLine: { lineStyle: { color: 'rgba(0,255,255,0.2)' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '全国牛存栏总量',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: [ 9562, 9817, 10215, 10508, 10046],
|
|
|
|
|
|
barWidth: '40%',
|
|
|
|
|
|
itemStyle: { color: '#00CDCD' },
|
|
|
|
|
|
label: { show: true, position: 'top', color: '#cfefff', fontSize: 10, formatter: '{c} 万头' }
|
|
|
|
|
|
}]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 已移除:2025年主要品种牛单价趋势预测配置
|
|
|
|
|
|
|
|
|
|
|
|
// 全国牛单价排行榜表格数据
|
|
|
|
|
|
nationalPriceTableRows: [
|
|
|
|
|
|
{ id: 1, province: '河北省', breed: '安格斯牛', price: 14200 },
|
|
|
|
|
|
{ id: 2, province: '山东省', breed: '荷斯坦牛', price: 17000 },
|
|
|
|
|
|
{ id: 3, province: '江苏省', breed: '复洲黄牛', price: 14500 },
|
|
|
|
|
|
{ id: 4, province: '浙江省', breed: '西门塔尔牛', price: 16800 },
|
|
|
|
|
|
{ id: 5, province: '新疆维吾尔自治区', breed: '夏洛莱牛', price: 16500 },
|
|
|
|
|
|
{ id: 6, province: '甘肃省', breed: '水牛', price: 17387 },
|
|
|
|
|
|
{ id: 7, province: '广东省', breed: '安格斯牛', price: 14200 },
|
|
|
|
|
|
{ id: 8, province: '广西壮族自治区', breed: '荷斯坦牛', price: 17000 },
|
|
|
|
|
|
{ id: 9, province: '湖南省', breed: '复洲黄牛', price: 14500 },
|
|
|
|
|
|
{ id: 10, province: '河南省', breed: '西门塔尔牛', price: 16800 }
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
|
|
// 全国牛单价排行榜配置(单位:元/头)
|
|
|
|
|
|
nationalPriceRankingOption: {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: { type: 'shadow' },
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const p = params[0]
|
|
|
|
|
|
return `${p.axisValue}<br/>${p.marker}${p.seriesName}: ${p.value} 元/头`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: { left: '18%', right: '12%', bottom: '15%', top: '20%' },
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '单价(元/头)',
|
|
|
|
|
|
nameTextStyle: { color: '#00ffff', fontSize: 11 },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 10 },
|
|
|
|
|
|
splitLine: { lineStyle: { color: 'rgba(0,255,255,0.2)' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: ['荷斯坦牛','西门塔尔牛','夏洛莱牛','复洲黄牛','安格斯牛','水牛'],
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 11 }
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '全国主要品种单价',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: [17000, 16800, 16500, 14500, 14200, 17387],
|
|
|
|
|
|
barWidth: '45%',
|
|
|
|
|
|
itemStyle: { color: '#00CDCD' },
|
|
|
|
|
|
label: { show: true, position: 'right', color: '#cfefff', fontSize: 10, formatter: '{c} 元/头' }
|
|
|
|
|
|
}]
|
2025-11-07 14:04:09 +08:00
|
|
|
|
},
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
// 地区-品种明细数据
|
|
|
|
|
|
detailRows: [
|
|
|
|
|
|
{ id: 1, region: '河北省', breed: '安格斯牛', stock: 68000, sold: 12000, price: 14200 },
|
|
|
|
|
|
{ id: 2, region: '山东省', breed: '荷斯坦牛', stock: 52000, sold: 9000, price: 17000 },
|
|
|
|
|
|
{ id: 3, region: '江苏省', breed: '复洲黄牛', stock: 72000, sold: 15000, price: 14500 },
|
|
|
|
|
|
{ id: 4, region: '浙江省', breed: '西门塔尔牛', stock: 61000, sold: 11000, price: 16800 },
|
|
|
|
|
|
{ id: 5, region: '新疆维吾尔自治区', breed: '夏洛莱牛', stock: 83000, sold: 13000, price: 16500 },
|
|
|
|
|
|
{ id: 6, region: '甘肃省', breed: '水牛', stock: 47000, sold: 8000, price: 17387 },
|
|
|
|
|
|
{ id: 7, region: '广东省', breed: '安格斯牛', stock: 55000, sold: 10000, price: 14200 },
|
|
|
|
|
|
{ id: 8, region: '广西壮族自治区', breed: '荷斯坦牛', stock: 43000, sold: 7500, price: 17000 },
|
|
|
|
|
|
{ id: 9, region: '湖南省', breed: '复洲黄牛', stock: 65000, sold: 12500, price: 14500 },
|
|
|
|
|
|
{ id: 10, region: '河南省', breed: '西门塔尔牛', stock: 58000, sold: 9800, price: 16800 }
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
|
|
// 耳标统计数据
|
|
|
|
|
|
earTagStats: {
|
|
|
|
|
|
completed: 45678,
|
|
|
|
|
|
planned: 52000
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 耳标佩戴统计堆叠柱状图配置
|
2025-11-26 17:31:42 +08:00
|
|
|
|
earTagChartOption: {
|
2025-10-27 17:29:42 +08:00
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: {
|
|
|
|
|
|
type: 'shadow'
|
|
|
|
|
|
},
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#ffffff'
|
|
|
|
|
|
},
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
let result = params[0].name + '<br/>';
|
|
|
|
|
|
params.forEach(function(item) {
|
|
|
|
|
|
result += item.marker + item.seriesName + ': ' + item.value + '头<br/>';
|
|
|
|
|
|
});
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
data: ['已佩戴', '未佩戴'],
|
|
|
|
|
|
top: '5%',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#ffffff',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
|
|
|
|
|
itemWidth: 12,
|
|
|
|
|
|
itemHeight: 8
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '15%',
|
|
|
|
|
|
right: '10%',
|
|
|
|
|
|
bottom: '15%',
|
|
|
|
|
|
top: '25%'
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '数量(头)',
|
|
|
|
|
|
nameTextStyle: {
|
|
|
|
|
|
color: '#00ffff',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#00ffff'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#ffffff',
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
},
|
|
|
|
|
|
splitLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: 'rgba(0, 255, 255, 0.2)'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: ['东方养殖场', '西部牧场', '南山农场', '北岭牧业', '中心养殖基地'],
|
|
|
|
|
|
axisLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#00ffff'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#ffffff',
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '已佩戴',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
stack: '总量',
|
|
|
|
|
|
data: [8500, 12000, 9800, 7200, 8178],
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: '#00ffff'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '未佩戴',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
stack: '总量',
|
|
|
|
|
|
data: [1500, 2200, 1800, 1300, 1322],
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: '#84acf0'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 牛只参保统计圆形进度图配置
|
|
|
|
|
|
insuranceChartOption: {
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'item',
|
|
|
|
|
|
formatter: '{a} <br/>{b}: {c}头 ({d}%)',
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#ffffff'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '参保统计',
|
|
|
|
|
|
type: 'pie',
|
|
|
|
|
|
radius: ['70%', '90%'],
|
|
|
|
|
|
center: ['50%', '50%'],
|
|
|
|
|
|
startAngle: 90,
|
|
|
|
|
|
avoidLabelOverlap: false,
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: false
|
|
|
|
|
|
},
|
|
|
|
|
|
labelLine: {
|
|
|
|
|
|
show: false
|
|
|
|
|
|
},
|
|
|
|
|
|
data: [
|
|
|
|
|
|
{
|
|
|
|
|
|
value: 160000,
|
|
|
|
|
|
name: '已参保',
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: {
|
|
|
|
|
|
type: 'linear',
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
x2: 1,
|
|
|
|
|
|
y2: 1,
|
|
|
|
|
|
colorStops: [{
|
|
|
|
|
|
offset: 0, color: '#00ffff'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 1, color: '#0080ff'
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
value: 40000,
|
|
|
|
|
|
name: '未参保',
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.1)'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
// 已移除:不同品种年度总销售额柱状图配置
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-11-26 17:31:42 +08:00
|
|
|
|
computed: {
|
|
|
|
|
|
nationalLivestockCount() {
|
|
|
|
|
|
return this.livestockBaseline || 0
|
|
|
|
|
|
},
|
|
|
|
|
|
nationalLivestockDisplay() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
return (this.nationalLivestockCount || 0).toLocaleString('zh-CN')
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return String(this.nationalLivestockCount || 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-11-07 14:04:09 +08:00
|
|
|
|
computed: {
|
2025-10-27 17:29:42 +08:00
|
|
|
|
totalLivestock() {
|
2025-11-07 14:04:09 +08:00
|
|
|
|
// 以数据源计算总存栏量(万头)
|
|
|
|
|
|
return this.livestockSpeciesData.reduce((sum, s) => sum + Math.round(s.count / 10000), 0)
|
2025-10-27 17:29:42 +08:00
|
|
|
|
},
|
|
|
|
|
|
filteredDetailRows() {
|
|
|
|
|
|
if (!this.selectedBreed) {
|
|
|
|
|
|
return this.detailRows
|
|
|
|
|
|
}
|
|
|
|
|
|
return this.detailRows.filter(row => row.breed === this.selectedBreed)
|
2025-11-26 17:31:42 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 品种单价排行榜(右侧)基于地区-品种明细,按价格升序
|
|
|
|
|
|
speciesPriceTableSortedRows() {
|
|
|
|
|
|
let rows = Array.isArray(this.detailRows) ? this.detailRows.map(r => ({
|
|
|
|
|
|
id: r.id,
|
|
|
|
|
|
breed: r.breed,
|
|
|
|
|
|
region: r.region,
|
|
|
|
|
|
price: r.price
|
|
|
|
|
|
})) : []
|
|
|
|
|
|
// 下拉选择生效:按包含关系过滤(处理“安格斯”匹配“安格斯牛”等)
|
|
|
|
|
|
if (this.rightSelectedBreed) {
|
|
|
|
|
|
rows = rows.filter(x => String(x.breed || '').includes(this.rightSelectedBreed))
|
|
|
|
|
|
}
|
|
|
|
|
|
rows.sort((a, b) => a.price - b.price)
|
|
|
|
|
|
return rows
|
|
|
|
|
|
},
|
|
|
|
|
|
// 全国省份单价排行榜(右侧图表):以 nationalPriceTableRows 为数据源,按单价升序
|
|
|
|
|
|
nationalProvincePriceRankingOption() {
|
|
|
|
|
|
const rows = Array.isArray(this.nationalPriceTableRows) ? [...this.nationalPriceTableRows] : []
|
|
|
|
|
|
rows.sort((a, b) => a.price - b.price)
|
|
|
|
|
|
const yCategories = rows.map(r => r.province)
|
|
|
|
|
|
const prices = rows.map(r => r.price)
|
|
|
|
|
|
return {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: { type: 'shadow' },
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const p = params[0]
|
|
|
|
|
|
return `${p.axisValue}<br/>${p.seriesName}: ${p.value} 元/头`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: { left: '0%', right: '10%', bottom: '10%', top: '10%', containLabel: true },
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '单价(元/头)',
|
|
|
|
|
|
nameTextStyle: { color: '#00ffff', fontSize: 11 },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 10 },
|
|
|
|
|
|
splitLine: { lineStyle: { color: 'rgba(0,255,255,0.2)' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: yCategories,
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 11 }
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '省份单价',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: prices,
|
|
|
|
|
|
barWidth: '45%',
|
|
|
|
|
|
itemStyle: { color: '#4e73df' },
|
|
|
|
|
|
label: { show: true, position: 'right', color: '#cfefff', fontSize: 10, formatter: '{c} 元/头' }
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 单价条形图需要的最大值(用于计算宽度百分比)
|
|
|
|
|
|
priceBarMax() {
|
|
|
|
|
|
const arr = Array.isArray(this.nationalPriceTableRows) ? this.nationalPriceTableRows.map(r => r.price) : []
|
|
|
|
|
|
const max = Math.max(...arr, 1)
|
|
|
|
|
|
return max
|
|
|
|
|
|
},
|
|
|
|
|
|
// 单价升序排列后的行数据
|
|
|
|
|
|
nationalPriceTableSortedRows() {
|
|
|
|
|
|
const rows = Array.isArray(this.nationalPriceTableRows) ? [...this.nationalPriceTableRows] : []
|
|
|
|
|
|
rows.sort((a, b) => a.price - b.price)
|
|
|
|
|
|
return rows
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2025-11-26 17:31:42 +08:00
|
|
|
|
// 格式化价格显示(千分位)
|
|
|
|
|
|
formatPrice(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
return Number(value || 0).toLocaleString('zh-CN')
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return String(value || 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 计算条形宽度样式
|
|
|
|
|
|
getPriceBarStyle(price) {
|
|
|
|
|
|
const max = this.priceBarMax || 1
|
|
|
|
|
|
const ratio = Math.max(0, Math.min(1, Number(price || 0) / max))
|
|
|
|
|
|
// 增强对比:非线性拉伸,最小5%,最大100%,采用幂函数放大差异
|
|
|
|
|
|
const percent = 5 + Math.pow(ratio, 0.6) * 95
|
|
|
|
|
|
return { width: `${percent.toFixed(2)}%` }
|
|
|
|
|
|
},
|
2025-11-07 14:04:09 +08:00
|
|
|
|
// 构建环形图(占比)
|
|
|
|
|
|
buildLivestockPieOption() {
|
|
|
|
|
|
const baseline = this.livestockBaseline
|
|
|
|
|
|
const species = this.livestockSpeciesData
|
|
|
|
|
|
const names = species.map(s => s.name)
|
|
|
|
|
|
const percents = species.map(s => Math.round(s.count / baseline * 100))
|
|
|
|
|
|
const pieData = percents.map((v, i) => ({
|
|
|
|
|
|
value: v,
|
|
|
|
|
|
name: names[i],
|
|
|
|
|
|
itemStyle: { color: species[i].color }
|
|
|
|
|
|
}))
|
|
|
|
|
|
return {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'item',
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: (params) => `${params.name}<br/>占比:${params.value}%`
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '占比(%)',
|
|
|
|
|
|
type: 'pie',
|
|
|
|
|
|
radius: ['35%', '49%'],
|
|
|
|
|
|
center: ['50%', '50%'],
|
|
|
|
|
|
avoidLabelOverlap: false,
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'outside',
|
|
|
|
|
|
fontSize: 11,
|
|
|
|
|
|
color: '#ffffff',
|
|
|
|
|
|
formatter: (p) => `${p.name}\n${p.value}%`
|
|
|
|
|
|
},
|
|
|
|
|
|
labelLine: { show: true, length: 12, length2: 8, lineStyle: { color: '#ffffff', width: 1 } },
|
|
|
|
|
|
emphasis: {
|
|
|
|
|
|
label: { show: true, fontSize: 12, fontWeight: 'bold', color: '#00ffff' }
|
|
|
|
|
|
},
|
|
|
|
|
|
data: pieData
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 构建柱状图(数量)
|
|
|
|
|
|
buildLivestockBarOption() {
|
|
|
|
|
|
const species = this.livestockSpeciesData
|
|
|
|
|
|
const names = species.map(s => s.name)
|
|
|
|
|
|
const countsWan = species.map(s => Math.round(s.count / 10000))
|
|
|
|
|
|
return {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: { type: 'shadow' },
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: (params) => {
|
|
|
|
|
|
const p = params[0]
|
|
|
|
|
|
return `${p.name}<br/>存栏量:${p.value} 万头`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: { left: '12%', right: '6%', top: '15%', bottom: '12%', containLabel: true },
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: names,
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 11, rotate: 0 }
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '数量(万头)',
|
|
|
|
|
|
nameTextStyle: { color: '#00ffff', fontSize: 12 },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 11 },
|
|
|
|
|
|
splitLine: { lineStyle: { color: 'rgba(0, 255, 255, 0.2)' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '数量(万头)',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
barWidth: '50%',
|
|
|
|
|
|
label: { show: true, position: 'top', color: '#eaffff', fontSize: 11, formatter: '{c} 万头' },
|
|
|
|
|
|
data: countsWan.map((v, i) => ({ value: v, itemStyle: { color: species[i].color } }))
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 刷新两个图表
|
|
|
|
|
|
refreshLivestockOption() {
|
|
|
|
|
|
this.livestockPieOption = this.buildLivestockPieOption()
|
|
|
|
|
|
this.livestockBarOption = this.buildLivestockBarOption()
|
|
|
|
|
|
},
|
2025-10-27 17:29:42 +08:00
|
|
|
|
filterByBreed() {
|
|
|
|
|
|
// 品种选择变化时的处理逻辑
|
|
|
|
|
|
// filteredDetailRows计算属性会自动更新
|
|
|
|
|
|
},
|
|
|
|
|
|
updateLivestockData() {
|
2025-11-07 14:04:09 +08:00
|
|
|
|
// 当前未提供地区维度的权威数据;保持全国基准展示
|
|
|
|
|
|
this.refreshLivestockOption()
|
2025-10-27 17:29:42 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
// 出栏率——环形图配置
|
|
|
|
|
|
buildSlaughterPieOption() {
|
|
|
|
|
|
const seriesData = this.slaughterSpeciesData.map(s => {
|
|
|
|
|
|
if (s.percent != null) {
|
|
|
|
|
|
return { value: s.percent, name: s.name, itemStyle: { color: s.color }, labelRange: `${s.percent}%` }
|
|
|
|
|
|
}
|
|
|
|
|
|
const mid = ((s.minPercent + s.maxPercent) / 2).toFixed(2)
|
|
|
|
|
|
return { value: +mid, name: s.name, itemStyle: { color: s.color }, labelRange: `${s.minPercent}-${s.maxPercent}%` }
|
|
|
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'item',
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: params => `${params.marker}${params.name}<br/>占比:${seriesData[params.dataIndex].labelRange}`
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: { show: false },
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '出栏占比',
|
|
|
|
|
|
type: 'pie',
|
|
|
|
|
|
radius: ['35%', '49%'],
|
|
|
|
|
|
center: ['44%', '50%'],
|
|
|
|
|
|
avoidLabelOverlap: true,
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
color: '#eaf7ff',
|
|
|
|
|
|
formatter: ({ dataIndex, name }) => `${name}\n${seriesData[dataIndex].labelRange}`,
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
|
|
|
|
|
labelLine: { show: true, length: 8, length2: 6 },
|
|
|
|
|
|
data: seriesData
|
|
|
|
|
|
}]
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
2025-11-07 14:04:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 出栏率——柱状图配置(区间值展示为中位数数值,标签文本展示区间)
|
|
|
|
|
|
buildSlaughterBarOption() {
|
|
|
|
|
|
const data = this.slaughterSpeciesData.map(s => {
|
|
|
|
|
|
if (s.count != null) {
|
|
|
|
|
|
return { value: Math.round(s.count / 10000), labelText: `${Math.round(s.count / 10000)}万头`, color: s.color, name: s.name }
|
|
|
|
|
|
}
|
|
|
|
|
|
const midCount = Math.round(((s.minCount + s.maxCount) / 2) / 10000)
|
|
|
|
|
|
const labelText = `${Math.round(s.minCount / 10000)}-${Math.round(s.maxCount / 10000)}万头`
|
|
|
|
|
|
return { value: midCount, labelText, color: s.color, name: s.name }
|
|
|
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: { type: 'shadow' },
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
|
|
|
|
borderColor: '#00ffff',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
textStyle: { color: '#ffffff' },
|
|
|
|
|
|
formatter: params => {
|
|
|
|
|
|
const p = params[0]
|
|
|
|
|
|
const d = data[p.dataIndex]
|
|
|
|
|
|
return `${p.marker}${d.name}<br/>出栏量:${d.labelText}`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: { top: '20%', right: '6%', bottom: '15%', left: '12%', containLabel: true },
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: data.map(d => d.name),
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 12 },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisTick: { lineStyle: { color: '#00ffff' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '出栏量(万头)',
|
|
|
|
|
|
nameTextStyle: { color: '#00ffff', fontSize: 12 },
|
|
|
|
|
|
axisLabel: { color: '#ffffff', fontSize: 11 },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
axisTick: { lineStyle: { color: '#00ffff' } },
|
|
|
|
|
|
splitLine: { lineStyle: { color: 'rgba(0, 255, 255, 0.2)' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '出栏量',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: data.map(d => ({ value: d.value, itemStyle: { color: d.color } })),
|
|
|
|
|
|
barWidth: '60%',
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'top',
|
|
|
|
|
|
color: '#eaf7ff',
|
|
|
|
|
|
formatter: ({ dataIndex }) => data[dataIndex].labelText,
|
|
|
|
|
|
fontSize: 11
|
|
|
|
|
|
}
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
refreshSlaughterOption() {
|
|
|
|
|
|
this.slaughterPieOption = this.buildSlaughterPieOption()
|
|
|
|
|
|
this.slaughterBarOption = this.buildSlaughterBarOption()
|
|
|
|
|
|
},
|
|
|
|
|
|
validateSlaughterData() {
|
|
|
|
|
|
const categories = ['hybrid', 'dairy_bull_calf', 'local_yellow', 'others']
|
|
|
|
|
|
const keysPresent = new Set(this.slaughterSpeciesData.map(s => s.key))
|
|
|
|
|
|
if (!categories.every(k => keysPresent.has(k))) {
|
|
|
|
|
|
this.validationMessageSlaughter = '数据完整性异常:缺少分类项,请检查数据源。'
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
let sum = 0
|
|
|
|
|
|
this.slaughterSpeciesData.forEach(s => {
|
|
|
|
|
|
if (s.percent != null) sum += s.percent
|
|
|
|
|
|
else sum += (s.minPercent + s.maxPercent) / 2
|
|
|
|
|
|
})
|
|
|
|
|
|
const ok = Math.abs(sum - 100) <= 0.5
|
|
|
|
|
|
this.validationMessageSlaughter = ok ? '' : `占比合计为${sum.toFixed(2)}%,未满足100%±0.5%校验。`
|
|
|
|
|
|
return ok
|
|
|
|
|
|
},
|
|
|
|
|
|
ingestSlaughterRecords(records) {
|
|
|
|
|
|
if (!Array.isArray(records)) return
|
|
|
|
|
|
const map = { hybrid: 0, dairy_bull_calf: 0, local_yellow: 0, others: 0 }
|
|
|
|
|
|
for (let i = 0; i < records.length; i++) {
|
|
|
|
|
|
const r = records[i]
|
|
|
|
|
|
if (map[r.categoryKey] != null) map[r.categoryKey] += r.count || 0
|
|
|
|
|
|
}
|
|
|
|
|
|
this.slaughterSpeciesData = this.slaughterSpeciesData.map(s => {
|
|
|
|
|
|
if (s.count != null) return { ...s, count: map[s.key] || s.count }
|
|
|
|
|
|
if (map[s.key] && map[s.key] > 0) {
|
|
|
|
|
|
const val = map[s.key]
|
|
|
|
|
|
return { ...s, minCount: Math.min(val, s.minCount ?? val), maxCount: Math.max(val, s.maxCount ?? val) }
|
|
|
|
|
|
}
|
|
|
|
|
|
return s
|
|
|
|
|
|
})
|
|
|
|
|
|
this.refreshSlaughterOption()
|
|
|
|
|
|
this.validateSlaughterData()
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
2025-11-07 14:04:09 +08:00
|
|
|
|
// 页面加载时分别初始化数据
|
|
|
|
|
|
this.refreshLivestockOption()
|
|
|
|
|
|
this.refreshSlaughterOption()
|
|
|
|
|
|
this.validateSlaughterData()
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.dashboard-container {
|
|
|
|
|
|
/* 移除flex布局,使用App.vue中的fixed布局 */
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
font-family: 'Microsoft YaHei', sans-serif;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 地图容器样式 */
|
|
|
|
|
|
.map-container {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%; /* 从68%改为100%,让地图占满整个中间区域 */
|
|
|
|
|
|
margin-top: 0; /* 移除负边距 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
.lowest-price-panel h3 {
|
|
|
|
|
|
color: #00d4ff;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
margin: 0 0 15px 0;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
text-align: left;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
.price-item {
|
|
|
|
|
|
background: rgba(0, 255, 255, 0.1);
|
|
|
|
|
|
border: 1px solid rgba(0, 255, 255, 0.3);
|
|
|
|
|
|
border-radius: 6px;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
padding: 10px;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
min-height: 80px; /* 设置最小高度确保内容显示 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.price-item:hover {
|
|
|
|
|
|
background: rgba(0, 255, 255, 0.2);
|
|
|
|
|
|
border-color: #00d4ff;
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.breed-name {
|
|
|
|
|
|
color: #00d4ff;
|
|
|
|
|
|
font-size: 13px; /* 增加字体大小 */
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
margin-bottom: 6px; /* 增加底部间距 */
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.province-info {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 3px; /* 增加间距 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.province {
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
font-size: 12px; /* 增加字体大小 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.price {
|
|
|
|
|
|
color: #00ff88;
|
|
|
|
|
|
font-size: 11px; /* 增加字体大小 */
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 左右侧面板容器边框 */
|
|
|
|
|
|
.dashboard-left::before,
|
|
|
|
|
|
.dashboard-right::before {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0px;
|
|
|
|
|
|
left: 10px;
|
|
|
|
|
|
right: 10px;
|
|
|
|
|
|
border: 2px solid #00d4ff;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
0 0 10px rgba(0, 212, 255, 0.3),
|
|
|
|
|
|
inset 0 0 10px rgba(0, 212, 255, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dashboard-left::after,
|
|
|
|
|
|
.dashboard-right::after {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 10px;
|
|
|
|
|
|
left: 10px;
|
|
|
|
|
|
right: 10px;
|
|
|
|
|
|
/* bottom: 10px; */
|
|
|
|
|
|
border: 1px solid rgba(0, 212, 255, 0.2);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 合并模块样式 */
|
|
|
|
|
|
.combined-panel {
|
|
|
|
|
|
height: 70vh; /* 进一步增加到70%视口高度 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.combined-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
height: calc(100% - 60px); /* 减去标题高度 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 上下布局样式 */
|
|
|
|
|
|
.combined-content.vertical-layout {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-section {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
background: rgba(0, 20, 40, 0.3);
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
2025-10-27 17:29:42 +08:00
|
|
|
|
border-radius: 4px;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 上下布局时的图表区域样式 */
|
|
|
|
|
|
.vertical-layout .chart-section {
|
|
|
|
|
|
min-height: 220px; /* 增加最小高度,提供更多空间 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-section h4 {
|
|
|
|
|
|
color: #00d4ff;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
margin: 0 0 10px 0;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
text-align: left;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
border-bottom: 1px solid rgba(0, 212, 255, 0.2);
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sales-section .chart,
|
|
|
|
|
|
.livestock-section .livestock-chart {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-height: 200px; /* 减小最小高度 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.echarts-container {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 面板样式 */
|
|
|
|
|
|
.panel {
|
|
|
|
|
|
background: rgba(7, 59, 68, 0.15);
|
|
|
|
|
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
|
|
|
|
border-radius: 6px;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
margin-bottom: 5px;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
backdrop-filter: blur(5px);
|
|
|
|
|
|
position: relative;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
overflow: hidden;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
box-shadow:
|
|
|
|
|
|
0 0 8px rgba(0, 212, 255, 0.2),
|
|
|
|
|
|
inset 0 0 8px rgba(0, 212, 255, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.panel-header {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
border-bottom: 1px solid rgba(0, 212, 255, 0.2);
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.panel-header::before {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 15px;
|
|
|
|
|
|
width: 30px;
|
|
|
|
|
|
height: 2px;
|
|
|
|
|
|
background: #00d4ff;
|
|
|
|
|
|
box-shadow: 0 0 4px rgba(0, 212, 255, 0.6);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.panel-header h3 {
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
padding-bottom: 5px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
z-index: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.panel-header h3::before {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: -10px;
|
|
|
|
|
|
top: 50%;
|
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
|
width: 4px;
|
|
|
|
|
|
height: 4px;
|
|
|
|
|
|
background: #00d4ff;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
box-shadow: 0 0 6px rgba(0, 212, 255, 0.8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
.region-select:hover,
|
|
|
|
|
|
.breed-selector:hover {
|
|
|
|
|
|
border-color: #00ffff;
|
|
|
|
|
|
box-shadow: 0 0 8px rgba(0, 255, 255, 0.3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.region-select option,
|
|
|
|
|
|
.breed-selector option {
|
|
|
|
|
|
background: rgba(0, 20, 40, 0.95);
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
padding: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 存栏总数统计样式 */
|
|
|
|
|
|
.livestock-panel .echarts-container {
|
|
|
|
|
|
display: flex;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
gap: 10px; /* 两图间距约16px */
|
2025-11-26 17:31:42 +08:00
|
|
|
|
height:190px;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
padding: 0 5px 5px 5px;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.total-display {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
/* margin-bottom: 1px; */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.total-number {
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #00ffff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.total-label {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #cccccc;
|
|
|
|
|
|
margin-top: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.livestock-chart {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 350px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
/* 新增:存栏率的两个图表容器 */
|
|
|
|
|
|
.livestock-pie {
|
|
|
|
|
|
flex: 0 0 40%;
|
|
|
|
|
|
height: 100%;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
2025-11-07 14:04:09 +08:00
|
|
|
|
.livestock-bar {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 100%;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
/* 统一图例样式,置于两图下方 */
|
|
|
|
|
|
.livestock-legend {
|
2025-10-27 17:29:42 +08:00
|
|
|
|
display: flex;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 10px 10px;
|
|
|
|
|
|
|
|
|
|
|
|
align-items: center;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
2025-11-07 14:04:09 +08:00
|
|
|
|
.livestock-legend .legend-item {
|
2025-10-27 17:29:42 +08:00
|
|
|
|
display: flex;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.livestock-legend .legend-color {
|
|
|
|
|
|
width: 12px;
|
|
|
|
|
|
height: 12px;
|
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
|
box-shadow: 0 0 6px rgba(0, 212, 255, 0.5);
|
|
|
|
|
|
}
|
|
|
|
|
|
.livestock-legend .legend-label {
|
|
|
|
|
|
color: #eaf7ff;
|
|
|
|
|
|
font-size: 12px;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
/* 小屏幕下纵向排列 */
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.livestock-panel .echarts-container {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.livestock-pie,
|
|
|
|
|
|
.livestock-bar {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 280px;
|
|
|
|
|
|
}
|
2025-10-27 17:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 14:04:09 +08:00
|
|
|
|
/* 出栏率统计样式 */
|
|
|
|
|
|
.slaughter-panel {
|
2025-11-26 17:31:42 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
/* 与“全国牛存栏率”模块保持一致的自适应面板高度 */
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
height: auto;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
.slaughter-panel .echarts-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
|
gap: 16px;
|
2025-11-26 17:31:42 +08:00
|
|
|
|
/* 图表容器高度与“全国牛存栏率”模块一致 */
|
|
|
|
|
|
flex: 0 0 230px;
|
|
|
|
|
|
height: 230px;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
.slaughter-pie {
|
|
|
|
|
|
flex: 0 0 42%;
|
2025-10-27 17:29:42 +08:00
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
2025-11-07 14:04:09 +08:00
|
|
|
|
.slaughter-bar {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.slaughter-legend {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 10px 10px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.slaughter-legend .legend-item { display: flex; align-items: center; gap: 6px; }
|
|
|
|
|
|
.slaughter-legend .legend-color { width: 12px; height: 12px; border-radius: 2px; box-shadow: 0 0 6px rgba(0, 212, 255, 0.5); }
|
|
|
|
|
|
.slaughter-legend .legend-label { color: #eaf7ff; font-size: 12px; }
|
|
|
|
|
|
.validation-message { margin-top: 6px; color: #ffcf6e; font-size: 12px; }
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.slaughter-panel { height: auto; }
|
|
|
|
|
|
.slaughter-panel .echarts-container { flex-direction: column; height: auto; }
|
|
|
|
|
|
.slaughter-pie, .slaughter-bar { width: 100%; height: 280px; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
.flip-card:hover .flip-card-inner {
|
|
|
|
|
|
transform: rotateY(180deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.flip-card-front {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
backface-visibility: hidden;
|
|
|
|
|
|
background: rgba(0, 255, 255, 0.15);
|
|
|
|
|
|
border: 1px solid rgba(0, 255, 255, 0.3);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
backdrop-filter: blur(10px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-number {
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #00ffff;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-label {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #cccccc;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-height: 200px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ear-tag-chart {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height:93%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
/* 已移除:品种单价排行榜样式 */
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
/* 明细表样式 */
|
|
|
|
|
|
.detail-table {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
height: 520px;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-header, .detail-row {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 1.2fr 1fr 1fr 1fr 1.2fr;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-header {
|
|
|
|
|
|
color: #84acf0;
|
|
|
|
|
|
border-bottom: 1px solid rgba(132, 172, 240, 0.2);
|
|
|
|
|
|
padding-bottom: 8px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-row {
|
|
|
|
|
|
color: #fff;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
/* padding: 6px 0; */
|
2025-10-27 17:29:42 +08:00
|
|
|
|
border-bottom: 1px dashed rgba(132, 172, 240, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-row:hover {
|
|
|
|
|
|
background: rgba(132, 172, 240, 0.1);
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 17:31:42 +08:00
|
|
|
|
/* 已移除:销售额柱状图模块样式 */
|
2025-10-27 17:29:42 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.company-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.company-bar {
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
height: 12px;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.1);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.company-fill {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
transition: width 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.company-name {
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
}
|
2025-11-07 14:04:09 +08:00
|
|
|
|
|
|
|
|
|
|
/* 存栏率模块工具栏与数据说明 */
|
|
|
|
|
|
.panel-tools {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tool-btn {
|
|
|
|
|
|
background: rgba(0, 212, 255, 0.15);
|
|
|
|
|
|
border: 1px solid rgba(0, 212, 255, 0.4);
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
border-radius: 6px;
|
2025-11-26 17:31:42 +08:00
|
|
|
|
padding: 4px 4px;
|
2025-11-07 14:04:09 +08:00
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tool-btn:hover {
|
|
|
|
|
|
background: rgba(0, 212, 255, 0.25);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.data-notes {
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
min-height: 10%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
color: #00d4ff;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.data-source {
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.7);
|
|
|
|
|
|
}
|
2025-11-26 17:31:42 +08:00
|
|
|
|
</style>
|