lvkun996 2 роки тому
батько
коміт
5c98f9d632

+ 25 - 0
src/api/iot/device.ts

@@ -318,3 +318,28 @@ export const upgradationOtaByDeviceId = (deviceId: string, otaPkgId: string) =>
     }
   })
 }
+
+/** 视频流 */
+export const liveById = (deviceId: string) => {
+  return request<string>({
+    url: `/toTransport/rts/${deviceId}`,
+    method: 'POST'
+  })
+}
+
+/** 视频流通道控制 */
+export const liveControlRts = (deviceId: string, channel: number) => {
+  return request<string>({
+    url: `/toTransport/controlRts/${deviceId}/${channel}`,
+    method: 'POST'
+  })
+}
+
+/** 自定义视频流 */
+export const liveCustomRtsUrl = (data: {id: string, rtsUrl: string}) => {
+  return request<string>({
+    url: '/device/rtsUrl',
+    method: 'PUT',
+    data
+  })
+}

+ 13 - 1
src/controller/iot/device.ts

@@ -2,7 +2,7 @@ import {
   addDevice, addSubDevice, delDevice, delDeviceMul, delDeviceTag,
   getDeviceById, getDeviceCount, getDeviceList, getDeviceMsgList, addDeviceMsg, getDeviceTag,
   getSubDeviceList, updateDeviceLabel, addDeviceCmd, getDeviceCmdList, addDeviceTag, addDeviceGroup,
-  listDeviceGroup, postGroupBindDevice, delGroupBindDevice, getDeviceByGroup, getDevicePage, delSubDevice, getDeviceAttribute, getDevicShadow, getDeviceTopology, getDeviceSession, getDeviceAttributes, getDeviceSecret, getOtaByDeviceId, otaUpgradationRecordByDeviceId, upgradationOtaByDeviceId
+  listDeviceGroup, postGroupBindDevice, delGroupBindDevice, getDeviceByGroup, getDevicePage, delSubDevice, getDeviceAttribute, getDevicShadow, getDeviceTopology, getDeviceSession, getDeviceAttributes, getDeviceSecret, getOtaByDeviceId, otaUpgradationRecordByDeviceId, upgradationOtaByDeviceId, liveById, liveControlRts, liveCustomRtsUrl
 } from '@/api/iot/device'
 import { DeviceMsgEnum, OtaStatusEnum } from '@/enum/common'
 import { message } from 'ant-design-vue'
@@ -291,4 +291,16 @@ export class DeviceContriller {
     await upgradationOtaByDeviceId(deviceId, otaPkgId)
     message.success('升级设备成功')
   }
+
+  static async liveById (deviceId: string) {
+    return liveById(deviceId)
+  }
+
+  static async liveControlRts (deviceId: string, channel: number) {
+    return liveControlRts(deviceId, channel)
+  }
+
+  static async liveCustomRtsUrl (data: {id: string, rtsUrl: string}) {
+    return liveCustomRtsUrl(data)
+  }
 }

+ 100 - 2
src/pages/Iot/device/components/live.vue

@@ -1,10 +1,108 @@
 <template>
   <a-card>
-
+    <a-row  align="middle" justify="space-between" style="width: 100%; height: 68px" class="title">
+      <a-col :span="12" >
+        视频流地址: {{state.deviceDetail.rtsPlayUrl}}
+      </a-col>
+      <a-col :span="12">
+        <a-space>
+          <a-button @click="openModal('custom')" >自定义视频流</a-button>
+          <a-button type="primary" @click="openModal('control')" >视频流通道控制</a-button>
+          <a-button @click="getDeviceById" >获取视频流</a-button>
+        </a-space>
+      </a-col>
+    </a-row>
+    <video-player-tsx
+      :video-url="state.deviceDetail.rtsPlayUrl"
+    />
   </a-card>
+
+<modal-pro
+  :label="modalTitle"
+  :open="state.visible"
+  @cancel="state.visible = false"
+  @ok="ok"
+>
+<a-form  :labelCol="{span: 6}" :wrapperCol="{span: 14}" >
+  <a-form-item label="视频流通道" v-bind="validateInfos.channel" >
+    <a-input-number v-model:value="formState.channel" ></a-input-number>
+  </a-form-item>
+  <a-form-item label="视频流地址" v-bind="validateInfos.rtsUrl" >
+    <a-input  v-model:value="formState.rtsUrl" ></a-input>
+  </a-form-item>
+</a-form>
+</modal-pro>
 </template>
 
 <script lang="ts" setup >
+import { VideoPlayerTsx } from '@/components/VideoPlayer/index'
+import { DeviceContriller } from '@/controller'
+import { onMounted, reactive, computed } from 'vue'
+import { useRoute } from 'vue-router'
+import { Form } from 'ant-design-vue'
+
+const route = useRoute()
+
+const deviceId = route.query.id as string
+
+const modalTitle = computed(() => state.modalType === 'control' ? '填写通道' : ' 填写视频流')
+
+const state = reactive<{
+  deviceDetail: Partial<IOT.API.DEVICE.Device>,
+  modalType: 'custom' | 'control'
+  visible: boolean
+  playUrl: string
+}>({
+  deviceDetail: {},
+  modalType: 'custom',
+  visible: false,
+  playUrl: ''
+})
+
+const formState = reactive({
+  channel: '',
+  rtsUrl: ''
+})
+
+const useForm = Form.useForm
+
+const { resetFields, validate, validateInfos } = useForm(formState, reactive({
+  channel: [{ required: true, message: '请填写通道数' }],
+  rtsUrl: [{ required: true, message: '请填写视频流地址' }]
+}))
+
+const ok = async () => {
+  state.modalType === 'custom' ? await DeviceContriller.liveCustomRtsUrl({ id: '', rtsUrl: formState.rtsUrl }) : await DeviceContriller.liveControlRts(deviceId, formState.channel as unknown as number)
+  getLive()
+  state.visible = false
+}
+
+const openModal = (modalType: 'custom' | 'control') => {
+  state.modalType = modalType
+  state.visible = true
+}
+
+const getLive = async () => {
+  const { data } = await DeviceContriller.liveById(deviceId)
+  state.playUrl = data
+}
+
+const getDeviceById = async () => {
+  state.deviceDetail = await DeviceContriller.byId(deviceId)
+}
+
+onMounted(() => {
+  getDeviceById()
+  getLive()
+})
+
 </script>
 
-<style></style>
+<style lang="less" scoped >
+@import '~@/styles/theme.less';
+
+.title {
+  background-color: @bg-color-1;
+  padding-left: 40px;
+}
+</style>

+ 1 - 1
src/pages/Iot/device/components/ota.vue

@@ -169,7 +169,7 @@ onMounted(() => {
 })
 </script>
 
-<style lang="less" >
+<style lang="less" scoped >
 @import '~@/styles/theme.less';
 
 .title {

+ 95 - 40
src/pages/Iot/device/detail.vue

@@ -1,12 +1,15 @@
 <template>
   <a-card>
-    <a-tabs v-model:activeKey="state.tabsActive">
+    <a-spin spinning="" >
+      <a-tabs v-model:activeKey="state.tabsActive">
       <a-tab-pane
-        v-for="item in tabs"
+        v-for="item in state.tabs"
         :key="item.key"
         :tab="item.name"
       />
-    </a-tabs>
+      </a-tabs>
+    </a-spin>
+
     <OverView  :deviceId="state.deviceId" :key="state.deviceId" v-if="state.tabsActive === '1'"/>
     <CloudView   v-else-if="state.tabsActive === '2'"/>
     <DeviceShadow v-else-if="state.tabsActive === '3'" />
@@ -14,11 +17,12 @@
     <SubDevice @goDetail="goDetail" v-else-if="state.tabsActive === '5'" />
     <DeviceTag @goDetail="goDetail" v-else-if="state.tabsActive === '6'" />
     <Ota v-else-if="state.tabsActive === '7'" />
+    <Live v-else-if="state.tabsActive === '8'" />
   </a-card>
 </template>
 
 <script lang="ts" setup >
-import { computed, onMounted, reactive } from 'vue'
+import { onMounted, reactive } from 'vue'
 import OverView from './components/overview.vue'
 import CloudView from './components/cloudview.vue'
 import DeviceShadow from './components/deviceShadow.vue'
@@ -26,51 +30,88 @@ import MsgTrack from './components/msgTrack.vue'
 import SubDevice from './components/subDevice.vue'
 import DeviceTag from './components/deviceTag.vue'
 import Ota from './components/ota.vue'
+import Live from './components/live.vue'
 import { useRoute } from 'vue-router'
 import { DeviceContriller } from '@/controller'
-import { StateEffect } from '@codemirror/state'
 
-const tabs = [
-  {
-    name: '概述',
-    key: '1'
-  },
-  {
-    name: '云端下发',
-    key: '2'
-  },
-  {
-    name: '设备影子',
-    key: '3'
-  },
-  {
-    name: '消息跟踪',
-    key: '4'
-  },
-  {
-    name: '子设备',
-    key: '5'
-  },
-  {
-    name: '标签',
-    key: '6'
-  },
-  {
-    name: 'OTA',
-    key: '7'
-  },
-  {
-    name: 'Live',
-    key: '8'
-  }
-]
+// const tabs = [
+//   {
+//     name: '概述',
+//     key: '1'
+//   },
+//   {
+//     name: '云端下发',
+//     key: '2'
+//   },
+//   {
+//     name: '设备影子',
+//     key: '3'
+//   },
+//   {
+//     name: '消息跟踪',
+//     key: '4'
+//   },
+//   {
+//     name: '子设备',
+//     key: '5'
+//   },
+//   {
+//     name: '标签',
+//     key: '6'
+//   },
+//   {
+//     name: 'OTA',
+//     key: '7'
+//   },
+//   {
+//     name: 'Live',
+//     key: '8'
+//   }
+// ]
 
 const route = useRoute()
+
 const deviceId = route.query.id as string
 
 const state = reactive({
   tabsActive: '1',
-  deviceId: deviceId
+  spinning: false,
+  deviceId: deviceId,
+  deviceDetail: {},
+  tabs: [
+    {
+      name: '概述',
+      key: '1'
+    },
+    {
+      name: '云端下发',
+      key: '2'
+    },
+    {
+      name: '设备影子',
+      key: '3'
+    },
+    {
+      name: '消息跟踪',
+      key: '4'
+    },
+    {
+      name: '子设备',
+      key: '5'
+    },
+    {
+      name: '标签',
+      key: '6'
+    },
+    {
+      name: 'OTA',
+      key: '7'
+    },
+    {
+      name: 'Live',
+      key: '8'
+    }
+  ]
 })
 
 const goDetail = ({ id }) => {
@@ -78,6 +119,20 @@ const goDetail = ({ id }) => {
   state.deviceId = id
 }
 
+const getDeviceById = async () => {
+  state.spinning = true
+  const deviceDetail = await DeviceContriller.byId(deviceId)
+  state.deviceDetail = deviceDetail
+  if (!deviceDetail.rtsUrl) {
+    state.tabs.splice(7, 1)
+  }
+  state.spinning = false
+}
+
+onMounted(() => {
+  getDeviceById()
+})
+
 </script>
 
 <style lang="less" scoped >

+ 1 - 2
src/pages/rts/stream/index.vue

@@ -28,8 +28,7 @@
     @ok="state.visible = false"
     destroyOnClose
   >
-  <!-- :video-url="useFlvUrl(state.detail.Path!)" -->
-    <video-player-tsx  />
+    <video-player-tsx :video-url="useFlvUrl(state.detail.Path!)" />
   </modal-pro>
 </template>
 

+ 2 - 0
src/type/iot.d.ts

@@ -134,6 +134,8 @@ declare namespace IOT {
         lastConnectTs: string
         lastActivityTs: string
         authType: 'SECRET' | 'X509CERT'
+        rtsPlayUrl: string
+        rtsUrl: string
       }
 
       interface DeviceTag {