Sfoglia il codice sorgente

Merge branch 'master' of http://www.sysuimars.cn:3000/feiniao/feiniao-pc-vue

wangsisi 4 mesi fa
parent
commit
1a00f633fd

BIN
src/assets/images/common/task-icon.png


BIN
src/assets/images/map/air-icon.png


BIN
src/assets/images/map/air-offline-icon.png


BIN
src/assets/images/map/arrow-icon.png


BIN
src/assets/images/map/arrow-offline-icon.png


BIN
src/assets/images/map/drone-icon.png


BIN
src/assets/images/map/drone-offline-icon.png


BIN
src/assets/images/map/text-bj.png


BIN
src/assets/images/map/text-offline-bj.png


+ 80 - 66
src/components/toolList.vue

@@ -1,89 +1,103 @@
 <template>
-  <div :class="['tool-list', 'tool-' + direction]">
-    <div :class="['tool-item',{'text':item.name==='home'},{active:index===active}]" v-for="(item,index) in list" :key="index" @click="handleActive(item,index)">{{item.title}}</div>
-  </div>
+    <div :class="['tool-list', 'tool-' + direction]">
+        <div
+            :class="['tool-item', { text: item.name === 'home' }, { active: index === active }]"
+            v-for="(item, index) in list"
+            :key="index"
+            @click="handleActive(item, index)"
+        >
+            {{ item.title }}
+        </div>
+    </div>
 </template>
 
 <script setup>
-import {ref} from 'vue'
+import { ref } from "vue";
 import eventBus from "@/api/eventBus";
-import {useRouter} from "vue-router";
+import { useRouter } from "vue-router";
 const router = useRouter();
 const props = defineProps({
-  direction: {
-    type: String,
-    defalut: "",
-  },
-  list: {
-    type: Array,
-    defalut: [],
-  },
+    direction: {
+        type: String,
+        defalut: "",
+    },
+    list: {
+        type: Array,
+        defalut: [],
+    },
 });
 
-const emit = defineEmits(['handleActive'])
+const emit = defineEmits(["handleActive"]);
+
+eventBus.on("tool:updateAct", (e) => {
+    active.value = e;
+});
+
+const active = ref(0);
+const handleActive = (value, index) => {
+    active.value = index;
+    emit("handleActive", value);
+};
 
-eventBus.on('tool:updateAct',(e)=>{
-  active.value = e
-})
 
-const active = ref(0)
-const handleActive = (value,index) =>{
-    active.value = index
-    emit('handleActive',value)
+function resetActive(i) {
+    active.value = i;
 }
+
+defineExpose({ resetActive });
 </script>
 
 <style lang="scss" scoped>
 .tool-list {
-  width: 54px;
-  height: 100%;
-  background: #232323;
-  border: 0.6px solid rgb(255, 255, 255, 0.4);
-  box-sizing: border-box;
-  border-radius: 4px;
-  display: flex;
-  flex-direction: column;
-  justify-content: space-evenly;
-  position: relative;
-  &.tool-left {
-    margin-right: 10px;
-    border-left: none;
-  }
-  &.tool-right {
-    margin-left: 10px;
-    border-right: none;
-  }
-  .tool-item {
-    font-size: 20px;
-    writing-mode: vertical-rl; /* 从右到左的竖排 */
-    text-orientation: upright; /* 保持文字直立,而不是旋转 */
-    white-space: nowrap; /* 防止文本换行 */
-    line-height: 54px;
-    letter-spacing: 6px;
-    color: #fff;
-    font-family: "PangMenZhengDao";
-    cursor: pointer;
+    width: 54px;
     height: 100%;
-    text-align: center;
-    &.tool-item:first-child{
-        border-radius: 4px 4px 0 0;
+    background: #232323;
+    border: 0.6px solid rgb(255, 255, 255, 0.4);
+    box-sizing: border-box;
+    border-radius: 4px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-evenly;
+    position: relative;
+    &.tool-left {
+        margin-right: 10px;
+        border-left: none;
     }
-    &.tool-item:last-child{
-        border-radius: 0 0 4px 4px;
+    &.tool-right {
+        margin-left: 10px;
+        border-right: none;
     }
-    &.text{
-        writing-mode:horizontal-tb;
-        height: 40px;
-        line-height: 40px;
-        letter-spacing: 1px;
-        width: 100%;
+    .tool-item {
+        font-size: 20px;
+        writing-mode: vertical-rl; /* 从右到左的竖排 */
+        text-orientation: upright; /* 保持文字直立,而不是旋转 */
+        white-space: nowrap; /* 防止文本换行 */
+        line-height: 54px;
+        letter-spacing: 6px;
+        color: #fff;
+        font-family: "PangMenZhengDao";
+        cursor: pointer;
+        height: 100%;
         text-align: center;
-        font-size: 16px;
-    }
-    &.active{
-        background: #101010;
-        color: #FFD489;
+        &.tool-item:first-child {
+            border-radius: 4px 4px 0 0;
+        }
+        &.tool-item:last-child {
+            border-radius: 0 0 4px 4px;
+        }
+        &.text {
+            writing-mode: horizontal-tb;
+            height: 40px;
+            line-height: 40px;
+            letter-spacing: 1px;
+            width: 100%;
+            text-align: center;
+            font-size: 16px;
+        }
+        &.active {
+            background: #101010;
+            color: #ffd489;
+        }
     }
-  }
 }
 </style>

+ 1 - 0
src/views/home/album/album_compoents/albumDrawBox.vue

@@ -89,6 +89,7 @@ async function drawWatermark(event) {
 }
 
 function drawWatermark2(img,weather) {
+  if (!img || !img.width) return
   const canvas = canvasRef.value;
   let scale = 3
   canvas.width = img.width * scale;

+ 4 - 4
src/views/home/album/index.vue

@@ -329,7 +329,7 @@ onMounted(() => {
 
     farmId.value = sessionStorage.getItem("farmId")
     // getFarmDetail(farmId.value);
-    // getFarmWorkList(farmId.value);
+    getFarmWorkList(farmId.value);
     // window.addEventListener("scroll", debouncedHandleScroll);
 
     window.addEventListener("scroll", debouncedHandleScroll);
@@ -697,14 +697,14 @@ function addNsRecord(){
                     margin-left: 90px;
                     width: 183px;
                     height: 32px;
-                    background: #fff;
+                    background: rgba(255, 255, 255, 0.28);
                     border-radius: 30px;
                     padding: 2px;
                     box-sizing: border-box;
-                    box-shadow: 0 2px 4px #ccc;
+                    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16);
                     .btn-box {
                         height: 100%;
-                        background: linear-gradient(0deg,#fce6c0 0%, #FF9500 31% , #FF9500 78%);
+                        background: linear-gradient(0deg,#ffeac8 0%, #FF9500 31% , #ff9501 78%);
                         border-radius: 30px;
                         display: flex;
                         align-items: center;

+ 17 - 0
src/views/home/components/rightComponents/recordList.vue

@@ -0,0 +1,17 @@
+<template>
+    <div class="list album-r">
+        <chart-box name="农事列表" arrow="arrow-left">
+            <album></album>
+        </chart-box>
+    </div>
+</template>
+
+<script setup>
+import chartBox from "@/components/chartBox.vue";
+import album from "../../album/index.vue";
+
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 208 - 0
src/views/home/components/rightComponents/rightAerial.vue

@@ -0,0 +1,208 @@
+<template>
+    <div class="list-wrap">
+        <div class="task-content">
+            <div
+                class="task-item"
+                :class="{ active: item.id === oldId }"
+                v-for="(item, index) in taskList"
+                :key="index"
+                @click="handleItem(item.id)"
+            >
+                <div class="item-title">
+                    <img src="@/assets/images/common/task-icon.png" alt="" />
+                    <span class="title-text">无人机编号{{ item.code }}</span>
+                    <span class="task-status" v-if="item.status">执行中</span>
+                    <span class="task-status offline" v-else>已离线</span>
+                </div>
+                <div class="item-content">
+                    <div class="item-img">
+                        <img :src="item.icon" alt="" />
+                    </div>
+                    <div class="item-info">
+                        <div class="info-item">
+                            执行时间:<span class="val-text">{{ item.executeDate }}</span>
+                        </div>
+                        <div class="info-item">
+                            飞巡河道:<span class="val-text">{{ item.region }}</span>
+                        </div>
+                        <div class="info-item">
+                            当前位置:<span class="val-text">{{ item.location }}</span>
+                        </div>
+                    </div>
+                </div>
+                <div class="edit-btn" @click.stop="editLine(item)" v-show="item.id === oldId">编辑</div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref } from "vue";
+
+const taskList = ref([]);
+
+const getList = () => {
+    // VE_API.image.droneList().then(res =>{
+    //     taskList.value = res.data || []
+    // })
+    taskList.value = [
+        {
+            id: 1,
+            code: "F001",
+            status: true,
+            geom: "POINT(110.352173 20.8225)",
+            icon: "https://birdseye-img.sysuimars.com/shuichan/image.png",
+            executeDate: "2025-05-16",
+            region: "湛江市雷州市东里镇",
+            location: "110.352173,20.8225",
+        },
+        {
+            id: 2,
+            code: "F002",
+            status: false,
+            geom: "POINT(110.595729 21.371418)",
+            icon: "https://birdseye-img.sysuimars.com/shuichan/image.png",
+            executeDate: "2025-05-14",
+            region: "河道2",
+            location: "110.595729 21.371418",
+        },
+        {
+            id: 3,
+            code: "F003",
+            status: false,
+            geom: "POINT(110.793233 21.407839)",
+            icon: "https://birdseye-img.sysuimars.com/shuichan/image.png",
+            executeDate: "2025-05-14",
+            region: "河道3",
+            location: "110.793233 21.407839",
+        },
+        {
+            id: 4,
+            code: "F004",
+            status: false,
+            geom: "POINT(110.615398 21.197396)",
+            icon: "https://birdseye-img.sysuimars.com/shuichan/image.png",
+            executeDate: "2025-05-13",
+            region: "河道4",
+            location: "110.615398 21.197396",
+        },
+        {
+            id: 5,
+            code: "F005",
+            status: false,
+            geom: "POINT(110.63254 21.399645)",
+            icon: "https://birdseye-img.sysuimars.com/shuichan/image.png",
+            executeDate: "2025-05-13",
+            region: "河道5",
+            location: "110.63254 21.615908",
+        },
+    ];
+};
+
+const emit = defineEmits(["airLineCallback", "startEditLine"]);
+const oldId = ref(null);
+const handleItem = (id) => {
+    if (id !== oldId.value) {
+        oldId.value = id;
+    } else {
+        oldId.value = null;
+    }
+    const filterArr = taskList.value.filter((item) => item.id === oldId.value);
+    emit("airLineCallback", filterArr[0] || {});
+};
+
+const isEdit = ref(false)
+function editLine() {
+    isEdit.value = true
+    emit("startEditLine")
+}
+
+onMounted(() => {
+    getList();
+});
+</script>
+
+<style lang="scss" scoped>
+.list-wrap {
+    width: calc(100% - 54px - 10px);
+    height: 100%;
+    padding: 2px 0 20px 8px;
+    box-sizing: border-box;
+    overflow: auto;
+    background: #101010;
+    border: 1px solid #444444;
+    border-radius: 8px 0 0 8px;
+
+    .task-item {
+        margin-top: 10px;
+        background: #232323;
+        border-radius: 8px;
+        padding: 12px 16px;
+        cursor: pointer;
+        border: 1px solid transparent;
+        &.active {
+            border: 1px solid #ffd887;
+        }
+        .item-title {
+            display: flex;
+            align-items: center;
+            padding-bottom: 10px;
+            border-bottom: 1px solid rgba(245, 245, 245, 0.1);
+            color: #fff;
+            font-size: 16px;
+            .title-text {
+                padding-left: 8px;
+            }
+            .task-status {
+                margin-left: 8px;
+                border: 0.5px solid #ffd489;
+                border-radius: 2px;
+                height: 20px;
+                line-height: 18px;
+                padding: 1px 6px;
+                box-sizing: border-box;
+                font-size: 12px;
+                color: #f7be5a;
+                &.offline {
+                    color: #727272;
+                    border-color: #727272;
+                }
+            }
+        }
+        .item-content {
+            padding: 12px 0;
+            display: flex;
+            align-items: center;
+            .item-img {
+                img {
+                    width: 68px;
+                    height: 68px;
+                    object-fit: cover;
+                    border-radius: 2px;
+                }
+            }
+            .item-info {
+                padding-left: 10px;
+                color: #6c6c6c;
+                font-size: 14px;
+                .val-text {
+                    color: #fff;
+                }
+                .info-item + .info-item {
+                    padding-top: 2px;
+                }
+            }
+        }
+        .edit-btn {
+            width: 100%;
+            height: 36px;
+            border-radius: 4px;
+            text-align: center;
+            line-height: 36px;
+            color: #1D1D1D;
+            font-size: 14px;
+            background: linear-gradient(180deg, #FFD887, #ED9E1E);
+        }
+    }
+}
+</style>

+ 187 - 129
src/views/home/index.vue

@@ -5,28 +5,39 @@
             <navigation style="margin-left: 50px" @handleTab="handleTab"></navigation>
             <div class="left yes-events" :class="{ 'collapsed-left': isLeftShrink }">
                 <div class="home-btn">
-                    <div class="btn" @click="changeLeftComponent(0)" :class="{active: activeBtn === 0}">实时感知</div>
-                    <div class="btn" @click="changeLeftComponent(1)" :class="{active: activeBtn === 1}">诊断识别</div>
+                    <div class="btn" @click="changeLeftComponent(0)" :class="{ active: activeBtn === 0 }">实时感知</div>
+                    <div class="btn" @click="changeLeftComponent(1)" :class="{ active: activeBtn === 1 }">诊断识别</div>
                 </div>
-                <tool-list direction="left" ref="leftTool" :list="leftToolList[activeBtn]" @handleActive="handleActiveLeft"></tool-list>
+                <tool-list
+                    direction="left"
+                    ref="leftTool"
+                    :list="leftToolList[activeBtn]"
+                    @handleActive="handleActiveLeft"
+                ></tool-list>
                 <component :is="components[currentComponent]" />
                 <!-- 箭头 -->
                 <div class="arrow" @click="handleShrink('left')">
-                    <el-icon class="icon" :class="{ 'arrow-left': isLeftShrink }" color="#141414"><DArrowLeft /></el-icon>
+                    <el-icon class="icon" :class="{ 'arrow-left': isLeftShrink }" color="#141414"
+                        ><DArrowLeft
+                    /></el-icon>
                 </div>
             </div>
             <div class="home-bottom">
-                <img class="img yes-events" @click="handlePage" src="@/assets/images/home/table-btn-sk.png" alt="">
+                <img class="img yes-events" @click="handlePage" src="@/assets/images/home/table-btn-sk.png" alt="" />
                 <!-- <div class="garden-file" :class="{ isShrink: isShrink }">
                     <home-file></home-file>
                 </div> -->
             </div>
             <div class="right yes-events" :class="{ 'collapsed-right': isRightShrink }">
                 <div class="home-btn">
-                    <div class="btn" @click="changeRightComponent(0)" :class="{active: activeRightBtn === 0}">精细农事</div>
-                    <div class="btn" @click="changeRightComponent(1)" :class="{active: activeRightBtn === 1}">人机执行</div>
+                    <div class="btn" @click="changeRightComponent(0)" :class="{ active: activeRightBtn === 0 }">
+                        精细农事
+                    </div>
+                    <div class="btn" @click="changeRightComponent(1)" :class="{ active: activeRightBtn === 1 }">
+                        人机执行
+                    </div>
                 </div>
-                <div class="list album-r">
+                <!-- <div class="list album-r">
                     <chart-box name="农事列表" arrow="arrow-left" :class="{ 'list-wrap': rightIndex === 0 }">
                         <template v-if="rightIndex === 0">
                             <album></album>
@@ -38,8 +49,15 @@
                             </div>
                         </template>
                     </chart-box>
-                </div>
-                <tool-list direction="right" ref="rightTool" :list="rightToolList[activeRightBtn]" @handleActive="handleActiveRight"></tool-list>
+                </div> -->
+
+                <component :is="components[currentRightComponent]" @airLineCallback="airLineCallback" @startEditLine="startEditLine" />
+                <tool-list
+                    direction="right"
+                    ref="rightTool"
+                    :list="rightToolList[activeRightBtn]"
+                    @handleActive="handleActiveRight"
+                ></tool-list>
                 <!-- 箭头 -->
                 <!-- <div class="arrow" @click="handleShrink('right')">
                     <el-icon class="icon" :class="{ 'arrow-right': isRightShrink }" color="#141414"><DArrowRight /></el-icon>
@@ -50,7 +68,7 @@
             <!-- <img class="legend yes-events" src="@/assets/images/home/legend-img.png" alt="" /> -->
             <div v-if="legendArr && legendArr.length" class="map-bg map-legend yes-events">
                 <div class="item" v-for="(legend, legendI) in legendArr" :key="legendI">
-                    <span class="legend-block" :style="{background: legend.color}"></span>
+                    <span class="legend-block" :style="{ background: legend.color }"></span>
                     {{ legend.name }}
                 </div>
             </div>
@@ -97,8 +115,7 @@
         </div>
         <div class="overview-file">
             <div class="box-title">总体档案</div>
-            <div class="base-data" id="file-overview">
-            </div>
+            <div class="base-data" id="file-overview"></div>
             <div class="list" id="file-text">
                 <div class="list-item" v-for="item in photoList" :key="item.key">
                     <div class="list-name">
@@ -129,10 +146,8 @@
                 </div>
             </div>
         </div>
-
     </div>
     <FarmFightTask class="farm-fight-task" :farmId="currentFarm.id"></FarmFightTask>
-
 </template>
 
 <script setup>
@@ -160,7 +175,7 @@ import AlbumCarousel from "./album_compoents/albumCarousel.vue";
 import compareDialog from "./album_compoents/compareDialog.vue";
 import album from "./album/index.vue";
 import PdfDialog from "../../components/PdfDialog";
-import StaticMapLayers from "@/components/static_map_change/Layers.js"
+import StaticMapLayers from "@/components/static_map_change/Layers.js";
 import FarmFightTask from "./components/farmFightTask";
 import leftFly from "./components/leftComponents/leftFly.vue";
 import leftWeather from "./components/leftComponents/leftWeather.vue";
@@ -168,29 +183,31 @@ import leftStation from "./components/leftComponents/leftStation.vue";
 import weatherPage from "./components/leftComponents/weatherPage.vue";
 import leftDiseases from "./components/leftComponents/leftDiseases.vue";
 import leftNutrition from "./components/leftComponents/leftNutrition.vue";
+import rightAerial from "./components/rightComponents/rightAerial.vue";
+import recordList from "./components/rightComponents/recordList.vue";
+import AirLineStringLayer from "./map/airLineStringLayer";
 
-const activeBtn = ref(0)
-const leftTool = ref(null)
+const activeBtn = ref(0);
+const leftTool = ref(null);
 function changeLeftComponent(i) {
-    activeBtn.value = i
-    handleActiveLeft(leftToolList[i][0])
+    activeBtn.value = i;
+    handleActiveLeft(leftToolList[i][0]);
     // if(i){
     //     isDisable.value = false
     // }else{
     //     isDisable.value = true
     // }
-    leftTool.value.resetActive(0)
+    leftTool.value.resetActive(0);
 }
 
-const rightTool = ref(null)
-const activeRightBtn = ref(0)
+const rightTool = ref(null);
+const activeRightBtn = ref(0);
 function changeRightComponent(i) {
-    activeRightBtn.value = i
-    handleActiveRight(rightToolList[i][0])
-    rightTool.value.resetActive(0)
+    activeRightBtn.value = i;
+    handleActiveRight(rightToolList[i][0]);
+    rightTool.value.resetActive(0);
 }
 
-
 let store = useStore();
 const components = {
     leftFly,
@@ -200,7 +217,9 @@ const components = {
     weatherPage,
     phenologyPage,
     leftDiseases,
-    leftNutrition
+    leftNutrition,
+    rightAerial,
+    recordList,
 };
 //当前农场
 const currentFarm = {
@@ -217,6 +236,7 @@ let staticMapLayers = null;
 let samplePointLayer = null;
 let regionLayer = null;
 let blueRegionLayer = null;
+let airLineStringLayer = null;
 const router = useRouter();
 const mapRef = ref();
 onMounted(() => {
@@ -224,22 +244,25 @@ onMounted(() => {
     // homeMap.initMap(store.getters.userinfo.location, mapRef.value);
     // regionLayer = new RegionLayer(homeMap.kmap.map, currentFarm, currentRegion)
     samplePointLayer = new SamplePointLayer(homeMap.kmap);
-    VE_API.warning.fetchWarningLayer({
-      k: "gspgjdfbt",
-      resultType: "json",
-    }).then(({data}) => {
-      staticMapLayers = new StaticMapLayers(homeMap.kmap, data)
-      eventBus.on("showGspgjdfbt",function(v){
-        if(v){
-          staticMapLayers.showSingle("聚类结果3", true)
-        }else{
-          staticMapLayers.hideAll()
-        }
-      })
-    })
+    VE_API.warning
+        .fetchWarningLayer({
+            k: "gspgjdfbt",
+            resultType: "json",
+        })
+        .then(({ data }) => {
+            staticMapLayers = new StaticMapLayers(homeMap.kmap, data);
+            eventBus.on("showGspgjdfbt", function (v) {
+                if (v) {
+                    staticMapLayers.showSingle("聚类结果3", true);
+                } else {
+                    staticMapLayers.hideAll();
+                }
+            });
+        });
     blueRegionLayer = new BlueRegionLayer(homeMap.kmap);
-    function changeStaticMapLayers(e){
-      // staticMapLayers.
+    airLineStringLayer = new AirLineStringLayer(homeMap.kmap);
+    function changeStaticMapLayers(e) {
+        // staticMapLayers.
     }
 
     getYellow();
@@ -250,28 +273,27 @@ onMounted(() => {
     //选项卡子项事件监听
     // eventBus.on("handleTabItem", handleTabItem);
     // 是否开启指标对比
-    eventBus.on("compareTree", handleCompare)
+    eventBus.on("compareTree", handleCompare);
     eventBus.on("clickToCompare:point", toggleCompare);
 });
 
 onUnmounted(() => {
     eventBus.off("area:id", areaId);
     // eventBus.off("handleTabItem", handleTabItem);
-    eventBus.off("compareTree", handleCompare)
+    eventBus.off("compareTree", handleCompare);
     eventBus.off("clickToCompare:point", toggleCompare);
 });
 
-
 function handleCompare(v) {
-    isShrink.value = v
+    isShrink.value = v;
     if (v === false) {
-        showCompareBtn.value = v
+        showCompareBtn.value = v;
     }
 }
 
 const blueList = ref([]);
 const getBlueRegionList = (callback) => {
-    if(!organId.value){
+    if (!organId.value) {
         return;
     }
     let selectAll = undefined;
@@ -307,22 +329,22 @@ const getBlueRegionList = (callback) => {
     });
 };
 // 图例
-const legendArr = ref([])
+const legendArr = ref([]);
 
 const organId = ref(null);
 const regionId = ref(null);
 const tabName = ref("");
 const tabId = ref(0);
-eventBus.off("changePointLegend", toggleLegend)
-eventBus.on("changePointLegend", toggleLegend)
-function toggleLegend({colorObj}) {
-    legendArr.value = colorObj?.list
+eventBus.off("changePointLegend", toggleLegend);
+eventBus.on("changePointLegend", toggleLegend);
+function toggleLegend({ colorObj }) {
+    legendArr.value = colorObj?.list;
 }
 //选项卡事件监听
 const handleTab = async ({ name, id, isUpdate, params, legend, colorObj }) => {
-    eventBus.emit("changePointType", {legend, colorObj})
-    legendArr.value = colorObj?.list
-    console.log('name, id, isUpdate, params', name, id, isUpdate, params, legend, colorObj);
+    eventBus.emit("changePointType", { legend, colorObj });
+    legendArr.value = colorObj?.list;
+    console.log("name, id, isUpdate, params", name, id, isUpdate, params, legend, colorObj);
     tabName.value = name;
     tabId.value = id;
     if (id === 0) {
@@ -366,28 +388,6 @@ const handleTabItem = (e) => {
     // }
 };
 
-const reportData = ref({});
-const blueListConvert = (data, index) => {
-    const list = [];
-    for (let key in data) {
-        const filterData = reportData.value.blueZoneLegendList[index].list.filter((item) => item.val === key);
-        const arr = data[key];
-        arr.forEach((item) => {
-            const listObj = blueList.value.filter((ele) => ele.blueZoneCode === item);
-            const updateList = listObj.map((ele) => {
-                return {
-                    ...ele,
-                    level: key,
-                    name: filterData[0].name,
-                    color: filterData[0].color,
-                };
-            });
-            list.push(...updateList);
-        });
-    }
-    return list;
-};
-
 const getFarmIndexReport = (callback) => {
     // const params = { farmId:organId.value,regionId:regionId.value, type: tabName.value };
     //   VE_API.farm.farmIndexReport(params).then(({data,code}) => {
@@ -558,37 +558,38 @@ const currentComponent = ref("leftFly");
 const handleActiveLeft = (e) => {
     currentComponent.value = e.componentName;
 };
-const leftToolList = [[
+const leftToolList = [
+    [
         {
-        title: "飞巡感知",
-        componentName: "leftFly",
-    },
-    {
-        title: "气象感知",
-        componentName: "leftWeather"
-    },
-    {
-        title: "人工感知",
-        componentName: "phenologyPage",
-    },
-    {
-        title: "站点感知",
-        componentName: "leftStation",
-    },
+            title: "飞巡感知",
+            componentName: "leftFly",
+        },
+        {
+            title: "气象感知",
+            componentName: "leftWeather",
+        },
+        {
+            title: "人工感知",
+            componentName: "phenologyPage",
+        },
+        {
+            title: "站点感知",
+            componentName: "leftStation",
+        },
     ],
     [
         {
             title: "首页",
-            name:'home',
-            componentName: "homePage"
+            name: "home",
+            componentName: "homePage",
         },
         {
             title: "气象预警",
-            componentName: "weatherPage"
+            componentName: "weatherPage",
         },
         {
             title: "物候调节",
-            componentName: "phenologyPage"
+            componentName: "phenologyPage",
         },
         {
             title: "病虫指标",
@@ -598,29 +599,87 @@ const leftToolList = [[
             title: "营养评估",
             componentName: "leftNutrition"
         },
-    ]
+    ],
 ];
 
 const rightIndex = ref(0);
-const handleActiveRight = ({ index }) => {
-    rightIndex.value = index;
-    btnIndex.value = null;
-    btnName.value = "";
-    samplePointLayer.updateAreaStatus(false);
-    regionLayer.resetData();
-    samplePointLayer.resetPoint();
-    if (index !== 0) {
-        act.value = null;
-    }
+// const handleActiveRight = ({ index }) => {
+//     rightIndex.value = index;
+//     btnIndex.value = null;
+//     btnName.value = "";
+//     samplePointLayer.updateAreaStatus(false);
+//     if (index !== 0) {
+//         act.value = null;
+//     }
+// };
+
+const currentRightComponent = ref("recordList");
+const handleActiveRight = (e) => {
+    currentRightComponent.value = e.componentName;
 };
-const hanleRightIndex = (num) => {
-    rightIndex.value = num;
-    eventBus.emit("tool:updateAct", num);
+
+function convertPointsToArray(data) {
+    return data.map((item) => {
+        // 提取POINT字符串中的坐标部分
+        const coords = item.point.match(/POINT\(([^)]+)\)/)[1];
+        // 将坐标拆分为经度和纬度,并转换为数字
+        const [lng, lat] = coords.split(" ").map(Number);
+        return [lng, lat];
+    });
+}
+
+//添加航线回调
+const airLineCallback = (data) => {
+    console.log("data", data);
+    if (data?.id) {
+        // VE_API.home.waylinePoint({droneId:data.id}).then(res =>{
+        //     const arr = convertPointsToArray(res.data)
+        //     airLineStringLayer.initData(arr,data.geom,data.code)
+        // })
+        const res = [
+            {
+                id: "13",
+                droneId: "2",
+                point: "POINT(110.603131056 21.36505974)",
+            },
+            {
+                id: "14",
+                droneId: "2",
+                point: "POINT(110.599708557 21.36655847)",
+            },
+            {
+                id: "15",
+                droneId: "2",
+                point: "POINT(110.600641966 21.36925613)",
+            },
+            {
+                id: "16",
+                droneId: "2",
+                point: "POINT(110.59876442 21.36856673)",
+            },
+            {
+                id: "17",
+                droneId: "2",
+                point: "POINT(110.596886873 21.37040512)",
+            },
+        ];
+        const arr = convertPointsToArray(res);
+        airLineStringLayer.initData(arr, data.geom, data.code);
+    } else {
+        airLineStringLayer.clearLayer();
+    }
 };
-const rightToolList = [[
+
+const isEditLine = ref(false)
+function startEditLine() {
+    isEditLine.value = true
+}
+
+const rightToolList = [
+    [
         {
             title: "农事列表",
-            componentName: "leftFly",
+            componentName: "recordList",
             index: 0,
         },
         {
@@ -632,7 +691,7 @@ const rightToolList = [[
     [
         {
             title: "无人机",
-            componentName: "leftFly",
+            componentName: "rightAerial",
             index: 2,
         },
         {
@@ -645,7 +704,7 @@ const rightToolList = [[
             componentName: "leftFly",
             index: 2,
         },
-    ]
+    ],
 ];
 
 // 跳转果园档案
@@ -693,11 +752,10 @@ const handleShrink = (position) => {
 };
 
 const photoList = ref([
-    {key: "病虫", statement: "病虫 2025年02月19日,发现毛毡病异常1级"},
-    {key: "异常", statement: "2025年03月17日,发现花量大异常3级"},
-    {key: "营养", statement: "无营养异常"},
+    { key: "病虫", statement: "病虫 2025年02月19日,发现毛毡病异常1级" },
+    { key: "异常", statement: "2025年03月17日,发现花量大异常3级" },
+    { key: "营养", statement: "无营养异常" },
 ]);
-
 </script>
 
 <style lang="scss" scoped>
@@ -740,8 +798,8 @@ const photoList = ref([
                 line-height: 38px;
                 cursor: pointer;
                 &.active {
-                    background: linear-gradient(180deg, #FFD887, #ED9E1E);
-                    color: #1D1D1D;
+                    background: linear-gradient(180deg, #ffd887, #ed9e1e);
+                    color: #1d1d1d;
                 }
             }
             .btn + .btn {
@@ -758,13 +816,13 @@ const photoList = ref([
             position: relative;
             transition: transform 0.3s;
         }
-        .collapsed-left{
+        .collapsed-left {
             transform: translateX(-430px);
         }
-        .collapsed-right{
+        .collapsed-right {
             transform: translateX(430px);
         }
-        .arrow-left{
+        .arrow-left {
             transform: rotate(180deg);
         }
         .left {
@@ -864,7 +922,7 @@ const photoList = ref([
             height: 152px;
             align-self: flex-end;
             justify-content: center;
-            .img{
+            .img {
                 width: 268px;
                 height: 66px;
                 cursor: pointer;
@@ -1058,7 +1116,7 @@ const photoList = ref([
             font-size: 20px;
             color: #ffd489;
             .tag {
-                border: 1px solid #FFD489;
+                border: 1px solid #ffd489;
                 border-radius: 4px;
                 font-size: 12px;
                 display: inline-block;
@@ -1191,7 +1249,7 @@ const photoList = ref([
         }
     }
 }
-.farm-fight-task{
+.farm-fight-task {
     position: fixed;
     top: 100px;
     left: 25%;

+ 165 - 0
src/views/home/map/airLineStringLayer.js

@@ -0,0 +1,165 @@
+import * as KMap from "@/utils/ol-map/KMap";
+import { Circle, Fill, Stroke, Style, Text, Icon } from "ol/style.js";
+import LineString from "ol/geom/LineString";
+import { newPoint } from "@/utils/map.js";
+import Point from "ol/geom/Point";
+import { Feature } from "ol";
+
+/**
+ * @description 地图层对象
+ */
+class airLineStringLayer {
+    constructor(map) {
+        let that = this;
+        this.vectorStyle = new KMap.VectorStyle();
+
+        this.lineStringLayer = new KMap.VectorLayer("lineStringLayer", 9999, {
+            style: this.styleFunction,
+        });
+        map.addLayer(this.lineStringLayer.layer);
+        this.kmap = map;
+
+        // 位置图标
+        this.pointLayer = new KMap.VectorLayer("pointLayer", 9999, {
+            style: () => {
+                return new Style({
+                    image: new Icon({
+                        src: require(`@/assets/images/map/drone-icon.png`),
+                        scale: 0.38,
+                    }),
+                });
+            },
+        });
+        map.addLayer(this.pointLayer.layer);
+
+        // 位置图标
+        this.pointOfflineLayer = new KMap.VectorLayer("pointOfflineLayer", 9999, {
+            style: () => {
+                return new Style({
+                    image: new Icon({
+                        src: require(`@/assets/images/map/drone-offline-icon.png`),
+                        scale: 0.38,
+                    }),
+                });
+            },
+        });
+        map.addLayer(this.pointOfflineLayer.layer);
+    }
+
+    styleFunction(feature) {
+        const type = feature.get('type');
+        const geometry = feature.getGeometry();
+        const styles = [];
+
+        // 处理线段的样式
+        if (geometry.getType() === 'LineString') {
+            styles.push(
+                new Style({
+                    stroke: new Stroke({
+                        color: type === 'Online' ? '#FFD689' : '#FFFFFF',
+                        width: 3,
+                    }),
+                })
+            );
+
+            geometry.forEachSegment(function (start, end) {
+                // 计算中间点坐标
+                const midX = (start[0] + end[0]) / 2;
+                const midY = (start[1] + end[1]) / 2;
+                const midPoint = [midX, midY];
+                // 计算线段方向角(弧度)
+                const dx = end[0] - start[0];
+                const dy = end[1] - start[1];
+                const rotation = Math.atan2(dy, dx);
+
+                // 添加箭头样式
+                styles.push(
+                    new Style({
+                        geometry: new Point(midPoint),
+                        image: new Icon({
+                            src: require(`@/assets/images/map/${type === 'Online' ? 'arrow' : 'arrow-offline'}-icon.png`),
+                            anchor: [0.5, 0.5],
+                            scale: 0.8,
+                            zIndex: 2,
+                            rotateWithView: true,
+                            rotation: -rotation,
+                        }),
+                    })
+                );
+            });
+        }
+
+        // 处理点位的样式
+        if (geometry.getType() === 'Point') {
+            styles.push(
+                new Style({
+                    image: new Icon({
+                        src: require(`@/assets/images/map/${type === 'Online' ? 'air' : 'air-offline'}-icon.png`),
+                        scale: 1,
+                        displacement: [0, 20],
+                    }),
+                }),
+                new Style({
+                    image: new Icon({
+                        src: require(`@/assets/images/map/${type === 'Online' ? 'text' : 'text-offline'}-bj.png`),
+                        scale: 0.42,
+                        displacement: [5, 110],
+                        zIndex: 2,
+                    }),
+                }),
+                new Style({
+                    text: new Text({
+                        font: "18px PangMenZhengDao",
+                        text: feature.get('pointIndex') || '', // 显示顺序编号
+                        offsetY: -47,
+                        fill: new Fill({ color: "#fff" }),
+                    }),
+                })
+            );
+        }
+
+        return styles;
+    }
+
+    initData(droneArr, dronePoint, name) {
+        this.clearLayer();
+        //在线数据
+        const lineCoordinates = {
+            type: 'Online',
+            arr: droneArr
+        };
+
+        // 创建线特征
+        let lineGeometry = new LineString(lineCoordinates.arr);
+        let lineFeature = new Feature({
+            geometry: lineGeometry,
+        });
+        lineFeature.set("type", lineCoordinates.type);
+        this.lineStringLayer.addFeature(lineFeature);
+
+        // 为每个点位创建单独的特征并设置顺序编号
+        lineCoordinates.arr.forEach((coord, index) => {
+            let pointFeature = new Feature({
+                geometry: new Point(coord),
+            });
+            pointFeature.set("type", lineCoordinates.type);
+            pointFeature.set("pointIndex", (index + 1).toString()); // 设置从1开始的顺序编号
+            this.lineStringLayer.addFeature(pointFeature);
+        });
+
+        // 添加无人机位置点
+        const pointVal = { id: 1, wkt: dronePoint, type: 'Online' };
+        let point = newPoint(pointVal, 'wkt');
+        this.pointLayer.addFeature(point);
+
+        this.kmap.fit(this.lineStringLayer.source.getExtent(), { padding: [230, 230, 230, 230] });
+    }
+
+    clearLayer() {
+        this.lineStringLayer && this.lineStringLayer.layer.getSource().clear();
+        this.pointLayer && this.pointLayer.layer.getSource().clear();
+        this.pointOfflineLayer && this.pointOfflineLayer.layer.getSource().clear();
+    }
+}
+
+export default airLineStringLayer;