yanghao 23 часов назад
Родитель
Сommit
b547324b74

+ 1 - 1
.env.local

@@ -3,7 +3,7 @@ NODE_ENV=development
 
 VITE_DEV=true
 
-# 请求路径  http://192.168.188.149:48080  https://iot.deepoil.cc
+# 请求路径  http://192.168.188.149:48080  https://iot.deepoil.cc  http://172.26.0.3:48080
 VITE_BASE_URL='http://172.26.0.3:48080'
 
 # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务

+ 64 - 40
src/views/pms/video_center/sip/components/player/DeviceTree.vue

@@ -1,72 +1,78 @@
 <template>
   <div id="DeviceTree" style="width: 100%; height: 100%; background-color: #ffffff; overflow: auto">
-    <div style="line-height: 3vh; margin-bottom: 10px; font-size: 17px;" class="pl-5 mt-2">设备列表</div>
-    <el-tree 
-      ref="treeRef" 
-      :props="defaultProps" 
-      :current-node-key="selectchannelId" 
+    <div style="line-height: 3vh; margin-bottom: 10px; font-size: 17px" class="pl-5 mt-2"
+      >设备列表</div
+    >
+    <el-tree
+      ref="treeRef"
+      :props="defaultProps"
+      :current-node-key="selectchannelId"
       :default-expanded-keys="expandIds"
-      :highlight-current="true" 
-      @node-click="handleNodeClick" 
-      :load="loadNode" 
-      lazy 
+      :highlight-current="true"
+      @node-click="handleNodeClick"
+      :load="loadNode"
+      lazy
       node-key="id"
       style="min-width: 100%; display: inline-block !important"
     >
       <template #default="{ node, data }">
         <span class="custom-tree-node" style="width: 100%">
-          <span 
-            v-if="data.type === 0 && data.online" 
+          <span
+            v-if="data.type === 0 && data.online"
             title="在线设备"
             class="device-online iconfont icon-jiedianleizhukongzhongxin2"
           ></span>
-          <span 
-            v-if="data.type === 0 && !data.online" 
+          <span
+            v-if="data.type === 0 && !data.online"
             title="离线设备"
             class="device-offline iconfont icon-jiedianleizhukongzhongxin2"
           ></span>
-          <span 
-            v-if="data.type === 3 && data.online" 
+          <span
+            v-if="data.type === 3 && data.online"
             title="在线通道"
             class="device-online iconfont icon-shebeileijiankongdian"
           ></span>
-          <span 
-            v-if="data.type === 3 && !data.online" 
+          <span
+            v-if="data.type === 3 && !data.online"
             title="离线通道"
             class="device-offline iconfont icon-shebeileijiankongdian"
           ></span>
-          <span 
-            v-if="data.type === 4 && data.online" 
+          <span
+            v-if="data.type === 4 && data.online"
             title="在线通道-球机"
             class="device-online iconfont icon-shebeileiqiuji"
           ></span>
-          <span 
-            v-if="data.type === 4 && !data.online" 
+          <span
+            v-if="data.type === 4 && !data.online"
             title="离线通道-球机"
             class="device-offline iconfont icon-shebeileiqiuji"
           ></span>
-          <span 
-            v-if="data.type === 5 && data.online" 
+          <span
+            v-if="data.type === 5 && data.online"
             title="在线通道-半球"
             class="device-online iconfont icon-shebeileibanqiu"
           ></span>
-          <span 
-            v-if="data.type === 5 && !data.online" 
+          <span
+            v-if="data.type === 5 && !data.online"
             title="离线通道-半球"
             class="device-offline iconfont icon-shebeileibanqiu"
           ></span>
-          <span 
-            v-if="data.type === 6 && data.online" 
+          <span
+            v-if="data.type === 6 && data.online"
             title="在线通道-枪机"
             class="device-online iconfont icon-shebeileiqiangjitongdao"
           ></span>
-          <span 
-            v-if="data.type === 6 && !data.online" 
+          <span
+            v-if="data.type === 6 && !data.online"
             title="离线通道-枪机"
             class="device-offline iconfont icon-shebeileiqiangjitongdao"
           ></span>
-          <span v-if="data.online" style="padding-left: 1px" class="device-online">{{ node.label }}</span>
-          <span v-if="!data.online" style="padding-left: 1px" class="device-offline">{{ node.label }}</span>
+          <span v-if="data.online" style="padding-left: 1px" class="device-online">{{
+            node.label
+          }}</span>
+          <span v-if="!data.online" style="padding-left: 1px" class="device-offline">{{
+            node.label
+          }}</span>
         </span>
       </template>
     </el-tree>
@@ -111,7 +117,7 @@ const selectchannelId = ref('')
 const defaultProps = reactive({
   children: 'children',
   label: 'name',
-  isLeaf: 'isLeaf',
+  isLeaf: 'isLeaf'
 })
 
 // 查询参数
@@ -119,7 +125,7 @@ const queryParams = reactive({
   pageNum: 1,
   pageSize: 100,
   status: 3,
-  deviceType: 3,
+  deviceType: 3
 })
 
 // 生命周期钩子
@@ -136,7 +142,7 @@ onUnmounted(() => {
 const handleNodeClick = (data, node, element) => {
   selectData.value = node.data
   selectchannelId.value = node.data.value
-  
+
   if (node.level !== 0) {
     // 修正:设备节点(level=1)和通道节点(level>1)都触发事件
     if (typeof props.clickEvent === 'function') {
@@ -160,7 +166,7 @@ const loadNode = (node, resolve) => {
             id: data[i].serialNumber,
             type: 0,
             online: data[i].status === 3,
-            userData: data[i],
+            userData: data[i]
           }
           nodeList.push(node)
         }
@@ -173,7 +179,13 @@ const loadNode = (node, resolve) => {
     let channelArray = []
     listSipDeviceChannel(node.data.userData.serialNumber).then((res) => {
       if (res != null) {
-        channelArray = channelArray.concat(res)
+        let list = []
+        res.forEach((item) => {
+          if (item.basicData.model === 'Camera') {
+            list.push(item)
+          }
+        })
+        channelArray = channelArray.concat(list)
         channelDataHandler(channelArray, resolve)
       } else {
         resolve([])
@@ -197,7 +209,13 @@ const channelDataHandler = (data, resolve) => {
         if (item.id.length > 14) {
           let channelType = item.id.substring(10, 13)
           // 111-DVR编码;112-视频服务器编码;118-网络视频录像机(NVR)编码;131-摄像机编码;132-网络摄像机(IPC)编码
-          if (channelType !== '111' && channelType !== '112' && channelType !== '118' && channelType !== '131' && channelType !== '132') {
+          if (
+            channelType !== '111' &&
+            channelType !== '112' &&
+            channelType !== '118' &&
+            channelType !== '131' &&
+            channelType !== '132'
+          ) {
             type = -1
             // 1-球机;2-半球;3-固定枪机;4-遥控枪机
           } else if (item.basicData.ptztype === 1) {
@@ -220,10 +238,16 @@ const channelDataHandler = (data, resolve) => {
         deviceId: item.deviceId,
         type: type,
         online: item.status === 3,
-        userData: item.basicData,
+        userData: item.basicData
       }
 
-      if (channelType === '111' || channelType === '112' || channelType === '118' || channelType === '131' || channelType === '132') {
+      if (
+        channelType === '111' ||
+        channelType === '112' ||
+        channelType === '118' ||
+        channelType === '131' ||
+        channelType === '132'
+      ) {
         nodeList.push(node)
       }
     }
@@ -260,4 +284,4 @@ defineExpose({
 .device-offline {
   color: #727272;
 }
-</style>
+</style>

+ 183 - 143
src/views/pms/video_center/sip/components/player/easy.vue

@@ -1,10 +1,15 @@
 <template>
-  <div ref="easyPlayerRef" style="width: 200px; height: 300px; background-color: #000000"></div>
+  <div
+    ref="easyPlayerRef"
+    style="width: 100%; height: 100%; background-color: #000000; margin: 0 auto"
+  ></div>
 </template>
 
 <script setup>
 import { ref, reactive, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
 import { ptzdirection, ptzscale } from '@/api/pms/video/sipdevice'
+import { useRoute } from 'vue-router'
+const route = useRoute()
 
 // 响应式数据
 const easyPlayerRef = ref(null)
@@ -12,6 +17,10 @@ const playInfo = ref({})
 const playInfo2 = ref({})
 const playtype = ref('play')
 const props = defineProps({
+  videourl: {
+    type: String,
+    default: ''
+  },
   playerInfo: {
     type: Object,
     default: null
@@ -25,10 +34,15 @@ const props = defineProps({
     default: '630px'
   }
 })
+const playing = ref(false)
 
-const videoUrl = ref('')
+let videoUrl = ref('')
 const isPlay = ref(false)
 
+let easyplayer = {}
+
+const emit = defineEmits(['screenshot', 'destroy'])
+
 const config = reactive({
   hasAudio: true,
   isLive: true,
@@ -36,39 +50,125 @@ const config = reactive({
   WCS: false
 })
 
-// 方法定义
-const play = async (url) => {
-  console.log('EasyPlayer 播放视频 url: ', url)
-  videoUrl.value = url
-  await onDestroy()
-  playCreate()
-  onPlayer()
+const playCreate = () => {
+  const container = easyPlayerRef.value
+  if (!container) return
+
+  const uid = route.params._uid || Date.now() // 使用时间戳作为唯一标识
+
+  easyplayer[uid] = new EasyPlayerPro(container, {
+    isLive: config.isLive,
+    bufferTime: 0.2,
+    stretch: false,
+    MSE: config.MSE,
+    WCS: config.WCS,
+    hasAudio: config.hasAudio,
+    watermark: { text: { content: '' }, right: 10, top: 10 },
+    isBand: true,
+    btns: {
+      play: true,
+      audio: true,
+      record: true,
+      zoom: true,
+      ptz: true,
+      quality: true,
+      stretch: false,
+      screenshot: true,
+      fullscreen: true
+    }
+  })
+
+  let easyplay = easyplayer[uid]
+
+  easyplay.on('fullscreen', function (flag) {
+    console.log('is fullscreen', flag)
+  })
+
+  easyplay.on('ptz', (direction) => {
+    handlePtz(direction)
+  })
+
+  easyplay.on('playbackRate', (rate) => {
+    easyplay.setRate(rate)
+  })
+
+  easyplay.on('playbackSeek', (data) => {
+    console.log('playbackSeek', data)
+  })
+
+  playInfo.value = easyplayer
+  if (playInfo2.value && playInfo2.value.id && playInfo2.value.deviceId) {
+    playInfo.value.channelId = playInfo2.value.id
+    playInfo.value.deviceId = playInfo2.value.deviceId
+  }
+
+  playInfo.value.playtype = playtype.value
 }
 
-const pause = () => {
-  onPause()
+// 播放视频
+function play(url) {
+  const uid = route.params._uid || Date.now()
+
+  // 确保容器已准备就绪
+  if (!easyPlayerRef.value) {
+    console.error('Cannot play: container is not ready')
+    return
+  }
+
+  if (easyplayer[uid]) {
+    destroy().then(() => {
+      if (easyplayer[uid]) {
+        easyplayer[uid].play(url)
+      } else {
+        easyplayer[uid].on('load', () => {
+          console.log('load 播放')
+          easyplayer[uid].play(url)
+        })
+      }
+    })
+  } else {
+    playCreate()
+
+    if (easyplayer[uid]) {
+      easyplayer[uid].play(url)
+    } else {
+      easyplayer[uid].on('load', () => {
+        console.log('load 播放')
+        easyplayer[uid].play(url)
+      })
+    }
+  }
 }
 
-const destroy = () => {
-  onDestroy()
+const pause = () => {
+  const uid = route.params._uid || Date.now()
+
+  if (easyplayer[uid]) {
+    easyplayer[uid].pause()
+  }
+  playing.value = false
 }
 
-const registercallback = (events, func) => {}
+// 截图
+const screenshot = () => {
+  const uid = route.params._uid || Date.now()
 
-const onUse = (type) => {
-  if (type === 'hasAudio') {
-    config.hasAudio = !config.hasAudio
-  } else {
-    config.MSE = false
-    config.WCS = false
-    if (type === 'MSE') config.MSE = true
-    if (type === 'WCS') config.WCS = true
+  if (easyplayer[uid]) {
+    easyplayer[uid].screenshot()
+    emit('screenshot', easyplayer[uid].screenshot())
   }
-  if (isPlay.value) {
-    onDestroy().then(() => {
+}
+
+const destroy = async () => {
+  const uid = route.params._uid || Date.now()
+
+  if (easyplayer[uid]) {
+    await easyplayer[uid].destroy().then(() => {
+      easyplayer[uid] = null
+      playing.value = false
       playCreate()
-      onPlayer()
     })
+    emit('destroy', uid)
   }
 }
 
@@ -78,47 +178,16 @@ const setFullscreen = () => {
   }
 }
 
-const onPause = () => {
-  if (playInfo.value) {
-    playInfo.value.pause()
-  }
-}
-
 const onMute = () => {
-  if (playInfo.value) {
-    playInfo.value.setMute(true)
-  }
-}
+  // if (playInfo.value) {
+  //   playInfo.value.setMute(true)
+  // }
 
-const onPlayer = () => {
-  isPlay.value = true
-  nextTick(() => {
-    if (playInfo.value) {
-      playInfo.value
-        .play(videoUrl.value)
-        .then(() => {})
-        .catch((e) => {
-          console.error(e)
-        })
-    }
-  })
-}
+  const uid = route.params._uid || Date.now()
 
-const onPlayerPlayback = () => {
-  onDestroy().then(() => {
-    playCreate()
-    config.isLive = false
-    nextTick(() => {
-      if (playInfo.value) {
-        playInfo.value
-          .play(videoUrl.value)
-          .then(() => {})
-          .catch((e) => {
-            console.error(e)
-          })
-      }
-    })
-  })
+  if (easyplayer[uid]) {
+    easyplayer[uid].setMute(true)
+  }
 }
 
 const onStop = async () => {
@@ -127,24 +196,6 @@ const onStop = async () => {
   playCreate()
 }
 
-const onDestroy = () => {
-  return new Promise((resolve) => {
-    if (playInfo.value) {
-      playInfo.value.destroy()
-      playInfo.value = null
-    }
-    setTimeout(() => {
-      resolve()
-    }, 100)
-  })
-}
-
-const onReplay = async () => {
-  await onDestroy()
-  playCreate()
-  onPlayer()
-}
-
 // 处理PTZ控制
 const handlePtz = (arrow) => {
   let leftRight = 0
@@ -172,93 +223,82 @@ const handlePtz = (arrow) => {
   }
 }
 
-const playCreate = () => {
-  const container = easyPlayerRef.value
-  if (!container) return
-
-  const easyplayer = new EasyPlayerPro(container, {
-    isLive: config.isLive,
-    bufferTime: 0.2,
-    stretch: false,
-    MSE: config.MSE,
-    WCS: config.WCS,
-    hasAudio: config.hasAudio,
-    watermark: { text: { content: '' }, right: 10, top: 10 },
-    isBand: true,
-    btns: {
-      play: true,
-      audio: true,
-      record: true,
-      zoom: true,
-      ptz: true,
-      quality: true,
-      stretch: false,
-      screenshot: true,
-      fullscreen: true
+watch(
+  () => props.videourl,
+  (newData, oldData) => {
+    if (easyPlayerRef.value) {
+      play(newData)
     }
-  })
-
-  easyplayer.on('fullscreen', function (flag) {
-    console.log('is fullscreen', flag)
-  })
-
-  easyplayer.on('ptz', (direction) => {
-    handlePtz(direction)
-  })
+  },
+  { immediate: true }
+)
 
-  easyplayer.on('playbackRate', (rate) => {
-    easyplayer.setRate(rate)
-  })
+// 更新播放器DOM尺寸
+const updatePlayerDomSize = () => {
+  if (!easyPlayerRef.value) return
 
-  easyplayer.on('playbackSeek', (data) => {
-    console.log('playbackSeek', data)
-  })
+  let dom = easyPlayerRef.value
+  let width = dom.parentNode.clientWidth
+  let height = (9 / 16) * width
+  const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
 
-  playInfo.value = easyplayer
-  if (playInfo2.value && playInfo2.value.channelId && playInfo2.value.deviceId) {
-    playInfo.value.channelId = playInfo2.value.channelId
-    playInfo.value.deviceId = playInfo2.value.deviceId
+  if (height > clientHeight) {
+    height = clientHeight
+    width = (16 / 9) * height
   }
 
-  playInfo.value.playtype = playtype.value
+  dom.style.width = width + 'px'
+  dom.style.height = height + 'px'
 }
-watch(
-  () => props.playerInfo,
-  (newVal, oldVal) => {
-    playInfo.value = newVal
-    playInfo2.value = newVal
-    if (newVal && newVal.playtype !== '') {
-      playtype.value = newVal.playtype
-    }
-  }
-)
 // 生命周期钩子
 onMounted(() => {
+  console.log('####################', props.playerInfo)
+  window.onerror = (msg) => {
+    // console.error(msg)
+  }
+
+  // 确保DOM已经渲染完毕后再初始化播放器
+  nextTick(() => {
+    updatePlayerDomSize()
+    window.onresize = () => {
+      updatePlayerDomSize()
+    }
+
+    let paramUrl = decodeURIComponent(route.params.url)
+    let url = props.videourl !== undefined ? props.videourl : paramUrl
+    console.log('初始化时的地址为: ' + url)
+
+    // 确保容器已准备就绪
+    if (easyPlayerRef.value) {
+      play(url)
+    } else {
+      console.error('Container element is not available')
+    }
+  })
   playInfo.value = props.playerInfo
   playInfo2.value = props.playerInfo
+  videoUrl.value = props.videourl
+
   if (playInfo.value && playInfo.value.playtype !== '') {
     playtype.value = playInfo.value.playtype
   }
-  playCreate()
 })
 
-onBeforeUnmount(() => {
-  onDestroy()
+onUnmounted(() => {
+  if (easyplayer[route.params._uid]) {
+    easyplayer[route.params._uid].destroy()
+  }
+  playing.value = false
 })
 
 defineExpose({
   play,
   pause,
   destroy,
-  registercallback,
-  onUse,
   setFullscreen,
-  onPause,
   onMute,
-  onPlayer,
-  onPlayerPlayback,
   onStop,
-  onReplay
+  updatePlayerDomSize
 })
 </script>
 

+ 81 - 59
src/views/pms/video_center/sip/splitview.vue

@@ -1,6 +1,12 @@
 <template>
   <div style="height: 100%">
-    <el-card id="devicePosition" shadow="never" style="height: calc(100% - 40px);border: 0;" :body-style="{ padding: '0px' }" class="border-none">
+    <el-card
+      id="devicePosition"
+      shadow="never"
+      style="height: calc(100% - 40px); border: 0"
+      :body-style="{ padding: '0px' }"
+      class="border-none"
+    >
       <el-container
         v-loading="loading"
         style="height: 100%"
@@ -66,7 +72,8 @@
               <player
                 v-else
                 :ref="(el) => setPlayerRef(el, i - 1)"
-                :video-url="videoUrl[i - 1]"
+                :videourl="videoUrl[i - 1]"
+                :playerInfo="playInfoRes"
                 fluent
                 autoplay
                 @screenshot="shot"
@@ -85,10 +92,11 @@
 import { ref, reactive, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
 import { useRoute } from 'vue-router'
 import { FullScreen, Menu, Grid } from '@element-plus/icons-vue'
-import player from './components/player/jessibuca.vue'
+// import player from './components/player/jessibuca.vue'
+import player from './components/player/easy.vue'
 import DeviceTree from './components/player/DeviceTree.vue'
 import { startPlay } from '@/api/pms/video/channel'
-import { listSipDeviceChannel } from '@/api/pms/video/sipdevice';
+import { listSipDeviceChannel } from '@/api/pms/video/sipdevice'
 
 const { t } = useI18n()
 
@@ -107,8 +115,6 @@ const count = ref(15)
 const total = ref(0)
 const loading = ref(false)
 
-
-
 // 设置播放器引用
 const setPlayerRef = (el, index) => {
   if (el) {
@@ -146,24 +152,25 @@ watch(
   async (newSplit, oldSplit) => {
     // 只有当分屏数增加(例如从1到4,或从4到9)且有当前选中设备时才执行
     if (newSplit > oldSplit && currentDevice.value) {
-      console.log(`分屏从 ${oldSplit} 变为 ${newSplit},自动填充设备 ${currentDevice.value.name} 的通道`)
-      
+      console.log(
+        `分屏从 ${oldSplit} 变为 ${newSplit},自动填充设备 ${currentDevice.value.name} 的通道`
+      )
+
       // 延迟执行,确保DOM更新完成
       await nextTick()
-      
+
       loading.value = true
       try {
         // 1. 重新获取当前设备的通道
         const channels = await getDeviceChannels(currentDevice.value.id)
-        
+
         if (!channels || channels.length === 0) {
           console.warn('该设备下没有可用通道')
           return
         }
-        
+
         // 2. 重新分配通道到所有播放器
         await assignChannelsToPlayers(channels)
-        
       } catch (error) {
         console.error('分屏变化时填充通道出错:', error)
         ElMessage.error('自动填充通道失败')
@@ -209,72 +216,81 @@ const destroy = (idx) => {
 }
 const currentDevice = ref(null) // 存储当前选中的设备信息
 // 点击事件
+let playerInfo = ref([])
 const clickEvent = async (data) => {
   // 情况1:点击的是设备节点 (type === 0)
   if (data.type === 0) {
-     currentDevice.value = {
+    currentDevice.value = {
       id: data.userData?.serialNumber,
       name: data.name,
       data: data
     }
-    const deviceId = data.userData?.serialNumber; // 从树节点数据中提取设备ID
-    if (!deviceId) return;
+    const deviceId = data.userData?.serialNumber // 从树节点数据中提取设备ID
+    if (!deviceId) return
 
-    loading.value = true;
+    loading.value = true
     try {
       // 1. 获取该设备下的所有通道
-      const channels = await getDeviceChannels(deviceId);
+      const channels = await getDeviceChannels(deviceId)
+      channels.forEach((channel) => {
+        if (channel.basicData.model === 'Camera') {
+          playerInfo.value.push(channel)
+        }
+      })
+
+      console.log('playerInfo>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', playerInfo.value)
+      console.log('videourl**************************', videoUrl.value)
+
       if (!channels || channels.length === 0) {
-        console.warn('该设备下没有可用通道');
-        return;
+        console.warn('该设备下没有可用通道')
+        return
       }
 
       // 2. 将通道智能分配给播放器
-      await assignChannelsToPlayers(channels);
-
+      await assignChannelsToPlayers(channels)
     } catch (error) {
-      console.error('处理设备通道时出错:', error);
+      console.error('处理设备通道时出错:', error)
     } finally {
-      loading.value = false;
+      loading.value = false
     }
   }
   // 情况2:点击的是具体的通道节点,保持原有逻辑不变
   else if (data.userData?.channelSipId) {
-    sendDevicePush(data.userData);
+    sendDevicePush(data.userData)
   }
-};
+}
 
 const getDeviceChannels = async (deviceId) => {
   try {
-    const response = await listSipDeviceChannel(deviceId);
-    console.log('获取设备通道列表成功:', response);
+    const response = await listSipDeviceChannel(deviceId)
+    console.log('获取设备通道列表成功:', response)
     // 假设接口返回的是通道数组,且每个通道对象结构符合 { basicData: { channelSipId, ... }, ... }
-    return response || [];
+    return response || []
   } catch (error) {
-    console.error('获取设备通道列表失败:', error);
-    return [];
+    console.error('获取设备通道列表失败:', error)
+    return []
   }
-};
+}
 
 const assignChannelsToPlayers = async (channels) => {
   const currentSplit = spilt.value
   console.log(`分配 ${channels.length} 个通道到 ${currentSplit} 个播放窗口`)
-  
+
   // 决定从哪个播放器窗口开始分配:始终从第一个窗口(0)开始
   // 这样保证每次分屏变化时都能从头开始重新分配
   const startPlayerIndex = 0
-  
+
   // 决定从哪个通道开始取:总是从第一个通道开始
   const startChannelIndex = 0
-  
+
   // 循环,为当前分屏布局中的每个位置分配通道
   for (let screenPosition = 0; screenPosition < currentSplit; screenPosition++) {
     const channelIndex = startChannelIndex + screenPosition
     const targetPlayerIndex = startPlayerIndex + screenPosition
-    
+
     // 延迟执行,避免同时发起大量请求
-    await new Promise(resolve => setTimeout(resolve, 50))
-    
+    await new Promise((resolve) => setTimeout(resolve, 50))
+
     if (channelIndex < channels.length) {
       // 有对应通道,开始播放
       const channelData = channels[channelIndex]
@@ -301,39 +317,45 @@ const assignChannelsToPlayers = async (channels) => {
 // 通知设备上传媒体流
 const sendDevicePush = (itemData, targetIndex = null) => {
   // 关键修改:允许从外部传入 targetIndex,默认使用当前激活的 playerIdx
-  const playIndex = targetIndex !== null ? targetIndex : playerIdx.value;
+  const playIndex = targetIndex !== null ? targetIndex : playerIdx.value
 
-  save(itemData, playIndex); // 保存数据也要使用正确的索引
+  save(itemData, playIndex) // 保存数据也要使用正确的索引
 
-  let deviceId = itemData.deviceSipId;
-  let channelId = itemData.channelSipId;
-  loading.value = true;
+  let deviceId = itemData.deviceSipId
+  let channelId = itemData.channelSipId
+  loading.value = true
 
   return startPlay(deviceId, channelId)
     .then((response) => {
-      let res = response;
+      let res = response
       if (window.location.protocol === 'http:') {
-        itemData.playUrl = res.ws_flv;
+        itemData.playUrl = res.ws_flv
       } else {
-        itemData.playUrl = res.wss_flv;
+        itemData.playUrl = res.wss_flv
       }
-      itemData.streamId = res.streamId;
-      setPlayUrl(itemData.playUrl, playIndex); // 播放URL设置到指定位置
+      itemData.streamId = res.streamId
+      setPlayUrl(itemData.playUrl, playIndex) // 播放URL设置到指定位置
     })
     .finally(() => {
-      loading.value = false;
-    });
-};
-
-
-
+      loading.value = false
+    })
+}
 
+let playInfoRes = ref('')
 // 设置播放URL
 const setPlayUrl = (url, idx) => {
   const newVideoUrls = [...videoUrl.value]
   newVideoUrls[idx] = url
   videoUrl.value = newVideoUrls
 
+  playerInfo.value.forEach((item) => {
+    if (videoUrl.value[0].includes(item.id) && videoUrl.value[0].includes(item.deviceId)) {
+      playInfoRes.value = item
+    }
+  })
+
+  console.log('hhhhhhhhhhhhhhhhhhhhhhh', videoUrl.value)
+
   setTimeout(() => {
     window.localStorage.setItem('videoUrl', JSON.stringify(videoUrl.value))
   }, 100)
@@ -367,18 +389,18 @@ const shot = (e) => {
   let blob = base64ToBlob(e)
   let evt = document.createEvent('HTMLEvents')
   evt.initEvent('click', true, true)
-  aLink.download = 't("sip.splitview998531-5")' 
+  aLink.download = 't("sip.splitview998531-5")'
   aLink.href = URL.createObjectURL(blob)
   aLink.click()
 }
 
 // 保存数据
 const save = (item, index) => {
-  let dataStr = window.localStorage.getItem('playData') || '[]';
-  let data = JSON.parse(dataStr);
-  data[index] = item;
-  window.localStorage.setItem('playData', JSON.stringify(data));
-};
+  let dataStr = window.localStorage.getItem('playData') || '[]'
+  let data = JSON.parse(dataStr)
+  data[index] = item
+  window.localStorage.setItem('playData', JSON.stringify(data))
+}
 
 // 清除数据
 const clear = (idx) => {