cuiqian2004
2025-10-17 68ce9382090846dc3a03a057a18a7d09f30e45e5
pages/map/index.vue
@@ -1,73 +1,543 @@
<template>
   <view class="pages-map">
      <view class="view-content">
         <uni-nav-bar :fixed="true" status-bar right-text="" left-text="" :leftWidth="24" :rightWidth="28"
            :title="navigationBarTitle">
            <view class="uni-navbar-container-inner">
               <text class="uni-nav-bar-text">{{navigationBarTitle }}</text>
               <image class="icon" v-if="sceneList.length > 1 && !mapOperationType" src="/images/Vector.svg"
                  alt="SVG 图片" @click="clickShowMenu" />
            </view>
            <template v-slot:left>
               <view @click="clickBack">
                  <uni-icons type="left" size="24"></uni-icons>
               </view>
            </template>
            <!-- <template v-slot:right>
               <view v-if="sceneList.length > 0 && !mapOperationType">
                  <a @click="clickMore">
                     <uni-icons class="uni-panel-bar-icon" type="more-filled" size="24"></uni-icons>
                  </a>
               </view>
            </template> -->
         </uni-nav-bar>
         <view class="no-content" v-if="unlinked">
            <image class="img" src="/images/image 25.png" alt=" 图片" mode="aspectFit" />
            <image class="img" src="/images/image_25.png" alt=" 图片" mode="aspectFit" />
            <view class="title">车辆连接失败</view>
            <view class="space">请检查你的网络设置或重新加载</view>
         </view>
         <view class="map-content" v-show="!unlinked">
            <view class="text-button-group">
               <a-button type="primary" class="button" @click="clickStationList">
                  站点列表
               </a-button>
               <a-button type="primary" class="button" @click="clickTeachingList">
                  示教路线列表
               </a-button>
         <!--    <SceneCreateInfo v-else-if="mapOperationType =='scene_create'" class="map-content" :ip="vehicleIp"
            v-model:opSceneType="opSceneType" @create-ok="onCreateSceneOk"></SceneCreateInfo> -->
         <view class="map-content" v-show="mapOperationType !='scene_create'">
            <view class="content">
               <view ref="canvasCtx" class="fabric" id="canvasMap" :message="ctxDataStr"
                  :change:message="ctx.receiveMsg">
               </view>
               <view class="loading-overlay" v-if="bgLoading">
                  <view class="loading-content">
                     <view class="loading-spinner"></view>
                     <text>加载中... {{ bgProgressPercent }}%</text>
                  </view>
               </view>
               <view class="position-site" v-if="mapOperationStatus =='pos' " @click="clickPositionStation">
                  <text class="ico my-location-rounded"></text>
                  获取搬运车位置和朝向
               </view>
               <view class="position" v-else @click="clickVehiclePosition">
                  <text class="ico my-location-rounded"></text>
                  <!-- <image class="img" src="/images/material-symbols_my-location-rounded.svg" alt="SVG 图片" /> -->
               </view>
               <view v-if="this.mapOperationType ==''" class="teaching-path-show"
                  :class="showTeachingPathFlag?'selected':''" @click="clickShowTeachingPath">
                  <text class="ico layer"></text>
               </view>
               <view class="station-info"
                  :style="{'left':(stationViewPos.x - 120)+ 'px','top':(stationViewPos.y + stationViewPos.height/2 + 10)+'px'}"
                  v-if="mapOperationType =='edit_station'">
                  <view class=" left">
                     <view class="line">站点名称:
                     </view>
                     <view class="line"> 坐标(x,y):
                     </view>
                     <view class="line">朝向:
                     </view>
                  </view>
                  <view class="right">
                     <view class="line"> {{stationEdit.name}}
                     </view>
                     <view class="line">
                        {{ Math.floor( stationEdit.x*1000)/1000}},{{ Math.floor( stationEdit.y*1000)/1000}}
                     </view>
                     <view class="line"> {{ Math.floor(180* stationEdit.angle/Math.PI)}}°
                     </view>
                  </view>
               </view>
            </view>
         </view>
      </view>
      <view class="bottom" v-if="!unlinked">
      <view class="bottom">
         <view class="bottom-content" v-if="mapOperationType =='edit_scene_name'">
            <view class="tip">请输入场景名称</view>
            <view class="name-input">
               <input ref="refInputName" :focus="true" placeholder="请输入场景名称" :value="sceneInputName"
                  @input="onInputName" />
               <uni-icons class="clear" color="#ccc" type="clear" size="20" v-if="sceneInputName"
                  @click="clickClearName"></uni-icons>
            </view>
            <view class="text-button-group">
               <a-button type="primary" class="button" :disabled="loading || sceneInputName.trim() == ''"
                  @click="clickNameOK">确认</a-button>
               <a-button type="ghost" class="button" :disabled="loading" @click="clickNameCancel">取消</a-button>
            </view>
         </view>
         <view class="bottom-content">
         <template
            v-else-if="mapOperationType =='teaching_add_station' || mapOperationType =='add_station' || mapOperationType =='edit_station'">
            <view class="bottom-content" v-if="mapOperationStatus =='pos' ">
               <view class="tip">调节位置</view>
               <view class="row-group">
                  <view class="coordinate">
                     <text class="name">横坐标:</text>
                     <input ref="refInputX" class="number-input" type="number" :value="stationEdit.x"
                        @input="onInputStationX" :maxlength="4" />
                     <uni-icons class="clear" color="#ccc" type="clear" size="20"
                        v-if="stationEdit.x && stationEdit.x!='0'" @click="clickClearStationX"></uni-icons>
                  </view>
                  <view class="coordinate">
                     <text class="name">竖坐标:</text>
                     <input ref="refInputX" class="number-input" type="number" :value="stationEdit.y"
                        @input="onInputStationY" :maxlength="4" />
                     <uni-icons class="clear" color="#ccc" type="clear" size="20"
                        v-if="stationEdit.y&& stationEdit.y!='0'" @click="clickClearStationY"></uni-icons>
                  </view>
               </view>
               <view class="tip">调节朝向</view>
               <view class="angle-group">
                  <image class="img-angle" :src="angleSvg" alt="SVG 图片" />
                  <image class="img-angle-pos" src="/images/Frame_153.svg" alt="SVG 图片"
                     @touchstart="handleAngleTouchStart" @touchmove="handleAngleTouchMove" />
               </view>
            </view>
            <view class="bottom-content" v-else>
               <view class="tip">请输入站点名称</view>
               <view class="name-input">
                  <input ref="refInputName" :focus="true" placeholder="输入站点名称" :value="stationEdit.name"
                     @input="onInputStationName" />
                  <uni-icons class="clear" color="#ccc" type="clear" size="20" v-if="stationEdit.name"
                     @click="clickClearStationName"></uni-icons>
               </view>
               <view class="text-button-group">
                  <a-button class="button" :disabled="loading" @click="clickStationNameCancel">取消</a-button>
                  <a-button type="primary" class="button" :disabled="loading || stationEdit.name.trim() == ''"
                     @click="clickStationNameOK">确定</a-button>
               </view>
            </view>
         </template>
         <view class="bottom-content" v-else-if="mapOperationType =='regiona_planning'">
            <view class="img-button-group">
               <view fill="none" class="button" @click="clickManualPlan">
                  <text class="ico conversion-path"></text>
                  <view class="text">人工规划</view>
               </view>
               <view type="text" class="button " @click="clickVehicleTrajectoryPlan">
                  <text class="ico conversion-path"></text>
                  <view class="text ">车辆轨迹规划</view>
               </view>
            </view>
         </view>
         <view class="bottom-content" v-else-if="mapOperationType =='vehicle_trajectory_planning'">
            <template v-if="mapOperationStatus=='feasible_region' || mapOperationStatus=='prohibition_region'">
               <view class="tip">区域规划</view>
               <view>可按住各端点调整虚拟墙位置,按【+】按钮可添加顶点,区域需为闭合图形</view>
            </template>
            <view class="img-button-group" v-else>
               <view fill="none" class="button" @click="clickPlanFeasibleRegion">
                  <!-- <text class="ico conversion-path"></text> -->
                  <uni-icons class="img" type="checkmarkempty" size="36" color="#1890FF"></uni-icons>
                  <view class="text">可行区</view>
               </view>
               <view type="text" class="button " @click="clickPlanProhibitionRegion">
                  <text class="ico placeholder-bold"></text>
                  <view class="text ">禁行区</view>
               </view>
            </view>
         </view>
         <view class="bottom-content" v-else-if="mapOperationType =='manual_planning'">
            <template v-if="mapOperationStatus=='feasible_region' || mapOperationStatus=='prohibition_region'">
               <view class="tip">区域规划</view>
               <view>可按住各端点调整虚拟墙位置,按【+】按钮可添加顶点,区域需为闭合图形</view>
            </template>
            <template v-else-if="mapOperationStatus=='virtual_wall'">
               <view class="tip">区域规划</view>
               <view>可按住两端点调整虚拟墙位置</view>
            </template>
            <view class="img-button-group" v-else>
               <view fill="none" class="button" @click="clickPlanFeasibleRegion">
                  <!--    <text class="ico conversion-path"></text> -->
                  <uni-icons class="img" type="checkmarkempty" size="36" color="#1890FF"></uni-icons>
                  <view class="text">可行区</view>
               </view>
               <view type="text" class="button " @click="clickPlanProhibitionRegion">
                  <text class="ico placeholder-bold"></text>
                  <view class="text ">禁行区</view>
               </view>
               <view type="text" class="button " @click="clickPlanVirtualWall">
                  <text class="dashed-line"></text>
                  <view class="text ">虚拟墙</view>
               </view>
            </view>
         </view>
         <view class="bottom-content" v-else-if="mapOperationType =='scene_create'"></view>
         <template v-else-if="mapOperationType =='public_teaching' ">
            <view class="bottom-content" v-if="mapOperationStatus =='teaching'">
               <view class="tip">路径记录中...</view>
               <view v-if="mapOperationType =='public_teaching'">
                  <!-- 主路/支路 -->
                  <view>正在记录搬运车行进路径,完成后点按钮以结束示教。在示教过程中可以添加站点。</view>
                  <view class="switch-type">可随时切换示教模式
                     <view class="switch-button-group">
                        <view class="switch-button"
                           :class="teachingModeCur.mode_type ==0?'switch-button-checked':''"
                           @click="onTeachingModeType(0)">默认</view>
                        <view class="switch-button "
                           :class="teachingModeCur.mode_type ==1?'switch-button-checked':''"
                           @click="onTeachingModeType(1)">双向</view>
                        <view class="switch-button "
                           :class="teachingModeCur.mode_type ==2?'switch-button-checked':''"
                           @click="onTeachingModeType(2)">智能</view>
                     </view>
                  </view>
               </view>
               <view v-else>
                  正在记录搬运车行进路径,完成后点按钮以结束示教
               </view>
               <view class="text-button-group">
                  <a-button v-if="mapOperationType =='public_teaching'" type="ghost" class="button"
                     @click="clickAddStation">添加站点</a-button>
                  <a-button type="primary" class="button" @click="clickTeachingEnd">结束记录</a-button>
               </view>
            </view>
            <view class="bottom-content" v-else-if="mapOperationStatus =='end'">
               <view class="tip">路径记录完成</view>
               <view>
                  要将该段路径保存为示教路径吗?
               </view>
               <view class="text-button-group">
                  <a-button type="primary" class="button" :disabled="loading"
                     @click="clickTeachingSave">保存为示教路径</a-button>
                  <a-button type="ghost" class="button" :disabled="loading"
                     @click="clickTeachingReset">重新记录</a-button>
               </view>
            </view>
            <view class="bottom-content" v-else-if="mapOperationStatus =='save'">
               <view class="tip">示教完成</view>
               <view>
                  已将路径保存为示教路径
               </view>
               <view class="text-button-group">
                  <a-button type="primary" class="button" :disabled="loading"
                     @click="clickTeachingFinish">完成</a-button>
               </view>
            </view>
            <view class="bottom-content" v-else>
               <view class="tip">即将开始公共示教</view>
               <view>
                  请选择要进行主路还是支路示教,点【开始记录】后将记录搬运车的行进路线作为公共示教路线。开始记录后可随时切换示教模式。
               </view>
               <view class="text-button-group">
                  <view class="switch-type">
                     <view class="switch-button-group">
                        <view class="switch-button"
                           :class="teachingModeCur.mode_type ==0?'switch-button-checked':''"
                           @click="onTeachingModeType(0)">默认</view>
                        <view class="switch-button "
                           :class="teachingModeCur.mode_type ==1?'switch-button-checked':''"
                           @click="onTeachingModeType(1)">双向</view>
                        <view class="switch-button "
                           :class="teachingModeCur.mode_type ==2?'switch-button-checked':''"
                           @click="onTeachingModeType(2)">智能</view>
                     </view>
                  </view>
                  <a-button type="primary" class="button" :disabled="loading"
                     @click="clickTeachingStart">开始记录</a-button>
               </view>
            </view>
         </template>
         <view class="bottom-content" v-else-if="mapOperationType =='edit_map'">
            <view class="img-button-group">
               <view fill="none" class="button" @click="clickRename">
                  <text class="ico rename"></text>
                  <view class="text">重命名</view>
               </view>
               <view type="text" class="button " @click="clickRegionaPlan">
                  <text class="ico zone"></text>
                  <view class="text">区域规划</view>
               </view>
               <view fill="none" class="button" @click="clickExtendMap">
                  <text class="ico expand"></text>
                  <view class="text">扩展地图</view>
               </view>
               <!-- <view type="text" class="button" @click="clickMapEdit">
                  <text class="ico edit-line"></text>
                  <view class="text"> 编辑地图</view>
               </view> -->
               <view type="text" class="button" @click="clickDelete">
                  <text class="ico delete-outline"></text>
                  <view class="text">删除场景</view>
               </view>
            </view>
         </view>
         <view class="bottom-content" v-else>
            <view class="img-button-group">
               <view fill="none" class="button" @click="clickMapStation">
                  <text class="ico location1"></text>
                  <view class="text"> 添加站点</view>
                  <view class="text">添加站点</view>
               </view>
               <view fill="none" class="button" @click="clickTeaching">
                  <text class="ico teach"></text>
                  <view class="text">路径示教</view>
               </view>
               <!-- <view type="text" class="button " @click="clickRegionaPlan">
                  <text class="ico layer"></text>
                  <view class="text">区域规划</view>
               </view> -->
               <view type="text" class="button" @click="clickMapEdit">
                  <text class="ico edit-line"></text>
                  <view class="text"> 编辑地图</view>
               </view>
               <view type="text" class="button" @click="clickMapTask">
                  <text class="ico task-list"></text>
                  <view class="text">车辆任务</view>
                  <view class="text">任务设置</view>
               </view>
            </view>
         </view>
      </view>
      <view>
         <uni-popup ref="refPopupMenu" background-color="transparent" maskBackgroundColor="rgba(0, 0, 0, 0.2)">
            <view class="popup-content">
               <view class="popup-content-menu "
                  :style="{'margin-top':menuPopup.top+'rpx','margin-left':menuPopup.left+'rpx'}">
                  <view class="popup-content-menu-item" v-for="(item,index) in menuPopup.list" :key="index"
                     @click="menuItemChange(item,menuPopup.type)">
                     {{item}}
                  </view>
               </view>
            </view>
         </uni-popup>
         <uni-popup ref="refPopupOperateStation" background-color="transparent"
            maskBackgroundColor="rgba(0, 0, 0, 0.2)" @click="closePopuBtn">
            <view class="popup-content">
               <view class="popup-content-btn">
                  <view class="img-button-group">
                     <view fill="none" class="button" @click.stop="clickStationDelete">
                        <text class="ico delete-outline"></text>
                        <view class="text"> 批量删除</view>
                     </view>
                     <view type="text" class="button" @click.stop="clickStationPostion">
                        <text class="ico edit-line"></text>
                        <view class="text">调整位置朝向</view>
                     </view>
                     <view type="text" class="button" @click.stop="clickStationRename">
                        <text class="ico rename"></text>
                        <view class="text">重命名</view>
                     </view>
                  </view>
               </view>
            </view>
         </uni-popup>
         <uni-popup ref="refPopupOperateTeaching" background-color="transparent"
            maskBackgroundColor="rgba(0, 0, 0, 0.2)">
            <view class="popup-content">
               <view class="popup-content-btn">
                  <view class="img-button-group">
                     <view fill="none" class="button" @click.stop="clickTeachingEdit">
                        <text class="ico edit-line"></text>
                        <view class="text">编辑</view>
                     </view>
                     <view fill="none" class="button" @click.stop="clickTeachingDelete">
                        <text class="ico red delete-outline "></text>
                        <view class="text">删除</view>
                     </view>
                  </view>
               </view>
            </view>
         </uni-popup>
         <uni-popup ref="refPopupTeachingUpdate" type="dialog">
            <uni-popup-dialog type="info" cancelText="取消" confirmText="确定" title="示教更新"
               @confirm="dialogTeachingUpdateConfirm" @close="dialogTeachingUpdateClose">
               <view class="popup-dialog-content">
                  <view class="popup-content-item">
                     <radio-group @change="radioTeachinMainRoadChange">
                        <label class="radio">
                           <radio :value="1" :checked="selectTeachingMode.main_road == 1" />主路
                        </label>
                        <label class="radio">
                           <radio :value="0" :checked="selectTeachingMode.main_road != 1" />支路
                        </label>
                     </radio-group>
                  </view>
                  <view class="popup-content-item">
                     <radio-group @change="radioTeachinBidirectionChange">
                        <label class="radio">
                           <radio :value="1" :checked="selectTeachingMode.bidirection == 1" />双向
                        </label>
                        <label class="radio">
                           <radio :value="0" :checked="selectTeachingMode.bidirection != 1" />单向
                        </label>
                     </radio-group>
                  </view>
               </view>
            </uni-popup-dialog>
         </uni-popup>
      </view>
   </view>
</template>
<script src="./js/ctx.js" module="ctx" lang="renderjs"></script>
<script>
   import {
      ref
   } from "vue";
   import {
      showToast,
      showModal
      showModal,
      session,
      showError,
      showInfo
   } from "@/comm/utils.js"
   // import OIFabric from "@/components/oi-fabric/index.vue"
   import {
      Button
   } from 'antd-mobile-vue-next'
   import SceneCreateInfo from './infos/scene-create.vue'
   import {
      getAllScene,
      getMapUrl,
      handoffScene,
      updateScene,
      delScene,
      stations,
      getAgvState,
      addStation,
      updateStation,
      delStation,
      getTeachingMode,
      teachingModeFlag,
      getCurrentTeachingData,
      delTeachingMode,
      delTeachingModeData,
      checkAgvLocationDistanceError,
      splitTeachingMode,
      updateSplitTeachingData,
      deleteSplitTeachingData
   } from "@/api/vehicle.js"
   export default {
      name: "PagesMap",
      components: {
         'a-button': Button
         'a-button': Button,
         SceneCreateInfo
      },
      data() {
         return {
            loading: false,
            navigationBarTitle: "",
            opSceneType: "",
            vehicleIp: "",
            sceneId: "",
            mapShowAgv: false,
            menuPopup: {
               type: "",
               list: []
            },
            sceneList: [],
            ctxDataStr: "[]",
            mapOperationType: "",
            mapOperationStatus: "",
            mapOperationStatus: "",
            teachingMode: {},
            teachingModeCur: {},
            stationViewPos: {
               x: 0,
               y: 0,
               width: 0,
               height: 0
            },
            stationEdit: {
               stationID: "",
               name: "",
               x: 0,
               y: 0,
               angle: 0
            },
            sceneInputName: "",
            showClearName: false,
            stationList: [],
            unlinked: true
            angleSvg: "/static/images/angle0.svg",
            windowWidth: 375,
            bgProgressPercent: 0,
            bgLoading: false,
            isMapEdit: false,
            wallList: [],
            regionList: [],
            unlinked: false,
            showTeachingPathFlag: true,
            curTeachingPathFlag: false,
            curTeachingPathTime: 0,
            curMapInfo: {
               proportion: 1,
               img_proportion: 1,
               max_x: 1,
               max_y: 1,
               min_x: 0,
               min_y: 0,
               img_x: 1,
               img_y: 1
            },
            positioningAgv: false,
            isPageVisible: true,
            destroyFlag: false,
         }
      },
      computed: {
         getMaxStationNo() {
            let num = 0
            this.stationList.forEach((item) => {
@@ -79,15 +549,70 @@
         },
      },
      watch: {
         mapOperationType(val) {
            let name = this.sceneId || "地图"
            if (val == "add_station" || val == "teaching_add_station") {
               name = "添加站点"
            } else if (val == "edit_station") {
               name = "编辑站点"
            } else if (val == "scene_create") {
               name = "构建场景"
            } else if (val == "edit_map") {
               name = "编辑地图"
            } else if (val == "manual_planning") {
               name = "人工规划"
            } else if (val == "vehicle_trajectory_planning") {
               name = "车辆轨迹规划"
            } else if (val == "public_teaching") {
               name = "路径示教"
            }
            this.setData({
               navigationBarTitle: name
            })
         }
      },
      onLoad(option) {
         const _this = this
         console.log(option)
         this.vehicleIp = option.ip || ""
         this.isPageVisible = true
         uni.getSystemInfo({
            success(e) {
               _this.windowWidth = e.windowWidth
            },
         })
         this.loadData()
      },
      onShow() {
         this.isPageVisible = true
      },
      onHide() {
         this.isPageVisible = false
      },
      async onUnload() {
         this.isPageVisible = false
         console.log("onUnload")
      },
      onBackPress() {
         this.isPageVisible = false
         if (this.destroyFlag)
            return false
         else {
            this.ctxDataStr = JSON.stringify([{
               method: "destroy",
            }])
            return true
         }
      },
      methods: {
         setData(obj) {
            let that = this;
@@ -112,60 +637,1933 @@
         },
         async loadData() {
            try {
               const info = await getAgvState(this.vehicleIp)
               this.setData({
                  unlinked: false
               })
               await this.loadSceneList()
               if (this.sceneList.length > 0) {
                  this.mapOperationType = ''
                  const scene = this.sceneList[0]
                  this.changeMap(scene)
               } else {
                  uni.navigateBack({
                     delta: 1, //返回层数,2则上上页
                  })
               }
               this.refreshAgvPosition()
            } catch (ex) {
               this.setData({
                  unlinked: true
               })
               showError(ex)
            }
         },
         clickShowMenu() {
            // const list = [...this.sceneList]
            // for(let i =0; i < 20;i++){
            //    list.push("test" + i)
            // }
            this.menuPopup = {
               type: "scene",
               list: this.sceneList,
               left: 225,
               top: 140
            }
            this.$refs.refPopupMenu.open("top")
         },
         clickBack() {
            uni.navigateBack({
               delta: 1
            })
         clickMore() {
            this.menuPopup = {
               type: "menu",
               list: ["构建场景", "地图扩展", "重命名", "删除"],
               left: 450,
               top: 140
            }
            this.$refs.refPopupMenu.open("top")
         },
         async clickBack() {
            if (this.mapOperationType == "scene_create") {
               if (this.opSceneType == "scan") {
                  showModal("已构建场景将会被删除", "是否中断场景构建?").then((res) => {
                     if (res) {
                        if (this.sceneList.length == 0) {
                           const eventChannel = this.getOpenerEventChannel();
                           eventChannel.emit('check_connect', !this.unlinked);
                           uni.navigateBack({
                              delta: 1
                           })
                        } else {
                           this.opSceneType = ""
                           this.mapOperationType = ""
                        }
                     }
                  })
               } else {
                  if (this.opSceneType != "") {
                     await this.loadSceneList()
                     if (this.sceneList.length == 0) {
                        const eventChannel = this.getOpenerEventChannel();
                        eventChannel.emit('check_connect', !this.unlinked);
                        uni.navigateBack({
                           delta: 1
                        })
                     }
                  } else {
                     const eventChannel = this.getOpenerEventChannel();
                     eventChannel.emit('check_connect', !this.unlinked);
                     uni.navigateBack({
                        delta: 1
                     })
                  }
               }
            } else if (this.mapOperationType == "edit_map") {
               this.mapOperationType = ""
            } else if (this.mapOperationType == "regiona_planning") {
               this.mapOperationType = "edit_map"
            } else if (this.mapOperationType == "vehicle_trajectory_planning") {
               if (this.mapOperationStatus == "feasible_region" || this.mapOperationStatus ==
                  "prohibition_region") {
                  showModal("正在进行区域规划。", "是否要退出区域规划?").then((res) => {
                     if (res) {
                        this.mapOperationStatus = ""
                     }
                  })
               } else {
                  this.mapOperationType = "regiona_planning"
               }
               return
            } else if (this.mapOperationType == "manual_planning") {
               if (this.mapOperationStatus == "virtual_wall" ||
                  this.mapOperationStatus == "feasible_region" ||
                  this.mapOperationStatus == "prohibition_region") {
                  showModal("正在进行区域规划。", "是否要退出区域规划?").then((res) => {
                     if (res) {
                        if (this.mapOperationStatus == "virtual_wall") {
                           this.ctxDataStr = JSON.stringify([{
                              method: "remove_wall",
                              param: [this.wallEdit]
                           }])
                           this.wallEdit = {}
                        } else {
                           this.ctxDataStr = JSON.stringify([{
                              method: "remove_region",
                              param: [this.regionEdit]
                           }])
                           this.regionEdit = {}
                        }
                        this.mapOperationStatus = ""
                     }
                  })
               } else {
                  this.mapOperationType = "regiona_planning"
               }
               return
            } else if (this.mapOperationType == "edit_station") {
               this.mapOperationType = ""
               if (this.mapOperationStatus == "pos") {
                  this.ctxDataStr = JSON.stringify([{
                     method: "edit_station_pos",
                     param: undefined
                  }])
               }
               this.$refs.refPopupOperateStation.open("bottom")
            } else if (this.mapOperationType == "add_station") {
               this.mapOperationType = ""
               if (this.stationEdit.stationID) {
                  this.ctxDataStr = JSON.stringify([{
                     method: "remove_station",
                     param: [this.stationEdit]
                  }, {
                     method: "set_selectable",
                     param: true
                  }])
               }
            } else if (this.mapOperationType == "teaching_add_station") {
               this.mapOperationType = "public_teaching"
               this.mapOperationStatus = "teaching"
               if (this.stationEdit.stationID) {
                  this.ctxDataStr = JSON.stringify([{
                     method: "remove_station",
                     param: [this.stationEdit]
                  }])
               }
            } else if (this.mapOperationType == "public_teaching") {
               if (this.mapOperationStatus) {
                  showModal("已记录的路径将会被删除。", "是否要退出示教?").then(async (res) => {
                     if (res) {
                        const listDataStr = []
                        if (this.mapOperationStatus == 'end' || this.mapOperationStatus ==
                           'save') {
                           try {
                              await delTeachingMode(this.vehicleIp, [this.teachingModeCur])
                              listDataStr.push({
                                 method: "remove_teaching_path",
                                 param: {
                                    name: this.teachingModeCur.name,
                                    mode: "Public"
                                 },
                              })
                           } catch (ex) {
                              showError(ex)
                           }
                        }
                        listDataStr.push({
                           method: "teaching_finish",
                        })
                        this.ctxDataStr = JSON.stringify(listDataStr)
                        this.mapOperationType = ""
                     }
                  })
               } else {
                  this.ctxDataStr = JSON.stringify([{
                     method: "teaching_finish",
                  }])
                  this.mapOperationType = ""
               }
            } else {
               const eventChannel = this.getOpenerEventChannel();
               eventChannel.emit('check_connect', !this.unlinked);
               uni.navigateBack({
                  delta: 1
               })
            }
         },
         clickStationList() {
            uni.navigateTo({
               url: `/pages/station/index?ip=${this.vehicleIp}`
            })
         async onCreateSceneOk(name) {
            this.opSceneType = ""
            this.mapOperationType = ""
            await this.loadSceneList()
            if (this.sceneList.length == 1) {
               this.changeMap(this.sceneList[0])
            } else if (this.sceneList.length > 1) {
               this.changeMap(name)
            }
         },
         clickTeachingList() {
            uni.navigateTo({
               url: `/pages/teaching/list?ip=${this.vehicleIp}`
         clickStartConstructScene() {
         },
         clickDownloadScene() {
         },
         menuItemChange(item, type) {
            const _this = this
            this.$refs.refPopupMenu.close()
            if (type == "scene") {
               this.changeMap(item)
            } else if (type == "menu") {
               if (item == "构建场景") {
                  // this.mapOperationType = 'scene_create'
                  // this.opSceneType = 'add_name'
                  uni.navigateTo({
                     url: `/pages/map/scene?ip=${_this.vehicleIp}&opType=create`,
                     events: {
                        // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
                        create_finish: function(data) {
                           _this.onCreateSceneOk(data)
                        },
                     }
                  })
               } else if (item == "地图扩展") {
                  this.clickExtendMap()
               } else if (item == "重命名") {
                  this.clickRename()
               } else if (item == "删除") {
                  this.clickDelete()
               }
            }
         },
         async loadAgvState() {
            try {
               const info = await getAgvState(this.vehicleIp)
               return info
            } catch (ex) {
               showToast(ex)
               return {}
            }
         },
         async loadCurrentTeachingData() {
            try {
               const paths = await getCurrentTeachingData(this.vehicleIp) || []
               return paths
            } catch (ex) {
               showToast(ex)
               return []
            }
         },
         async loadStations() {
            try {
               const info = await stations(this.vehicleIp)
               return info.station_list || []
            } catch (ex) {
               showError(ex)
               return []
            }
         },
         async loadMapInfo(id) {
            try {
               const info = await getMapUrl(this.vehicleIp, id)
               return info
            } catch (ex) {
               showError(ex)
               return {}
            }
         },
         async changeMap(id) {
            this.mapShowAgv = false
            this.setData({
               sceneId: id,
               navigationBarTitle: id || "地图"
            })
            try {
               uni.showLoading({
                  title: "切换场景中"
               })
               this.setData({
                  unlinked: false
               })
               await handoffScene(this.vehicleIp, "", id)
            } catch (ex) {
               this.setData({
                  unlinked: true
               })
               return
            } finally {
               uni.hideLoading()
            }
            try {
               this.setData({
                  bgProgressPercent: 0,
                  bgLoading: true
               })
               const infoAgv = await this.loadAgvState()
               const stationLst = await this.loadStations()
               const infoMap = await this.loadMapInfo(id)
               this.curMapInfo = {
                  proportion: parseInt(infoMap.proportion) || 1,
                  img_proportion: parseInt(infoMap.img_proportion) || 1,
                  max_x: parseInt(infoMap.max_x) || 1,
                  max_y: parseInt(infoMap.max_y) || 1,
                  min_x: parseInt(infoMap.min_x) || 0,
                  min_y: parseInt(infoMap.min_y) || 0,
                  img_x: parseInt(infoMap.img_x) || 1,
                  img_y: parseInt(infoMap.img_y) || 1
               }
               this.setData({
                  bgProgressPercent: 30,
                  bgLoading: infoMap.filedata ? true : false
               })
               this.stationList = stationLst
               this.teachingMode = await this.loadTeachingMode()
               this.ctxDataStr = JSON.stringify([{
                     method: "init",
                     param: {
                        editMode: true
                     }
                  }, {
                     method: "background",
                     param: infoMap
                  },
                  {
                     method: "update_agv_state",
                     param: infoAgv
                  },
                  {
                     method: "add_station",
                     param: stationLst
                  },
                  {
                     method: "show_teaching_path",
                     param: {
                        show: this.showTeachingPathFlag
                     }
                  },
                  {
                     method: "public_teaching_path",
                     param: {
                        list: this.teachingMode.Public || [],
                        show: this.showTeachingPathFlag
                     }
                  },
                  {
                     method: "station_teaching_path",
                     param: {
                        list: this.teachingMode.Stations || [],
                        show: this.showTeachingPathFlag
                     }
                  },
                  {
                     method: "move_pt_center",
                     param: {
                        x: infoAgv.x,
                        y: infoAgv.y
                     }
                  }
               ])
               this.positioningAgv = true
               this.mapShowAgv = true
            } catch (ex) {
               this.setData({
                  bgProgressPercent: 0,
                  bgLoading: false
               })
               showError(ex)
            }
         },
         receiveRenderData(param) {
            console.log('接收到视图层的数据:', param);
            if (param.method === "destroy_complete") {
               if (param.param) {
                  this.destroyFlag = true
                  uni.navigateBack({
                     delta: 1
                  })
               }
            } else if (param.method == "set_backgroud_progress") {
               if (param.type == "start") {
                  this.setData({
                     bgProgressPercent: 50,
                     bgLoading: true
                  })
               } else if (param.type == "progress") {
                  this.setData({
                     bgProgressPercent: 50 + (param.percent || 0) / 2
                  })
               } else if (param.type == "end") {
                  this.setData({
                     bgProgressPercent: 100,
                     bgLoading: true
                  })
                  setTimeout(() => {
                     this.setData({
                        bgLoading: false
                     })
                  }, 500)
               } else if (param.type == "error") {
                  this.setData({
                     bgProgressPercent: 0,
                     bgLoading: false
                  })
               }
            } else if (param.method == "edit_station") {
               this.stationEdit = param.station
               this.stationViewPos = {
                  x: param.view?.x || 0,
                  y: param.view?.y || 0,
                  width: param.view?.width || 0,
                  height: param.view?.height || 0,
               }
               const angle = this.getStantardAngle(this.stationEdit.angle * 180 / Math.PI)
               this.angleSvg = `/static/images/angle${angle}.svg`
               this.mapOperationType = ""
               this.$refs.refPopupOperateStation.open("bottom")
            } else if (param.method == "update_station") {
               this.stationEdit.stationID = param.station?.stationID
               this.stationEdit.angle = param.station.angle
               this.stationEdit.x = param.station.x
               this.stationEdit.y = param.station.y
               this.stationViewPos.x = param.view?.x || 0
               this.stationViewPos.y = param.view?.y || 0
            } else if (param.method == "edit_finish") {
               if (param.cmd == "ok") {
                  if (param.type == "station") {
                     this.mapOperationStatus = ""
                     this.stationEdit.stationID = param.data?.stationID
                     this.stationEdit.name = param.data?.name
                     this.stationEdit.angle = param.data?.angle
                     this.stationEdit.x = param.data?.x
                     this.stationEdit.y = param.data?.y
                     const angle = this.getStantardAngle(this.stationEdit.angle * 180 / Math.PI)
                     this.angleSvg = `/static/images/angle${angle}.svg`
                     if (this.mapOperationType == "teaching_add_station") {
                        this.positioningAgv = true
                     }
                     this.clickStationPositonOk()
                  } else if (param.type == "edit_teaching") {
                     // console.log(param.type,JSON.stringify(param.data))
                     this.removeTeachingModeData(param.data)
                     this.ctxDataStr = JSON.stringify([])
                     this.mapOperationType = ""
                  } else if (param.type == "virtual_wall") {
                     this.wallEdit = param.data
                     this.wallList.push(param.data)
                     this.mapOperationStatus = ""
                  } else if (param.type == "region") {
                     this.regionEdit = param.data
                     this.regionList.push(param.data)
                     this.mapOperationStatus = ""
                  }
               } else if (param.cmd == "cancel") {
                  if (param.type == "edit_teaching") {
                     this.ctxDataStr = JSON.stringify([])
                     this.mapOperationType = ""
                  } else if (this.mapOperationType == "manual_planning") {
                     if (this.mapOperationStatus == "virtual_wall") {
                        this.ctxDataStr = JSON.stringify([{
                           method: "remove_wall",
                           param: [this.wallEdit]
                        }])
                        this.wallEdit = {}
                     } else {
                        this.ctxDataStr = JSON.stringify([{
                           method: "remove_region",
                           param: [this.regionEdit]
                        }])
                        this.regionEdit = {}
                     }
                     this.mapOperationStatus = ""
                  } else if (this.mapOperationType == "teaching_add_station") {
                     this.ctxDataStr = JSON.stringify([{
                        method: "remove_station",
                        param: [{
                           stationID: this.stationEdit.stationID
                        }],
                     }])
                     this.stationEdit.stationID = ""
                     this.mapOperationType = "public_teaching"
                     this.mapOperationStatus = "teaching"
                     this.positioningAgv = true
                  } else if (this.mapOperationType == "edit_station") {
                     this.mapOperationType = ""
                     this.mapOperationStatus = ""
                     if (this.mapOperationStatus == "pos") {
                        this.ctxDataStr = JSON.stringify([{
                           method: "edit_station_pos",
                           param: undefined
                        }])
                     }
                     this.$refs.refPopupOperateStation.open("bottom")
                  } else if (this.mapOperationType == "add_station") {
                     this.mapOperationType = ""
                     this.mapOperationStatus = ""
                     this.ctxDataStr = JSON.stringify([{
                        method: "remove_station",
                        param: [this.stationEdit]
                     }, {
                        method: "set_selectable",
                        param: true
                     }])
                  }
               }
            } else if (param.method == "select_teaching_path") {
               console.log("point", param.point)
               if (param.type == "station") {
                  this.selectTeachingMode = {
                     mode: "Stations",
                     name: param.data?.name || "",
                     src_dst: param.data?.src_dst || "",
                     point: param.point
                  }
               } else if (param.type == "public") {
                  this.selectTeachingMode = {
                     mode: "Public",
                     edge_name: param.data?.edge_name || "",
                     name: param.data?.name || "",
                     point: param.point,
                     main_road: param.data?.main_road || 0,
                     bidirection: param.data?.bidirection || 0,
                  }
                  console.log(this.selectTeachingMode.main_road, this.selectTeachingMode)
               }
               this.$refs.refPopupOperateTeaching.open("bottom")
            } else if (param.method == "cancel_positioning_agv") {
               if (this.mapOperationType == "public_teaching" &&
                  this.mapOperationStatus == "teaching") {
                  this.positioningAgv = true
               } else
                  this.positioningAgv = false
            } else if (param.method == "show_log") {
               const listLog = session.getValue("request_log") || []
               listLog.unshift(param.data)
               session.setValue("request_log", listLog)
            }
         },
         clickMapStation() {
            uni.navigateTo({
               url: `/pages/station/index?ip=${this.vehicleIp}&isAdd=1`
            })
            this.stationEdit = {
               stationID: "",
               name: "",
               x: 0,
               y: 0,
               angle: 0,
            }
            this.mapOperationType = "add_station"
            this.mapOperationStatus = ""
         },
         clickAddStation() {
            this.stationEdit = {
               stationID: "",
               name: "",
               x: 0,
               y: 0,
               angle: 0,
            }
            this.mapOperationType = "teaching_add_station"
            this.mapOperationStatus = ""
         },
         clickMapEdit() {
            this.mapOperationType = "edit_map"
         },
         clickExtendMap() {
            const _this = this
            uni.navigateTo({
               url: `/pages/map/edit?ip=${this.vehicleIp}`
               url: `/pages/map/scene?ip=${this.vehicleIp}&opType=extend&sceneId=${this.sceneId}`,
               events: {
                  // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
                  create_finish: function(data) {
                     _this.onCreateSceneOk(data)
                  },
               }
            })
         },
         clickMapTask() {
            uni.navigateTo({
               url: `/pages/map/task?ip=${this.vehicleIp}`
               url: `/pages/task/list?ip=${this.vehicleIp}`
            })
         },
         clickTeaching() {
            this.mapOperationStatus = ""
            this.teachingModeCur = {
               mode: "Public",
               mode_type: 0,
            }
            this.positioningAgv = true
            this.mapOperationType = "public_teaching"
            this.ctxDataStr = JSON.stringify([{
               method: "public_teaching",
            }])
         showError(ex) {
            let exStr = JSON.stringify(ex)
            if (exStr == "{}")
               exStr = ex
            let tip = typeof ex.msg == "string" ? ex.msg : exStr
            showModal(tip, "错误", false)
            // uni.navigateTo({
            //    url: `/pages/map/teaching?ip=${this.vehicleIp}&sceneId=${this.sceneId}&list=${JSON.stringify(this.sceneList)}`
            // })
         },
         clickRegionaPlan() {
            this.mapOperationType = "regiona_planning"
         },
         clickRename() {
            this.sceneInputName = this.sceneId
            this.mapOperationType = 'edit_scene_name'
         },
         async loadSceneList() {
            try {
               const _this = this
               const res = await getAllScene(this.vehicleIp) || []
               const list = res?.sceneList || []
               this.setData({
                  unlinked: false
               })
               getApp().globalData.sceneList = list
               this.sceneList = list
               if (list.length === 0) {
                  this.opSceneType = ''
                  // this.mapOperationType = 'scene_create'
                  // this.setData({
                  //    sceneId: "",
                  //    navigationBarTitle: "地图"
                  // })
                  // uni.navigateTo({
                  //    url: `/pages/map/scene?ip=${this.vehicleIp}`,
                  //    events: {
                  //       // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
                  //       create_finish: function(data) {
                  //          _this.onCreateSceneOk(data)
                  //       },
                  //    }
                  // })
                  uni.navigateBack({
                     delta: 1, //返回层数,2则上上页
                  })
                  return
               }
            } catch (ex) {
               showError(ex)
            }
         },
         clickDelete() {
            const _this = this
            showModal(`删除场景[${this.sceneId}]会把场景对应的地图任务信息都会删除,是否确认删除?`, "删除场景").then(async (res) => {
               if (res) {
                  try {
                     uni.showLoading({
                        title: "删除场景中"
                     })
                     this.mapShowAgv = false
                     await delScene(this.vehicleIp, this.sceneId)
                     await this.loadSceneList()
                     if (this.sceneList.length > 0)
                        this.changeMap(this.sceneList[0])
                     // else {
                     //    _this.mapOperationType = ""
                     //    setTimeout(() => {
                     //       uni.navigateBack({
                     //          delta: 1, //返回层数,2则上上页
                     //       })
                     //    }, 500)
                     // }
                  } catch (ex) {
                     showError(ex)
                  } finally {
                     uni.hideLoading()
                  }
               }
            })
         },
         clickManualPlan() {
            this.mapOperationType = "manual_planning"
            this.mapOperationStatus = ""
         },
         clickVehicleTrajectoryPlan() {
            this.mapOperationType = "vehicle_trajectory_planning"
            this.mapOperationStatus = ""
         },
         async clickPlanFeasibleRegion() {
            try {
               this.mapOperationStatus = "feasible_region"
               if (this.mapOperationType == "manual_planning") {
                  const agv = await this.loadAgvState()
                  const offset = 0.1 * this.curMapInfo.img_proportion
                  this.regionEdit = {
                     id: `region_${new Date().getTime()}`,
                     color: "#71d13c",
                     type: "feasible_region",
                     path: [{
                           x: agv.x - offset,
                           y: agv.y - offset
                        }, {
                           x: agv.x - offset,
                           y: agv.y + offset
                        }, {
                           x: agv.x + offset,
                           y: agv.y + offset
                        },
                        {
                           x: agv.x + offset,
                           y: agv.y - offset
                        }
                     ]
                  }
                  this.ctxDataStr = JSON.stringify([{
                        method: "update_agv_state",
                        param: agv
                     }, {
                        method: "add_region",
                        param: [this.regionEdit]
                     },
                     {
                        method: "move_pt_center",
                        param: {
                           x: agv.x,
                           y: agv.y
                        }
                     }
                  ])
               }
            } catch (ex) {
               showError(ex)
            }
         },
         async clickPlanProhibitionRegion() {
            try {
               this.mapOperationStatus = "prohibition_region"
               if (this.mapOperationType == "manual_planning") {
                  const agv = await this.loadAgvState()
                  const offset = 0.1 * this.curMapInfo.img_proportion
                  this.regionEdit = {
                     id: `region_${new Date().getTime()}`,
                     color: "#ff4d4f",
                     type: "prohibition_region",
                     path: [{
                           x: agv.x - offset,
                           y: agv.y - offset
                        }, {
                           x: agv.x - offset,
                           y: agv.y + offset
                        }, {
                           x: agv.x + offset,
                           y: agv.y + offset
                        },
                        {
                           x: agv.x + offset,
                           y: agv.y - offset
                        }
                     ]
                  }
                  this.ctxDataStr = JSON.stringify([{
                        method: "update_agv_state",
                        param: agv
                     }, {
                        method: "add_region",
                        param: [this.regionEdit]
                     },
                     {
                        method: "move_pt_center",
                        param: {
                           x: agv.x,
                           y: agv.y
                        }
                     }
                  ])
               }
            } catch (ex) {
               showError(ex)
            }
         },
         async clickPlanVirtualWall() {
            try {
               const agv = await this.loadAgvState()
               const offset = 0.1 * this.curMapInfo.img_proportion
               this.mapOperationStatus = "virtual_wall"
               this.wallEdit = {
                  id: `wall_${new Date().getTime()}`,
                  color: "#ff4d4f",
                  type: "virtual_wall",
                  path: [{
                        x: agv.x,
                        y: agv.y - offset
                     },
                     {
                        x: agv.x + offset,
                        y: agv.y + offset
                     }
                  ]
               }
               this.ctxDataStr = JSON.stringify([{
                     method: "update_agv_state",
                     param: agv
                  }, {
                     method: "add_wall",
                     param: [this.wallEdit]
                  },
                  {
                     method: "move_pt_center",
                     param: {
                        x: agv.x,
                        y: agv.y
                     }
                  }
               ])
            } catch (ex) {
               showError(ex)
            }
         },
         clickNameCancel() {
            this.mapOperationType = ''
         },
         async clickNameOK() {
            try {
               uni.showLoading({
                  title: "更新场景名称"
               })
               this.loading = true
               const name = this.sceneInputName.trim()
               if (!name) {
                  showToast("场景名称不能为空!")
                  return
               }
               // console.log(name, this.sceneId)
               if (name == this.sceneId) {
                  showToast("场景名称未变化!")
                  return
               }
               const curIndex = this.sceneList.findIndex((param) => param == this.sceneId)
               this.mapOperationType = ""
               await updateScene(this.vehicleIp, this.sceneId, name)
               this.sceneId = name
               if (curIndex > -1) {
                  this.sceneList[curIndex] = name
               }
               this.setData({
                  navigationBarTitle: name
               })
               showToast("场景重命名成功!")
            } catch (ex) {
               this.mapOperationType = "edit_scene_name"
               showError(ex)
            } finally {
               uni.hideLoading()
               this.loading = false
            }
         },
         clickClearName() {
            this.showClearName = false
            this.sceneInputName = ""
         },
         onInputName(event) {
            this.sceneInputName = event.detail.value.trim();
            if (this.sceneInputName)
               this.showClearName = true
            else
               this.showClearName = false
         },
         closePopuBtn() {
            this.ctxDataStr = JSON.stringify([{
               method: "set_selectable",
               param: true
            }])
            this.mapOperationType = ""
         },
         clickStationDelete() {
            const _this = this
            uni.navigateTo({
               url: `/pages/station/delete?ip=${ this.vehicleIp}`,
               events: {
                  // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
                  delete_finish: function(data) {
                     console.log(data)
                     const list = data.map((a) => {
                        return {
                           stationID: a
                        }
                     })
                     _this.ctxDataStr = JSON.stringify([{
                        method: "remove_station",
                        param: list
                     }])
                  }
               }
            })
            //this.stationDelete(this.stationEdit)
            // const _this = this
            // showModal("该站点已绑定任务,删除站点后绑定的任务会停止并删除", "是否确认删除?").then((res) => {
            //    if (res) {
            //    }
            // })
         },
         async stationAdd(item) {
            try {
               uni.showLoading({
                  title: "正在新建站点"
               })
               await addStation(this.vehicleIp, item)
               await updateStation(this.vehicleIp, item)
               this.stationList.push({
                  stationID: item.stationID,
                  name: item.name,
                  angle: item.angle,
                  x: item.y,
                  y: item.x
               })
            } catch (ex) {
               showError(ex)
            } finally {
               uni.hideLoading()
            }
         },
         async stationUpdate(item) {
            try {
               uni.showLoading({
                  title: "正在更新站点"
               })
               await updateStation(this.vehicleIp, item)
               const curIndex = this.stationList.findIndex((a) => a.stationID ==
                  item
                  .stationID)
               if (curIndex > -1) {
                  const station = this.stationList[curIndex]
                  station.name = item.name
                  station.angle = item.angle
                  station.x = item.y
                  station.y = item.x
               }
            } catch (ex) {
               showError(ex)
            } finally {
               uni.hideLoading()
            }
         },
         async clickStationPositonOk() {
            try {
               if (this.mapOperationType == "add_station") {
                  this.stationAdd(this.stationEdit)
               } else if (this.mapOperationType == "teaching_add_station") {
                  this.stationAdd(this.stationEdit)
                  this.mapOperationType = "public_teaching"
                  this.mapOperationStatus = "teaching"
                  this.positioningAgv = true
                  return
               } else if (this.mapOperationType == "edit_station") {
                  this.stationUpdate(this.stationEdit)
               }
               this.ctxDataStr = JSON.stringify([{
                  method: "set_selectable",
                  param: true
               }])
               this.mapOperationType = ''
            } catch (ex) {
               showError(ex)
            }
         },
         async stationDelete(item) {
            try {
               uni.showLoading({
                  title: "正在删除站点"
               })
               this.$refs.refPopupOperateStation.close()
               await delStation(this.vehicleIp, [item.stationID])
               const curIndex = this.stationList.findIndex((a) => a
                  .stationID == item.stationID)
               if (curIndex > -1) {
                  this.stationList.splice(curIndex, 1)
               }
               this.mapOperationType = ""
               this.ctxDataStr = JSON.stringify([{
                  method: "remove_station",
                  param: [item]
               }, {
                  method: "set_selectable",
                  param: true
               }])
            } catch (ex) {
               showError(ex)
            } finally {
               uni.hideLoading()
            }
         },
         clickStationPostion() {
            this.mapOperationType = "edit_station"
            this.mapOperationStatus = "pos"
            this.$refs.refPopupOperateStation.close()
            this.ctxDataStr = JSON.stringify([{
               method: "edit_station_pos",
               param: this.stationEdit
            }])
         },
         clickStationRename() {
            this.mapOperationType = "edit_station"
            this.mapOperationStatus = ""
            this.$refs.refPopupOperateStation.close()
         },
         clickStationNameCancel() {
            if (this.mapOperationType == "edit_station") {
               this.ctxDataStr = JSON.stringify([{
                  method: "set_selectable",
                  param: true
               }])
               this.mapOperationType = ""
               this.$refs.refPopupOperateStation.open("bottom")
            } else if (this.mapOperationType == "add_station") {
               this.mapOperationType = ""
               this.ctxDataStr = JSON.stringify([{
                  method: "set_selectable",
                  param: true
               }])
            } else if (this.mapOperationType == "teaching_add_station") {
               this.mapOperationType = "public_teaching"
               this.mapOperationStatus = "teaching"
            }
         },
         async clickStationNameOK() {
            try {
               const name = this.stationEdit.name.trim()
               if (!name) {
                  showToast("站点名称还未输入")
                  return
               }
               this.loading = true
               if (this.mapOperationType == 'add_station' || this.mapOperationType == "teaching_add_station") {
                  const agv = await this.loadAgvState()
                  this.stationEdit = {
                     stationID: this.getMaxStationNo + 1,
                     name: name,
                     x: agv.x || 0,
                     y: agv.y || 0,
                     angle: agv.angle || 0,
                  }
                  const angle = this.getStantardAngle(this
                     .stationEdit.angle * 180 / Math.PI)
                  this.angleSvg = `/static/images/angle${angle}.svg`
                  this.ctxDataStr = JSON.stringify([{
                     method: "update_agv_state",
                     param: agv
                  }, {
                     method: "update_station",
                     param: [this.stationEdit]
                  }, {
                     method: "edit_station_pos",
                     param: this.stationEdit
                  }, {
                     method: "move_pt_center",
                     param: {
                        x: agv.x,
                        y: agv.y
                     }
                  }])
                  this.mapOperationStatus = "pos"
               } else if (this.mapOperationType ==
                  'edit_station') {
                  this.stationEdit.name = name
                  await updateStation(this.vehicleIp, this
                     .stationEdit)
                  this.ctxDataStr = JSON.stringify([{
                     method: "update_station",
                     param: [this.stationEdit]
                  }, {
                     method: "set_selectable",
                     param: true
                  }])
                  this.mapOperationStatus = "pos"
                  this.$refs.refPopupOperateStation.open("bottom")
               }
            } catch (ex) {
               showError(ex)
            } finally {
               this.loading = false
            }
         },
         clickClearStationName() {
            this.stationEdit.name = ""
            this.showClearName = false
         },
         onInputStationName(event) {
            this.stationEdit.name = event.detail.value.trim();
            if (this.stationEdit.name)
               this.showClearName = true
            else
               this.showClearName = false
         },
         onInputStationX(event) {
            console.log(event)
            this.stationEdit.x = Number(event.detail.value);
            console.log(this.stationEdit.x)
            this.ctxDataStr = JSON.stringify([{
               method: "update_station",
               param: [this.stationEdit]
            }, {
               method: "move_pt_center",
               param: {
                  x: this.stationEdit.x,
                  y: this.stationEdit.y
               }
            }])
         },
         onInputStationY(event) {
            this.stationEdit.y = Number(event.detail.value);
            console.log(this.stationEdit.y)
            this.ctxDataStr = JSON.stringify([{
               method: "update_station",
               param: [this.stationEdit]
            }, {
               method: "move_pt_center",
               param: {
                  x: this.stationEdit.x,
                  y: this.stationEdit.y
               }
            }])
         },
         clickClearStationX() {
            this.stationEdit.x = 0
            this.ctxDataStr = JSON.stringify([{
               method: "update_station",
               param: [this.stationEdit]
            }, {
               method: "move_pt_center",
               param: {
                  x: this.stationEdit.x,
                  y: this.stationEdit.y
               }
            }])
         },
         clickClearStationY() {
            this.stationEdit.y = 0
            this.ctxDataStr = JSON.stringify([{
               method: "update_station",
               param: [this.stationEdit]
            }, {
               method: "move_pt_center",
               param: {
                  x: this.stationEdit.x,
                  y: this.stationEdit.y
               }
            }])
         },
         getStantardAngle(angle) {
            let resAngle = 0
            if (angle < -157.5) {
               resAngle = 180
            } else if (angle < -112.5) {
               resAngle = -135
            } else if (angle < -67.5) {
               resAngle = -90
            } else if (angle < -22.5) {
               resAngle = -45
            } else if (angle < 22.5) {
               resAngle = 0
            } else if (angle < 67.5) {
               resAngle = 45
            } else if (angle < 112.5) {
               resAngle = 90
            } else if (angle < 157.5) {
               resAngle = 135
            } else if (angle <= 180) {
               resAngle = 180
            } else {
               resAngle = 0
            }
            return resAngle
         },
         touchAngleChange(e) {
            let angle = 0
            const ptX = e.touches[0].clientX
            const offX = ptX // ptX - e.target.offsetLeft
            const offW = 300 / 16
            const centerPt = this.windowWidth / 2
            if (offX < centerPt - 8 * offW) {
               return
            } else if (offX < centerPt - 7 * offW) {
               angle = 180
            } else if (offX < centerPt - 5 * offW) {
               angle = -135
            } else if (offX < centerPt - 3 * offW) {
               angle = -90
            } else if (offX <= centerPt - offW) {
               angle = -45
            } else if (offX < centerPt + offW) {
               angle = 0
            } else if (offX < centerPt + 3 * offW) {
               angle = 45
            } else if (offX < centerPt + 5 * offW) {
               angle = 90
            } else if (offX < centerPt + 7 * offW) {
               angle = 135
            } else if (offX <= centerPt + 8 * offW) {
               angle = 180
            } else {
               return
            }
            this.stationEdit.angle = angle * Math.PI / 180
            this.angleSvg = `/static/images/angle${angle}.svg`
            this.ctxDataStr = JSON.stringify([{
               method: "update_station",
               param: [this.stationEdit]
            }])
         },
         handleAngleTouchStart(e) {
            //   console.log("handleAngleTouchStart", e)
            this.touchAngleChange(e)
         },
         handleAngleTouchMove(e) {
            //   console.log("handleAngleTouchMove", e)
            this.touchAngleChange(e)
         },
         async clickVehiclePosition() {
            try {
               this.positioningAgv = true
               const infoAgv = await this.loadAgvState()
               this.ctxDataStr = JSON.stringify([{
                  method: "update_agv_state",
                  param: infoAgv
               }, {
                  method: "move_pt_center",
                  param: {
                     x: infoAgv.x,
                     y: infoAgv.y
                  }
               }])
            } catch (ex) {
               showError(ex)
            }
         },
         async clickPositionStation() {
            try {
               const infoAgv = await this.loadAgvState()
               this.stationEdit.x = infoAgv.x
               this.stationEdit.y = infoAgv.y
               this.stationEdit.angle = infoAgv.angle
               const angle = this.getStantardAngle(this
                  .stationEdit.angle * 180 / Math.PI)
               console.log(this.stationEdit.angle, angle, this
                  .angleSvg)
               this.angleSvg =
                  `/static/images/angle${angle}.svg`
               this.ctxDataStr = JSON.stringify([{
                     method: "update_agv_state",
                     param: infoAgv
                  }, {
                     method: "update_station",
                     param: [this.stationEdit]
                  },
                  {
                     method: "move_pt_center",
                     param: {
                        x: infoAgv.x,
                        y: infoAgv.y
                     }
                  }
               ])
            } catch (ex) {
               showError(ex)
            }
         },
         async loadTeachingMode() {
            try {
               const {
                  data
               } = await splitTeachingMode(this.vehicleIp)
               return data || {
                  Public: [],
                  Stations: []
               }
            } catch (ex) {
               showError(ex)
               return {
                  Public: [],
                  Stations: []
               }
            }
         },
         async reloadTeachingMode(finish) {
            try {
               this.teachingMode = await this.loadTeachingMode()
               const list = [{
                     method: "clear_teaching_path",
                  },
                  {
                     method: "public_teaching_path",
                     param: {
                        list: this.teachingMode.Public || [],
                        show: this.showTeachingPathFlag
                     }
                  },
                  {
                     method: "station_teaching_path",
                     param: {
                        list: this.teachingMode.Stations || [],
                        show: this.showTeachingPathFlag
                     }
                  }
               ]
               if (finish) {
                  list.push({
                     method: "teaching_finish",
                  })
               }
               this.ctxDataStr = JSON.stringify(list)
            } catch (ex) {
               showError(ex)
            }
         },
         async clickShowTeachingPath() {
            try {
               if (this.showTeachingPathFlag) {
                  this.ctxDataStr = JSON.stringify([{
                     method: "show_teaching_path",
                     param: {
                        show: false
                     }
                  }])
                  this.showTeachingPathFlag = false
                  return
               }
               this.showTeachingPathFlag = true
               //this.teachingMode = await this.loadTeachingMode()
               this.ctxDataStr = JSON.stringify([
                  // {
                  //    method: "clear_teaching_path",
                  // },
                  // {
                  //    method: "public_teaching_path",
                  //    param: this.teachingMode
                  //       .Public || []
                  // },
                  // {
                  //    method: "station_teaching_path",
                  //    param: this.teachingMode
                  //       .Stations || []
                  // },
                  {
                     method: "show_teaching_path",
                     param: {
                        show: true
                     }
                  }
               ])
            } catch (ex) {
               showError(ex)
            }
         },
         async refreshAgvPosition() {
            try {
               if (this.isPageVisible && this.mapShowAgv) {
                  const agv = await this.loadAgvState()
                  const listCtrData = [{
                     method: "update_agv_state",
                     param: agv
                  }]
                  // if (this.mapOperationType === "public_teaching" && this.mapOperationStatus ===
                  //    "teaching") {
                  const list = await this.loadCurrentTeachingData()
                  listCtrData.push({
                     method: "update_current_teaching",
                     param: {
                        main_road: 1, //this.teachingModeCur.main_road,
                        pos_list: list
                     }
                  })
                  if (list.length > 0) {
                     this.curTeachingPathTime += 1
                     this.curTeachingPathFlag = true
                     if (this.curTeachingPathTime % 5 == 0) {
                        const listStationCtxData = await this.getRefreshStationCtxData() || []
                        if (listStationCtxData.length > 0) {
                           listCtrData.push(...listStationCtxData)
                        }
                     }
                  } else {
                     if (this.curTeachingPathFlag) {
                        this.curTeachingPathFlag = false
                        this.curTeachingPathTime = 0
                        const teaching = await this.loadTeachingMode()
                        const publicOld = this.teachingMode.Public || []
                        const stationOld = this.teachingMode.Stations || []
                        const publicNew = teaching.Public || []
                        const stationNew = teaching.Stations || []
                        const publicAdd = []
                        const stationAdd = []
                        for (let i in publicNew) {
                           const item = publicNew[i]
                           const curIndex = publicOld.findIndex((a) => a.name == item.name && a.edge_name == item.edge_name )
                           if (curIndex < 0) {
                              publicAdd.push(item)
                              publicOld.push(item)
                           }
                        }
                        for (let i in stationNew) {
                           const item = stationNew[i]
                           const curIndex = stationOld.findIndex((a) => a.name == item.name)
                           if (curIndex < 0) {
                              stationAdd.push(item)
                              stationOld.push(item)
                           }
                        }
                        this.teachingMode.Public = publicOld
                        this.teachingMode.Stations = stationOld
                        if (publicAdd.length > 0) {
                           listCtrData.push({
                              method: "public_teaching_path",
                              param: {
                                 list: publicAdd,
                                 show: this.showTeachingPathFlag
                              }
                           })
                        }
                        if (stationAdd.length > 0) {
                           listCtrData.push({
                              method: "station_teaching_path",
                              param: {
                                 list: stationAdd,
                                 show: this.showTeachingPathFlag
                              }
                           })
                        }
                        const listStationCtxData = await this.getRefreshStationCtxData() || []
                        if (listStationCtxData.length > 0) {
                           listCtrData.push(...listStationCtxData)
                        }
                     }
                  }
                  // }
                  if (this.positioningAgv) {
                     if (this.curTeachingPathFlag) {
                        listCtrData.push({
                           method: "move_pt_center",
                           param: {
                              x: agv.x,
                              y: agv.y,
                           }
                        })
                     } else {
                        listCtrData.push({
                           method: "move_pt_visible",
                           param: {
                              x: agv.x,
                              y: agv.y,
                              width: 80,
                              height: 80,
                           }
                        })
                     }
                  }
                  this.ctxDataStr = JSON.stringify(listCtrData)
               }
               //setTimeout(this.refreshAgvPosition, 1000);
            } catch (ex) {
               // showError(ex).then((res) => {
               // })
               showToast(ex)
            } finally {
               // 无论成功失败,1 秒后再来
               setTimeout(this.refreshAgvPosition, 1000);
            }
         },
         async getRefreshStationCtxData() {
            try {
               const listCtrData = []
               const listOld = this.stationList
               const listId = listOld.map((a) => a.stationID)
               const stationLst = await this.loadStations()
               const listNew = stationLst.filter((a) => {
                  return !listId.includes(a.stationID)
               })
               // console.log(listId.length,listNew.length,stationLst.length)
               // console.log(listId)
               if (listId.length + listNew.length > stationLst.length) {
                  const listId2 = stationLst.map((a) => a.stationID)
                  const listRemove = listOld.filter((a) => {
                     return !listId2.includes(a.stationID)
                  })
                  if (listRemove.length > 0) {
                     listCtrData.push({
                        method: "remove_station",
                        param: listRemove
                     })
                     this.stationList = stationLst
                  }
               }
               if (listNew.length > 0) {
                  listCtrData.push({
                     method: "add_station",
                     param: listNew
                  })
                  this.stationList = stationLst
               }
               return listCtrData
            } catch (ex) {
               showToast(ex)
               return []
            }
         },
         askTeachingBiDirection(teachingMode) {
            showModal("选择当前示教路线类型?", "示教结束", true, "双向路线",
               "单向路线").then((res) => {
               if (res) {
                  teachingMode.bidirection = "1"
               } else {
                  teachingMode.bidirection = "0"
               }
               teachingMode.teaching_flag = 0
               this.finishTeaching(teachingMode)
            })
         },
         async finishTeaching(teachingMode) {
            try {
               uni.showLoading({
                  title: "示教结束"
               })
               await teachingModeFlag(this.vehicleIp, teachingMode)
               this.mapOperationStatus = "end"
            } catch (ex) {
               showError(ex)
            } finally {
               uni.hideLoading()
            }
         },
         async clickTeachingStart() {
            const _this = this
            try {
               uni.showLoading({
                  title: "示教开始"
               })
               this.loading = false
               this.mapOperationStatus = "teaching"
               await _this.teachingStart("Public")
            } catch (ex) {
               showError(ex)
            } finally {
               this.loading = false
               uni.hideLoading()
            }
         },
         clickTeachingEnd() {
            if (this.mapOperationType ==
               "station_teaching") {
               this.teachingEnd("Stations")
            } else {
               this.teachingEnd("Public")
            }
         },
         clickTeachingReset() {
            const _this = this
            showModal("已记录的路径将会被删除。", "是否要重新记录?")
               .then(async (res) => {
                  if (res) {
                     try {
                        this.loading = true
                        await delTeachingMode(_this.vehicleIp, [_this.teachingModeCur])
                        _this.mapOperationStatus = ""
                        const listDataStr = []
                        listDataStr.push({
                           method: "remove_teaching_path",
                           param: {
                              name: _this.teachingModeCur.name,
                              mode: "Public"
                           },
                        })
                        _this.ctxDataStr = JSON.stringify(listDataStr)
                     } catch (ex) {
                        showError(ex)
                     } finally {
                        this.loading = false
                     }
                  } else {
                     _this.mapOperationStatus = "save"
                  }
               })
         },
         async clickTeachingSave() {
            this.mapOperationStatus = "save"
            try {} catch (ex) {
               showError(ex)
            }
         },
         clickTeachingFinish() {
            this.mapOperationType = ""
            //this.reloadTeachingMode(true)
         },
         async teachingStart(mode) {
            try {
               /*if (mode == "Stations") {
                  const res = await checkAgvLocationDistanceError(this.vehicleIp, this.startStationID)
                  if (res?.error) {
                     this.calibratioStationType = "start"
                     this.$refs.refPopupCalibration.open()
                  } else {
                     // const name =
                     //    `${ this.stationName(this.startStationID)}_${ this.stationName(this.endStationID)}`
                     this.teachingModeCur = {
                        mode: "Stations",
                        src_dst: `${this.startStationID}_${this.endStationID}`,
                        name: "",
                        teaching_flag: 1,
                     }
                     this.ctxDataStr = JSON.stringify([{
                        method: "set_selectable",
                        param: false,
                     }])
                     const res2 = await teachingModeFlag(this.vehicleIp, this.teachingModeCur)
                     if (res2?.name)
                        this.teachingModeCur.name = res2.name
                  }
               } else {*/
               const mode_type = this
                  .teachingModeCur
                  .mode_type
               this.teachingModeCur = {
                  mode: "Public",
                  src_dst: ``,
                  name: "",
                  teaching_flag: 1,
                  mode_type
               }
               const res2 =
                  await teachingModeFlag(
                     this.vehicleIp,
                     this.teachingModeCur)
               if (res2?.name) {
                  this.teachingModeCur.name = res2.name
               }
            } catch (ex) {
               showError(ex)
            }
         },
         async teachingEnd(mode) {
            try {
               this.loading = true
               // if (mode == "Stations") {
               //    const res = await checkAgvLocationDistanceError(this.vehicleIp, this.endStationID)
               //    if (res.error) {
               //       this.calibratioStationType = "end"
               //       this.$refs.refPopupCalibration.open()
               //    } else {
               //       this.askTeachingBiDirection(this.teachingModeCur)
               //    }
               // } else {
               //    this.askTeachingBiDirection(this.teachingModeCur)
               // }
               // this.askTeachingBiDirection(
               //    this
               //    .teachingModeCur
               // )
               this.teachingModeCur.teaching_flag = 0
               await this.finishTeaching(this.teachingModeCur)
            } catch (ex) {
               showError(ex)
            } finally {
               this.loading = false
            }
         },
         async onTeachingModeType(val) {
            try {
               if (this.mapOperationStatus) {
                  if (this.teachingModeCur.mode_type == val) {
                     return
                  }
                  this.teachingModeCur.teaching_flag = 0
                  const oldName = this.teachingModeCur.name
                  await teachingModeFlag(this.vehicleIp, this.teachingModeCur)
                  this.teachingModeCur.mode_type = val
                  this.teachingModeCur.teaching_flag = 1
                  this.teachingModeCur.mode = "Public"
                  this.teachingModeCur.name = ""
                  const res = await teachingModeFlag(this.vehicleIp, this
                     .teachingModeCur)
                  if (val == 1)
                     showToast("已将示教切换成双向模式")
                  else if (val == 2)
                     showToast("已将示教切换成智能模式")
                  else
                     showToast("已将示教切换成默认模式")
                  /*if (val == 0)
                     showToast(
                        "已将该路段路径保存为主路示教路线"
                     )
                  else
                     showToast(
                        "已将该路段路径保存为支路示教路线"
                     )
                  if (res?.name)
                     this.teachingModeCur.name = res.name
                  const {
                     data
                  } = await splitTeachingMode(this.vehicleIp)
                  const publicList = data.Public || []
                  const curIndex = publicList.findIndex((a) => a.name == oldName)
                  if (curIndex > -1) {
                     this.ctxDataStr = JSON.stringify([{
                        method: "public_teaching_path",
                        param: {
                           list: [publicList[curIndex]],
                           show: true
                        }
                     }])
                  }
*/
               } else {
                  this.teachingModeCur.mode_type = val
               }
            } catch (ex) {
               showError(ex)
            }
         },
         clickTeachingDelete() {
            this.$refs
               .refPopupOperateTeaching
               .close()
            this.removeTeachingMode(
               this
               .selectTeachingMode
            )
         },
         clickTeachingEdit() {
            this.$refs.refPopupOperateTeaching.close()
            this.$refs.refPopupTeachingUpdate.open("")
            // this.mapOperationType =
            //    "edit_teaching"
            // this.ctxDataStr = JSON
            //    .stringify([{
            //       method: "edit_teaching",
            //       param: this.selectTeachingMode,
            //    }])
         },
         radioTeachinMainRoadChange(evt) {
            this.selectTeachingMode.main_road = evt.detail.value
         },
         radioTeachinBidirectionChange(evt) {
            this.selectTeachingMode.bidirection = evt.detail.value
         },
         async dialogTeachingUpdateConfirm() {
            try {
               uni.showLoading({
                  title: "更新示教中"
               })
               const item = this.selectTeachingMode
               await updateSplitTeachingData(this.vehicleIp, item)
               this.ctxDataStr =
                  JSON.stringify(
                     [{
                        method: "update_teaching",
                        param: item,
                     }])
               this.selectTeachingMode = {}
               showToast("更新示教成功")
            } catch (ex) {
               showError(
                  ex)
            } finally {
               uni.hideLoading()
            }
         },
         dialogTeachingUpdateClose() {
            this.$refs.refPopupTeachingUpdate.close()
         },
         async removeTeachingMode(item) {
            try {
               uni.showLoading({
                  title: "删除示教中"
               })
               await deleteSplitTeachingData(this.vehicleIp, item
                  .edge_name, item.name)
               //await delTeachingMode(this.vehicleIp, [item])
               this.ctxDataStr =
                  JSON.stringify(
                     [{
                        method: "remove_teaching_path",
                        param: item,
                     }])
               showToast("删除示教成功")
            } catch (ex) {
               showError(
                  ex)
            } finally {
               uni.hideLoading()
            }
         },
         async removeTeachingModeData(data) {
            try {
               uni.showLoading({
                  title: "删除示教数据中"
               })
               await delTeachingModeData(this.vehicleIp, data)
               showToast("删除示教成功")
               this.reloadTeachingMode()
            } catch (ex) {
               showError(ex)
            } finally {
               uni.hideLoading()
            }
         },
      }
   }
@@ -208,6 +2606,7 @@
         left: 0;
         right: 0;
         bottom: 0;
         background-color: #ddd;
         display: flex;
         flex-direction: column;
      }
@@ -217,6 +2616,174 @@
         display: flex;
         flex: 1;
         margin: auto;
         flex-direction: column;
         align-items: center;
         justify-content: center;
         .loading-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 999;
            .loading-content {
               background-color: #fff;
               padding: 60rpx 100rpx;
               border-radius: 20rpx;
               text-align: center;
            }
            .loading-spinner {
               width: 120rpx;
               height: 120rpx;
               border: 20rpx solid #f3f3f3;
               border-top: 20rpx solid #1890FF;
               border-radius: 50%;
               animation: spin 1s linear infinite;
               margin: 0 auto 40rpx;
            }
            @keyframes spin {
               0% {
                  transform: rotate(0deg);
               }
               100% {
                  transform: rotate(360deg);
               }
            }
         }
         .content {
            overflow: auto;
            position: absolute;
            left: 0;
            right: 0;
            bottom: 0;
            top: 0;
            .fabric {
               width: 100%;
               height: 100%;
               background-color: #fff;
            }
         }
         .position {
            position: absolute;
            right: 50rpx;
            bottom: 500rpx;
            .img {
               width: 65rpx;
               height: 65rpx;
            }
            .ico {
               font-size: 65rpx;
               color: #1890FF;
            }
         }
         .position-site {
            display: flex;
            position: absolute;
            margin: 2rpx;
            right: 40rpx;
            bottom: 500rpx;
            flex-direction: row;
            padding: 10rpx;
            border-radius: 10rpx;
            background-color: #fff;
            border: 2rpx solid #1890FF;
            justify-content: center;
            align-items: center;
            color: #1890FF;
            font-size: 32rpx;
            .img {
               width: 40rpx;
               height: 40rpx;
               margin: 0 10rpx;
            }
            .ico {
               font-size: 40rpx;
               color: #1890FF;
            }
         }
         .station-info {
            display: flex;
            position: absolute;
            flex-direction: row;
            border-radius: 10rpx;
            background-color: #fff;
            border: 1px solid #1890FF;
            font-size: 15px;
            .left {
               display: flex;
               flex-direction: column;
               width: 180rpx;
               color: #aaa;
               .line {
                  padding: 15rpx 5rpx 15rpx 10rpx;
               }
            }
            .right {
               display: flex;
               flex-direction: column;
               .line {
                  padding: 15rpx 10rpx 15rpx 5rpx;
                  text-align: right;
               }
            }
         }
         .teaching-path-show {
            position: absolute;
            right: 50rpx;
            top: 200rpx;
            padding: 12rpx;
            border: 1px solid #1890FF;
            border-radius: 36rpx;
            width: 72rpx;
            height: 72rpx;
            background-color: #fff;
            .ico {
               font-size: 40rpx;
               color: #1890FF;
            }
         }
         .selected {
            background-color: #1890FF20;
         }
         .station-edit-cancel {
            position: absolute;
            color: #F5222D;
            font-size: 60rpx;
         }
         .station-edit-ok {
            position: absolute;
            color: #52C41A;
            font-size: 60rpx;
         }
         .text-button-group {
            display: flex;
@@ -225,14 +2792,12 @@
            align-items: center;
            flex-direction: column;
            font-size: 30rpx !important;
            background-color: #eee;
            .button {
               margin-top: 20rpx;
               width: 375rpx;
            }
         }
      }
@@ -245,6 +2810,7 @@
         flex-direction: column;
         font-size: 30rpx;
         font-weight: 400;
         background-color: #000fff;
         .title {
            font-size: 40rpx;
@@ -271,51 +2837,190 @@
            padding-bottom: 10rpx;
            background-color: #fff;
            border-radius: 10rpx;
         }
            .title {
               font-size: 40rpx;
               margin-bottom: 10rpx;
            }
      }
            .tip {
               color: #888;
               margin: 10rpx;
               text-align: left;
            }
      .img-button-group {
         display: flex;
         //width: 100%;
         flex-direction: row;
         border-radius: 10px;
         border: 1px solid #fff;
         font-size: 30rpx !important;
         justify-content: space-around;
         .button {
            margin: 10rpx 20rpx;
            height: 144rpx !important;
            border: 0;
            display: flex;
            flex-direction: column;
            background-color: #00000000;
            .img {
               margin: auto;
               width: 72rpx;
               height: 72rpx;
            .row-group {
               display: flex;
               flex-direction: row;
               margin: 10rpx 0;
            }
            .ico {
               margin: auto;
               font-size: 72rpx;
            .angle-group {
               padding: 10rpx;
               display: flex;
               flex-direction: column;
               justify-content: center;
               align-items: center;
               .img-angle {
                  width: 128rpx;
                  height: 42rpx;
                  margin-bottom: 10rpx;
               }
               .img-angle-pos {
                  width: 300px;
                  height: 64rpx;
                  margin: 10rpx;
               }
            }
            .coordinate {
               flex: 1;
               display: flex;
               flex-direction: row;
               align-items: center;
               // .name{
               //    padding: 10rpx 0;
               // }
            }
            .number-input {
               flex: 1;
               background-color: #fff;
               padding: 10rpx;
               border-radius: 8rpx;
               color: #1890FF;
            }
            .text {
            .name-input {
               width: calc(100% - 20rpx);
               margin-bottom: 10rpx;
               background-color: #fff;
               padding: 10rpx;
               border-radius: 8rpx;
               display: flex;
               flex-direction: row;
               color: #1890FF;
               input {
                  flex: 1;
               }
            }
         }
         .img-button-group {
            display: flex;
            //width: 100%;
            flex-direction: row;
            border-radius: 10px;
            border: 1px solid #fff;
            font-size: 30rpx !important;
            justify-content: space-around;
            .button {
               margin: 10rpx 10rpx;
               height: 144rpx !important;
               border: 0;
               display: flex;
               flex-direction: column;
               background-color: #00000000;
               .img {
                  margin: auto;
                  width: 72rpx;
                  height: 72rpx;
               }
               .dashed-line {
                  width: 72rpx;
                  height: 72rpx;
                  border-left: 8rpx dashed #1890FF;
                  /* 设置左侧边框为虚线 */
                  transform: rotate(45deg);
                  /* 旋转45度 */
                  transform-origin: bottom left;
                  /* 设置旋转的基点 */
               }
               .ico {
                  margin: auto;
                  font-size: 72rpx;
                  color: #1890FF;
               }
               .text {
                  margin: auto;
               }
            }
         }
         .text-button-group {
            display: flex;
            width: 100%;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            font-size: 30rpx !important;
            .button {
               margin: auto;
               margin-top: 20rpx;
               width: calc(100% - 10rpx);
            }
         }
         .switch-type {
            width: 100%;
            align-items: center;
            vertical-align: middle;
            .switch-button-group {
               width: 96%;
               height: 32px;
               border: 1px solid #dfdfdf;
               border-radius: 16px;
               background-color: #dfdfdf;
               display: flex;
               flex: row;
               .switch-button {
                  flex: 1;
                  border-radius: 16px;
                  color: #000000A5;
                  height: 32px;
                  line-height: 32px;
                  text-align: center;
                  box-shadow: 0px 2px 8px 0px #0000000C;
               }
               .switch-button-checked {
                  box-shadow: 0px 2px 8px 0px #0000000C;
                  background-color: #fff;
                  color: #1890FF;
               }
            }
         }
      }
      .red {
         color: red !important;
      }
      .popup-content {
         display: flex;
@@ -324,16 +3029,27 @@
         background-color: transparent;
      }
      .popup-dialog-content {
         display: flex;
         flex-direction: column;
         .popup-content-item {
            padding: 10rpx;
         }
      }
      .popup-content-menu {
         margin-top: 75px;
         margin-left: 120px;
         width: 150px;
         margin-top: 140rpx;
         margin-left: 225rpx;
         width: 300rpx;
         max-height: 50vh;
         overflow: auto;
         align-items: center;
         justify-content: center;
         flex-direction: column;
         background-color: #fff;
         border-radius: 5px;
         border: 1px solid gray;
         border: 1px solid #aaa;
      }
      .popup-content-menu-item {
@@ -341,16 +3057,69 @@
         flex-wrap: nowrap;
         flex-direction: row !important;
         align-items: center;
         padding: 4px 8px;
         padding: 8px;
         font-size: 16px;
         border-bottom: 1px solid #aaa;
         .img {
            width: 20px;
            height: 20px;
            margin: 5px;
         }
      }
      .popup-content-menu-item:last-child {
         border-bottom: 0;
      }
      .popup-content-menu-item:hover {
         background-color: #eee;
      }
      .popup-content-btn {
         margin-bottom: 20rpx;
         margin-left: 50rpx;
         width: 600rpx;
         background-color: #fff;
         border-radius: 5px;
         display: flex;
         .img-button-group {
            display: flex;
            //width: 100%;
            flex-direction: row;
            border-radius: 10px;
            border: 1px solid #fff;
            font-size: 30rpx !important;
            margin: auto;
            .button {
               margin: 10rpx 20rpx;
               height: 144rpx !important;
               border: 0;
               display: flex;
               flex-direction: column;
               background-color: #00000000;
               .img {
                  margin: auto;
                  width: 72rpx;
                  height: 72rpx;
               }
               .ico {
                  margin: auto;
                  font-size: 72rpx;
                  color: #1890FF;
               }
               .text {
                  margin: auto;
               }
            }
         }
      }
   }