Explorar o código

fix: 校准物候期

lxf hai 1 día
pai
achega
f39c807d07

+ 2 - 2
src/views/old_mini/create_farm/index.vue

@@ -33,9 +33,9 @@
                                         <div class="position-wrap">
                                             <el-input placeholder="农场位置" readonly v-model="ruleForm.address"
                                                 autocomplete="off" />
-                                            <!-- <div class="draw-btn" @click="toSubPage">
+                                            <div class="draw-btn" @click="toSubPage">
                                                 {{ hasDefaultPolygon ? "点击勾选地块" : "新增地块" }}
-                                            </div> -->
+                                            </div>
                                         </div>
                                     </el-form-item>
                                     <el-form-item label="种植作物" prop="speciesItem">

+ 280 - 0
src/views/old_mini/create_farm/map/editMap copy.js

@@ -0,0 +1,280 @@
+import * as KMap from "@/utils/ol-map/KMap";
+import * as util from "@/common/ol_common.js";
+import config from "@/api/config.js";
+import Style from "ol/style/Style";
+import Icon from "ol/style/Icon";
+import Fill from "ol/style/Fill";
+import Stroke from "ol/style/Stroke";
+import { Point } from 'ol/geom';
+import Feature from "ol/Feature";
+import * as proj from "ol/proj";
+import { getArea } from 'ol/sphere.js';
+import WKT from "ol/format/WKT.js";
+import GeoJSON from "ol/format/GeoJSON.js";
+import * as turf from "@turf/turf";
+import proj4 from "proj4"
+import { register } from "ol/proj/proj4";
+proj4.defs("EPSG:38572","+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs");
+register(proj4);
+
+/**
+ * @description 地图层对象
+ */
+class EditMap {
+  constructor() {
+    let that = this;
+    let vectorStyle = new KMap.VectorStyle();
+    this.vectorStyle = vectorStyle;
+
+    // 位置图标
+    this.clickPointLayer = new KMap.VectorLayer("clickPointLayer", 9999, {
+      style: (f) => {
+        return new Style({
+          image: new Icon({
+            src: require("@/assets/img/home/garden-point.png"),
+            scale: 0.5,
+            anchor: [0.5, 1],
+          }),
+        });
+      },
+    });
+
+    // 小网格图层(约 1 亩参考网格)
+    this.gridLayer = new KMap.VectorLayer("gridLayer", 900, {
+      style: (feature) => {
+        const selected = !!feature.get("selected");
+        return new Style({
+          fill: new Fill({
+            color: selected ? "rgba(255, 64, 64, 0.45)" : "rgba(255, 255, 255, 0.08)",
+          }),
+          stroke: new Stroke({
+            color: selected ? "rgba(255, 64, 64, 0.95)" : "rgba(255, 255, 255, 0.4)",
+            width: selected ? 1.8 : 1,
+          }),
+        });
+      },
+    });
+    this.selectedGridIds = new Set();
+    this.gridClickHandlerBound = false;
+    // 1 亩约 666.67m²,正方形边长约 25.82m
+    this.gridSideKm = 0.02582;
+  }
+
+  initMap(location, target) {
+    let level = 16;
+    let coordinate = util.wktCastGeom(location).getFirstCoordinate();
+    this.kmap = new KMap.Map(target, level, coordinate[0], coordinate[1], null, 8, 22);
+    let xyz2 = config.base_img_url3 + "map/lby/{z}/{x}/{y}.png";
+    this.kmap.addXYZLayer(xyz2, { minZoom: 8, maxZoom: 22 }, 2);
+    this.kmap.addLayer(this.clickPointLayer.layer);
+    this.kmap.addLayer(this.gridLayer.layer);
+    this.setMapPoint(coordinate)
+
+    this.kmap.initDraw((e) => {
+      this.rebuildGridFromPolygon();
+    })
+    
+    // 监听drawstart事件,在开始绘制前检查是否已有地块
+    this.kmap.draw.on('drawstart', (e) => {
+      const features = this.kmap.getLayerFeatures();
+      if (features && features.length >= 1) {
+        // 提示用户先删除当前地块
+        this.onDrawLimit && this.onDrawLimit();
+        // 取消本次绘制
+        this.kmap.draw.abortDrawing();
+      }
+    });
+    
+    this.kmap.startDraw()
+    this.kmap.modifyDraw(() => {
+      this.rebuildGridFromPolygon();
+    })
+    this.bindGridClick();
+  }
+
+  setAreaGeometry(geometryArr, needFitView = false) {
+    let that = this
+    geometryArr.map(item => {
+      // 不使用 setLayerWkt,而是手动添加要素,避免自动缩放视图
+      const format = new WKT()
+      const mapProjection = that.kmap.map.getView().getProjection()
+      let geometry = format.readGeometry(item, {
+        dataProjection: 'EPSG:4326',
+        featureProjection: mapProjection
+      })
+      let f = new Feature({ geometry: geometry })
+      that.kmap.polygonLayer.source.addFeature(f)
+    })
+    this.rebuildGridFromPolygon();
+    // 根据参数决定是否需要自适应地块范围
+    if (needFitView) {
+      this.fitView()
+    }
+  }
+
+
+  fitView(){
+    let extent = this.kmap.polygonLayer.source.getExtent()
+    // 地图自适应到区域可视范围
+    this.kmap.getView().fit(extent, { duration: 500, padding: [100, 100, 100, 100] });
+  }
+
+  clearLayer(){
+    // this.kmap.removeLayer(this.clickPointLayer.layer)
+    this.kmap.polygonLayer.source.clear();
+    this.gridLayer.source.clear();
+    this.selectedGridIds.clear();
+  }
+
+  getAreaGeometry() {
+    const features = this.kmap.getLayerFeatures()
+    let geometryArr = []
+    let area = 0
+    const format = new WKT()
+    // 获取图层上的Polygon,转成WKT用于回显
+    features.forEach(item => {
+      // 使用 writeGeometry 而不是 writeFeature,因为 setLayerWkt 期望的是几何体的 WKT
+      const geometry = item.getGeometry()
+      geometryArr.push(format.writeGeometry(geometry, {
+        dataProjection: 'EPSG:4326',
+        featureProjection: this.kmap.map.getView().getProjection()
+      }))
+      let geom = geometry.clone()
+      geom.transform(proj.get("EPSG:4326"), proj.get("EPSG:38572"))
+      let areaItem = getArea(geom)
+      areaItem = (areaItem + areaItem / 2) / 1000;
+      area += areaItem
+    })
+    return {geometryArr, mianji: area.toFixed(2)}  // 修改为 mianji 字段,与创建页面保持一致
+  }
+
+  setMapPosition(center) {
+    this.kmap.getView().animate({
+      center,
+      zoom: 17,
+      duration: 500,
+    });
+    this.setMapPoint(center)
+  }
+
+  setMapPoint(coordinate) {
+    this.clickPointLayer.source.clear()
+    let point = new Feature(new Point(coordinate))
+    this.clickPointLayer.addFeature(point)
+  }
+
+  // 删除当前地块
+  deleteCurrentPolygon() {
+    this.kmap.polygonLayer.source.clear();
+    this.gridLayer.source.clear();
+    this.selectedGridIds.clear();
+  }
+
+  // 设置绘制限制回调
+  setDrawLimitCallback(callback) {
+    this.onDrawLimit = callback;
+  }
+
+  bindGridClick() {
+    if (!this.kmap?.map || this.gridClickHandlerBound) return;
+    this.gridClickHandlerBound = true;
+    this.kmap.on("singleclick", (evt) => {
+      let hitFeature = null;
+      this.kmap.map.forEachFeatureAtPixel(evt.pixel, (feature, layer) => {
+        if (layer === this.gridLayer.layer) {
+          hitFeature = feature;
+          return feature;
+        }
+        return null;
+      });
+      if (!hitFeature) return;
+
+      const gridId = hitFeature.get("gridId");
+      const isSelected = !!hitFeature.get("selected");
+      hitFeature.set("selected", !isSelected);
+      if (isSelected) {
+        this.selectedGridIds.delete(gridId);
+      } else {
+        this.selectedGridIds.add(gridId);
+      }
+      hitFeature.changed();
+    });
+  }
+
+  rebuildGridFromPolygon() {
+    if (!this.kmap?.polygonLayer?.source || !this.gridLayer?.source) return;
+    const features = this.kmap.polygonLayer.source.getFeatures();
+    this.gridLayer.source.clear();
+    this.selectedGridIds.clear();
+    if (!features || !features.length) return;
+
+    const format = new WKT();
+    const geojsonFormat = new GeoJSON();
+    const polygonGeometries = [];
+    features.forEach((feature) => {
+      const geometry = feature.getGeometry();
+      if (!geometry) return;
+      const wkt = format.writeGeometry(geometry, {
+        dataProjection: "EPSG:4326",
+        featureProjection: this.kmap.map.getView().getProjection(),
+      });
+      const turfGeom = turf.wktToGeoJSON ? turf.wktToGeoJSON(wkt) : null;
+      if (turfGeom) {
+        polygonGeometries.push(turfGeom);
+        return;
+      }
+      // 回退:用 OL 读为 GeoJSON geometry
+      const json = geojsonFormat.writeGeometryObject(geometry, {
+        dataProjection: "EPSG:4326",
+        featureProjection: this.kmap.map.getView().getProjection(),
+      });
+      polygonGeometries.push(json);
+    });
+    if (!polygonGeometries.length) return;
+
+    const multiPolygonCoords = [];
+    polygonGeometries.forEach((geom) => {
+      if (!geom) return;
+      if (geom.type === "Polygon") {
+        multiPolygonCoords.push(geom.coordinates);
+      } else if (geom.type === "MultiPolygon") {
+        geom.coordinates.forEach((coords) => multiPolygonCoords.push(coords));
+      }
+    });
+    if (!multiPolygonCoords.length) return;
+
+    const farmPolygon = turf.multiPolygon(multiPolygonCoords);
+    const bbox = turf.bbox(farmPolygon);
+    const squareGrid = turf.squareGrid(bbox, this.gridSideKm, { units: "kilometers" });
+    if (!squareGrid?.features?.length) return;
+
+    squareGrid.features.forEach((gridFeature, index) => {
+      let clipped = null;
+      try {
+        clipped = turf.intersect(gridFeature, farmPolygon);
+      } catch (_) {
+        try {
+          // 兼容 turf 不同版本的 intersect 入参
+          clipped = turf.intersect(turf.featureCollection([gridFeature, farmPolygon]));
+        } catch (e) {
+          clipped = null;
+        }
+      }
+      if (!clipped) return;
+      const geometryObj = clipped.geometry;
+      if (!geometryObj) return;
+
+      const olGeometry = geojsonFormat.readGeometry(geometryObj, {
+        dataProjection: "EPSG:4326",
+        featureProjection: this.kmap.map.getView().getProjection(),
+      });
+      if (!olGeometry) return;
+      const cell = new Feature({ geometry: olGeometry });
+      cell.set("gridId", `grid-${index}`);
+      cell.set("selected", false);
+      this.gridLayer.source.addFeature(cell);
+    });
+  }
+}
+
+export default EditMap;

+ 11 - 1
src/views/old_mini/growth_report/adjustPopup.vue

@@ -36,7 +36,7 @@
 
 <script setup>
 import { ref } from 'vue';
-import { Popup } from "vant";
+import { Popup, showToast } from "vant";
 
 const show = ref(false);
 
@@ -49,6 +49,16 @@ const close = () => {
 }
 
 const handleConfirm = () => {
+    const hasPeriod = periodList.value.some((item) => item.selected);
+    const hasChild = childList.value.some((item) => item.selected);
+    if (!hasPeriod) {
+        showToast("请选择物候期");
+        return;
+    }
+    if (!hasChild) {
+        showToast("请选择生育期");
+        return;
+    }
     close();
 }
 

+ 6 - 6
src/views/old_mini/growth_report/index.vue

@@ -109,9 +109,7 @@
                     <div class="box-text">
                         <div class="box-bg">
                             <div class="types-info">
-                                当前 <span class="text-bold">桂味</span> 处于为 梢期-新梢萌动<span class="text-link" @click="handleAdjustPopup">(校准物候期)</span>,
-                                当前 <span class="text-bold">桂某某品种味</span> 处于为 梢期-新梢萌动<span class="text-link" @click="handleAdjustPopup">(校准物候期)</span>,
-                                当前 <span class="text-bold">某某品种</span> 处于为 梢期-新梢萌动<span class="text-link" @click="handleAdjustPopup">(校准物候期)</span>
+                                当前 <span class="text-bold">桂味、妃子笑</span> 处于为  新梢萌动<span class="text-link" @click="handleAdjustPopup">(校准物候期)</span>
                             </div>
                         </div>
                         <div class="warning-part">
@@ -356,9 +354,11 @@ const closeSwipeGuide = () => {
 const closeTabMask = () => {
     showTabMask.value = false;
     if (pendingSwipeGuide.value) {
-        showSwipeGuide.value = true;
-        pendingSwipeGuide.value = false;
-        localStorage.setItem(SWIPE_GUIDE_KEY, "1");
+        setTimeout(() => {
+            showSwipeGuide.value = true;
+            pendingSwipeGuide.value = false;
+            localStorage.setItem(SWIPE_GUIDE_KEY, "1");
+        }, 500);
     }
 };