Pārlūkot izejas kodu

fix: 查看区域弹窗

lxf 1 nedēļu atpakaļ
vecāks
revīzija
9f9ccc30e3

+ 141 - 0
src/views/old_mini/work_detail/components/areaMap.js

@@ -0,0 +1,141 @@
+import * as KMap from "@/utils/ol-map/KMap";
+import * as util from "@/common/ol_common.js";
+import config from "@/api/config.js";
+import { Vector as VectorSource } from "ol/source.js";
+import { Point } from 'ol/geom';
+import { newPoint, newAreaFeature } from "@/utils/map";
+import { GeoJSON, WKT } from 'ol/format'
+import { Feature } from "ol";
+import { getArea } from "ol/sphere"
+import * as turf from "@turf/turf"
+import Style from "ol/style/Style";
+import Icon from "ol/style/Icon";
+import { Fill, Text, Stroke } from "ol/style";
+import * as proj from "ol/proj";
+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);
+
+/**
+ *
+ */
+class AreaMap {
+    constructor() {
+        let that = this;
+        let vectorStyle = new KMap.VectorStyle()
+        this.gardenPolygonLayer = new KMap.VectorLayer("gardenPolygonLayer", 999, {
+            minZoom: 11,
+            maxZoom: 22,
+            source: new VectorSource({}),
+            style: function (f) {
+                let style2 = vectorStyle.getPolygonStyle("#00000080", "#2199F8", 2)
+
+                let style3 = new Style({
+                    text: new Text({
+                        font: "14px sans-serif",
+                        text: f.get("mianji") + "亩",
+                        // offsetX: 28,
+                        offsetY: 10,
+                        fill: new Fill({ color: "#fff" }), // 字体颜色
+                    }),
+                });
+                return [style2]
+            }
+        });
+
+        // 位置图标
+        this.clickPointLayer = new KMap.VectorLayer("clickPointLayer", 9999, {
+            style: (f) => {
+                let pointIcon = new Style({
+                    image: new Icon({
+                        src: require("@/assets/img/home/garden-point.png"),
+                        scale: 0.5,
+                        anchor: [0.5, 1],
+                    }),
+                });
+                let nameText = new Style({
+                    text: new Text({
+                        font: "14px sans-serif",
+                        text: f.get("name"),
+                        offsetY: 10,
+                        fill: new Fill({ color: "#fff" }), // 字体颜色
+                        stroke: new Stroke({
+                            color: "#000",
+                            width: 0.5,
+                        }),
+                    }),
+                });
+                return [pointIcon, nameText]
+            },
+        });
+    }
+
+
+    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.gardenPolygonLayer.layer);
+        this.kmap.addLayer(this.clickPointLayer.layer);
+    }
+
+    initLayer(item) {
+        // this.gardenPolygonLayer.refresh()
+        if (this.gardenPolygonLayer.source) {
+            this.gardenPolygonLayer.source.clear()
+        }
+        if (item.pointWkt) {
+            let f = newPoint(item, "pointWkt")
+            f.set("name", item.name)
+            this.clickPointLayer.source.addFeature(f)
+        }
+        console.log('initLayer', item)
+        if (item.geomWkt) {
+            // let f = new Feature({
+            //     organId: item.organId, // 用于查找点击选中地块的编辑,有多个地块时用id筛选
+            //     geometry: new WKT().readGeometry(item.geomWkt)
+            // })
+            // let geometry = new WKT().readGeometry(item.geomWkt)
+            // geometry.transform(proj.get("EPSG:4326"), proj.get("EPSG:38572"))
+            let f = newAreaFeature(item, "geomWkt")
+            //   let area = getArea(geometry)
+            //   area = (area + area / 2) / 1000;
+            f.set("mianji", item.mianji)
+            this.gardenPolygonLayer.source.addFeature(f)
+        }
+        this.fitView()
+    }
+
+    /**
+   * 调整地图视图以适应地块范围
+   */
+    fitView() {
+        let extent = this.gardenPolygonLayer.source.getExtent()
+        if (extent) {
+            // 地图自适应到区域可视范围
+            this.kmap.getView().fit(extent, { duration: 50, padding: [80, 80, 80, 80] });
+        }
+    }
+
+    fitByGardenId(gardenId, hasMapAnimate) {
+        this.gardenPolygonLayer.source.forEachFeature((f) => {
+            if (f.get("organId") == gardenId) {
+                const extent = f.getGeometry().getExtent()
+                this.kmap.getView().fit(extent, { padding: [160, 60, 340, 60], duration: hasMapAnimate ? 1500 : 0 });
+                const currentZoom = this.kmap.getView().getZoom();
+                if (currentZoom > 16) {
+                    // this.kmap.getView().setZoom(16);
+                    this.kmap.getView().animate({
+                        zoom: 16,
+                        duration: hasMapAnimate ? 1500 : 0 // 动画持续时间,单位为毫秒
+                    });
+                }
+            }
+        })
+    }
+}
+
+export default AreaMap;

+ 91 - 0
src/views/old_mini/work_detail/components/mapInfo.vue

@@ -0,0 +1,91 @@
+<template>
+    <div class="map-info">
+        <!-- <div class="popup-title" v-if="showTitle">执行区域</div> -->
+        <div class="map-box">
+            <div class="map" ref="mapContainer"></div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, nextTick, onMounted, watch } from "vue";
+import IndexMap from "@/views/old_mini/home/map/index.js";
+import AreaMap from "./areaMap.js";
+
+const props = defineProps({
+    farmId: {
+        type: [Number, String],
+        default: null,
+    },
+    showTitle: {
+        type: Boolean,
+        default: true,
+    },
+});
+
+const mapContainer = ref(null);
+const indexMap = new IndexMap();
+const areaMap = new AreaMap();
+
+// 加载农场地图信息
+const loadFarmMap = async () => {
+    // if (!props.farmId) return;
+
+    try {
+        const res = await VE_API.farm.getFarmDetail({ farmId: 98230 });
+        if (res.code !== 0 || !res.data) return;
+
+        const farmInfo = res.data;
+        const point = farmInfo.pointWkt;
+
+        nextTick(() => {
+            // 如果地图已经初始化,则更新中心点和地块;否则初始化地图
+            if (areaMap.kmap) {
+                areaMap.initLayer(farmInfo);
+            } else if (point && mapContainer.value) {
+                areaMap.initMap(point, mapContainer.value);
+                areaMap.initLayer(farmInfo);
+            }
+        });
+    } catch (e) {
+        // 忽略地图加载错误,避免影响主流程
+    }
+};
+
+onMounted(() => {
+    loadFarmMap();
+});
+
+// farmId 变化时重新加载地图
+watch(
+    () => props.farmId,
+    () => {
+        loadFarmMap();
+    }
+);
+</script>
+
+<style lang="scss" scoped>
+.map-info {
+    width: 100%;
+}
+    .popup-title {
+        text-align: center;
+        font-size: 24px;
+        font-family: "PangMenZhengDao";
+        padding-bottom: 12px;
+    }
+
+.map-box {
+    width: 100%;
+    height: 350px;
+    position: relative;
+
+    .map {
+        width: 100%;
+        height: 100%;
+        clip-path: inset(0px round 5px);
+        pointer-events: none;
+    }
+}
+</style>

+ 80 - 13
src/views/old_mini/work_detail/index.vue

@@ -8,7 +8,7 @@
                 <div class="status-l">
                     <div class="status-title">{{ handleTagType(detail?.flowStatus) }}</div>
                     <div class="status-sub" v-if="triggerDateText && detail?.flowStatus === 0">
-                        执行时间已经过去 {{ daysDiff }} 天了 
+                        执行时间已经过去 {{ daysDiff }} 天了
                     </div>
                     <div class="status-sub" v-if="detail?.flowStatus === 1">
                         距离执行时间还差 {{ daysDiff }} 天
@@ -50,11 +50,11 @@
                             </div>
                             <div class="form-item">
                                 <div class="item-name">执行区域</div>
-                                <div class="item-text light-text">
+                                <div class="item-text light-text area-text">
                                     桂味种植区域
+                                    <!-- <div class="area-btn" @click="handleViewArea">查看区域</div> -->
+                                    <div class="area-btn area-btn-right" @click="toDraw">建议勾选<el-icon><ArrowRight /></el-icon></div>
                                 </div>
-                                <div class="area-btn">建议勾选</div>
-                                <!-- <div class="area-btn">查看区域</div> -->
                             </div>
                             <div class="form-item">
                                 <div class="item-name">注意事项</div>
@@ -143,28 +143,36 @@
         </div>
         <ExecutePopup ref="executePopupRef" />
 
-        
-    <upload-tips v-model:show="showUploadTipsPopup" />
+
+
+        <upload-tips v-model:show="showUploadTipsPopup" />
     </div>
+    <!-- 执行区域地图弹窗 -->
+    <popup v-model:show="showMapPopup" closeable class="map-popup">
+        <map-info :farmId="detail.farmId" />
+    </popup>
 </template>
 
 <script setup>
 import wx from "weixin-js-sdk";
 import customHeader from "@/components/customHeader.vue";
-import { ref, computed, onActivated } from "vue";
+import { ref, computed, onMounted } from "vue";
 import { useRouter } from "vue-router";
 import { formatDate } from "@/common/commonFun";
 import ExecutePopup from "./components/executePopup.vue";
 import { base_img_url2 } from "@/api/config";
 import UploadTips from "@/components/popup/uploadTips.vue";
+import { Popup } from "vant";
+import MapInfo from "./components/mapInfo.vue";
 
-const showUploadTipsPopup = ref(true);
+const showUploadTipsPopup = ref(false);
 
 const router = useRouter();
 // const info = JSON.parse(localStorage.getItem("localUserInfo") || "{}");
 const info = { appType: 1 };
 
 const detail = ref({
+    farmId: 766,
     "consequenceText": "",
     "id": null,
     "reCheckText": "",
@@ -347,6 +355,20 @@ const detail = ref({
 });
 
 
+const maybeShowUploadTips = () => {
+    if (detail.value?.flowStatus !== 1) return;
+    const shown = sessionStorage.getItem('upload_tips');
+    if (shown === "1") return;
+
+    sessionStorage.setItem('upload_tips', "1");
+    showUploadTipsPopup.value = true;
+};
+
+onMounted(() => {
+    maybeShowUploadTips();
+});
+
+
 // 计算距离执行时间的天数差
 const daysDiff = computed(() => {
     if (!detail.value?.executeDate) {
@@ -398,10 +420,10 @@ const hasRemark = (prescription, stageIndex) => {
 };
 
 const handleTagType = (tagType) => {
-    if(tagType === 0) return "已过期";
-    if(tagType === 1) return "待认证";
-    if(tagType === 2) return "待触发";
-    if(tagType === 3) return "已完成";
+    if (tagType === 0) return "已过期";
+    if (tagType === 1) return "待认证";
+    if (tagType === 2) return "待触发";
+    if (tagType === 3) return "已完成";
     return "--"
 }
 
@@ -414,6 +436,16 @@ const handleExecute = () => {
 };
 
 
+const showMapPopup = ref(false);
+
+const handleViewArea = () => {
+    showMapPopup.value = true;
+}
+
+const toDraw = () => {
+    router.push("/draw_region");
+}
+
 const handleBack = () => {
     router.back();
 };
@@ -497,18 +529,22 @@ const changeExecutionMethod = (stageIndex, value) => {
             background: #FF4F4F;
         }
     }
+
     &.status-1 {
         &::after {
             background: #FF953D;
         }
     }
+
     &.status-2 {
         &::after {
             background: #C7C7C7;
         }
     }
+
     &.status-3 {
         padding-top: 30px;
+
         &::after {
             background: #2199F8;
         }
@@ -534,6 +570,7 @@ const changeExecutionMethod = (stageIndex, value) => {
 }
 
 .box-wrap {
+
     // background: #ffffff;
     // border-radius: 8px;
     // padding: 14px 10px 10px 10px;
@@ -544,15 +581,17 @@ const changeExecutionMethod = (stageIndex, value) => {
         padding: 14px 10px 10px 10px;
         box-shadow: 0 2px 8px rgba(15, 35, 52, 0.06);
     }
+
     .photo-box {
         margin-top: 10px;
         padding: 11px 10px;
         font-size: 14px;
-    
+
         .photo-title {
             color: #000;
             padding-bottom: 9px;
         }
+
         .photo-sub-title {
             padding-bottom: 9px;
             color: #767676;
@@ -644,6 +683,19 @@ const changeExecutionMethod = (stageIndex, value) => {
     color: #767676;
     margin-top: 4px;
 
+    .area-btn {
+        border: 1px solid rgba(0, 0, 0, 0.1);
+        padding: 0 10px;
+        color: #767676;
+    }
+
+    .area-btn-right {
+        padding-right: 4px;
+        display: inline-flex;
+        align-items: center;
+        gap: 4px;
+    }
+
     .item-name {
         padding-right: 26px;
         color: rgba(0, 0, 0, 0.2);
@@ -657,6 +709,11 @@ const changeExecutionMethod = (stageIndex, value) => {
             color: #2199F8;
         }
     }
+    .area-text {
+        display: inline-flex;
+        align-items: center;
+        gap: 10px;
+    }
 }
 
 .light-text {
@@ -817,9 +874,11 @@ const changeExecutionMethod = (stageIndex, value) => {
     display: flex;
     // justify-content: center;
     justify-content: space-between;
+
     &.center-btn {
         justify-content: center;
     }
+
     position: fixed;
     bottom: 0px;
     left: 0;
@@ -841,4 +900,12 @@ const changeExecutionMethod = (stageIndex, value) => {
         font-size: 14px;
     }
 }
+
+.map-popup {
+    width: 92%;
+    // max-width: 420px;
+    border-radius: 8px;
+    padding: 12px;
+    box-sizing: border-box;
+}
 </style>