|
|
@@ -1,10 +1,13 @@
|
|
|
<template>
|
|
|
<div class="chart-list">
|
|
|
<div class="chart-item">
|
|
|
- <chart-box :name="`${props.areaName}作物种植面积占比`">
|
|
|
+ <chart-box :name="`四川省斑块占比统计`">
|
|
|
<div class="box-content">
|
|
|
<div class="chart-dom">
|
|
|
- <pie-chart :key="`pie-${activeBaseTab}`" :chartData="pieChartData" :totalArea="totalArea"></pie-chart>
|
|
|
+ <pie-chart
|
|
|
+ :chartData="pieChartData"
|
|
|
+ :totalArea="totalArea"
|
|
|
+ ></pie-chart>
|
|
|
</div>
|
|
|
<div class="box-bg">
|
|
|
<div class="legend-list">
|
|
|
@@ -23,7 +26,23 @@
|
|
|
</chart-box>
|
|
|
</div>
|
|
|
<div class="chart-item">
|
|
|
- <chart-box :name="`${props.areaName}小麦物候进程分布`">
|
|
|
+ <chart-box :name="`四川省物候进程分布`">
|
|
|
+ <template #title-right>
|
|
|
+ <el-select
|
|
|
+ v-model="selectedPieItem"
|
|
|
+ placeholder="全部"
|
|
|
+ size="small"
|
|
|
+ style="width: 100px"
|
|
|
+ @change="fetchStatPhenologyAreaRatioByCropType"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in options"
|
|
|
+ :key="item.speciesId"
|
|
|
+ :label="item.speciesName"
|
|
|
+ :value="item.speciesId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
<div class="box-content">
|
|
|
<div class="chart-dom">
|
|
|
<bar-chart :key="`region-${activeBaseTab}`" :chartData="regionChartData"></bar-chart>
|
|
|
@@ -33,10 +52,14 @@
|
|
|
</chart-box>
|
|
|
</div>
|
|
|
<div class="chart-item">
|
|
|
- <chart-box :name="threeTitle">
|
|
|
+ <chart-box name="四川省用地面积统计">
|
|
|
<div class="box-content">
|
|
|
<div class="chart-dom">
|
|
|
- <bar-chart :key="`yield-${activeBaseTab}`" :chartData="yieldChartData" :yAxisFormatter="yAxisFormatter"></bar-chart>
|
|
|
+ <bar-chart
|
|
|
+ :key="`yield-${activeBaseTab}`"
|
|
|
+ :chartData="yieldChartData"
|
|
|
+ :yAxisFormatter="yAxisFormatter"
|
|
|
+ ></bar-chart>
|
|
|
</div>
|
|
|
<div class="box-bg">{{ yieldSummaryText }}</div>
|
|
|
</div>
|
|
|
@@ -48,8 +71,7 @@
|
|
|
<script setup>
|
|
|
import chartBox from "@/components/chartBox.vue";
|
|
|
import pieChart from "./pieChart.vue";
|
|
|
-import lineChart from "./lineChart.vue";
|
|
|
-import { computed, ref, watch,onMounted} from "vue";
|
|
|
+import { computed, ref, watch, onMounted } from "vue";
|
|
|
import { pieOption } from "./chartOption.js";
|
|
|
import barChart from "./barChart.vue";
|
|
|
|
|
|
@@ -72,6 +94,9 @@ const props = defineProps({
|
|
|
const pieChartData = ref([]);
|
|
|
const totalArea = ref(0);
|
|
|
|
|
|
+// 物候进程分布标题右侧下拉框选中项(来自饼图数据)
|
|
|
+const selectedPieItem = ref(null);
|
|
|
+
|
|
|
// 区域占比图表数据
|
|
|
const regionChartData = ref({
|
|
|
categories: [], // 区域名称数组
|
|
|
@@ -90,15 +115,9 @@ const yieldChartData = ref({
|
|
|
// 预估产量摘要文字
|
|
|
const yieldSummaryText = ref("暂无数据");
|
|
|
|
|
|
-// 根据 activeBaseTab 动态设置 y 轴单位
|
|
|
+// y 轴不显示单位
|
|
|
const yAxisFormatter = computed(() => {
|
|
|
- return props.activeBaseTab === "物候期分布" ? "{value}亩" : "{value}吨";
|
|
|
-});
|
|
|
-
|
|
|
-// 种植面积趋势图表数据
|
|
|
-const areaTrendChartData = ref({
|
|
|
- xAxisData: [], // 时间轴数据
|
|
|
- series: [], // 系列数据
|
|
|
+ return "{value}%";
|
|
|
});
|
|
|
|
|
|
// 计算图例数据
|
|
|
@@ -108,15 +127,27 @@ const legendData = computed(() => {
|
|
|
}
|
|
|
return pieChartData.value.map((item, index) => {
|
|
|
const percent = ((item.value / totalArea.value) * 100).toFixed(1);
|
|
|
+ // 优先使用地图图例接口返回的颜色(与名称对应),没有匹配到再使用默认颜色
|
|
|
+ const legendItem = legendArr.value.find((l) => l.name === item.name);
|
|
|
+ const color = legendItem && legendItem.color ? legendItem.color : pieOption.color[index % pieOption.color.length];
|
|
|
return {
|
|
|
name: item.name,
|
|
|
value: Math.round(item.value), // 显示整数
|
|
|
percent: percent,
|
|
|
- color: pieOption.color[index % pieOption.color.length],
|
|
|
+ color: color,
|
|
|
};
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+const legendArr = ref([]);
|
|
|
+const fetchMapLegend = () => {
|
|
|
+ VE_API.warning.fetchMapLegend().then((res) => {
|
|
|
+ if (res.code === 0 && res.data && res.data.length > 0) {
|
|
|
+ legendArr.value = res.data;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
const threeTitle = ref(`${props.areaName}作物预估产量对比`);
|
|
|
|
|
|
// 监听 activeBaseTab 变化
|
|
|
@@ -137,9 +168,6 @@ watch(
|
|
|
}
|
|
|
);
|
|
|
|
|
|
-const currentYear = ref(2025);
|
|
|
-const currentQuarter = ref(1);
|
|
|
-
|
|
|
// 监听 areaName 变化,更新标题
|
|
|
watch(
|
|
|
() => props.areaName,
|
|
|
@@ -155,84 +183,83 @@ watch(
|
|
|
onMounted(() => {
|
|
|
// 初始化时调用一次
|
|
|
initData();
|
|
|
- // eventBus.off("weatherTime:changeTime");
|
|
|
- // eventBus.on("weatherTime:changeTime", ({index, year, quarter}) => {
|
|
|
- // currentYear.value = year;
|
|
|
- // currentQuarter.value = quarter;
|
|
|
- // initData()
|
|
|
- // });
|
|
|
});
|
|
|
|
|
|
const initData = () => {
|
|
|
- // 切换 tab 时,先清空所有图表数据,避免显示旧数据
|
|
|
- fetchStatSpeciesAreaYield();
|
|
|
- if (props.activeBaseTab === "物候期分布") {
|
|
|
- // 清空其他 tab 的数据
|
|
|
- pieChartData.value = [];
|
|
|
- totalArea.value = 0;
|
|
|
- areaTrendChartData.value = { xAxisData: [], series: [] };
|
|
|
-
|
|
|
- threeTitle.value = `${props.areaName}小麦预告产量统计`;
|
|
|
- fetchStatPhenologyRatio();
|
|
|
- fetchStatRegionYieldRatio();
|
|
|
- } else if (props.activeBaseTab === "作物分布") {
|
|
|
- // 清空物候期分布的数据
|
|
|
- regionChartData.value = { categories: [], values: [] };
|
|
|
- regionSummaryText.value = "暂无数据";
|
|
|
-
|
|
|
- threeTitle.value = `${props.areaName}作物预估产量对比`;
|
|
|
- fetchAreaTrend();
|
|
|
- } else {
|
|
|
- // // 其他 tab(预警分布、农场分布、农服管理)时,清空所有图表数据
|
|
|
- // pieChartData.value = [];
|
|
|
- // totalArea.value = 0;
|
|
|
- // regionChartData.value = { categories: [], values: [] };
|
|
|
- // areaTrendChartData.value = { xAxisData: [], series: [] };
|
|
|
- // yieldChartData.value = { categories: [], values: [] };
|
|
|
- // regionSummaryText.value = "暂无数据";
|
|
|
- // yieldSummaryText.value = "暂无数据";
|
|
|
- }
|
|
|
+ fetchStatRegionAreaRatio();
|
|
|
+ fetchStatLandTypeAreaRatio();
|
|
|
+ fetchStatPhenologyAreaRatioByCropType();
|
|
|
+};
|
|
|
+
|
|
|
+const options = ref([]);
|
|
|
+//种植面积占比
|
|
|
+const fetchStatRegionAreaRatio = () => {
|
|
|
+ VE_API.warning
|
|
|
+ .fetchStatRegionAreaRatio()
|
|
|
+ .then((res) => {
|
|
|
+ if (res.code === 0 && res.data && res.data.length > 0) {
|
|
|
+ // 转换接口数据为饼图格式
|
|
|
+ // 饼图数据格式:{ value: 种植面积, name: 物种名称 }
|
|
|
+ const chartData = res.data.map((item) => ({
|
|
|
+ value: item.plantArea, // 种植面积
|
|
|
+ name: item.speciesName, // 物种名称
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 计算总种植面积
|
|
|
+ const total = chartData.reduce((sum, item) => sum + item.value, 0);
|
|
|
+
|
|
|
+ // 更新饼图数据
|
|
|
+ pieChartData.value = chartData;
|
|
|
+ totalArea.value = total;
|
|
|
+ options.value = res.data
|
|
|
+ options.value.unshift({ speciesId: null, speciesName: "全部" });
|
|
|
+ fetchMapLegend();
|
|
|
+ } else {
|
|
|
+ // 接口返回空数据时,仅清空饼图数据
|
|
|
+ pieChartData.value = [];
|
|
|
+ totalArea.value = 0;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error("获取区域产量占比数据失败:", error);
|
|
|
+ yieldChartData.value = {
|
|
|
+ categories: [],
|
|
|
+ values: [],
|
|
|
+ };
|
|
|
+ yieldSummaryText.value = "暂无数据";
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
-//统计指定物种在下级区划中的预估产量占比
|
|
|
-const fetchStatRegionYieldRatio = () => {
|
|
|
- const params = {
|
|
|
- speciesId: 1,
|
|
|
- adminCode: props.areaCode,
|
|
|
- adminLevel: "province",
|
|
|
- };
|
|
|
+//按地块类型统计面积及面积占比
|
|
|
+const fetchStatLandTypeAreaRatio = () => {
|
|
|
VE_API.warning
|
|
|
- .fetchStatRegionYieldRatio(params)
|
|
|
+ .fetchStatLandTypeAreaRatio()
|
|
|
.then((res) => {
|
|
|
if (res.code === 0 && res.data && res.data.length > 0) {
|
|
|
// 转换接口数据为图表格式
|
|
|
- const categories = res.data.map((item) => item.adminName);
|
|
|
- // 如果是物候期分布,使用 expectYield(但单位显示为亩),否则使用 expectYield(单位显示为吨)
|
|
|
- const values = res.data.map((item) => parseFloat(item.expectYield.toFixed(2)));
|
|
|
+ const categories = res.data.map((item) => item.landTypeName);
|
|
|
+ const values = res.data.map((item) => parseFloat((item.areaRatio * 100).toFixed(2))); // 转换为百分比,保留两位小数
|
|
|
|
|
|
- // 更新图表数据
|
|
|
+ // 更新图表数据到 yieldChartData
|
|
|
yieldChartData.value = {
|
|
|
categories,
|
|
|
values,
|
|
|
};
|
|
|
|
|
|
- // 找到最大值的区域
|
|
|
- let maxValue = 0;
|
|
|
- let maxRegion = "";
|
|
|
+ // 找到最大占比的物候期
|
|
|
+ let maxRatio = 0;
|
|
|
+ let maxPhenology = "";
|
|
|
res.data.forEach((item) => {
|
|
|
- if (item.expectYield > maxValue) {
|
|
|
- maxValue = item.expectYield;
|
|
|
- maxRegion = item.adminName;
|
|
|
+ if (item.areaRatio > maxRatio) {
|
|
|
+ maxRatio = item.areaRatio;
|
|
|
+ maxPhenology = item.landTypeName;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 更新摘要文字
|
|
|
- if (maxRegion) {
|
|
|
- const maxValueFormatted = maxValue.toFixed(1);
|
|
|
- const unit = props.activeBaseTab === "物候期分布" ? "亩" : "吨";
|
|
|
- yieldSummaryText.value = `${maxRegion}的${
|
|
|
- props.activeBaseTab === "物候期分布" ? "种植面积" : "预估产量"
|
|
|
- }最大,为${maxValueFormatted}${unit}`;
|
|
|
+ if (maxPhenology) {
|
|
|
+ const maxPercent = (maxRatio * 100).toFixed(1);
|
|
|
+ yieldSummaryText.value = `${maxPhenology}的种植面积最大,占比${maxPercent}%`;
|
|
|
} else {
|
|
|
yieldSummaryText.value = "暂无数据";
|
|
|
}
|
|
|
@@ -245,7 +272,7 @@ const fetchStatRegionYieldRatio = () => {
|
|
|
}
|
|
|
})
|
|
|
.catch((error) => {
|
|
|
- console.error("获取区域产量占比数据失败:", error);
|
|
|
+ console.error("获取地块类型面积占比数据失败:", error);
|
|
|
yieldChartData.value = {
|
|
|
categories: [],
|
|
|
values: [],
|
|
|
@@ -254,24 +281,17 @@ const fetchStatRegionYieldRatio = () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-//统计指定物种在不同物候期下的面积占比
|
|
|
-const fetchStatPhenologyRatio = () => {
|
|
|
- const params = {
|
|
|
- speciesId: 1,
|
|
|
- adminCode: props.areaCode,
|
|
|
- adminLevel: "province",
|
|
|
- };
|
|
|
-
|
|
|
+const fetchStatPhenologyAreaRatioByCropType = () => {
|
|
|
VE_API.warning
|
|
|
- .fetchStatPhenologyRatio(params)
|
|
|
+ .fetchStatPhenologyAreaRatioByCropType({ cropTypeId: selectedPieItem.value })
|
|
|
.then((res) => {
|
|
|
if (res.code === 0 && res.data && res.data.length > 0) {
|
|
|
- console.log(res.data);
|
|
|
- // 转换接口数据为图表格式
|
|
|
- const categories = res.data.map((item) => item.phenologyName);
|
|
|
- const values = res.data.map((item) => parseFloat((item.areaRatio * 100).toFixed(2))); // 转换为百分比,保留两位小数
|
|
|
+ // 转换接口数据为图表格式(物候进程分布)
|
|
|
+ // 横轴:物候期名称,纵轴:面积占比(百分比)
|
|
|
+ const categories = res.data.map((item) => item.speciesName);
|
|
|
+ const values = res.data.map((item) => parseFloat((item.areaRatio * 100).toFixed(2)));
|
|
|
|
|
|
- // 更新图表数据
|
|
|
+ // 更新区域图表数据
|
|
|
regionChartData.value = {
|
|
|
categories,
|
|
|
values,
|
|
|
@@ -283,7 +303,7 @@ const fetchStatPhenologyRatio = () => {
|
|
|
res.data.forEach((item) => {
|
|
|
if (item.areaRatio > maxRatio) {
|
|
|
maxRatio = item.areaRatio;
|
|
|
- maxPhenology = item.phenologyName;
|
|
|
+ maxPhenology = item.speciesName;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@@ -295,6 +315,7 @@ const fetchStatPhenologyRatio = () => {
|
|
|
regionSummaryText.value = "暂无数据";
|
|
|
}
|
|
|
} else {
|
|
|
+ // 接口返回空数据时,清空区域图表数据
|
|
|
regionChartData.value = {
|
|
|
categories: [],
|
|
|
values: [],
|
|
|
@@ -302,8 +323,8 @@ const fetchStatPhenologyRatio = () => {
|
|
|
regionSummaryText.value = "暂无数据";
|
|
|
}
|
|
|
})
|
|
|
- .catch((error) => {
|
|
|
- console.error("获取物候期占比数据失败:", error);
|
|
|
+ .catch(() => {
|
|
|
+ // 错误时也清空数据
|
|
|
regionChartData.value = {
|
|
|
categories: [],
|
|
|
values: [],
|
|
|
@@ -311,162 +332,6 @@ const fetchStatPhenologyRatio = () => {
|
|
|
regionSummaryText.value = "暂无数据";
|
|
|
});
|
|
|
};
|
|
|
-
|
|
|
-const fetchAreaTrend = () => {
|
|
|
- const params = {
|
|
|
- speciesIds: [1, 222, 60876],
|
|
|
- adminCode: props.areaCode,
|
|
|
- adminLevel: "province",
|
|
|
- };
|
|
|
- VE_API.warning.fetchAreaTrend(params).then((res) => {
|
|
|
- if (res.code === 0 && res.data && res.data.length > 0) {
|
|
|
- // 收集所有唯一的时间点(year-quarter组合)
|
|
|
- const timePointSet = new Set();
|
|
|
- res.data.forEach((species) => {
|
|
|
- species.timeSeries.forEach((item) => {
|
|
|
- const timeKey = `${item.year}Q${item.quarter}`;
|
|
|
- timePointSet.add(timeKey);
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- // 转换为数组并排序
|
|
|
- const xAxisData = Array.from(timePointSet).sort((a, b) => {
|
|
|
- const [yearA, quarterA] = a.split("Q").map(Number);
|
|
|
- const [yearB, quarterB] = b.split("Q").map(Number);
|
|
|
- if (yearA !== yearB) return yearA - yearB;
|
|
|
- return quarterA - quarterB;
|
|
|
- });
|
|
|
-
|
|
|
- // 定义颜色映射(可以根据需要调整)
|
|
|
- const colorMap = {
|
|
|
- 荔枝: "#2199F8",
|
|
|
- 籼稻: "#178B00",
|
|
|
- 小麦: "#FAA53D",
|
|
|
- };
|
|
|
-
|
|
|
- // 为每个作物创建系列数据
|
|
|
- const series = res.data.map((species) => {
|
|
|
- // 创建时间点到种植面积的映射
|
|
|
- const dataMap = new Map();
|
|
|
- species.timeSeries.forEach((item) => {
|
|
|
- const timeKey = `${item.year}Q${item.quarter}`;
|
|
|
- dataMap.set(timeKey, item.plantArea);
|
|
|
- });
|
|
|
-
|
|
|
- // 根据 xAxisData 顺序生成数据数组
|
|
|
- const data = xAxisData.map((timeKey) => {
|
|
|
- return dataMap.has(timeKey) ? parseFloat(dataMap.get(timeKey).toFixed(2)) : null;
|
|
|
- });
|
|
|
-
|
|
|
- return {
|
|
|
- name: species.speciesName,
|
|
|
- type: "line",
|
|
|
- smooth: true,
|
|
|
- showSymbol: false,
|
|
|
- data: data,
|
|
|
- itemStyle: {
|
|
|
- color: colorMap[species.speciesName] || "#2199F8",
|
|
|
- },
|
|
|
- lineStyle: {
|
|
|
- color: colorMap[species.speciesName] || "#2199F8",
|
|
|
- },
|
|
|
- };
|
|
|
- });
|
|
|
-
|
|
|
- // 更新图表数据
|
|
|
- areaTrendChartData.value = {
|
|
|
- xAxisData,
|
|
|
- series,
|
|
|
- };
|
|
|
- } else {
|
|
|
- console.log("空数据");
|
|
|
- // 接口返回空数据时,清空图表数据
|
|
|
- areaTrendChartData.value = {
|
|
|
- xAxisData: [],
|
|
|
- series: [],
|
|
|
- };
|
|
|
- }
|
|
|
- }).catch(() => {
|
|
|
- // 错误时也清空数据
|
|
|
- areaTrendChartData.value = {
|
|
|
- xAxisData: [],
|
|
|
- series: [],
|
|
|
- };
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-const fetchStatSpeciesAreaYield = () => {
|
|
|
- const params = {
|
|
|
- year: 2025,
|
|
|
- adminCode: props.areaCode,
|
|
|
- adminLevel: null,
|
|
|
- };
|
|
|
- VE_API.warning.fetchStatSpeciesAreaYield(params).then((res) => {
|
|
|
- if (res.code === 0 && res.data && res.data.length > 0) {
|
|
|
- // 转换接口数据为图表格式(用于饼图)
|
|
|
- const chartData = res.data.map((item) => ({
|
|
|
- value: item.plantArea, // 种植面积
|
|
|
- name: item.speciesName, // 作物名称
|
|
|
- expectYield: item.expectYield, // 预估产量
|
|
|
- speciesId: item.speciesId, // 作物ID
|
|
|
- }));
|
|
|
-
|
|
|
- // 计算总种植面积
|
|
|
- const total = chartData.reduce((sum, item) => sum + item.value, 0);
|
|
|
-
|
|
|
- // 更新饼图数据
|
|
|
- pieChartData.value = chartData;
|
|
|
- totalArea.value = total;
|
|
|
-
|
|
|
- // 处理预估产量数据(用于柱状图)
|
|
|
- const categories = res.data.map((item) => item.speciesName);
|
|
|
- const values = res.data.map((item) => parseFloat(item.expectYield.toFixed(2))); // 保留两位小数
|
|
|
-
|
|
|
- // 更新预估产量图表数据
|
|
|
- yieldChartData.value = {
|
|
|
- categories,
|
|
|
- values,
|
|
|
- };
|
|
|
-
|
|
|
- // 找到最大预估产量的作物
|
|
|
- let maxYield = 0;
|
|
|
- let maxSpecies = "";
|
|
|
- res.data.forEach((item) => {
|
|
|
- if (item.expectYield > maxYield) {
|
|
|
- maxYield = item.expectYield;
|
|
|
- maxSpecies = item.speciesName;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // 更新摘要文字
|
|
|
- if (maxSpecies) {
|
|
|
- const maxYieldFormatted = maxYield.toFixed(1);
|
|
|
- yieldSummaryText.value = `${maxSpecies}的预估产量最高,为${maxYieldFormatted}吨`;
|
|
|
- } else {
|
|
|
- yieldSummaryText.value = "暂无数据";
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 接口返回空数据时,清空图表数据
|
|
|
- pieChartData.value = [];
|
|
|
- totalArea.value = 0;
|
|
|
- yieldChartData.value = {
|
|
|
- categories: [],
|
|
|
- values: [],
|
|
|
- };
|
|
|
- yieldSummaryText.value = "暂无数据";
|
|
|
- }
|
|
|
- }).catch((error) => {
|
|
|
- console.error("获取作物面积产量数据失败:", error);
|
|
|
- // 错误时也清空数据
|
|
|
- pieChartData.value = [];
|
|
|
- totalArea.value = 0;
|
|
|
- yieldChartData.value = {
|
|
|
- categories: [],
|
|
|
- values: [],
|
|
|
- };
|
|
|
- yieldSummaryText.value = "暂无数据";
|
|
|
- });
|
|
|
-};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|