lxf пре 1 недеља
родитељ
комит
a22a353fb4

+ 9 - 0
src/api/modules/agri_land_crop.js

@@ -0,0 +1,9 @@
+import config from "../config"
+const url = config.one_map_url + "agri_land_crop/";
+
+export default {
+    queryDistribution: {
+        url: url + "query_distribution",
+        type: "post",
+    },
+}

+ 0 - 0
src/assets/images/map/type/水稻.png → src/assets/images/map/type/籼稻.png


+ 87 - 23
src/views/warningHome/index.vue

@@ -498,16 +498,16 @@ const activeBaseTab = ref("作物分布");
 const legendImg = ref("");
 const warningLayers = ref({});
 
-onMounted(() => {
+onMounted(async () => {
     warningMap.initMap(store.getters.userinfo.location, mapRef.value);
     alarmLayer = new AlarmLayer(warningMap.kmap);
     staticMapLayers = new StaticMapLayers(warningMap.kmap);
     staticMapPointLayers = new StaticMapPointLayers(warningMap.kmap);
     distributionLayer = new DistributionLayer(warningMap.kmap);
-    getSpeciesListData();
+    await getSpeciesListData();
     // 作物分布默认选中
-    handleDistributionTreeDefault()
-    handleDistributionLayer();
+    await handleDistributionTreeDefault()
+    await handleDistributionLayer();
 
     eventBus.emit("warningMap:init", warningMap.kmap);
 
@@ -559,12 +559,11 @@ onUnmounted(() => {
 });
 
 // 作物分布默认选中并展开第一个节点,在地图上显示对应分布图层
-const handleDistributionLayer = () => {
+const handleDistributionLayer = async () => {
     // 默认选中并展开第一个“果类”节点,在地图上显示对应分布图层
     const firstCategory = treeActionData.value[0];
     if (firstCategory) {
-        const defaultNodes = [firstCategory, ...(firstCategory.children || [])];
-        distributionLayer.initData(defaultNodes);
+        await getDistributionData(firstCategory.id);
     }
 };
 
@@ -578,11 +577,32 @@ const handleDistributionTreeDefault = () => {
 };
 
 // 物候期分布默认选中并展开第一个节点,在地图上显示对应分布图层
-const handlePhenologyLayer = () => {
+const handlePhenologyLayer = async () => {
     const firstCategory = treeActionData.value[0].children[0];
     if (firstCategory) {
-        const defaultNodes = [firstCategory, ...(firstCategory.children[0]?.children || [])];
-        distributionLayer.initData(defaultNodes);
+        // 递归查找最后一层的节点(没有子节点的叶子节点)
+        const getLastLevelNodes = (node) => {
+            const lastLevelNodes = [];
+            if ((!node.items || node.items.length === 0) && (!node.children || node.children.length === 0)) {
+                lastLevelNodes.push(node);
+            } else {
+                const children = node.items || node.children || [];
+                children.forEach((child) => {
+                    lastLevelNodes.push(...getLastLevelNodes(child));
+                });
+            }
+            return lastLevelNodes;
+        };
+        
+        const lastLevelNodes = getLastLevelNodes(firstCategory);
+        const lastLevelIds = lastLevelNodes.map((n) => n.id);
+        
+        // 并发请求所有数据
+        const promises = lastLevelIds.map((id) => getDistributionData(id));
+        const results = await Promise.all(promises);
+        const finalMapData = results.flat();
+        
+        distributionLayer.initData(finalMapData);
     }
 };
 
@@ -596,12 +616,32 @@ const handlePhenologyTreeDefault = () => {
 };
 
 // 预警分布默认选中并展开第一个节点,在地图上显示对应分布图层
-const handleAlarmLayer = () => {
+const handleAlarmLayer = async () => {
     const firstCategory = treeActionData.value[0].children[0];
-    console.log('firstCategory', firstCategory);
     if (firstCategory) {
-        const defaultNodes = [firstCategory];
-        distributionLayer.initData(defaultNodes);
+        // 递归查找最后一层的节点(没有子节点的叶子节点)
+        const getLastLevelNodes = (node) => {
+            const lastLevelNodes = [];
+            if ((!node.items || node.items.length === 0) && (!node.children || node.children.length === 0)) {
+                lastLevelNodes.push(node);
+            } else {
+                const children = node.items || node.children || [];
+                children.forEach((child) => {
+                    lastLevelNodes.push(...getLastLevelNodes(child));
+                });
+            }
+            return lastLevelNodes;
+        };
+        
+        const lastLevelNodes = getLastLevelNodes(firstCategory);
+        const lastLevelIds = lastLevelNodes.map((n) => n.id);
+        
+        // 并发请求所有数据
+        const promises = lastLevelIds.map((id) => getDistributionData(id));
+        const results = await Promise.all(promises);
+        const finalMapData = results.flat();
+        
+        distributionLayer.initData(finalMapData);
     }
 };
 
@@ -610,7 +650,6 @@ const handleAlarmTreeDefault = () => {
     defaultCheckedKeys.value = [
         treeActionData.value[0]?.children[0]?.id
     ];
-    console.log('defaultCheckedKeys', defaultCheckedKeys.value);
     defaultExpandedKeys.value = [treeActionData.value[0]?.id];
 };
 
@@ -740,12 +779,19 @@ const handleTabClick = (item) => {
     }
 };
 
-const getSpeciesListData = () => {
-    VE_API.species.speciesList().then((res) => {
-        treeActionData.value = res.data;
-    });
+const getSpeciesListData = async () => {
+    const res = await VE_API.species.speciesList();
+    treeActionData.value = res.data;
 };
 
+const getDistributionData = async (speciesId) => {
+    const {data} = await VE_API.agri_land_crop.queryDistribution({
+        year: 2025,
+        quarter: 1,
+        speciesId
+    });
+    return data;
+};
 const props1 = {
     checkStrictly: true,
 };
@@ -833,11 +879,11 @@ const getNodeLevelInfo = (id) => {
     return { level: 0, secondId: null };
 };
 
-const getTreeChecks = (nodeData, data) => {
+const getTreeChecks = async (nodeData, data) => {
     const { checkedNodes } = data;
     let finalCheckedNodes = checkedNodes;
 
-    // 物候期分布:限制“二级只能选一个,三级不限个数”
+    // 物候期分布:限制"二级只能选一个,三级不限个数"
     if ((activeBaseTab.value === "物候期分布" || activeBaseTab.value === "预警分布") && treeRef.value) {
         const tree = treeRef.value;
         const { level, secondId } = getNodeLevelInfo(nodeData.id);
@@ -868,7 +914,7 @@ const getTreeChecks = (nodeData, data) => {
                     });
                 });
             } else {
-                // 当前二级分支已经被全部取消勾选 → 清空激活记录,允许“全部不选”
+                // 当前二级分支已经被全部取消勾选 → 清空激活记录,允许"全部不选"
                 activePhenologySecondId.value = null;
             }
         }
@@ -879,7 +925,25 @@ const getTreeChecks = (nodeData, data) => {
     }
 
     // 任意 tab 下,最终都用当前选中的节点驱动地图渲染
-    distributionLayer.initData(finalCheckedNodes);
+    // 提取最后一级节点的 id 到数组(没有子节点的叶子节点)
+    const lastLevelIds = finalCheckedNodes
+        .filter((n) => (!n.items || n.items.length === 0) && (!n.children || n.children.length === 0))
+        .map((n) => n.id);
+    
+    // 并发请求所有数据,等待所有 Promise 完成
+    const promises = lastLevelIds.map((id) => {
+        const node = finalCheckedNodes.find((n) => n.id === id);
+        if (node) {
+            return getDistributionData(node.id);
+        }
+        return Promise.resolve([]);
+    });
+    
+    // 等待所有请求完成,并将结果扁平化
+    const results = await Promise.all(promises);
+    const finalMapData = results.flat();
+    
+    distributionLayer.initData(finalMapData);
 };
 </script>
 

+ 98 - 119
src/views/warningHome/map/distributionLayer.js

@@ -4,6 +4,7 @@ import { Feature } from "ol";
 import { WKT } from "ol/format";
 import { Circle, Fill, Stroke, Style, Text, Icon, RegularShape } from "ol/style.js";
 import Photo from "ol-ext/style/Photo";
+import { newPoint, newPolymerFeature } from "@/utils/map.js";
 
 import pointBgImg from "@/assets/images/map/point_bg.png";
 
@@ -24,11 +25,11 @@ class DistributionLayer {
         this.distributionPointLayer = new KMap.VectorLayer("distributionPointLayer", 99, {
             source: new VectorSource({}),
             style: function (f) {
-                const label = f.get("label") || "";
+                const label = f.get("speciesName") || "";
                 const baseColor = f.get("color") || "#2199F8";
                 const farmName = f.get("farmName") || "";
-                const imgUrl = f.get("imgUrl") || "";
                 const imgName = f.get("imgName") || "";
+                const speciesIcon = f.get("speciesIcon");
 
                 // 方块填充色背景(在白色描边 PNG 底图下方,参考 UI)
                 const squareBgStyle = new Style({
@@ -39,6 +40,7 @@ class DistributionLayer {
                         fill: new Fill({
                             color: baseColor,
                         }),
+                        imgSize: [34, 34],
                         // 向上平移一点,让方块主要位于指针上方
                         displacement: [0, 4],
                     }),
@@ -72,40 +74,33 @@ class DistributionLayer {
                 // 农场名称(显示在点位下方,白色文字)
                 const farmNameStyle = farmName
                     ? new Style({
-                          text: new Text({
-                              text: farmName,
-                              font: "normal 19px sans-serif",
-                              offsetY: 45, // 向下偏移,位于点位下方
-                              textAlign: "center",
-                              fill: new Fill({
-                                  color: "#FFFFFF",
-                              }),
-                              stroke: new Stroke({
-                                  color: "rgba(0,0,0,0.6)",
-                                  width: 2,
-                              }),
-                          }),
-                      })
+                        text: new Text({
+                            text: farmName,
+                            font: "normal 19px sans-serif",
+                            offsetY: 45, // 向下偏移,位于点位下方
+                            textAlign: "center",
+                            fill: new Fill({
+                                color: "#FFFFFF",
+                            }),
+                            stroke: new Stroke({
+                                color: "rgba(0,0,0,0.6)",
+                                width: 2,
+                            }),
+                        }),
+                    })
                     : null;
                 const typeImgStyle = new Style({
-                    // image: new Photo({
-                    //     // src: imgUrl,
-                    //     src: imgName,
-                    //     radius: 23,
-                    //     shadow: 0,
-                    //     crop: false,
-                    //     displacement: [0, 4],
-                    // }),
                     image: new Icon({
                         // src: imgUrl,
-                        src: imgName,
+                        src: speciesIcon,
                         scale: 0.8,
                         displacement: [0, 4],
                     }),
                 });
 
                 // 先画纯色方块,再画白色描边 PNG 和文字,最后画农场名称
-                const styles = [squareBgStyle, iconAndTextStyle, typeImgStyle];
+                const styles = [squareBgStyle, iconAndTextStyle];
+                if (speciesIcon) styles.push(typeImgStyle);
                 if (farmNameStyle) styles.push(farmNameStyle);
                 return styles;
             },
@@ -120,113 +115,97 @@ class DistributionLayer {
                 return new Style({
                     image: new Icon({
                         src: imgName,
+                        imgSize: [45, 45],
+                        width: 45,
+                        height: 45,
                         scale: 0.9,
                     }),
                 });
             },
         });
         this.kmap.addLayer(this.facilityPointLayer.layer)
-  }
-
-  /**
-   * 清空当前图层上的所有数据
-   */
-  clear() {
-    if (this.distributionLayer && this.distributionLayer.source) {
-      this.distributionLayer.source.clear();
-    }
-    if (this.distributionPointLayer && this.distributionPointLayer.source) {
-      this.distributionPointLayer.source.clear();
     }
-    if (this.facilityPointLayer && this.facilityPointLayer.source) {
-      this.facilityPointLayer.source.clear();
-    }
-  }
-
-  initData(data) {
-    // 每次加载前先清空旧数据(多用于“作物分布 / 物候期分布 / 农场分布”)
-    this.clear();
-
-    const addPointFeaturesFromNode = (node) => {
-      // 如果当前节点本身有 wktArr,则直接用当前节点的数据画点
-      if (node.wktArr) {
-        for (let wkt of node.wktArr) {
-          const f = new Feature({
-            geometry: new WKT().readGeometry(wkt),
-          });
-          f.set("imgName", node.imgName);
-          f.set("label", node.label);
-          f.set("color", node.color);
-          if (node.farmName) {
-            f.set("farmName", node.farmName);
-          }
-          this.distributionPointLayer.source.addFeature(f);
-        }
-      }
 
-      // 否则如果有 children,就在 children 这一层继续找
-      if (node.children) {
-        for (let child of node.children) {
-          addPointFeaturesFromNode(child);
+    /**
+     * 清空当前图层上的所有数据
+     */
+    clear() {
+        if (this.distributionLayer && this.distributionLayer.source) {
+            this.distributionLayer.source.clear();
+        }
+        if (this.distributionPointLayer && this.distributionPointLayer.source) {
+            this.distributionPointLayer.source.clear();
+        }
+        if (this.facilityPointLayer && this.facilityPointLayer.source) {
+            this.facilityPointLayer.source.clear();
         }
-      }
-    };
-
-    for (let item of data) {
-      // 面数据(区域多边形)
-    //   if (item.geom) {
-    //     const f = new Feature({
-    //       geometry: new WKT().readGeometry(item.geom),
-    //     });
-    //     f.set("color", item.color);
-    //     f.set("fillColor", item.fillColor);
-    //     this.distributionLayer.source.addFeature(f);
-    //   }
-
-      // 点数据:根据是否有 children / wktArr 递归查找
-      addPointFeaturesFromNode(item);
     }
 
-    // 所有点位添加完成后,地图范围自适应到包含 distributionPointLayer 的所有点
-    const pointExtent = this.distributionPointLayer.source.getExtent();
-    if (pointExtent && !isNaN(pointExtent[0])) {
-      this.kmap.map.getView().fit(pointExtent, {
-        padding: [280, 400, 200, 150],
-        duration: 500,
-      });
-    }
-  }
-
-  /**
-   * 设施数据加载(冷链冷库 / 加工厂)
-   * 只操作 facilityPointLayer,不影响作物分布图层
-   */
-  initFacilityData(list = []) {
-    if (!this.facilityPointLayer || !this.facilityPointLayer.source) return;
-    this.facilityPointLayer.source.clear();
-
-    const extentSource = new VectorSource({});
-
-    for (let item of list) {
-      if (!item.wktArr) continue;
-      for (let wkt of item.wktArr) {
-        const f = new Feature({
-          geometry: new WKT().readGeometry(wkt),
-        });
-        f.set("imgName", item.imgName);
-        this.facilityPointLayer.source.addFeature(f);
-        extentSource.addFeature(f);
-      }
+    initData(data) {
+        // 每次加载前先清空旧数据(多用于“作物分布 / 物候期分布 / 农场分布”)
+        this.clear();
+
+        for (let item of data) {
+            // 面数据(区域多边形)
+            // if (item.geom) {
+            //     item.color = item.color || "#2199F8";
+            //     item.fillColor = item.fillColor || "rgba(0, 69, 4, 0.5)";
+            //     this.distributionLayer.source.addFeature(newPolymerFeature(item));
+            // }
+            if (item.centerPoint) {
+                item.color = item.color || "#2199F8";
+                item.wkt = item.centerPoint;
+                this.distributionPointLayer.source.addFeature(newPoint(item));
+            }
+        }
+        // const extent = this.distributionLayer.source.getExtent();
+        // if (extent && !isNaN(extent[0])) {
+        //     this.kmap.map.getView().fit(extent, {
+        //         padding: [280, 400, 200, 150],
+        //         duration: 500,
+        //     });
+        // }
+
+        // 所有点位添加完成后,地图范围自适应到包含 distributionPointLayer 的所有点
+        const pointExtent = this.distributionPointLayer.source.getExtent();
+        if (pointExtent && !isNaN(pointExtent[0])) {
+            this.kmap.map.getView().fit(pointExtent, {
+                padding: [280, 400, 200, 150],
+                duration: 500,
+            });
+        }
     }
 
-    const extent = extentSource.getExtent();
-    if (extent && !isNaN(extent[0])) {
-      this.kmap.map.getView().fit(extent, {
-        padding: [280, 400, 200, 150],
-        duration: 500,
-      });
+    /**
+     * 设施数据加载(冷链冷库 / 加工厂)
+     * 只操作 facilityPointLayer,不影响作物分布图层
+     */
+    initFacilityData(list = []) {
+        if (!this.facilityPointLayer || !this.facilityPointLayer.source) return;
+        this.facilityPointLayer.source.clear();
+
+        const extentSource = new VectorSource({});
+
+        for (let item of list) {
+            if (!item.wktArr) continue;
+            for (let wkt of item.wktArr) {
+                const f = new Feature({
+                    geometry: new WKT().readGeometry(wkt),
+                });
+                f.set("imgName", item.imgName);
+                this.facilityPointLayer.source.addFeature(f);
+                extentSource.addFeature(f);
+            }
+        }
+
+        const extent = extentSource.getExtent();
+        if (extent && !isNaN(extent[0])) {
+            this.kmap.map.getView().fit(extent, {
+                padding: [280, 400, 200, 150],
+                duration: 500,
+            });
+        }
     }
-  }
 }
 
 

+ 2 - 2
src/views/warningHome/warningMap.js

@@ -19,8 +19,8 @@ class HomeMap {
   initMap(location, target) {
     let level = 9;
     let coordinate = util.wktCastGeom(location).getFirstCoordinate();
-    this.kmap = new KMap.Map(target, level, coordinate[0], coordinate[1], null, 9, 22);
-    this.addMapListen()
+    this.kmap = new KMap.Map(target, level, coordinate[0], coordinate[1], null, 7, 22);
+    // this.addMapListen()
     // 添加比例尺控件
     const scaleLine = new ScaleLine({
       units: 'metric' // 可以选择 'imperial' 或 'metric'