Преглед на файлове

Merge remote-tracking branch 'origin/master'

S0025136190 преди 1 година
родител
ревизия
aa84591306

+ 1 - 1
Web/index.html

@@ -6,7 +6,7 @@
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <link rel="icon" href="/src/assets/public/favicon.ico" />
   <title>上云无人机管理平台</title>
-  <script type="text/javascript" src="/src/components/easyPlayer/depend/EasyPlayer-element.min.js"></script>
+  <script type="text/javascript" src="EasyPlayer-element.min.js"></script>
 </head>
 
 <body>

Файловите разлики са ограничени, защото са твърде много
+ 122 - 238
Web/package-lock.json


+ 0 - 1
Web/package.json

@@ -12,7 +12,6 @@
   },
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",
-    "agora-rtc-sdk-ng": "^4.12.1",
     "ant-design-vue": "^2.2.8",
     "axios": "^0.21.1",
     "eventemitter3": "^5.0.0",

Файловите разлики са ограничени, защото са твърде много
+ 11 - 503
Web/public/EasyPlayer-element.min.js


+ 0 - 0
Web/src/components/easyPlayer/depend/EasyPlayer.wasm → Web/public/EasyPlayer.wasm


+ 0 - 6
Web/src/App.vue

@@ -2,9 +2,6 @@
   <a-config-provider :locale="locale">
     <div class="app">
       <router-view />
-      <!-- <div class="map-wrapper">
-        <GMap />
-      </div> -->
     </div>
   </a-config-provider>
 </template>
@@ -12,14 +9,11 @@
 <script lang="ts">
 import { defineComponent } from 'vue'
 import { useMyStore } from './store'
-import GMap from '/@/components/GMap.vue'
 import zhCN from 'ant-design-vue/es/locale/zh_CN';
 import 'moment/dist/locale/zh-cn';
 
 export default defineComponent({
   name: 'App',
-  components: { GMap },
-
   setup() {
     const store = useMyStore();
 

+ 1 - 1
Web/src/api/pilot-bridge.ts

@@ -280,4 +280,4 @@ export default {
       localStorage.clear()
     }
   }
-}
+}

Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
Web/src/assets/icons/end.svg


BIN
Web/src/assets/icons/hardstand.png


BIN
Web/src/assets/icons/plane.png


BIN
Web/src/assets/icons/satellite.png


Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
Web/src/assets/icons/start.svg


+ 77 - 4
Web/src/components/GMap.vue

@@ -27,6 +27,18 @@
         </a>
       </div>
     </div>
+    <!-- 地图类型切换控件 -->
+    <div class="g-mapType" :style="{ right: drawVisible ? '316px' : '16px' }">
+      <img :src="planeSrc" v-if="state.mapType === 0" @click="onClickSwitchMapType" />
+      <img :src="satelliteSrc" v-else @click="onClickSwitchMapType" />
+    </div>
+    <!-- 最下方信息区域 -->
+    <div class="g-info">
+      <AimOutlined style="margin-right: 10px;" />
+      <div>
+        WGS 84
+      </div>
+    </div>
     <!-- 飞机OSD -->
     <div v-if="osdVisible.visible && !osdVisible.is_dock" v-drag-window class="osd-panel fz12">
       <div class="pl5 pr5 flex-align-center flex-row flex-justify-between"
@@ -508,7 +520,7 @@
 </template>
 
 <script lang="ts">
-import { computed, defineComponent, onMounted, reactive, ref, watch } from 'vue'
+import { computed, defineComponent, onMounted, reactive, ref, watch, onUnmounted } from 'vue'
 import {
   generateLineContent,
   generatePointContent,
@@ -534,8 +546,10 @@ import {
 } from '/@/types/device'
 import pin from '/@/assets/icons/pin-2d8cf0.svg'
 import M30 from '/@/assets/icons/m30.png'
+import planeSrc from '/@/assets/icons/plane.png'
+import satelliteSrc from '/@/assets/icons/satellite.png'
 import {
-  BorderOutlined, LineOutlined, CloseOutlined, ControlOutlined, TrademarkOutlined, ArrowDownOutlined,
+  BorderOutlined, LineOutlined, CloseOutlined, AimOutlined, ControlOutlined, TrademarkOutlined, ArrowDownOutlined,
   ThunderboltOutlined, SignalFilled, GlobalOutlined, HistoryOutlined, CloudUploadOutlined, RocketOutlined,
   FieldTimeOutlined, CloudOutlined, CloudFilled, FolderOpenOutlined, RobotFilled, ArrowUpOutlined, CarryOutOutlined
 } from '@ant-design/icons-vue'
@@ -546,7 +560,6 @@ import { useDockControl } from './g-map/use-dock-control'
 import DroneControlPanel from './g-map/DroneControlPanel.vue'
 import { useConnectMqtt } from './g-map/use-connect-mqtt'
 import LivestreamOthers from './livestream-others.vue'
-import LivestreamAgora from './livestream-agora.vue'
 import FlightAreaActionIcon from './flight-area/FlightAreaActionIcon.vue'
 import { EFlightAreaType } from '../types/flight-area'
 import { useFlightArea } from './flight-area/use-flight-area'
@@ -557,6 +570,7 @@ export default defineComponent({
     BorderOutlined,
     LineOutlined,
     CloseOutlined,
+    AimOutlined,
     ControlOutlined,
     TrademarkOutlined,
     ThunderboltOutlined,
@@ -577,7 +591,6 @@ export default defineComponent({
     CarryOutOutlined,
     RocketOutlined,
     LivestreamOthers,
-    LivestreamAgora,
     FlightAreaActionIcon,
   },
   name: 'GMap',
@@ -592,11 +605,20 @@ export default defineComponent({
     const mouseMode = ref(false)
     const store = useMyStore()
     const state = reactive({
+      mapType: 0,// 地图类型 0-普通 1-卫星
       currentType: '',
       coverIndex: 0,
       isFlightArea: false,
       deviceLiveStatus: false,// 设备直播状态
     })
+
+    // 点击切换地图类型
+    const onClickSwitchMapType = () => {
+      const mapType = state.mapType === 0 ? 1 : 0;
+      state.mapType = mapType;
+      useMouseToolHook.onChangeMapType(mapType);
+    }
+
     const str: string = '--'
     const deviceInfo: any = reactive({
       gateway: {
@@ -794,6 +816,10 @@ export default defineComponent({
       useGMapManageHook.globalPropertiesConfig(app)
     })
 
+    onUnmounted(() => {
+      root.$map.destroy()
+    })
+
     const { getDrawFlightAreaCallback, onFlightAreaDroneLocationWs } = useFlightArea()
     useFlightAreaDroneLocationEvent(onFlightAreaDroneLocationWs)
 
@@ -1047,7 +1073,10 @@ export default defineComponent({
       pin,
       state,
       M30,
+      planeSrc,
+      satelliteSrc,
       deviceInfo,
+      onClickSwitchMapType,
       EGear,
       EModeCode,
       str,
@@ -1108,6 +1137,40 @@ export default defineComponent({
   }
 }
 
+.g-mapType {
+  width: 28px;
+  height: 28px;
+  background: white;
+  border-radius: 2px;
+  line-height: 28px;
+  text-align: center;
+  position: absolute;
+  bottom: 50px;
+  right: 16px;
+  cursor: pointer;
+
+  img {
+    width: 18px;
+    height: 18px;
+  }
+}
+
+.g-info {
+  width: 100%;
+  height: 26px;
+  padding: 0 16px;
+  background: rgba(255, 255, 255, 0.7);
+  border-radius: 2px;
+  line-height: 28px;
+  text-align: center;
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+}
+
 .osd-panel {
   position: absolute;
   margin-left: 10px;
@@ -1187,4 +1250,14 @@ export default defineComponent({
   height: 660px;
   background: #232323;
 }
+</style>
+
+<style lang="scss">
+.amap-logo {
+  display: none !important;
+}
+
+.amap-copyright {
+  display: none !important;
+}
 </style>

+ 7 - 1
Web/src/components/common/nav.vue

@@ -7,6 +7,12 @@
           设备管理
         </span>
       </a-menu-item>
+      <a-menu-item :key="'/' + ERouterName.WORKSPACE">
+        <CodepenOutlined />
+        <span>
+          项目工作空间
+        </span>
+      </a-menu-item>
       <a-menu-item :key="'/' + ERouterName.TASK">
         <ContainerOutlined />
         <span>
@@ -36,7 +42,7 @@
 </template>
 <script lang="ts" setup>
 import { reactive, watchEffect } from 'vue';
-import { GatewayOutlined, ContainerOutlined, HddOutlined, PictureOutlined, VideoCameraOutlined, TeamOutlined } from '@ant-design/icons-vue';
+import { GatewayOutlined, CodepenOutlined, ContainerOutlined, HddOutlined, PictureOutlined, VideoCameraOutlined, TeamOutlined } from '@ant-design/icons-vue';
 import { ERouterName } from '/@/types/enums';
 import router from '/@/router';
 

+ 3 - 4
Web/src/components/common/topbar.vue

@@ -2,9 +2,7 @@
   <div class="width-100 flex-row flex-justify-between flex-align-center"
     style="height: 60px;border-bottom: 1px solid #F0F2F5;">
     <div>
-      <a-button type="primary" @click="onClickToWorkspace">
-        项目工作空间
-      </a-button>
+      <img :src="logoSrc" style="width: 30px;height: 30px;">
     </div>
     <div style="cursor: pointer;" class="height-100 fz16 flex-row flex-justify-between flex-align-center">
       <a-dropdown>
@@ -31,10 +29,11 @@
 
 <script lang="ts" setup>
 import { onMounted, ref } from 'vue'
+import { UserOutlined, PoweroffOutlined } from '@ant-design/icons-vue'
+import logoSrc from '/@/assets/icons/cloudapi.png'
 import { getRoot } from '/@/root'
 import { getPlatformInfo } from '/@/api/manage'
 import { ELocalStorageKey, ERouterName } from '/@/types'
-import { UserOutlined, PoweroffOutlined } from '@ant-design/icons-vue'
 
 const root = getRoot()
 

+ 0 - 398
Web/src/components/livestream-agora.vue

@@ -1,398 +0,0 @@
-<template>
-  <div class="flex-column flex-justify-start flex-align-center">
-    <div id="player" style="width: 720px; height: 420px; border: 1px solid"></div>
-    <p class="fz24">Live streaming source selection</p>
-    <div class="flex-row flex-justify-center flex-align-center mt10">
-      <template v-if="livePara.liveState && dronePara.isDockLive">
-        <span class="mr10">Lens:</span>
-        <a-radio-group v-model:value="dronePara.lensSelected" button-style="solid">
-          <a-radio-button v-for="lens in dronePara.lensList" :key="lens" :value="lens">{{lens}}</a-radio-button>
-        </a-radio-group>
-      </template>
-      <template v-else>
-      <a-select
-        style="width:150px"
-        placeholder="Select Drone"
-        v-model:value="dronePara.droneSelected"
-      >
-        <a-select-option
-          v-for="item in dronePara.droneList"
-          :key="item.value"
-          :value="item.value"
-          @click="onDroneSelect(item)"
-          >{{ item.label }}</a-select-option
-        >
-      </a-select>
-      <a-select
-        class="ml10"
-        style="width:150px"
-        placeholder="Select Camera"
-        v-model:value="dronePara.cameraSelected"
-      >
-        <a-select-option
-          v-for="item in dronePara.cameraList"
-          :key="item.value"
-          :value="item.value"
-          @click="onCameraSelect(item)"
-          >{{ item.label }}</a-select-option
-        >
-      </a-select>
-      <!-- <a-select
-        class="ml10"
-        style="width:150px"
-        placeholder="Select Lens"
-        @select="onVideoSelect"
-      >
-        <a-select-option
-          v-for="item in dronePara.videoList"
-          :key="item.value"
-          :value="item.value"
-          >{{ item.label }}</a-select-option
-        >
-      </a-select> -->
-      </template>
-      <a-select
-        class="ml10"
-        style="width:150px"
-        placeholder="Select Clarity"
-        @select="onClaritySelect"
-      >
-        <a-select-option
-          v-for="item in clarityList"
-          :key="item.value"
-          :value="item.value"
-          >{{ item.label }}</a-select-option
-        >
-      </a-select>
-    </div>
-    <p class="fz16 mt10">
-      Note: Obtain The Following Parameters From https://console.agora.io
-    </p>
-    <div class="flex-row flex-justify-center flex-align-center">
-      <span class="mr10">AppId:</span>
-      <a-input v-model:value="agoraPara.appid" placeholder="APP ID"></a-input>
-      <span class="ml10">Token:</span>
-      <a-input
-        class="ml10"
-        v-model:value="agoraPara.token"
-        placeholder="Token"
-      ></a-input>
-      <span class="ml10">Channel:</span>
-      <a-input
-        class="ml10"
-        v-model:value="agoraPara.channel"
-        placeholder="Channel"
-      ></a-input>
-    </div>
-    <div class="mt20 flex-row flex-justify-center flex-align-center">
-      <a-button v-if="livePara.liveState && dronePara.isDockLive" type="primary" large @click="onSwitch">Switch Lens</a-button>
-      <a-button v-else type="primary" large @click="onStart">Play</a-button>
-      <a-button class="ml20" type="primary" large @click="onStop"
-        >Stop</a-button
-      >
-      <a-button class="ml20" type="primary" large @click="onUpdateQuality"
-        >Update Clarity</a-button
-      >
-      <a-button v-if="!livePara.liveState || !dronePara.isDockLive" class="ml20" type="primary" large @click="onRefresh"
-        >Refresh Live Capacity</a-button
-      >
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import AgoraRTC, { IAgoraRTCClient, IAgoraRTCRemoteUser } from 'agora-rtc-sdk-ng'
-import { message } from 'ant-design-vue'
-import { onMounted, reactive } from 'vue'
-import { uuidv4 } from '../utils/uuid'
-import { CURRENT_CONFIG as config } from '/@/api/http/config'
-import { changeLivestreamLens, getLiveCapacity, setLivestreamQuality, startLivestream, stopLivestream } from '/@/api/manage'
-import { getRoot } from '/@/root'
-
-const root = getRoot()
-
-const clarityList = [
-  {
-    value: 0,
-    label: 'Adaptive'
-  },
-  {
-    value: 1,
-    label: 'Smooth'
-  },
-  {
-    value: 2,
-    label: 'Standard'
-  },
-  {
-    value: 3,
-    label: 'HD'
-  },
-  {
-    value: 4,
-    label: 'Super Clear'
-  }
-]
-
-interface SelectOption {
-  value: any,
-  label: string,
-  more?: any
-}
-
-let agoraClient = {} as IAgoraRTCClient
-const agoraPara = reactive({
-  appid: config.agoraAPPID,
-  token: config.agoraToken,
-  channel: config.agoraChannel,
-  uid: 123456,
-  stream: {}
-})
-const dronePara = reactive({
-  livestreamSource: [],
-  droneList: [] as SelectOption[],
-  cameraList: [] as SelectOption[],
-  videoList: [] as SelectOption[],
-  droneSelected: undefined as string | undefined,
-  cameraSelected: undefined as string | undefined,
-  videoSelected: undefined as string | undefined,
-  claritySelected: 0,
-  lensList: [] as string[],
-  lensSelected: undefined as string | undefined,
-  isDockLive: false
-})
-const livePara = reactive({
-  url: '',
-  webrtc: {} as any,
-  videoId: '',
-  liveState: false
-})
-const nonSwitchable = 'normal'
-const onRefresh = async () => {
-  dronePara.droneList = []
-  dronePara.cameraList = []
-  dronePara.videoList = []
-  dronePara.droneSelected = undefined
-  dronePara.cameraSelected = undefined
-  dronePara.videoSelected = undefined
-  await getLiveCapacity({})
-    .then(res => {
-      if (res.code === 0) {
-        if (res.data === null) {
-          console.warn('warning: get live capacity is null!!!')
-          return
-        }
-        dronePara.livestreamSource = res.data
-        dronePara.droneList = []
-
-        console.log('live_capacity:', dronePara.livestreamSource)
-
-        if (dronePara.livestreamSource) {
-          dronePara.livestreamSource.forEach((ele: any) => {
-            dronePara.droneList.push({ label: ele.name + '-' + ele.sn, value: ele.sn, more: ele.cameras_list })
-          })
-        }
-      }
-    })
-    .catch(error => {
-      message.error(error)
-      console.error(error)
-    })
-}
-
-onMounted(() => {
-  onRefresh()
-  agoraClient = AgoraRTC.createClient({ mode: 'live', codec: 'vp8' })
-  agoraClient.setClientRole('audience', { level: 2 })
-  if (agoraClient.connectionState === 'DISCONNECTED') {
-    agoraClient.join(agoraPara.appid, agoraPara.channel, agoraPara.token)
-  }
-  // Subscribe when a remote user publishes a stream
-  agoraClient.on('user-joined', async (user: IAgoraRTCRemoteUser) => {
-    message.info('user[' + user.uid + '] join')
-  })
-  agoraClient.on('user-published', async (user: IAgoraRTCRemoteUser, mediaType: 'audio' | 'video') => {
-    await agoraClient.subscribe(user, mediaType)
-    if (mediaType === 'video') {
-      console.log('subscribe success')
-      // Get `RemoteVideoTrack` in the `user` object.
-      const remoteVideoTrack = user.videoTrack!
-      // Dynamically create a container in the form of a DIV element for playing the remote video track.
-      remoteVideoTrack.play(document.getElementById('player') as HTMLElement)
-    }
-  })
-  agoraClient.on('user-unpublished', async (user: any) => {
-    console.log('unpublish live:', user)
-    message.info('unpublish live')
-  })
-  agoraClient.on('exception', async (e: any) => {
-    console.log(e)
-    message.error(e.msg)
-  })
-})
-const handleError = (err: any) => {
-  console.error(err)
-}
-const handleJoinChannel = (uid: any) => {
-  agoraPara.uid = uid
-}
-const onStart = async () => {
-  const that = this
-  console.log(
-    'drone parameter:',
-    dronePara.droneSelected,
-    dronePara.cameraSelected,
-    dronePara.videoSelected,
-    dronePara.claritySelected
-  )
-  const timestamp = new Date().getTime().toString()
-  const liveTimestamp = timestamp
-  if (
-    dronePara.droneSelected == null ||
-    dronePara.cameraSelected == null ||
-    dronePara.claritySelected == null
-  ) {
-    message.warn('waring: not select live para!!!')
-    return
-  }
-  agoraClient.setClientRole('audience', { level: 2 })
-  if (agoraClient.connectionState === 'DISCONNECTED') {
-    await agoraClient.join(agoraPara.appid, agoraPara.channel, agoraPara.token)
-  }
-  livePara.videoId =
-    dronePara.droneSelected +
-    '/' +
-    dronePara.cameraSelected + '/' + (dronePara.videoSelected || nonSwitchable + '-0')
-  console.log(agoraPara)
-
-  livePara.url =
-    'channel=' +
-    agoraPara.channel +
-    '&sn=' +
-    dronePara.droneSelected +
-    '&token=' +
-    encodeURIComponent(agoraPara.token) +
-    '&uid=' +
-    agoraPara.uid
-
-  startLivestream({
-    url: livePara.url,
-    video_id: livePara.videoId,
-    url_type: 0,
-    video_quality: dronePara.claritySelected
-  })
-    .then(res => {
-      if (res.code !== 0) {
-        return
-      }
-      livePara.liveState = true
-    })
-    .catch(err => {
-      console.error(err)
-    })
-}
-const onStop = async () => {
-  if (
-    dronePara.droneSelected == null ||
-    dronePara.cameraSelected == null ||
-    dronePara.claritySelected == null
-  ) {
-    message.warn('waring: not select live para!!!')
-    return
-  }
-  livePara.videoId =
-    dronePara.droneSelected +
-    '/' +
-    dronePara.cameraSelected + '/' + (dronePara.videoSelected || nonSwitchable + '-0')
-
-  stopLivestream({
-    video_id: livePara.videoId
-  }).then(res => {
-    if (res.code === 0) {
-      message.success(res.message)
-      livePara.liveState = false
-      dronePara.lensSelected = ''
-      console.log('stop play livestream')
-    }
-  })
-}
-const onDroneSelect = (val: SelectOption) => {
-  dronePara.cameraList = []
-  dronePara.videoList = []
-  dronePara.lensList = []
-
-  dronePara.cameraSelected = undefined
-  dronePara.videoSelected = undefined
-  dronePara.lensSelected = undefined
-  dronePara.droneSelected = val.value
-  if (!val.more) {
-    return
-  }
-  val.more.forEach((ele: any) => {
-    dronePara.cameraList.push({ label: ele.name, value: ele.index, more: ele.videos_list })
-  })
-}
-const onCameraSelect = (val: SelectOption) => {
-  dronePara.cameraSelected = val.value
-  dronePara.videoSelected = undefined
-  dronePara.lensSelected = undefined
-  dronePara.videoList = []
-  dronePara.lensList = []
-  if (!val.more) {
-    return
-  }
-
-  val.more.forEach((ele: any) => {
-    dronePara.videoList.push({ label: ele.type, value: ele.index, more: ele.switch_video_types })
-  })
-  if (dronePara.videoList.length === 0) {
-    return
-  }
-  const firstVideo: SelectOption = dronePara.videoList[0]
-  dronePara.videoSelected = firstVideo.value
-  dronePara.lensList = firstVideo.more
-  dronePara.lensSelected = firstVideo.label
-  dronePara.isDockLive = dronePara.lensList?.length > 0
-}
-const onVideoSelect = (val: SelectOption) => {
-  dronePara.videoSelected = val.value
-  dronePara.lensList = val.more
-  dronePara.lensSelected = val.label
-}
-const onClaritySelect = (val: any) => {
-  dronePara.claritySelected = val
-}
-const onUpdateQuality = () => {
-  if (!livePara.liveState) {
-    message.info('Please turn on the livestream first.')
-    return
-  }
-  setLivestreamQuality({
-    video_id: livePara.videoId,
-    video_quality: dronePara.claritySelected
-  }).then(res => {
-    if (res.code === 0) {
-      message.success('Set the clarity to ' + clarityList[dronePara.claritySelected].label)
-    }
-  })
-}
-
-const onSwitch = () => {
-  if (dronePara.lensSelected === undefined || dronePara.lensSelected === nonSwitchable) {
-    message.info('The ' + nonSwitchable + ' lens cannot be switched, please select the lens to be switched.', 8)
-    return
-  }
-  changeLivestreamLens({
-    video_id: livePara.videoId,
-    video_type: dronePara.lensSelected
-  }).then(res => {
-    if (res.code === 0) {
-      message.success('Switching live camera successfully.')
-    }
-  })
-}
-</script>
-
-<style lang="scss" scoped>
-@import '/@/styles/index.scss';
-</style>

+ 1 - 1
Web/src/constants/index.ts

@@ -19,4 +19,4 @@ export const AMapConfig = {
     'AMap.MouseTool',
     'AMap.MoveAnimation'
   ]
-}
+}

+ 12 - 44
Web/src/hooks/use-g-map-cover.ts

@@ -168,56 +168,24 @@ export function useGMapCover() {
   }
 
   function updatePinElement(id: string, name: string, coordinates: GeojsonCoordinate, color?: string) {
-    const elements = getElementFromMap(id)
-    const textElements = getElementFromMap(id + '_text')
-    if (elements && elements.length > 0) {
-      const element = elements[0]
-      const icon = getPinIcon(color)
-      element.setPosition(new AMap.LngLat(coordinates[0], coordinates[1]))
-      element.setIcon(icon)
-      element.setTitle(name)
-      textElements[0].setText(name)
-    } else {
-      init2DPin(name, coordinates, color, {
-        id: id,
-        name: name
-      })
-    }
+    init2DPin(name, coordinates, color, {
+      id: id,
+      name: name
+    })
   }
 
   function updatePolylineElement(id: string, name: string, coordinates: GeojsonCoordinate[], color?: string) {
-    const elements = getElementFromMap(id)
-    const textElements = getElementFromMap(id + '_text')
-    if (elements && elements.length > 0) {
-      const element = elements[0]
-      const options = element.getOptions()
-      options.strokeColor = color || normalColor
-      element.setOptions(options)
-      textElements[0].setText(name)
-    } else {
-      initPolyline(name, coordinates, color, {
-        id: id,
-        name: name
-      })
-    }
+    initPolyline(name, coordinates, color, {
+      id: id,
+      name: name
+    })
   }
 
   function updatePolygonElement(id: string, name: string, coordinates: GeojsonCoordinate[][], color?: string) {
-    const elements = getElementFromMap(id)
-    const textElements = getElementFromMap(id + '_text')
-    if (elements && elements.length > 0) {
-      const element = elements[0]
-      const options = element.getOptions()
-      options.fillColor = color || normalColor
-      options.strokeColor = color || normalColor
-      element.setOptions(options)
-      textElements[0].setText(name)
-    } else {
-      initPolygon(name, coordinates, color, {
-        id: id,
-        name: name
-      })
-    }
+    initPolygon(name, coordinates, color, {
+      id: id,
+      name: name
+    })
   }
 
   function initTextInfo(content: string, coordinates: GeojsonCoordinate, id: string) {

+ 10 - 22
Web/src/hooks/use-g-map-trajectory.ts

@@ -1,6 +1,5 @@
 import { getRoot } from '/@/root'
-import startSrc from '/@/assets/icons/start.svg'
-import endSrc from '/@/assets/icons/end.svg'
+import hardstandSrc from '/@/assets/icons/hardstand.png'
 
 export function useGMapTrajectory() {
   const root = getRoot();
@@ -11,38 +10,27 @@ export function useGMapTrajectory() {
     // 绘制起点图标
     const startPosition = paths[0];
     const startIcon = new AMap.Icon({
-      size: new AMap.Size(40, 40),
-      image: startSrc,
-      imageSize: new AMap.Size(40, 40)
+      size: new AMap.Size(30, 30),
+      image: hardstandSrc,
+      imageSize: new AMap.Size(30, 30)
     })
     const startMarker = new AMap.Marker({
       position: new AMap.LngLat(startPosition[0], startPosition[startPosition.length - 1]),
       icon: startIcon,
-      offset: new AMap.Pixel(-20, -35)
-    })
-    // 绘制终点图标
-    const endPosition = paths[paths.length - 1];
-    const endIcon = new AMap.Icon({
-      size: new AMap.Size(40, 40),
-      image: endSrc,
-      imageSize: new AMap.Size(40, 40)
-    })
-    const endMarker = new AMap.Marker({
-      position: new AMap.LngLat(endPosition[0], endPosition[endPosition.length - 1]),
-      icon: endIcon,
-      offset: new AMap.Pixel(-20, -35)
+      offset: new AMap.Pixel(-20, -35),// 位置偏移
     })
     // 绘制轨迹折线
     const polyline = new AMap.Polyline({
       path: paths,
       strokeColor: '#2D8CF0',
-      strokeOpacity: 1,
-      strokeWeight: 2,
+      showDir: true,// 显示路线白色方向箭头
+      strokeOpacity: 1,// 轮廓线透明度
+      strokeWeight: 6,//线宽
       strokeStyle: 'solid',
     })
-    root.$map.add([startMarker, endMarker, polyline]);
+    root.$map.add([startMarker, polyline]);
     // 自动缩放地图到合适的视野级别
-    // root.$map.setFitView();
+    root.$map.setFitView([startMarker, polyline]);
   }
 
   return {

+ 4 - 1
Web/src/hooks/use-g-map.ts

@@ -14,10 +14,13 @@ export function useGMapManage() {
       ...AMapConfig
     }).then((AMap) => {
       state.aMap = AMap
-      state.map = new AMap.Map(container, {
+      const map = new AMap.Map(container, {
         center: [121.48, 31.22],
         zoom: 12
       })
+      const sale = new AMap.Scale();// 比例尺控件
+      map.addControl(sale);// 添加比例尺控件
+      state.map = map;
       state.mouseTool = new AMap.MouseTool(state.map)
       // 挂在到全局
       app.config.globalProperties.$aMap = state.aMap

+ 17 - 1
Web/src/hooks/use-mouse-tool.ts

@@ -131,7 +131,23 @@ export function useMouseTool() {
     }
   }
 
+  // 切换地图类型
+  const onChangeMapType = (type: number) => {
+    const AMap = root.$aMap;
+    const map = root.$map
+
+    map.remove(map.getLayers());
+    if (type === 0) {
+      // 标准图层
+      map.add(new AMap.createDefaultLayer());
+    } else if (type === 1) {
+      // 卫星图层
+      map.add(new AMap.TileLayer.Satellite());
+    }
+  }
+
   return {
-    mouseTool
+    mouseTool,
+    onChangeMapType
   }
 }

+ 2 - 0
Web/src/pages/page-pilot/pilot-home.vue

@@ -343,6 +343,7 @@ const connectCallback = async (arg: any) => {
     const wsParam: WsParam = components.get(EComponentName.Ws)
     wsParam.token = apiPilot.getToken()
     apiPilot.loadComponent(EComponentName.Ws, components.get(EComponentName.Ws))
+    console.log(wsParam, 'wsParam');
 
     // map
     const mapParam: MapParam = components.get(EComponentName.Map)
@@ -465,6 +466,7 @@ function refreshStatus() {
   wsState.value = apiPilot.isComponentLoaded(EComponentName.Ws) && apiPilot.wsGetConnectState()
     ? EStatusValue.CONNECTED
     : EStatusValue.DISCONNECT
+  console.log(wsState.value, 'wsState.value');
   mapState.value = apiPilot.isComponentLoaded(EComponentName.Map) ? EStatusValue.CONNECTED : EStatusValue.DISCONNECT
   tsaState.value = apiPilot.isComponentLoaded(EComponentName.Tsa) ? EStatusValue.CONNECTED : EStatusValue.DISCONNECT
   mediaState.value = apiPilot.isComponentLoaded(EComponentName.Media) ? EStatusValue.CONNECTED : EStatusValue.DISCONNECT

+ 4 - 2
Web/src/pages/page-web/projects/trajectory/index.vue

@@ -23,6 +23,7 @@ import Search from './components/Search.vue';
 import { apis } from '/@/api/custom/index';
 import router from '/@/router';
 import { useMyStore } from '/@/store';
+import { wgs84togcj02 } from '/@/vendors/coordtransform'
 
 const store = useMyStore()
 
@@ -127,7 +128,8 @@ const columns = [
     title: '操作',
     dataIndex: 'actions',
     fixed: 'right',
-    width: 80,
+    align: 'center',
+    width: 50,
     slots: { customRender: 'action' },
   },
 ]
@@ -161,7 +163,7 @@ const onClickLookTrajectory = async (id: string) => {
   router.push({ path: '/workspace' });
   const res = await apis.fetchTrajectoryMap(id);
   const list = res.data.map((item: any) => {
-    return [item.longitude, item.latitude]
+    return wgs84togcj02(item.longitude, item.latitude);
   });
   store.commit('SET_TRAJECTORY_LIST', list)
 }

+ 4 - 14
Web/src/pages/page-web/projects/workspace.vue

@@ -1,7 +1,6 @@
 <template>
   <div class="project-app-wrapper">
     <div class="left">
-      <!-- <Sidebar /> -->
       <div class="main-content uranus-scrollbar dark">
         <Tsa />
       </div>
@@ -10,28 +9,18 @@
       <div class="map-wrapper">
         <GMap />
       </div>
-      <div class="media-wrapper" v-if="root.$route.name === ERouterName.MEDIA">
-        <MediaPanel />
-      </div>
-      <div class="task-wrapper" v-if="root.$route.name === ERouterName.TASK">
-        <TaskPanel />
-      </div>
     </div>
   </div>
 </template>
+
 <script lang="ts" setup>
-import Sidebar from '/@/components/common/sidebar.vue'
 import Tsa from '/@/pages/page-web/projects/tsa.vue'
-import MediaPanel from '/@/components/MediaPanel.vue'
-import TaskPanel from '/@/components/task/TaskPanel.vue'
 import GMap from '/@/components/GMap.vue'
-import { EBizCode, ERouterName } from '/@/types'
-import { getRoot } from '/@/root'
+import { EBizCode } from '/@/types'
 import { useMyStore } from '/@/store'
 import { useConnectWebSocket } from '/@/hooks/use-connect-websocket'
 import EventBus from '/@/event-bus'
 
-const root = getRoot()
 const store = useMyStore()
 
 const messageHandler = async (payload: any) => {
@@ -129,6 +118,7 @@ const messageHandler = async (payload: any) => {
 // 监听ws 消息
 useConnectWebSocket(messageHandler)
 </script>
+
 <style lang="scss" scoped>
 @import '/@/styles/index.scss';
 
@@ -184,4 +174,4 @@ useConnectWebSocket(messageHandler)
     }
   }
 }
-</style>
+</style>

+ 1 - 3
Web/src/websocket/index.ts

@@ -1,6 +1,4 @@
-import { message } from 'ant-design-vue'
 import ReconnectingWebSocket from 'reconnecting-websocket'
-import { EBizCode } from '../types'
 
 interface WebSocketOptions {
   data: any
@@ -51,7 +49,7 @@ class ConnectWebSocket {
     })
 
     this._hasInit = true
-    
+
     this._socket.addEventListener('open', this._onOpen.bind(this))
     this._socket.addEventListener('close', this._onClose.bind(this))
     this._socket.addEventListener('error', this._onError.bind(this))

+ 7 - 0
Web/vite.config.ts

@@ -53,6 +53,13 @@ export default defineConfig(({ mode, command }) => {
       sourcemap: false,// 构建后不生成源代码
       write: true,// 构建的文件写入磁盘
       chunkSizeWarningLimit: 10240,// 触发警告的chunk大小10M
+      // 底层配置
+      rollupOptions: {
+        output: {
+          entryFileNames: 'js/[name]-[hash].js',
+          chunkFileNames: 'js/[name]-[hash].js',
+        }
+      },
     },
     esbuild: {
       drop: command === 'build' ? ['console', 'debugger'] : [],

Някои файлове не бяха показани, защото твърде много файлове са промени