lvkun 2 yıl önce
ebeveyn
işleme
862c789858

+ 1 - 1
public/index.html

@@ -4,7 +4,7 @@
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
-    <link rel="icon" href="logo.ico">
+    <link rel="icon" href="./logo.ico">
     <title>蛟龙云联</title>
     <style type="text/css">
       .icon {

+ 26 - 1
src/api/iot/device.ts

@@ -299,7 +299,7 @@ export const getOtaByDeviceId = (deviceId: string) => {
   })
 }
 
-export const getOtaPageByDeviceId = (params: IOT.API.DEVICE.OtaQueryParams) => {
+export const otaUpgradationRecordByDeviceId = (params: IOT.API.DEVICE.OtaQueryParams) => {
   return request<IOT.API.DEVICE.Ota[]>({
     url: '/deviceOta/page',
     method: 'GET',
@@ -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
+  })
+}

+ 1 - 1
src/api/iot/ota.ts

@@ -10,7 +10,7 @@ export const getOtaPkgPage = (params: IOT.API.OTA.QueryParams) => {
 
 export const getOtaPkgList = (params: IOT.API.OTA.QueryParams) => {
   return request<IOT.API.OTA.Detail[]>({
-    url: '/otaPkg/page',
+    url: '/otaPkg/list',
     method: 'GET',
     params
   })

+ 32 - 6
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, getOtaPageByDeviceId, 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'
@@ -77,13 +77,23 @@ export class DeviceContriller {
     }
   }
 
-  static async list (params: {modelId: string, deviceLabel: string, limit: number, lastId: string } = {
+  /**
+   *
+   * @param  deviceStatus 传递对应的key,就只会返回对应状态的设备,不填写返回全部
+   * @returns
+   */
+  static async list (params: {modelId: string, deviceLabel: string, limit: number, lastId: string, deviceStatus: 'INIT' | 'CONNECT' | 'DISCONNECT' | 'DISABLED' | ''} = {
     modelId: '',
     deviceLabel: '',
     limit: 10000,
-    lastId: ''
+    lastId: '',
+    deviceStatus: ''
   }) {
-    return await getDeviceList(params)
+    const data = await getDeviceList(params)
+    return {
+      ...data,
+      data: params.deviceStatus === '' ? data.data : data.data.filter(item => item.deviceStatus === params.deviceStatus)
+    }
   }
 
   static async post (data: IOT.API.DEVICE.BodyParams) {
@@ -269,12 +279,28 @@ export class DeviceContriller {
     }
   }
 
-  static async OtaPageByDeviceId (params: IOT.API.DEVICE.OtaQueryParams) {
-    return await getOtaPageByDeviceId(params)
+  static async OtaUpgradationRecordByDeviceId (params: IOT.API.DEVICE.OtaQueryParams) {
+    const data = await otaUpgradationRecordByDeviceId(params)
+    return {
+      ...data,
+      data: data.data.map(item => ({ ...item, otaTime: dayjs(item.otaTime).format('YYYY-MM-DD HH:mm:ss') }))
+    }
   }
 
   static async upgradationOtaByDeviceId ({ deviceId, otaPkgId }: {deviceId: string, otaPkgId: string}) {
     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)
+  }
 }

+ 9 - 3
src/controller/iot/ota.ts

@@ -1,4 +1,4 @@
-import { addOtaPkg, delOtaPkg, getOtaPkgById, getOtaPkgPage } from '@/api/iot/ota'
+import { addOtaPkg, delOtaPkg, getOtaPkgById, getOtaPkgList, getOtaPkgPage } from '@/api/iot/ota'
 import { PkgTypeEnum } from '@/enum/common'
 import { message } from 'ant-design-vue'
 
@@ -10,7 +10,13 @@ export class OtaController {
 
   static pkgTypeList = [{ value: PkgTypeEnum.FILE_URL, label: '地址访问' }, { value: PkgTypeEnum.FILE_ZIP, label: 'zip包' }]
 
-  static async page (params: IOT.API.OTA.QueryParams) {
+  static async page (params: IOT.API.OTA.QueryParams = {
+    page: 1,
+    pageSize: 10,
+    label: '',
+    version: '',
+    pkgType: ''
+  }) {
     return await getOtaPkgPage(params)
   }
 
@@ -20,7 +26,7 @@ export class OtaController {
     pkgType: '',
     limit: 10000
   }) {
-    return await getOtaPkgPage(params as any)
+    return await getOtaPkgList(params as any)
   }
 
   static async add (data: IOT.API.OTA.BodyParams) {

+ 0 - 1
src/hooks/effect.ts

@@ -2,7 +2,6 @@ import { Emitter } from '@/enum/emitter'
 import mitt from 'mitt'
 import { setBaseUrl } from '@/service/request'
 import { useRoute } from 'vue-router'
-
 import { ref, onUnmounted, onMounted } from 'vue'
 
 const emitter = mitt()

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

@@ -166,7 +166,7 @@ import { Form, message } from 'ant-design-vue'
 import dayjs from 'dayjs'
 
 const msg = '消息下发不依赖产品模型,平台会以异步方式(消息下发后无需等待设备侧回复响应)下发消息给设备。当前仅MQTT设备支持消息下发。'
-const cmdMsg = '如果设备所属产品定义了命令功能,则您可以通过应用调用平台接口或者操作下面的“下发命令”按钮下发命令。当前MQTT设备仅支持同步命令下发,NB设备仅支持异步命令下发 。'
+const cmdMsg = '如果设备所属产品定义了命令功能,则您可以通过应用调用平台接口或者操作下面的“下发命令”按钮下发命令。当前MQTT设备仅支持同步命令下发,设备仅支持异步命令下发 。'
 const modalTitle = '新增下发消息'
 const tabListNoTitle = [
   {

+ 108 - 0
src/pages/Iot/device/components/live.vue

@@ -0,0 +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 lang="less" scoped >
+@import '~@/styles/theme.less';
+
+.title {
+  background-color: @bg-color-1;
+  padding-left: 40px;
+}
+</style>

+ 44 - 28
src/pages/Iot/device/components/ota.vue

@@ -1,16 +1,22 @@
 <template>
   <a-card>
-    <a-row  align="middle" justify="space-between" style="width: 100%;height: 68px" class="title">
-      <a-col>
-        <a-space>
-          <span>设备名称:{{state.otaDetail.otaPkgLabel}}</span>
-          <span>设备版本:{{state.otaDetail.otaPkgVersion}}</span>
+
+    <a-row  align="middle" justify="space-between" style="width: 100%; height: 68px" class="title">
+      <a-col :span="12" >
+        <a-space :size="50" >
+          <span  style="font-size: 14px;font-weight: 500;" >OTA包名称:    {{state.otaDetail.otaPkgLabel}}   </span>
+          <span  style="font-size: 14px;font-weight: 500;" >OTA包版本号:  {{state.otaDetail.otaPkgVersion}} </span>
         </a-space>
       </a-col>
-      <a-col :span="2" >
+      <a-col :span="4" >
         <a-button type="primary" @click="openModal" >下发OTA程序包</a-button>
       </a-col>
     </a-row>
+
+    <a-row style="margin-top: 20px;">
+      <a-col style="font-size: 20px;font-weight: 600;" >设备升级历史</a-col>
+    </a-row>
+
     <a-table
       style="margin-top: 20px;"
       :columns="columns"
@@ -21,12 +27,13 @@
     >
       <template #bodyCell="{column, record}">
         <template v-if="column.key === 'status'" >
-          <a-tag :colo="DeviceContriller.otaStatusMap.get(record.status)?.color">
+          <a-tag :color="DeviceContriller.otaStatusMap.get(record.status)?.color">
             {{DeviceContriller.otaStatusMap.get(record.status)?.label}}
           </a-tag>
         </template>
       </template>
     </a-table>
+
   </a-card>
 
   <modal-pro
@@ -35,25 +42,32 @@
     @cancel="state.visible = false"
     @ok="ok"
   >
-  <a-form  :labelCol="{span: 6}" :wrapperCol="{span: 14}" >
-    <a-form-item label="所属产品" v-bind="validateInfos.deviceId" >
-      <!-- 这个写法丑陋的一批 -->
-      <select-tsx
-        v-model:value="otaState.deviceId"
-        :request="async () => {
-          const { data } = await DeviceContriller.list()
-          return data.map(item => ({name: item.deviceLabel, value: item.id, key: item.id}))
-        }"
-      />
-      </a-form-item>
-      <a-form-item label="所属产品" v-bind="validateInfos.otaPkgId" >
-      </a-form-item>
-  </a-form>
+    <a-form  :labelCol="{span: 6}" :wrapperCol="{span: 14}" >
+      <a-form-item label="所属产品" v-bind="validateInfos.deviceId" >
+        <!-- 这个写法丑陋的一批 -->
+        <select-tsx
+          v-model:value="otaState.deviceId"
+          :request="async () => {
+            const { data } = await DeviceContriller.list()
+            return data.filter(_ => _.deviceStatus === 'CONNECT').map(item => ({name: item.deviceLabel, value: item.id, key: item.id}))
+          }"
+        />
+        </a-form-item>
+        <a-form-item label="所属OTA包" v-bind="validateInfos.otaPkgId" >
+          <select-tsx
+            v-model:value="otaState.otaPkgId"
+            :request="async () => {
+              const { data } = await OtaController.list()
+              return data.map(item => ({name: item.label, value: item.id, key: item.id}))
+            }"
+          />
+        </a-form-item>
+    </a-form>
   </modal-pro>
 </template>
 
 <script setup lang="ts" >
-import { DeviceContriller } from '@/controller'
+import { DeviceContriller, OtaController } from '@/controller'
 import { onMounted, reactive } from 'vue'
 import { useRoute } from 'vue-router'
 import { Form } from 'ant-design-vue'
@@ -73,7 +87,7 @@ const columns = [
     dataIndex: 'otaPkgVersion'
   },
   {
-    title: 'OTA升级名称',
+    title: 'OTA升级时间',
     dataIndex: 'otaTime'
   },
   {
@@ -119,6 +133,7 @@ const { resetFields, validate, validateInfos } = useForm(otaState, {
 
 const openModal = () => {
   state.visible = true
+  resetFields({})
 }
 
 const ok = () => {
@@ -126,17 +141,18 @@ const ok = () => {
     await DeviceContriller.upgradationOtaByDeviceId(otaState)
     state.visible = false
     getOtaPkgByDeviceId()
+    getOtaUpgradationRecordByDeviceId()
   })
 }
 
 const changePage = ({ current }) => {
   queryState.page = current
-  getOtaPkgPageByDeviceId()
+  getOtaUpgradationRecordByDeviceId()
 }
 
-const getOtaPkgPageByDeviceId = async () => {
+const getOtaUpgradationRecordByDeviceId = async () => {
   state.loading = true
-  const { data, sum } = await DeviceContriller.OtaPageByDeviceId(queryState)
+  const { data, sum } = await DeviceContriller.OtaUpgradationRecordByDeviceId(queryState)
   state.loading = false
   state.dataSource = data
   queryState.total = sum
@@ -149,11 +165,11 @@ const getOtaPkgByDeviceId = async () => {
 
 onMounted(() => {
   getOtaPkgByDeviceId()
-  getOtaPkgPageByDeviceId()
+  getOtaUpgradationRecordByDeviceId()
 })
 </script>
 
-<style lang="less" >
+<style lang="less" scoped >
 @import '~@/styles/theme.less';
 
 .title {

+ 95 - 36
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,47 +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'
-  }
-]
+// 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 }) => {
@@ -74,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 >

+ 8 - 0
src/pages/Iot/device/index.vue

@@ -66,6 +66,9 @@
         <template v-if="column.key === 'deviceNodeType'" >
           <a-tag>{{record.deviceNodeType == 'GATEWAY'?'直连类型':'非直连类型'}}</a-tag>
         </template>
+        <template v-if="column.key === 'rtsUrl'" >
+          {{record.rtsUrl ? '支持': '否'}}
+        </template>
         <template v-if="column.key === 'action'">
             <a-space>
               <a @click="goDetailPage(record.id)">查看</a>
@@ -165,6 +168,11 @@ const columns = [
     title: '所属产品',
     dataIndex: 'modelLabel'
   },
+  {
+    title: '是否支持live',
+    dataIndex: 'rtsUrl',
+    key: 'rtsUrl'
+  },
   {
     title: '状态',
     dataIndex: 'deviceStatus',

+ 4 - 1
src/pages/Iot/model/components/modelDefine.vue

@@ -57,6 +57,7 @@
                 <a-space>
                     <a @click="openModel('cmdVisible', 'update', record)" >修改</a>
                     <a-popconfirm
+                      v-if="record.canRemove"
                       title="确实要删除吗?"
                       ok-text="确定"
                       cancel-text="取消"
@@ -345,7 +346,8 @@ const cmdRef = reactive({
   cmdLabel: '',
   cmdParams: [],
   cmdResponses: [],
-  modelId: ''
+  modelId: '',
+  canRemove: false
 })
 
 const cmdParamsRef = reactive({
@@ -446,6 +448,7 @@ const openModel = (key: string, opraState: 'add' | 'update', record: any = {}) =
     resetFields(record)
   } else {
     resetFieldsCmd(record)
+    if (!record.cmdParams) return
     state.dataCmdParams.requestData = record.cmdParams.map(item => {
       return {
         ...item,

+ 5 - 5
src/pages/Iot/model/detail.vue

@@ -17,11 +17,11 @@
     :labelStyle="{color: '#8a8e99'}"
     :contentStyle="{fontSize: '12px'}"
   >
-        <a-descriptions-item label="产品模型名称">{{state.model?.modelLabel}}</a-descriptions-item>
-        <a-descriptions-item label="设备类型">{{state.model?.deviceType}}</a-descriptions-item>
-        <a-descriptions-item label="协议类型">{{state.model?.transportType}}</a-descriptions-item>
-        <a-descriptions-item label="数据类型">{{state.model?.payloadType}}</a-descriptions-item>
-        <a-descriptions-item label="产品描述">{{state.model?.modelDescription}}</a-descriptions-item>
+    <a-descriptions-item label="产品模型名称">{{state.model?.modelLabel}}</a-descriptions-item>
+    <a-descriptions-item label="设备类型">{{state.model?.deviceType}}</a-descriptions-item>
+    <a-descriptions-item label="协议类型">{{state.model?.transportType}}</a-descriptions-item>
+    <a-descriptions-item label="数据类型">{{state.model?.payloadType}}</a-descriptions-item>
+    <a-descriptions-item label="产品描述">{{state.model?.modelDescription}}</a-descriptions-item>
   </a-descriptions>
   </a-card>
 

+ 5 - 1
src/pages/Iot/model/index.vue

@@ -109,6 +109,9 @@
     <a-form-item label="厂商描述">
       <a-textarea  :disabled="formOptions.disabled" v-model:value="modelRef.modelDescription" />
     </a-form-item>
+    <a-form-item label="支持视频流">
+      <a-switch v-model:checked="modelRef.rts" checked-children="支持" un-checked-children="不支持" />
+    </a-form-item>
    </a-form>
   </a-modal>
 </template>
@@ -196,7 +199,8 @@ const modelRef = reactive({
   transportType: '',
   payloadType: '',
   deviceType: '',
-  modelDescription: ''
+  modelDescription: '',
+  rts: false
 })
 
 const rulesRef = reactive({

+ 3 - 2
src/pages/Iot/ota/index.vue

@@ -1,6 +1,6 @@
 <template>
-<a-card title="ota包管理" >
-  <a-row justify="space-between" >
+<a-card title="OTA包管理" >
+  <a-row style="width: 100%;" justify="space-between" >
     <a-col :span="16" >
       <a-row :gutter="[8, 8]" >
         <a-col>
@@ -29,6 +29,7 @@
       <a-button type="primary" @click="openModal('add', {})">新增</a-button>
     </a-col>
   </a-row>
+
   <a-table
       style="margin-top: 10px;"
       :columns="columns"

+ 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>
 

+ 1 - 1
src/router/index.ts

@@ -163,7 +163,7 @@ const iot = {
     },
     {
       path: '/ota',
-      name: 'ota包管理',
+      name: 'OTA程序包',
       icon: 'FolderAddOutlined',
       component: () => import('@/pages/iot/ota/index.vue')
     },

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

@@ -17,6 +17,7 @@ declare namespace IOT {
         payloadType: string,
         deviceType: string,
         modelDescription: string,
+        rts: boolean // 用来标志是否具备视频流能力
       }
 
       interface ModelDot extends Model {
@@ -91,7 +92,8 @@ declare namespace IOT {
           'scope': string,
           'description': string
         }[],
-        'modelId': string
+        'modelId': string,
+        canRemove: boolean // 用来标志是否可以被删除,具备该值且者该值为true的情况下 命令是不能有删除按钮
       }
     }
 
@@ -132,6 +134,8 @@ declare namespace IOT {
         lastConnectTs: string
         lastActivityTs: string
         authType: 'SECRET' | 'X509CERT'
+        rtsPlayUrl: string
+        rtsUrl: string
       }
 
       interface DeviceTag {
@@ -459,7 +463,7 @@ declare namespace IOT {
         pageSize: number
         label: string
         version: string
-        pkgType: 'FILE_URL' | 'FILE_ZIP'
+        pkgType: 'FILE_URL' | 'FILE_ZIP' | ''
       }
       interface BodyParams {
         label: string