Procházet zdrojové kódy

feat:修改页面逻辑UI

wangsisi před 1 dnem
rodič
revize
2dae1feb7b

+ 15 - 0
src/api/modules/warning.js

@@ -84,5 +84,20 @@ export default {
         url: config.one_map_url + "agri_common/land_types",
         type: "get",
     },
+    //获取土地利用类型图例
+    fetchLandUseTypes: {
+        url: config.one_map_url + "agri_common/legend_tree",
+        type: "get",
+    },
+    //统计指定类型下的面积占比
+    fetchStatAreaRatioByType: {
+        url: config.one_map_url + "agri_chart_stat/stat_area_ratio_by_type",
+        type: "get",
+    },
+    //按物候期统计粮食作物的面积及面积占比
+    fetchStatPhenologyAreaRatioForGrain: {
+        url: config.one_map_url + "agri_chart_stat/stat_phenology_area_ratio_for_grain",
+        type: "get",
+    },
 }
 

+ 3 - 4
src/views/warningHome/components/chart_components/barChart.vue

@@ -33,13 +33,12 @@ const initData = () => {
         newOption.xAxis.data = props.chartData.categories;
         newOption.series[0].data = props.chartData.values;
 
-        // 如果数据项超过 8 个,启用滚动功能
         const dataLength = props.chartData.categories.length;
-        if (dataLength > 8) {
+        if (dataLength > 6) {
             // 调整 grid 的 bottom,为 dataZoom 留出空间
             newOption.grid.bottom = 20;
             // 使用滚动时,不需要旋转标签
-            newOption.xAxis.axisLabel.rotate = 0;
+            newOption.xAxis.axisLabel.rotate = 25;
 
             // 添加 dataZoom 配置,实现 x 轴滚动
             newOption.dataZoom = [
@@ -66,7 +65,7 @@ const initData = () => {
             // 数据项较少时,恢复默认的 bottom 值
             newOption.grid.bottom = 10;
             // 数据项少时,可以旋转标签以避免重叠
-            newOption.xAxis.axisLabel.rotate = dataLength >= 5 ? 30 : 0;
+            newOption.xAxis.axisLabel.rotate = dataLength >= 6 ? 25 : 0;
         }
     } else {
         // 数据为空时,清空图表

+ 129 - 131
src/views/warningHome/components/chart_components/chartList.vue

@@ -1,13 +1,10 @@
 <template>
     <div class="chart-list">
         <div class="chart-item">
-            <chart-box :name="`四川省斑块占比统计`">
+            <chart-box :name="`平泉街道${selectedCategory.category}占比统计`">
                 <div class="box-content">
                     <div class="chart-dom">
-                        <pie-chart
-                            :chartData="pieChartData"
-                            :totalArea="totalArea"
-                        ></pie-chart>
+                        <pie-chart :chartData="pieChartData" :totalArea="totalArea"></pie-chart>
                     </div>
                     <div class="box-bg">
                         <div class="legend-list">
@@ -26,21 +23,15 @@
             </chart-box>
         </div>
         <div class="chart-item">
-            <chart-box :name="`四川省物候进程分布`">
+            <chart-box :name="`平泉街道物候进程分布`">
                 <template #title-right>
                     <el-select
                         v-model="selectedPieItem"
-                        placeholder="全部"
                         size="small"
                         style="width: 100px"
-                        @change="fetchStatPhenologyAreaRatioByCropType"
+                        @change="fetchStatPhenologyAreaRatioForGrain"
                     >
-                        <el-option
-                            v-for="item in options"
-                            :key="item.speciesId"
-                            :label="item.speciesName"
-                            :value="item.speciesId"
-                        />
+                        <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
                     </el-select>
                 </template>
                 <div class="box-content">
@@ -52,7 +43,7 @@
             </chart-box>
         </div>
         <div class="chart-item">
-            <chart-box name="四川省用地面积统计">
+            <chart-box :name="`平泉街道非农化非量化占比统计`">
                 <div class="box-content">
                     <div class="chart-dom">
                         <bar-chart
@@ -71,9 +62,9 @@
 <script setup>
 import chartBox from "@/components/chartBox.vue";
 import pieChart from "./pieChart.vue";
-import { computed, ref, watch, onMounted } from "vue";
-import { pieOption } from "./chartOption.js";
+import { computed, ref, onMounted, onUnmounted } from "vue";
 import barChart from "./barChart.vue";
+import eventBus from "@/api/eventBus";
 
 const props = defineProps({
     activeBaseTab: {
@@ -94,6 +85,28 @@ const props = defineProps({
 const pieChartData = ref([]);
 const totalArea = ref(0);
 
+// 饼图颜色数组(与 chartOption.js 保持一致)
+const pieColors = ["#2199F8", "#14C9C9", "#FFCC4B", "#8F46F4", "#FF7878", "#9FDB1D"];
+
+// 图例数据(基于饼图数据计算)
+const legendData = computed(() => {
+    if (!pieChartData.value || pieChartData.value.length === 0 || totalArea.value === 0) {
+        return [];
+    }
+
+    return pieChartData.value.map((item, index) => {
+        const percent = ((item.value / totalArea.value) * 100).toFixed(2);
+        // 从饼图数据中获取颜色(优先使用 itemStyle.color,如果没有则使用默认颜色)
+        const color = item.itemStyle?.color || pieColors[index % pieColors.length];
+        return {
+            color: color,
+            name: item.name,
+            percent: parseFloat(percent),
+            value: Math.round(item.value),
+        };
+    });
+});
+
 // 物候进程分布标题右侧下拉框选中项(来自饼图数据)
 const selectedPieItem = ref(null);
 
@@ -106,164 +119,146 @@ const regionChartData = ref({
 // 区域占比摘要文字
 const regionSummaryText = ref("暂无数据");
 
-// 预估产量图表数据
+// 用地面积统计图表数据
 const yieldChartData = ref({
-    categories: [], // 作物名称数组
-    values: [], // 预估产量数组(单位:吨)
+    categories: [], // 类别名称数组
+    values: [], // 占比百分比数组
 });
 
-// 预估产量摘要文字
+// 用地面积统计摘要文字
 const yieldSummaryText = ref("暂无数据");
 
-// y 轴不显示单位
-const yAxisFormatter = computed(() => {
-    return "{value}%";
+onMounted(() => {
+    // 监听图例组件的变化事件
+    eventBus.on("landUseLegend:change", handleLandUseLegendChange);
+    // 初始化时请求用地面积统计数据(statType=1)
+    fetchYieldChartData();
 });
 
-// 计算图例数据
-const legendData = computed(() => {
-    if (!pieChartData.value.length || totalArea.value === 0) {
-        return [];
-    }
-    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: color,
-        };
-    });
+onUnmounted(() => {
+    // 移除事件监听
+    eventBus.off("landUseLegend:change", handleLandUseLegendChange);
 });
 
-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 变化
-watch(
-    () => props.activeBaseTab,
-    () => {
-        initData();
+// 处理图例组件变化
+const handleLandUseLegendChange = (data) => {
+    if (data.category === "作物类型" || data.nonGrain == null) {
+        options.value = data.children;
+        selectedPieItem.value = data.children[0].id;
     }
-);
-
-// 监听 areaCode 变化,当切换到物候期分布时重新获取数据
-watch(
-    () => props.areaCode,
-    (newVal) => {
-        if (newVal) {
-            initData();
-        }
-    }
-);
-
-// 监听 areaName 变化,更新标题
-watch(
-    () => props.areaName,
-    () => {
-        if (props.activeBaseTab === "物候期分布") {
-            threeTitle.value = `${props.areaName}小麦预告产量统计`;
-        } else if (props.activeBaseTab === "作物分布") {
-            threeTitle.value = `${props.areaName}作物预估产量对比`;
-        }
-    }
-);
-
-onMounted(() => {
-    // 初始化时调用一次
-    initData();
-});
-
-const initData = () => {
-    fetchStatRegionAreaRatio();
-    fetchStatLandTypeAreaRatio();
-    fetchStatPhenologyAreaRatioByCropType();
+    // 更新选中的类别信息
+    selectedCategory.value = {
+        category: data.category,
+        nonGrain: data.nonGrain,
+    };
+    // 使用新的 nonGrain 重新获取饼图数据
+    fetchStatRegionAreaRatio(data.nonGrain);
+    fetchStatPhenologyAreaRatioForGrain();
 };
 
 const options = ref([]);
+// 当前选中的类别信息
+const selectedCategory = ref({
+    category: null,
+    nonGrain: null,
+});
+
 //种植面积占比
-const fetchStatRegionAreaRatio = () => {
+const fetchStatRegionAreaRatio = (nonGrain = null) => {
+    const params = { statType: nonGrain || 0 };
     VE_API.warning
-        .fetchStatRegionAreaRatio()
+        .fetchStatAreaRatioByType(params)
         .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, // 物种名称
+                // 饼图数据格式:{ value: 种植面积, name: 物种名称, itemStyle: { color: 颜色 } }
+                const chartData = res.data.map((item, index) => ({
+                    value: item.plantArea,
+                    name: item.name,
+                    itemStyle: {
+                        color: item.color || pieColors[index % pieColors.length], // 使用接口返回的 color,如果没有则使用默认颜色
+                    },
                 }));
 
-                // 计算总种植面积
-                const total = chartData.reduce((sum, item) => sum + item.value, 0);
+                if (chartData.length > 0) {
+                    // 计算总种植面积
+                    const total = chartData.reduce((sum, item) => sum + (item.value || 0), 0);
 
-                // 更新饼图数据
-                pieChartData.value = chartData;
-                totalArea.value = total;
-                options.value = res.data
-                options.value.unshift({ speciesId: null, speciesName: "全部" });
-                fetchMapLegend();
+                    // 更新饼图数据
+                    pieChartData.value = chartData;
+                    totalArea.value = total;
+                } else {
+                    // 数据过滤后为空
+                    pieChartData.value = [];
+                    totalArea.value = 0;
+                }
             } else {
-                // 接口返回空数据时,仅清空饼图数据
+                // 接口返回空数据时,清空饼图数据
                 pieChartData.value = [];
                 totalArea.value = 0;
             }
         })
         .catch((error) => {
-            console.error("获取区域产量占比数据失败:", error);
-            yieldChartData.value = {
-                categories: [],
-                values: [],
-            };
-            yieldSummaryText.value = "暂无数据";
+            console.error("获取种植面积占比数据失败:", error);
+            // 错误时清空数据
+            pieChartData.value = [];
+            totalArea.value = 0;
         });
 };
 
-//按地块类型统计面积及面积占比
-const fetchStatLandTypeAreaRatio = () => {
+// 获取用地面积统计图表数据(statType=1)
+const fetchYieldChartData = () => {
+    const params = { statType: 1 }; // 固定为 1
     VE_API.warning
-        .fetchStatLandTypeAreaRatio()
+        .fetchStatAreaRatioByType(params)
         .then((res) => {
             if (res.code === 0 && res.data && res.data.length > 0) {
-                // 转换接口数据为图表格式
-                const categories = res.data.map((item) => item.landTypeName);
-                const values = res.data.map((item) => parseFloat((item.areaRatio * 100).toFixed(2))); // 转换为百分比,保留两位小数
+                // 计算总种植面积
+                const total = res.data.reduce((sum, item) => sum + (item.plantArea || 0), 0);
+                
+                // 转换接口数据为柱状图格式
+                const categories = res.data.map((item) => item.name);
+                const values = res.data.map((item) => {
+                    // 计算百分比
+                    const percent = total > 0 ? ((item.plantArea / total) * 100).toFixed(2) : 0;
+                    return parseFloat(percent);
+                });
 
-                // 更新图表数据到 yieldChartData
+                // 更新图表数据
                 yieldChartData.value = {
                     categories,
                     values,
                 };
 
-                // 找到最大占比的物候期
-                let maxRatio = 0;
-                let maxPhenology = "";
+                // 找到最大和最小占比的项
+                let maxValue = 0;
+                let maxName = "";
+                let minValue = Infinity;
+                let minName = "";
                 res.data.forEach((item) => {
-                    if (item.areaRatio > maxRatio) {
-                        maxRatio = item.areaRatio;
-                        maxPhenology = item.landTypeName;
+                    if (item.plantArea > maxValue) {
+                        maxValue = item.plantArea;
+                        maxName = item.name;
+                    }
+                    if (item.plantArea < minValue) {
+                        minValue = item.plantArea;
+                        minName = item.name;
                     }
                 });
 
                 // 更新摘要文字
-                if (maxPhenology) {
-                    const maxPercent = (maxRatio * 100).toFixed(1);
-                    yieldSummaryText.value = `${maxPhenology}的种植面积最大,占比${maxPercent}%`;
+                if (maxName && minName && total > 0) {
+                    const maxPercent = ((maxValue / total) * 100).toFixed(1);
+                    const minPercent = ((minValue / total) * 100).toFixed(1);
+                    yieldSummaryText.value = `${maxName}的种植面积最大,占比${maxPercent}%;${minName}的种植面积最小,占比${minPercent}%`;
+                } else if (maxName && total > 0) {
+                    const maxPercent = ((maxValue / total) * 100).toFixed(1);
+                    yieldSummaryText.value = `${maxName}的种植面积最大,占比${maxPercent}%`;
                 } else {
                     yieldSummaryText.value = "暂无数据";
                 }
             } else {
+                // 接口返回空数据时,清空图表数据
                 yieldChartData.value = {
                     categories: [],
                     values: [],
@@ -272,7 +267,8 @@ const fetchStatLandTypeAreaRatio = () => {
             }
         })
         .catch((error) => {
-            console.error("获取地块类型面积占比数据失败:", error);
+            console.error("获取用地面积统计数据失败:", error);
+            // 错误时清空数据
             yieldChartData.value = {
                 categories: [],
                 values: [],
@@ -281,9 +277,9 @@ const fetchStatLandTypeAreaRatio = () => {
         });
 };
 
-const fetchStatPhenologyAreaRatioByCropType = () => {
+const fetchStatPhenologyAreaRatioForGrain = () => {
     VE_API.warning
-        .fetchStatPhenologyAreaRatioByCropType({ cropTypeId: selectedPieItem.value })
+        .fetchStatPhenologyAreaRatioForGrain({ speciesId: selectedPieItem.value })
         .then((res) => {
             if (res.code === 0 && res.data && res.data.length > 0) {
                 // 转换接口数据为图表格式(物候进程分布)
@@ -302,17 +298,19 @@ const fetchStatPhenologyAreaRatioByCropType = () => {
                 // 找到最大占比的物候期
                 let maxRatio = 0;
                 let maxPhenology = "";
+                let maxPhenologyName = "";
                 res.data.forEach((item) => {
                     if (item.areaRatio > maxRatio) {
                         maxRatio = item.areaRatio;
                         maxPhenology = item.speciesName;
+                        maxPhenologyName = item.phenologyName;
                     }
                 });
 
                 // 更新摘要文字
                 if (maxPhenology) {
                     const maxPercent = (maxRatio * 100).toFixed(1);
-                    regionSummaryText.value = `${maxPhenology}的种植面积最大,占比${maxPercent}%`;
+                    regionSummaryText.value = `${maxPhenology}的种植面积最大,占比${maxPercent}%,进入${maxPhenologyName}`;
                 } else {
                     regionSummaryText.value = "暂无数据";
                 }

+ 1 - 1
src/views/warningHome/components/chart_components/chartOption.js

@@ -27,7 +27,7 @@ export const pieOption = {
         }
     },
     title: {
-        text: '种植面积(亩)',
+        text: '作物种植面积(亩)',
         subtext: '1000',
         x: '49%',
         y: '39%',

+ 338 - 0
src/views/warningHome/components/landUseLegend.vue

@@ -0,0 +1,338 @@
+<template>
+    <div class="land-use-legend yes-events">
+        <div
+            v-for="(category, index) in legendData"
+            :key="index"
+            class="legend-category"
+        >
+            <!-- 父级:可勾选 -->
+            <div class="category-header" @click="toggleExpand(category)">
+                <el-icon class="expand-icon" :class="{ expanded: category.expanded }"><CaretRight /></el-icon>
+                <el-checkbox
+                    v-model="category.checked"
+                    @change="handleCategoryChange(category)"
+                    @click.stop
+                    class="category-checkbox"
+                />
+                <span class="category-name">{{ category.name }}</span>
+            </div>
+            <!-- 子级:仅显示 -->
+            <div v-show="category.expanded" class="category-children">
+                <div
+                    v-for="(child, childIndex) in category.children"
+                    :key="childIndex"
+                    class="child-item"
+                >
+                    <span class="color-dot" :style="{ backgroundColor: child.color }"></span>
+                    <span class="child-name">{{ child.name }}</span>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from "vue";
+import eventBus from "@/api/eventBus";
+
+const props = defineProps({
+    data: {
+        type: Array,
+        default: () => [],
+    },
+});
+
+const emit = defineEmits(["change"]);
+
+// 默认数据(示例数据,可根据实际需求修改)
+const defaultData = [
+    {
+        name: "作物类",
+        checked: true,
+        expanded: true,
+        children: [
+            { name: "小麦", color: "#2199F8" },
+            { name: "油菜", color: "#FFA500" },
+        ],
+    },
+    {
+        name: "非农化非粮化类",
+        checked: false,
+        expanded: true,
+        children: [
+            { name: "撂荒", color: "#00CED1" },
+            { name: "林木", color: "#FF69B4" },
+            { name: "果树", color: "#90EE90" },
+            { name: "坑塘", color: "#008080" },
+            { name: "建设用地", color: "#FFA500" },
+        ],
+    },
+    {
+        name: "耕地类",
+        checked: false,
+        expanded: false,
+        children: [
+            { name: "水田", color: "#4169E1" },
+            { name: "旱地", color: "#8B4513" },
+            { name: "水浇地", color: "#228B22" },
+        ],
+    },
+];
+
+const legendData = ref([]);
+
+// 初始化数据
+const initData = () => {
+    if (props.data && props.data.length > 0) {
+        legendData.value = props.data.map((item) => ({
+            ...item,
+            expanded: item.expanded !== undefined ? item.expanded : false,
+            checked: item.checked !== undefined ? item.checked : false,
+        }));
+    } else {
+        legendData.value = defaultData.map((item) => ({ ...item }));
+    }
+};
+
+const fetchLandUseTypes = () => {
+    VE_API.warning.fetchLandUseTypes().then((res) => {
+        if (res.code === 0 && res.data && res.data.length > 0) {
+            // 处理接口返回的数据,确保格式正确
+            // 默认第一个勾选,全部展开
+            let processedData = res.data.map((item, index) => ({
+                ...item,
+                // 第一个默认勾选,其他不勾选
+                checked: index === 0,
+                // 全部默认展开
+                expanded: true,
+            }));
+            
+            legendData.value = processedData;
+            
+            // 如果第一个默认勾选,触发 change 事件
+            if (processedData.length > 0 && processedData[0].checked) {
+                const firstCategory = processedData[0];
+                emit("change", {
+                    category: firstCategory.name,
+                    checked: true,
+                    children: firstCategory.children || [],
+                    nonGrain: firstCategory.id || firstCategory.nonGrain || null,
+                });
+                // 通知地图更新
+                eventBus.emit("chartList:updateMap", {
+                    statType: firstCategory.id || firstCategory.nonGrain || null,
+                });
+            }
+        } else {
+            // 如果接口返回失败,使用默认数据
+            // 默认第一个勾选,全部展开
+            const defaultProcessed = defaultData.map((item, index) => ({
+                ...item,
+                checked: index === 0,
+                expanded: true,
+            }));
+            legendData.value = defaultProcessed;
+            
+            // 如果第一个默认勾选,触发 change 事件
+            if (defaultProcessed.length > 0 && defaultProcessed[0].checked) {
+                const firstCategory = defaultProcessed[0];
+                emit("change", {
+                    category: firstCategory.name,
+                    checked: true,
+                    children: firstCategory.children || [],
+                    nonGrain: firstCategory.id || firstCategory.nonGrain || null,
+                });
+                // 通知地图更新
+                eventBus.emit("chartList:updateMap", {
+                    statType: firstCategory.id || firstCategory.nonGrain || null,
+                });
+            }
+        }
+    }).catch((error) => {
+        console.error("获取土地利用类型失败:", error);
+        // 接口失败时使用默认数据
+        // 默认第一个勾选,全部展开
+        const defaultProcessed = defaultData.map((item, index) => ({
+            ...item,
+            checked: index === 0,
+            expanded: true,
+        }));
+        legendData.value = defaultProcessed;
+        
+        // 如果第一个默认勾选,触发 change 事件
+        if (defaultProcessed.length > 0 && defaultProcessed[0].checked) {
+            const firstCategory = defaultProcessed[0];
+            emit("change", {
+                category: firstCategory.name,
+                checked: true,
+                children: firstCategory.children || [],
+                nonGrain: firstCategory.id || firstCategory.nonGrain || null,
+            });
+            // 通知地图更新
+            eventBus.emit("chartList:updateMap", {
+                statType: firstCategory.id || firstCategory.nonGrain || null,
+            });
+        }
+    });
+};
+
+onMounted(() => {
+    fetchLandUseTypes();
+});
+
+// 切换展开/折叠
+const toggleExpand = (category) => {
+    category.expanded = !category.expanded;
+};
+
+// 处理父级勾选变化(单选逻辑)
+const handleCategoryChange = (category) => {
+    // 计算当前有多少个被选中的项(由于 v-model 已经更新了 category.checked,需要检查其他项)
+    const otherCheckedCount = legendData.value.filter((item) => item !== category && item.checked).length;
+    
+    // 如果用户尝试取消,且没有其他项被选中,阻止这个操作(确保至少有一个被选中)
+    if (!category.checked && otherCheckedCount === 0) {
+        // 阻止取消,保持选中状态
+        category.checked = true;
+        return;
+    }
+    
+    // 如果当前类别被选中,取消其他所有类别的选中状态
+    if (category.checked) {
+        legendData.value.forEach((item) => {
+            if (item !== category) {
+                item.checked = false;
+            }
+        });
+    }
+    
+    const nonGrainValue = category.id || category.nonGrain || null;
+    
+    emit("change", {
+        category: category.name,
+        checked: category.checked,
+        children: category.children,
+        nonGrain: nonGrainValue, // 传递 nonGrain
+    });
+    
+    // 通知地图更新,传递 statType 参数
+    if (category.checked) {
+        eventBus.emit("chartList:updateMap", {
+            statType: nonGrainValue,
+        });
+    }
+};
+
+</script>
+
+<style lang="scss" scoped>
+.land-use-legend {
+    position: fixed;
+    right: 420px;
+    top: 90px;
+    background: rgba(29, 29, 29, 0.86);
+    border: 1px solid rgba(255, 212, 137, 0.3);
+    border-radius: 8px;
+    padding: 16px;
+    min-width: 170px;
+    max-height: 80vh;
+    overflow-y: auto;
+    z-index: 10;
+    color: #fff;
+
+    .legend-category {
+        margin-bottom: 6px;
+
+        &:last-child {
+            margin-bottom: 0;
+        }
+    }
+
+    .category-header {
+        display: flex;
+        align-items: center;
+        cursor: pointer;
+
+        .category-checkbox {
+            margin-right: 8px;
+            ::v-deep {
+                .el-checkbox__inner {
+                    background-color: rgba(255, 212, 137, 0.3);
+                    border-color: rgba(255, 212, 137, 0.6);
+                    width: 16px;
+                    height: 16px;
+                }
+                .el-checkbox__input.is-checked .el-checkbox__inner {
+                    background-color: #f7be5a;
+                    border-color: #f7be5a;
+                    &::after {
+                        border-color: #000;
+                        border-width: 2px;
+                        left: 5px;
+                        top: 1px;
+                    }
+                }
+            }
+        }
+
+        .expand-icon {
+            margin-right: 8px;
+            display: inline-block;
+            transition: transform 0.3s;
+            color: rgba(255, 212, 137, 0.6);
+            font-size: 18px;
+            text-align: center;
+            line-height: 1;
+
+            &.expanded {
+                transform: rotate(90deg);
+            }
+        }
+
+        .category-name {
+            font-size: 14px;
+            color: rgba(255, 212, 137, 0.9);
+        }
+    }
+
+    .category-children {
+        margin-left: 47px;
+        padding-left: 0;
+
+        .child-item {
+            display: flex;
+            align-items: center;
+            padding: 5px 0;
+            font-size: 14px;
+            color: rgba(255, 255, 255, 0.8);
+
+            .color-dot {
+                width: 12px;
+                height: 12px;
+                margin-right: 6px;
+                border-radius: 2px;
+            }
+        }
+    }
+}
+
+// 滚动条样式
+.land-use-legend::-webkit-scrollbar {
+    width: 6px;
+}
+
+.land-use-legend::-webkit-scrollbar-track {
+    background: rgba(255, 255, 255, 0.1);
+    border-radius: 3px;
+}
+
+.land-use-legend::-webkit-scrollbar-thumb {
+    background: rgba(255, 212, 137, 0.3);
+    border-radius: 3px;
+
+    &:hover {
+        background: rgba(255, 212, 137, 0.5);
+    }
+}
+</style>
+

+ 30 - 16
src/views/warningHome/index.vue

@@ -28,7 +28,8 @@
                 ></chart-list>
             </div>
             <!-- 地图图例 -->
-            <map-legend></map-legend>
+            <!-- <map-legend></map-legend> -->
+            <land-use-legend @change="handleLegendChange"></land-use-legend>
             <!-- 地图搜索 -->
             <div class="warning-search yes-events">
                 <el-select
@@ -71,6 +72,7 @@ import StaticMapPointLayers from "@/components/static_map_change/pointLayer.js";
 import { onMounted, onUnmounted, ref, reactive, nextTick } from "vue";
 import fnHeader from "@/components/fnHeader.vue";
 import mapLegend from "./components/mapLegend.vue";
+import landUseLegend from "./components/landUseLegend.vue";
 import WarningMap from "./warningMap";
 import AlarmLayer from "./map/alarmLayer";
 import DistributionLayer from "./map/distributionLayer";
@@ -126,8 +128,8 @@ onMounted(async () => {
     staticMapPointLayers = new StaticMapPointLayers(warningMap.kmap);
     distributionLayer = new DistributionLayer(warningMap.kmap);
     await getSpeciesListData();
-    // 页面一进来,直接请求作物分布接口并渲染地块(不展示点位)
-    await initDefaultDistribution();
+
+    getDistributionData();
 
     // 数据加载完成后,再次更新地图尺寸以确保正确渲染
     if (warningMap.kmap && warningMap.kmap.map) {
@@ -143,7 +145,14 @@ onMounted(async () => {
         warningLayers.value = data;
     });
 
-    // 预警分布图层联动:仅在“预警分布”tab 显示时,才在地图上显示对应图层
+    // 监听图表组件的地图更新事件
+    eventBus.on("chartList:updateMap", async ({ statType }) => {
+        if (!distributionLayer) return;
+        // 使用 statType 参数请求地图数据
+        getDistributionData(statType);
+    });
+
+    // 预警分布图层联动:仅在"预警分布"tab 显示时,才在地图上显示对应图层
     eventBus.on("alarmList:changeMapLayer", ({ name, legendUrl }) => {
         // 47 行:只在 activeBaseTab === '预警分布' 时显示预警列表
         // 这里保持一致:只有在该 tab 下才显示地图图层,否则直接隐藏
@@ -247,6 +256,7 @@ sessionStorage.removeItem("farmId");
 
 onUnmounted(() => {
     eventBus.off("alarmList:changeMapLayer");
+    eventBus.off("chartList:updateMap");
     // 时间轴
     eventBus.off("weatherTime:changeTime");
 });
@@ -259,17 +269,8 @@ const getSpeciesListData = async () => {
     originalTreeData.value = JSON.parse(JSON.stringify(res.data));
 };
 
-// 页面初始化时,直接请求一次作物分布接口并渲染地块
-const initDefaultDistribution = async () => {
-    if (!distributionLayer) return;
-    // 不传物种 / 物候参数,由后端按默认规则返回全部或指定范围内的地块分布
-    const data = await getDistributionData();
-    // 只渲染地块面,不展示点位(在 getDistributionData 中已去掉 centerPoint)
-    distributionLayer.initData(data);
-};
-
-const getDistributionData = async () => {
-    const { data } = await VE_API.agri_land_crop.queryDistribution();
+const getDistributionData = async (statType = null) => {
+    const { data } = await VE_API.agri_land_crop.queryDistribution({ statType: statType || 0 });
     // 把点位图层去掉:不返回 centerPoint,只保留地块相关信息
     const list = Array.isArray(data)
         ? data.map((item) => {
@@ -277,7 +278,7 @@ const getDistributionData = async () => {
               return rest;
           })
         : [];
-    return list;
+    distributionLayer.initData(list);
 };
 const props1 = {
     checkStrictly: true,
@@ -588,6 +589,19 @@ const getTreeChecks = async (nodeData, data) => {
 
     distributionLayer.initData(finalMapData);
 };
+
+// 处理图例变化
+const handleLegendChange = (data) => {
+    console.log("图例变化:", data);
+    // 通过 eventBus 将选中的类别信息传递给饼图组件
+    if (data.checked) {
+        eventBus.emit("landUseLegend:change", {
+            category: data.category,
+            nonGrain: data.nonGrain,
+            children: data.children,
+        });
+    }
+};
 </script>
 
 <style lang="scss" scoped>