ソースを参照

设备负载控制

李富豪 1 年間 前
コミット
d8d921c295

+ 6 - 2
Web/src/api/drone-control/payload.ts

@@ -17,7 +17,8 @@ export async function postPayloadAuth(sn: string, body: PostPayloadAuthBody): Pr
 // TODO: 画面拖动控制
 export enum PayloadCommandsEnum {
   CameraModeSwitch = 'camera_mode_switch',
-  CameraPhotoTake = 'camera_photo_take',
+  CameraPhotoTakeStart = 'camera_photo_take',
+  CameraPhotoTakeStop = 'camera_photo_stop',
   CameraRecordingStart = 'camera_recording_start',
   CameraRecordingStop = 'camera_recording_stop',
   CameraFocalLengthSet = 'camera_focal_length_set',
@@ -65,7 +66,10 @@ export type PostPayloadCommandsBody = {
   cmd: PayloadCommandsEnum.CameraModeSwitch,
   data: PostCameraModeBody
 } | {
-  cmd: PayloadCommandsEnum.CameraPhotoTake,
+  cmd: PayloadCommandsEnum.CameraPhotoTakeStart,
+  data: PostCameraPhotoBody
+} | {
+  cmd: PayloadCommandsEnum.CameraPhotoTakeStop,
   data: PostCameraPhotoBody
 } | {
   cmd: PayloadCommandsEnum.CameraRecordingStart,

+ 180 - 25
Web/src/components/airport/components/InfoModal.vue

@@ -218,10 +218,10 @@
                   <a-button :icon="h(PoweroffOutlined)" @click="onDeviceStopLive" />
                 </a-tooltip>
               </div>
-              <div v-if="false">
+              <div v-if="deviceLive.cameraValue && deviceLive.playerUrl">
                 <div style="display: flex;margin-top: 10px;">
-                  <a-select style="width: 120px;margin-right: 5px;" placeholder="相机类型"
-                    v-model:value="payload.camera_type">
+                  <a-select style="width: 120px;margin-right: 5px;" placeholder="镜头类型"
+                    v-model:value="payload.camera_type" @change="onChangeCameraType">
                     <a-select-option value="wide">
                       广角
                     </a-select-option>
@@ -230,7 +230,7 @@
                     </a-select-option>
                   </a-select>
                   <a-select style="width: 120px;margin-right: 5px;" placeholder="重置云台"
-                    v-model:value="payload.reset_mode">
+                    v-model:value="payload.reset_mode" @change="onChangeResetMode">
                     <a-select-option :value="0">
                       回中
                     </a-select-option>
@@ -244,7 +244,8 @@
                       俯仰向下
                     </a-select-option>
                   </a-select>
-                  <a-select style="width: 120px;" placeholder="相机模式" v-model:value="payload.camera_mode">
+                  <a-select style="width: 120px;" placeholder="相机模式" v-model:value="payload.camera_mode"
+                    @change="onChangeCameraMode">
                     <a-select-option :value="0">
                       拍照
                     </a-select-option>
@@ -258,18 +259,28 @@
                 </div>
                 <div style="display: flex;align-items: center;padding-left: 10px;margin-top: 10px;">
                   <a-slider style="width: 200px;" :marks="payload.marks" :included="false" :min="2" :max="56"
-                    v-model:value="payload.zoom_factor" />
+                    v-model:value="payload.zoom_factor" :disabled="payload.camera_type !== 'zoom'"
+                    @change="onChangeZoomFactor" />
                   <div style="margin-left: 40px;">
-                    <a-tooltip title="拍摄" v-if="payload.camera_mode === 1">
+                    <a-tooltip title="全景拍照" v-if="payload.camera_mode === 3">
+                      <img style="width:40px;height:40px;cursor: pointer;" :src="videoSrc"
+                        v-if="!payload.take.pictureStatus" @click="startTakePhoto" />
+                      <img style="width:40px;height:40px;cursor: pointer;" :src="videoStopSrc" v-else
+                        @click="stopTakePhoto" />
+                    </a-tooltip>
+                    <a-tooltip title="录像" v-else-if="payload.camera_mode === 1">
                       <div style="text-align: center;">
-                        <img style="width:40px;height:40px;cursor: pointer;" :src="videoSrc">
+                        <img style="width:40px;height:40px;cursor: pointer;" :src="videoSrc"
+                          v-if="!payload.take.videoStatus" @click="startTakeVideo" />
+                        <img style="width:40px;height:40px;cursor: pointer;" :src="videoStopSrc" v-else
+                          @click="stopTakeVideo" />
                         <div style="margin-top: 5px;">
-                          00:00
+                          {{ formatTakeTime }}
                         </div>
                       </div>
                     </a-tooltip>
-                    <a-tooltip title="拍" v-else>
-                      <img style="width: 40px;height:40px;cursor: pointer;" :src="pictureSrc">
+                    <a-tooltip title="拍" v-else>
+                      <img style="width: 40px;height:40px;cursor: pointer;" :src="pictureSrc" @click="startTakePhoto" />
                     </a-tooltip>
                   </div>
                 </div>
@@ -422,7 +433,7 @@
 </template>
 
 <script lang="ts" setup>
-import { h, computed, reactive, ref, onMounted } from 'vue';
+import { h, computed, reactive, onMounted, watch } from 'vue';
 import { message } from 'ant-design-vue';
 import { CloseOutlined, PlaySquareOutlined, PoweroffOutlined } from '@ant-design/icons-vue'
 import LivePlayer from '/@/components/livePlayer/index.vue';
@@ -442,6 +453,7 @@ import aircraftSrc from '../icons/aircraft.svg';
 import aircraftSelectedSrc from '../icons/aircraft_selected.svg';
 import pictureSrc from '../icons/info/picture.png';
 import videoSrc from '../icons/info/video.png';
+import videoStopSrc from '../icons/info/video_stop.png';
 import controllerSrc from '../icons/info/controller.svg';
 import controllerErrorSrc from '../icons/info/controllerError.svg';
 import fourGSrc from '../icons/info/fourG.svg';
@@ -463,6 +475,7 @@ import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage'
 import DockControlPanel from '../../g-map/DockControlPanel.vue'
 import DroneControlPanel from '../../g-map/DroneControlPanel.vue'
 import { useDockControl } from '../../g-map/use-dock-control';
+import { usePayloadControl } from '../../g-map/use-payload-control';
 import { useMyStore } from '/@/store';
 import { getTextByModeCode, getTextByDockModeCode, getWindDirection } from '/@/utils/index'
 import EventBus from '/@/event-bus'
@@ -482,6 +495,20 @@ const store = useMyStore()
 // 机场控制面板
 const { dockControlPanelVisible, setDockControlPanelVisible, onCloseControlPanel, sendDockControlCmd } = useDockControl();
 
+// 飞机负载控制
+const {
+  checkPayloadAuth,// 检查负载控制
+  authPayload,// 获取负载控制
+  changeLiveLens,// 设置直播镜头
+  resetGimbal,// 重置云台
+  changeCameraFocalLength,// 变焦
+  switchCameraMode,// 切换相机模式
+  startTakeCameraPhoto,// 开始拍照
+  stopTakeCameraPhoto,// 结束拍照
+  startCameraRecording,// 开始录像
+  stopCameraRecording,// 结束录像
+} = usePayloadControl()
+
 const hmsInfo = computed(() => store.state.hmsInfo);
 
 // 适合飞行
@@ -734,10 +761,24 @@ const deviceLive: DeviceLive = reactive({
   playerUrl: '',
 })
 
-const payload = reactive({
-  camera_type: 'wide',// 相机类型
-  reset_mode: 0,// 重置云台
-  camera_mode: 0,// 相机模式
+interface Payload {
+  camera_type: 'wide' | 'zoom',
+  reset_mode?: number,
+  camera_mode?: number,
+  marks: any,
+  zoom_factor: number,
+  take: {
+    pictureStatus: boolean,
+    videoStatus: boolean,
+    time: number,
+    timer: any,
+  },
+}
+
+const payload = reactive<Payload>({
+  camera_type: 'wide',// 镜头类型
+  reset_mode: undefined,// 重置云台
+  camera_mode: undefined,// 相机模式
   marks: {
     2: '2倍',
     14: '14倍',
@@ -746,6 +787,19 @@ const payload = reactive({
     56: '56倍',
   },
   zoom_factor: 2,// 变焦倍数
+  take: {
+    pictureStatus: false,
+    videoStatus: false,
+    time: 0,
+    timer: undefined,
+  },
+});
+
+const formatTakeTime = computed(() => {
+  const totalSeconds = payload.take.time;
+  const minutes = Math.floor(totalSeconds / 60);
+  const seconds = totalSeconds % 60;
+  return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
 });
 
 const fetchLiveCapacity = async () => {
@@ -858,6 +912,18 @@ const onDockStopLive = async () => {
   }
 }
 
+// 点击一键返航
+const onClickReturnHome = async () => {
+  try {
+    await sendDockControlCmd({
+      sn: props.osdInfo.gateway_sn,
+      cmd: 'return_home' as any,
+    }, false)
+  } catch (error) {
+    console.error(error);
+  }
+}
+
 const onDeviceCameraSelect = (record: SelectOption) => {
   deviceLive.cameraValue = record.value;
   if (!record.more) {
@@ -899,6 +965,12 @@ const onDeviceStartLive = async () => {
       deviceLive.playerText = '';
       deviceLive.playerUrl = playerUrl;
       message.success('已开启直播');
+      const sn = props.osdInfo.gateway_sn;
+      // 获取负载控制
+      await authPayload(sn, cameraValue as string);
+      // console.log(props.deviceInfo?.device, 'props.deviceInfo');
+      // 更改镜头类型
+      await onChangeCameraType('wide');
     }
   } catch (e: any) {
     console.error(e);
@@ -921,16 +993,99 @@ const onDeviceStopLive = async () => {
   }
 }
 
-// 点击一键返航
-const onClickReturnHome = async () => {
-  try {
-    await sendDockControlCmd({
-      sn: props.osdInfo.gateway_sn,
-      cmd: 'return_home' as any,
-    }, false)
-  } catch (error) {
-    console.error(error);
+// 更改镜头类型
+const onChangeCameraType = async (cameraType: Payload['camera_type']) => {
+  payload.camera_type = cameraType;
+  const data = {
+    video_id: deviceLive.videoId,
+    video_type: cameraType,
+  }
+  await changeLiveLens(data);
+}
+
+// 更改重置云台
+const onChangeResetMode = async (resetMode: Payload['reset_mode']) => {
+  const data = {
+    payload_index: deviceLive.cameraValue as string,
+    reset_mode: resetMode as any,
+  }
+  const sn = props.osdInfo.gateway_sn;
+  await resetGimbal(sn, data);
+}
+
+// 更改相机模式
+const onChangeCameraMode = async (cameraMode: Payload['camera_mode']) => {
+  const data = {
+    payload_index: deviceLive.cameraValue as string,
+    camera_mode: cameraMode as any,
+  }
+  const sn = props.osdInfo.gateway_sn;
+  await switchCameraMode(sn, data);
+}
+
+// 更改变焦倍数
+const onChangeZoomFactor = async (zoomFactor: number) => {
+  const data = {
+    payload_index: deviceLive.cameraValue as string,
+    camera_type: 'zoom' as any,
+    zoom_factor: zoomFactor,
+  }
+  const sn = props.osdInfo.gateway_sn;
+  await changeCameraFocalLength(sn, data);
+}
+
+watch(() => props.deviceInfo, (newValue) => {
+  if (!newValue) {
+    return;
   }
+  const cameras = newValue.device.cameras;
+  if (cameras && cameras.length > 0) {
+    const cameraInfo = cameras[0];
+    // 拍照状态
+    const photoState = cameraInfo.photo_state;
+    payload.take.pictureStatus = !!photoState;
+    // 录像状态
+    const recordingState = cameraInfo.recording_state;
+    payload.take.videoStatus = !!recordingState;
+    if (!recordingState) {
+      payload.take.time = 0;
+      clearInterval(payload.take.timer);
+    }
+  }
+}, { deep: true });
+
+// 开始拍照
+const startTakePhoto = async () => {
+  const sn = props.osdInfo.gateway_sn;
+  const payloadIndex = deviceLive.cameraValue as string;
+  await startTakeCameraPhoto(sn, payloadIndex);
+}
+
+// 结束拍照
+const stopTakePhoto = async () => {
+  const sn = props.osdInfo.gateway_sn;
+  const payloadIndex = deviceLive.cameraValue as string;
+  await stopTakeCameraPhoto(sn, payloadIndex);
+}
+
+// 开始录像
+const startTakeVideo = async () => {
+  const sn = props.osdInfo.gateway_sn;
+  const payloadIndex = deviceLive.cameraValue as string;
+  const res = await startCameraRecording(sn, payloadIndex);
+  if (res) {
+    const timer = setInterval(() => {
+      payload.take.time = payload.take.time + 1;
+    }, 1000);
+    payload.take.timer = timer;
+  }
+}
+
+// 结束录像
+const stopTakeVideo = async () => {
+  const sn = props.osdInfo.gateway_sn;
+  const payloadIndex = deviceLive.cameraValue as string;
+  await stopCameraRecording(sn, payloadIndex);
 }
 </script>
 

BIN
Web/src/components/airport/icons/info/video_stop.png


+ 55 - 25
Web/src/components/g-map/use-payload-control.ts

@@ -1,4 +1,4 @@
-import { message } from 'ant-design-vue'
+import { message } from 'ant-design-vue';
 import {
   postPayloadAuth,
   postPayloadCommands,
@@ -7,62 +7,86 @@ import {
   PostCameraFocalLengthBody,
   PostGimbalResetBody,
   PostCameraAimBody,
-} from '/@/api/drone-control/payload'
-import { ControlSource } from '/@/types/device'
+} from '/@/api/drone-control/payload';
+import { changeLivestreamLens } from '/@/api/manage';
+import { ControlSource } from '/@/types/device';
+import { VideoType } from '/@/types/live-stream';
 
-export function usePayloadControl () {
-  function checkPayloadAuth (controlSource?: ControlSource) {
+export function usePayloadControl() {
+  function checkPayloadAuth(controlSource?: ControlSource) {
     if (controlSource !== ControlSource.A) {
-      message.error('Get Payload Control first')
-      return false
+      // message.error('请先获取有效的控制权限')
+      return false;
     }
-    return true
+    return true;
   }
 
-  async function authPayload (sn: string, payloadIndx: string) {
+  async function authPayload(sn: string, payloadIndx: string) {
     const { code } = await postPayloadAuth(sn, {
       payload_index: payloadIndx
     })
     if (code === 0) {
-      message.success('获取负载控制成功')
-      return true
+      return true;
     }
-    return false
+    return false;
   }
 
-  async function resetGimbal (sn: string, data: PostGimbalResetBody) {
+  async function changeLiveLens(data: { video_id: string, video_type: 'wide' | 'zoom' }) {
+    const { code } = await changeLivestreamLens(data);
+    if (code === 0) {
+
+    }
+  }
+
+  async function resetGimbal(sn: string, data: PostGimbalResetBody) {
     const { code } = await postPayloadCommands(sn, {
       cmd: PayloadCommandsEnum.GimbalReset,
       data: data
     })
     if (code === 0) {
-      message.success('重置云台成功')
+
     }
   }
 
-  async function switchCameraMode (sn: string, data: PostCameraModeBody) {
+  async function switchCameraMode(sn: string, data: PostCameraModeBody) {
     const { code } = await postPayloadCommands(sn, {
       cmd: PayloadCommandsEnum.CameraModeSwitch,
       data: data
     })
     if (code === 0) {
-      message.success('切换相机模式成功')
+
+    }
+  }
+
+  async function startTakeCameraPhoto(sn: string, payloadIndx: string) {
+    const { code } = await postPayloadCommands(sn, {
+      cmd: PayloadCommandsEnum.CameraPhotoTakeStart,
+      data: {
+        payload_index: payloadIndx
+      }
+    })
+    if (code === 0) {
+      message.success('开始拍照')
+      return true;
     }
+    return false;
   }
 
-  async function takeCameraPhoto (sn: string, payloadIndx: string) {
+  async function stopTakeCameraPhoto(sn: string, payloadIndx: string) {
     const { code } = await postPayloadCommands(sn, {
-      cmd: PayloadCommandsEnum.CameraPhotoTake,
+      cmd: PayloadCommandsEnum.CameraPhotoTakeStop,
       data: {
         payload_index: payloadIndx
       }
     })
     if (code === 0) {
-      message.success('拍照成功')
+      message.success('结束拍照')
+      return true;
     }
+    return false;
   }
 
-  async function startCameraRecording (sn: string, payloadIndx: string) {
+  async function startCameraRecording(sn: string, payloadIndx: string) {
     const { code } = await postPayloadCommands(sn, {
       cmd: PayloadCommandsEnum.CameraRecordingStart,
       data: {
@@ -71,10 +95,12 @@ export function usePayloadControl () {
     })
     if (code === 0) {
       message.success('开始录像')
+      return true;
     }
+    return false;
   }
 
-  async function stopCameraRecording (sn: string, payloadIndx: string) {
+  async function stopCameraRecording(sn: string, payloadIndx: string) {
     const { code } = await postPayloadCommands(sn, {
       cmd: PayloadCommandsEnum.CameraRecordingStop,
       data: {
@@ -83,20 +109,22 @@ export function usePayloadControl () {
     })
     if (code === 0) {
       message.success('结束录像')
+      return true;
     }
+    return false;
   }
 
-  async function changeCameraFocalLength (sn: string, data: PostCameraFocalLengthBody) {
+  async function changeCameraFocalLength(sn: string, data: PostCameraFocalLengthBody) {
     const { code } = await postPayloadCommands(sn, {
       cmd: PayloadCommandsEnum.CameraFocalLengthSet,
       data: data,
     })
     if (code === 0) {
-      message.success('变焦相机切换成功')
+      // message.success('变焦成功')
     }
   }
 
-  async function cameraAim (sn: string, data: PostCameraAimBody) {
+  async function cameraAim(sn: string, data: PostCameraAimBody) {
     const { code } = await postPayloadCommands(sn, {
       cmd: PayloadCommandsEnum.CameraAim,
       data: data,
@@ -109,9 +137,11 @@ export function usePayloadControl () {
   return {
     checkPayloadAuth,
     authPayload,
+    changeLiveLens,
     resetGimbal,
     switchCameraMode,
-    takeCameraPhoto,
+    startTakeCameraPhoto,
+    stopTakeCameraPhoto,
     startCameraRecording,
     stopCameraRecording,
     changeCameraFocalLength,