Browse Source

重构在线设备详情

李富豪 1 year ago
parent
commit
ef62023952

+ 0 - 197
Web/src/components/deviceLive/index.vue

@@ -1,197 +0,0 @@
-<template>
-  <div class="deviceLive">
-    <div class="deviceLive-frames">
-      <LivePlayer :text="state.playerText" :url="state.playerUrl" />
-    </div>
-    <div class="deviceLive-operation">
-      <a-select style="width:150px;margin-right: 13px;" placeholder="摄像头" v-model:value="state.cameraValue">
-        <a-select-option v-for="item in state.cameraList" :key="item.value" :value="item.value"
-          @click="onCameraSelect(item)">
-          {{ item.label }}
-        </a-select-option>
-      </a-select>
-      <a-select style="width:150px;margin-right: 13px;" placeholder="清晰度" v-model:value="state.clarityValue"
-        @select="onClaritySelect">
-        <a-select-option v-for="item in clarityList" :key="item.value" :value="item.value">
-          {{ item.label }}
-        </a-select-option>
-      </a-select>
-      <a-button style="margin-right: 13px;" type="primary" large @click="onStart">播放</a-button>
-      <a-button type="primary" large @click="onStop">停止</a-button>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import { reactive, onMounted } from 'vue';
-import { message } from 'ant-design-vue';
-import LivePlayer from '/@/components/livePlayer/index.vue';
-import { CURRENT_CONFIG as config } from '/@/api/http/config';
-import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage';
-
-interface Props {
-  sn: string,
-};
-
-const props = withDefaults(defineProps<Props>(), {
-
-});
-
-interface SelectOption {
-  value: any,
-  label: string,
-  more?: any
-}
-
-const clarityList: SelectOption[] = [
-  {
-    value: 0,
-    label: '自适应'
-  },
-  {
-    value: 1,
-    label: '流畅'
-  },
-  {
-    value: 2,
-    label: '标清'
-  },
-  {
-    value: 3,
-    label: '高清'
-  },
-  {
-    value: 4,
-    label: '超清'
-  }
-]
-
-interface State {
-  cameraList: SelectOption[],
-  cameraValue?: string,
-  videoList: SelectOption[],
-  videoValue?: string,
-  clarityValue: number,
-  videoId: string,
-  playerText: string,
-  playerUrl: string,
-}
-
-const state: State = reactive({
-  cameraList: [],
-  cameraValue: undefined,
-  videoList: [],
-  videoValue: undefined,
-  clarityValue: 0,
-  videoId: '',
-  playerText: '',
-  playerUrl: '',
-})
-
-const fetchLiveCapacity = async () => {
-  try {
-    const res = await getLiveCapacity({});
-    if (res.code === 0) {
-      const deviceInfo = res.data.filter((item: any) => item.sn === props.sn)[0];
-      const cameras_list = deviceInfo.cameras_list || [];
-      const cameraList = cameras_list.map((item: any) => {
-        return {
-          label: item.name,
-          value: item.index,
-          more: item.videos_list
-        }
-      })
-      state.cameraList = cameraList;
-    }
-  } catch (e: any) {
-    console.error(e);
-  }
-}
-
-onMounted(async () => {
-  await fetchLiveCapacity()
-})
-
-const onCameraSelect = (record: SelectOption) => {
-  state.cameraValue = record.value;
-  if (!record.more) {
-    return
-  }
-  const videoList = record.more.map((ele: any) => {
-    return {
-      label: ele.type,
-      value: ele.index,
-      more: ele.switch_video_types
-    }
-  })
-  state.videoList = videoList;
-  if (videoList.length === 0) {
-    return;
-  }
-  const firstVideo: SelectOption = videoList[0];
-  state.videoValue = firstVideo.value;
-}
-
-const onClaritySelect = (value: any) => {
-  state.clarityValue = value;
-}
-
-const onStart = async () => {
-  const { cameraValue, videoValue } = state;
-  if (!cameraValue) {
-    return message.warn('请选择摄像头');
-  }
-  const videoId = `${props.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
-  state.videoId = videoId;
-  const liveURL = config.rtmpURL;
-  try {
-    const res = await startLivestream({
-      url: liveURL,
-      video_id: videoId,
-      url_type: 1,// RTMP 
-      video_quality: state.clarityValue
-    });
-    if (res.code !== 0) {
-      state.playerText = res.message;
-    } else {
-      const playerUrl = res.data.url;
-      state.playerText = '';
-      state.playerUrl = playerUrl;
-      message.success('已开启直播');
-    }
-  } catch (e: any) {
-    console.error(e);
-  }
-}
-
-const onStop = async () => {
-  const { cameraValue, videoValue } = state;
-  if (!cameraValue) {
-    return message.warn('请选择摄像头');
-  }
-  const videoId = `${props.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
-  const res = await stopLivestream({
-    video_id: videoId,
-  });
-  if (res.code === 0) {
-    state.videoId = '';
-    state.playerUrl = '';
-    message.success('已停止直播');
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.deviceLive {
-  width: 100%;
-
-  &-frames {
-    width: 100%;
-    height: 270px;
-  }
-
-  &-operation {
-    margin-top: 20px;
-  }
-}
-</style>

+ 341 - 101
Web/src/components/onLineDevice/components/InfoModal.vue

@@ -11,7 +11,7 @@
     <div class="content-osd">
       <div class="content-osd-head">
         <div class="content-osd-head-icon">
-          <a-image style="width: 85%;" :src="M30" :preview="false" />
+          <a-image style="width: 80%;" :src="M30" :preview="false" />
           <div class="content-osd-head-icon-text">
             {{ osdInfo.model }}
           </div>
@@ -19,18 +19,41 @@
         <div class="content-osd-head-right">
           <div class="content-osd-head-right-top">
             <div class="content-osd-head-right-top-style">
-              飞行状态
+              {{ type === 'MANUAL' ? '手动飞行' : '航线飞行' }}
             </div>
-            <div>
+            <div class="content-osd-head-right-top-status">
               {{ getTextByModeCode(deviceInfo.device.mode_code) }}
             </div>
           </div>
           <div class="content-osd-head-right-bottom">
-            <div class="openLiveButton" @click="state.deviceLiveStatus = true" v-if="!state.deviceLiveStatus">
-              开启直播
+            <div class="content-osd-head-right-bottom-button">
+              <span class="openLiveButton" @click="state.deviceLiveStatus = true" v-if="!state.deviceLiveStatus">
+                开启直播
+              </span>
+              <span class="openLiveButton" @click="state.deviceLiveStatus = false" v-else>
+                关闭直播
+              </span>
             </div>
-            <div class="openLiveButton" @click="state.deviceLiveStatus = false" v-else>
-              关闭直播
+            <div class="content-osd-head-right-bottom-text">
+              如需切换直播请停止后重新发起
+            </div>
+          </div>
+          <div class="content-osd-head-right-select">
+            <div v-if="state.deviceLiveStatus">
+              <a-select style="width: 130px;margin-right: 5px;" placeholder="摄像头" v-model:value="state.cameraValue">
+                <a-select-option v-for="item in state.cameraList" :key="item.value" :value="item.value"
+                  @click="onCameraSelect(item)">
+                  {{ item.label }}
+                </a-select-option>
+              </a-select>
+              <a-select style="width: 130px;margin-right: 5px;" placeholder="清晰度" v-model:value="state.clarityValue"
+                @select="onClaritySelect">
+                <a-select-option v-for="item in clarityList" :key="item.value" :value="item.value">
+                  {{ item.label }}
+                </a-select-option>
+              </a-select>
+              <a-button style="margin-right: 5px;" :icon="h(PlaySquareOutlined)" @click="onStart" />
+              <a-button :icon="h(PoweroffOutlined)" @click="onStop" />
             </div>
           </div>
         </div>
@@ -38,99 +61,92 @@
       <div class="battery-slide">
         <div style="background: #535759;" class="width-100"></div>
         <div class="capacity-percent" :style="{ width: deviceInfo.device.battery.capacity_percent + '%' }"></div>
-        <div class="return-home" :style="{ width: deviceInfo.device.battery.return_home_power + '%' }"></div>
-        <div class="landing" :style="{ width: deviceInfo.device.battery.landing_power + '%' }"></div>
-        <div class="white-point" :style="{ left: deviceInfo.device.battery.landing_power + '%' }"></div>
-        <div class="battery" :style="{ left: deviceInfo.device.battery.capacity_percent + '%' }">
-          {{ Math.floor(deviceInfo.device.battery.remain_flight_time / 60) }}:
-          {{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' :
-            '' }}{{ deviceInfo.device.battery.remain_flight_time % 60 }}
-        </div>
       </div>
-
-
-
-
-      <DeviceLive :sn="osdInfo.sn" v-if="state.deviceLiveStatus" />
-      <a-row>
-        <a-col span="6">
-          <a-tooltip title="GPS卫星数">
-            <span>
-              GPS
-              <WifiOutlined />
-            </span>
-            <span class="ml10">{{ deviceInfo.device.position_state.gps_number }}</span>
-          </a-tooltip>
-        </a-col>
-        <a-col span="6">
-          <a-tooltip title="RTK">
-            <span>
-              RTK
-            </span>
-            <span class="ml10">{{ deviceInfo.device.position_state.rtk_number }}</span>
-          </a-tooltip>
-        </a-col>
-        <a-col span="6">
-          <a-tooltip title="电量">
-            <span>电量</span>
-            <span class="ml10">
-              {{ deviceInfo.device.battery.capacity_percent + '%' }}
-            </span>
-          </a-tooltip>
-        </a-col>
-        <a-col span="6">
-          <a-tooltip title="风向速度">
-            <span>W.S</span>
-            <span class="ml10">{{ deviceInfo.device.wind_speed === str ? str : (deviceInfo.device.wind_speed /
-              10).toFixed(2) + ' m/s' }}</span>
-          </a-tooltip>
-        </a-col>
-      </a-row>
-      <a-row>
-        <a-col span="6">
-          <a-tooltip title="海拔高度">
-            <span>ASL</span>
-            <span class="ml10">
-              {{ deviceInfo.device.height === str ? str : deviceInfo.device.height.toFixed(2) + ' m' }}
-            </span>
-          </a-tooltip>
-        </a-col>
-        <a-col span="6">
-          <a-tooltip title="离地高度">
-            <span>ALT</span>
-            <span class="ml10">
-              {{ deviceInfo.device.elevation === str ? str : deviceInfo.device.elevation.toFixed(2) + ' m' }}
-            </span>
-          </a-tooltip>
-        </a-col>
-        <a-col span="6">
-          <a-tooltip title="水平速度">
-            <span>H.S</span>
-            <span class="ml10">
-              {{ deviceInfo.device.horizontal_speed === str ? str :
-                deviceInfo.device.horizontal_speed.toFixed(2) + ' m/s' }}
-            </span>
-          </a-tooltip>
-        </a-col>
-        <a-col span="6">
-          <a-tooltip title="当前高度">
-            <span>H</span>
-            <span class="ml10">
-              {{ deviceInfo.device.home_distance === str ? str : deviceInfo.device.home_distance.toFixed(2) + ' m'
-              }}
-            </span>
-          </a-tooltip>
-        </a-col>
-      </a-row>
+      <LivePlayer :text="state.playerText" :url="state.playerUrl" v-if="state.deviceLiveStatus" />
+      <div class="content-osd-info">
+        <a-row>
+          <a-col span="6">
+            <a-tooltip title="GPS卫星数">
+              <span>
+                GPS
+                <WifiOutlined />
+              </span>
+              <span class="ml10">{{ deviceInfo.device.position_state.gps_number }}</span>
+            </a-tooltip>
+          </a-col>
+          <a-col span="6">
+            <a-tooltip title="RTK">
+              <span>
+                RTK
+              </span>
+              <span class="ml10">{{ deviceInfo.device.position_state.rtk_number }}</span>
+            </a-tooltip>
+          </a-col>
+          <a-col span="6">
+            <a-tooltip title="电量">
+              <span>电量</span>
+              <span class="ml10">
+                {{ deviceInfo.device.battery.capacity_percent + '%' }}
+              </span>
+            </a-tooltip>
+          </a-col>
+          <a-col span="6">
+            <a-tooltip title="风向速度">
+              <span>W.S</span>
+              <span class="ml10">{{ deviceInfo.device.wind_speed === str ? str : (deviceInfo.device.wind_speed /
+                10).toFixed(2) + ' m/s' }}</span>
+            </a-tooltip>
+          </a-col>
+        </a-row>
+        <a-row>
+          <a-col span="6">
+            <a-tooltip title="海拔高度">
+              <span>ASL</span>
+              <span class="ml10">
+                {{ deviceInfo.device.height === str ? str : deviceInfo.device.height.toFixed(2) + ' m' }}
+              </span>
+            </a-tooltip>
+          </a-col>
+          <a-col span="6">
+            <a-tooltip title="离地高度">
+              <span>ALT</span>
+              <span class="ml10">
+                {{ deviceInfo.device.elevation === str ? str : deviceInfo.device.elevation.toFixed(2) + ' m' }}
+              </span>
+            </a-tooltip>
+          </a-col>
+          <a-col span="6">
+            <a-tooltip title="水平速度">
+              <span>H.S</span>
+              <span class="ml10">
+                {{ deviceInfo.device.horizontal_speed === str ? str :
+                  deviceInfo.device.horizontal_speed.toFixed(2) + ' m/s' }}
+              </span>
+            </a-tooltip>
+          </a-col>
+          <a-col span="6">
+            <a-tooltip title="当前高度">
+              <span>H</span>
+              <span class="ml10">
+                {{ deviceInfo.device.home_distance === str ? str : deviceInfo.device.home_distance.toFixed(2) + ' m'
+                }}
+              </span>
+            </a-tooltip>
+          </a-col>
+        </a-row>
+      </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { reactive } from 'vue';
-import { CloseOutlined } from '@ant-design/icons-vue'
-import DeviceLive from '/@/components/deviceLive/index.vue'
+import { h, reactive, onMounted } from 'vue';
+import { message } from 'ant-design-vue';
+import { CloseOutlined, PlaySquareOutlined, PoweroffOutlined } from '@ant-design/icons-vue'
+import LivePlayer from '/@/components/livePlayer/index.vue';
 import M30 from '/@/assets/icons/m30.png'
+import { CURRENT_CONFIG as config } from '/@/api/http/config';
+import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage';
 import { getTextByModeCode } from '/@/utils/index'
 
 interface Props {
@@ -143,11 +159,152 @@ const props = withDefaults(defineProps<Props>(), {
 
 });
 
-const state = reactive({
+const str: string = '--';
+
+interface SelectOption {
+  value: any,
+  label: string,
+  more?: any
+}
+
+const clarityList: SelectOption[] = [
+  {
+    value: 0,
+    label: '自适应'
+  },
+  {
+    value: 1,
+    label: '流畅'
+  },
+  {
+    value: 2,
+    label: '标清'
+  },
+  {
+    value: 3,
+    label: '高清'
+  },
+  {
+    value: 4,
+    label: '超清'
+  }
+]
+
+interface State {
+  deviceLiveStatus: boolean,
+  cameraList: SelectOption[],
+  cameraValue?: string,
+  videoList: SelectOption[],
+  videoValue?: string,
+  clarityValue: number,
+  videoId: string,
+  playerText: string,
+  playerUrl: string,
+}
+
+const state: State = reactive({
   deviceLiveStatus: false,// 设备直播状态
+  cameraList: [],
+  cameraValue: undefined,
+  videoList: [],
+  videoValue: undefined,
+  clarityValue: 0,
+  videoId: '',
+  playerText: '',
+  playerUrl: '',
 })
 
-const str: string = '--';
+const fetchLiveCapacity = async () => {
+  try {
+    const res = await getLiveCapacity({});
+    if (res.code === 0) {
+      const deviceInfo = res.data.filter((item: any) => item.sn === props.osdInfo.sn)[0];
+      const cameras_list = deviceInfo.cameras_list || [];
+      const cameraList = cameras_list.map((item: any) => {
+        return {
+          label: item.name,
+          value: item.index,
+          more: item.videos_list
+        }
+      })
+      state.cameraList = cameraList;
+    }
+  } catch (e: any) {
+    console.error(e);
+  }
+}
+
+onMounted(async () => {
+  await fetchLiveCapacity()
+})
+
+const onCameraSelect = (record: SelectOption) => {
+  state.cameraValue = record.value;
+  if (!record.more) {
+    return
+  }
+  const videoList = record.more.map((ele: any) => {
+    return {
+      label: ele.type,
+      value: ele.index,
+      more: ele.switch_video_types
+    }
+  })
+  state.videoList = videoList;
+  if (videoList.length === 0) {
+    return;
+  }
+  const firstVideo: SelectOption = videoList[0];
+  state.videoValue = firstVideo.value;
+}
+
+const onClaritySelect = (value: any) => {
+  state.clarityValue = value;
+}
+
+const onStart = async () => {
+  const { cameraValue, videoValue } = state;
+  if (!cameraValue) {
+    return message.warn('请选择摄像头');
+  }
+  const videoId = `${props.osdInfo.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
+  state.videoId = videoId;
+  const liveURL = config.rtmpURL;
+  try {
+    const res = await startLivestream({
+      url: liveURL,
+      video_id: videoId,
+      url_type: 1,// RTMP 
+      video_quality: state.clarityValue
+    });
+    if (res.code !== 0) {
+      state.playerText = res.message;
+    } else {
+      const playerUrl = res.data.url;
+      state.playerText = '';
+      state.playerUrl = playerUrl;
+      message.success('已开启直播');
+    }
+  } catch (e: any) {
+    console.error(e);
+  }
+}
+
+const onStop = async () => {
+  const { cameraValue, videoValue } = state;
+  if (!cameraValue) {
+    return message.warn('请选择摄像头');
+  }
+  const videoId = `${props.osdInfo.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
+  const res = await stopLivestream({
+    video_id: videoId,
+  });
+  if (res.code === 0) {
+    state.videoId = '';
+    state.playerUrl = '';
+    message.success('已停止直播');
+  }
+}
 </script>
 
 <style lang="scss" scoped>
@@ -167,7 +324,7 @@ const str: string = '--';
     display: flex;
     justify-content: space-between;
     align-items: center;
-    border: 1px solid #515151;
+    border: 1px solid #535759;
   }
 
   &-osd {
@@ -177,8 +334,7 @@ const str: string = '--';
       display: flex;
 
       &-icon {
-        width: 60px;
-        height: 80px;
+        width: 80px;
         padding: 5px;
         background: #3d3d3d;
         display: flex;
@@ -194,25 +350,109 @@ const str: string = '--';
       }
 
       &-right {
+        width: 100%;
         padding: 5px;
 
         &-top {
-          height: 20px;
           margin: 10px 0;
           display: flex;
           align-items: center;
 
           &-style {
             width: 100px;
-            border-right: 1px solid #515151;
+            color: #2a994b;
+            border-right: 1px solid #535759;
+            margin-right: 5px;
+          }
+
+          &-status {
+            flex: 1;
+            padding-left: 5px;
+            background: #4a4d4e;
           }
         }
 
         &-bottom {
-          height: 20px;
+          display: flex;
+          align-items: center;
+
+          &-button {
+            width: 100px;
+            border-right: 1px solid #535759;
+            margin-right: 5px;
+
+            .openLiveButton {
+              padding: 2px 4px;
+              border: 1.5px solid #535759;
+              border-radius: 2px;
+              cursor: pointer;
+            }
+          }
+
+          &-text {
+            color: #535759;
+          }
+        }
+
+        &-select {
+          margin: 10px 0 5px;
         }
       }
     }
+
+    &-info {
+      padding: 5px;
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+// 修改按钮样式
+.ant-btn {
+  color: #FFFFFF;
+  background: transparent;
+  border: 1px solid #535759;
+
+  &:hover {
+    color: #fff;
+    background-color: transparent;
+    border-color: #535759;
+  }
+
+  &:focus {
+    color: #fff;
+    background-color: transparent;
+    border-color: #535759;
+  }
+}
+
+.ant-select-selector {
+  color: #FFFFFF;
+  background: transparent !important;
+  border: 1px solid #535759 !important;
+
+  box-shadow: none !important;
+}
+
+.ant-select-arrow {
+  color: #fff;
+}
+
+.ant-select-dropdown {
+  background-color: transparent;
+
+  .ant-select-item {
+    background-color: #000000 !important;
+    color: #fff;
+
+    &:hover {
+      background-color: #4a4a4a !important;
+    }
+  }
+
+  .ant-select-item-option-selected {
+    background-color: #3a3a3a;
   }
 }
 </style>