Parcourir la source

视频分屏问题

yanghao il y a 16 heures
Parent
commit
6f7a38f8a2

+ 95 - 75
src/views/pms/video_center/sip/splitview.vue

@@ -56,8 +56,9 @@
             </el-button>
           </div>
           <div style="height: 85vh; display: flex; flex-wrap: wrap">
+            <!-- 只渲染实际可用的通道数量,不超过当前分屏数量 -->
             <div
-              v-for="i in spilt"
+              v-for="i in Math.min(spilt, availableChannels.length || spilt)"
               :key="i"
               class="play-box"
               :style="liveStyle"
@@ -67,8 +68,9 @@
               <div
                 v-if="!videoUrl[i - 1]"
                 style="color: #ffffff; font-size: 30px; font-weight: bold"
-                >{{ i }}</div
               >
+                {{ i }}
+              </div>
               <player
                 v-else
                 :ref="(el) => setPlayerRef(el, i - 1)"
@@ -86,6 +88,28 @@
                 @destroy="destroy"
               />
             </div>
+
+            <!-- 如果通道数少于分屏数,显示空白占位 -->
+            <div
+              v-for="i in Math.max(0, spilt - availableChannels.length)"
+              :key="`empty-${i}`"
+              class="play-box"
+              :style="liveStyle"
+            >
+              <div
+                style="
+                  color: #ffffff;
+                  font-size: 30px;
+                  font-weight: bold;
+                  display: flex;
+                  align-items: center;
+                  justify-content: center;
+                  height: 100%;
+                "
+              >
+                {{ availableChannels.length + i }}
+              </div>
+            </div>
           </div>
         </el-main>
       </el-container>
@@ -120,6 +144,9 @@ const count = ref(15)
 const total = ref(0)
 const loading = ref(false)
 
+// 新增:存储可用通道
+const availableChannels = ref([])
+
 // 设置播放器引用
 const setPlayerRef = (el, index) => {
   if (el) {
@@ -140,7 +167,7 @@ const liveStyle = computed(() => {
   }
 
   nextTick(() => {
-    for (let i = 0; i < spilt.value; i++) {
+    for (let i = 0; i < Math.min(spilt.value, availableChannels.value.length || spilt.value); i++) {
       const player = playerRefs.value[i]
       if (player && typeof player.updatePlayerDomSize === 'function') {
         player.updatePlayerDomSize()
@@ -166,16 +193,8 @@ watch(
 
       loading.value = true
       try {
-        // 1. 重新获取当前设备的通道
-        const channels = await getDeviceChannels(currentDevice.value.id)
-
-        if (!channels || channels.length === 0) {
-          console.warn('该设备下没有可用通道')
-          return
-        }
-
-        // 2. 重新分配通道到所有播放器
-        await assignChannelsToPlayers(channels)
+        // 重新分配通道到所有播放器
+        await assignChannelsToPlayers(availableChannels.value)
       } catch (error) {
         console.error('分屏变化时填充通道出错:', error)
         ElMessage.error('自动填充通道失败')
@@ -183,18 +202,21 @@ watch(
         loading.value = false
       }
     }
-    // 可选:当分屏数减少时,可以清空多余的播放器
+    // 当分屏数减少时,清空超出当前通道数的播放器
     else if (newSplit < oldSplit) {
-      // 清空超出当前分屏数的播放器
-      for (let i = newSplit; i < oldSplit; i++) {
+      // 清空超出当前分屏数或超出通道数的播放器
+      const maxVisible = Math.min(newSplit, availableChannels.value.length)
+      for (let i = maxVisible; i < Math.max(oldSplit, availableChannels.value.length); i++) {
         const newVideoUrls = [...videoUrl.value]
-        newVideoUrls[i] = ''
-        videoUrl.value = newVideoUrls
-        clear(i + 1) // 清理存储的数据
+        if (newVideoUrls[i]) {
+          newVideoUrls[i] = ''
+          videoUrl.value = newVideoUrls
+          clear(i + 1) // 清理存储的数据
+        }
       }
     }
   },
-  { immediate: false } // 不需要立即执行
+  { immediate: false }
 )
 
 // 监听路由变化
@@ -237,22 +259,31 @@ const clickEvent = async (data) => {
     try {
       // 1. 获取该设备下的所有通道
       const channels = await getDeviceChannels(deviceId)
-      channels.forEach((channel) => {
-        if (channel.basicData.model === 'Camera') {
-          playerInfo.value.push(channel)
-        }
+
+      // 只保留摄像头类型的通道
+      const cameraChannels = channels.filter((channel) => channel.basicData.model === 'Camera')
+      availableChannels.value = cameraChannels
+
+      // 清空之前的数据
+      playerInfo.value = []
+      cameraChannels.forEach((channel) => {
+        playerInfo.value.push(channel)
       })
 
       console.log('playerInfo>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', playerInfo.value)
+      console.log('availableChannels>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', availableChannels.value)
       console.log('videourl**************************', videoUrl.value)
 
-      if (!channels || channels.length === 0) {
-        console.warn('该设备下没有可用通道')
+      if (!cameraChannels || cameraChannels.length === 0) {
+        console.warn('该设备下没有可用的摄像头通道')
+        // 清空所有播放器
+        const newVideoUrls = Array(spilt.value).fill('')
+        videoUrl.value = newVideoUrls
         return
       }
 
       // 2. 将通道智能分配给播放器
-      await assignChannelsToPlayers(channels)
+      await assignChannelsToPlayers(cameraChannels)
     } catch (error) {
       console.error('处理设备通道时出错:', error)
     } finally {
@@ -269,7 +300,6 @@ const getDeviceChannels = async (deviceId) => {
   try {
     const response = await listSipDeviceChannel(deviceId)
     console.log('获取设备通道列表成功:', response)
-    // 假设接口返回的是通道数组,且每个通道对象结构符合 { basicData: { channelSipId, ... }, ... }
     return response || []
   } catch (error) {
     console.error('获取设备通道列表失败:', error)
@@ -279,46 +309,34 @@ const getDeviceChannels = async (deviceId) => {
 
 const assignChannelsToPlayers = async (channels) => {
   const currentSplit = spilt.value
-  console.log(`分配 ${channels.length} 个通道到 ${currentSplit} 个播放窗口`)
+  const actualChannels = Math.min(channels.length, currentSplit)
 
-  // 决定从哪个播放器窗口开始分配:始终从第一个窗口(0)开始
-  // 这样保证每次分屏变化时都能从头开始重新分配
-  const startPlayerIndex = 0
+  console.log(`分配 ${actualChannels} 个通道到最多 ${currentSplit} 个播放窗口`)
 
-  // 决定从哪个通道开始取:总是从第一个通道开始
-  const startChannelIndex = 0
-
-  // 循环,为当前分屏布局中的每个位置分配通道
-  for (let screenPosition = 0; screenPosition < currentSplit; screenPosition++) {
-    const channelIndex = startChannelIndex + screenPosition
-    const targetPlayerIndex = startPlayerIndex + screenPosition
+  // 清空当前所有播放器
+  const newVideoUrls = Array(Math.max(currentSplit, channels.length)).fill('')
+  videoUrl.value = newVideoUrls
 
+  // 为每个可用通道分配播放器
+  for (let i = 0; i < actualChannels; i++) {
     // 延迟执行,避免同时发起大量请求
     await new Promise((resolve) => setTimeout(resolve, 50))
 
-    if (channelIndex < channels.length) {
-      // 有对应通道,开始播放
-      const channelData = channels[channelIndex]
-      // 构建符合 sendDevicePush 要求的参数格式
-      const playData = {
-        deviceSipId: channelData.deviceId,
-        channelSipId: channelData.basicData?.channelSipId || channelData.id,
-        name: channelData.name || `通道${channelIndex + 1}`,
-        ...channelData.basicData
-      }
-      console.log(`将通道 ${playData.name} 分配给播放器 ${targetPlayerIndex}`)
-      await sendDevicePush(playData, targetPlayerIndex)
-    } else {
-      // 没有更多通道,清空当前位置
-      const newVideoUrls = [...videoUrl.value]
-      newVideoUrls[targetPlayerIndex] = ''
-      videoUrl.value = newVideoUrls
-      // 清理存储的数据
-      clear(targetPlayerIndex + 1)
-      console.log(`播放器 ${targetPlayerIndex} 没有可用通道,已清空`)
+    const channelData = channels[i]
+    // 构建符合 sendDevicePush 要求的参数格式
+    const playData = {
+      deviceSipId: channelData.deviceId,
+      channelSipId: channelData.basicData?.channelSipId || channelData.id,
+      name: channelData.name || `通道${i + 1}`,
+      ...channelData.basicData
     }
+    console.log(`将通道 ${playData.name} 分配给播放器 ${i}`)
+    await sendDevicePush(playData, i)
   }
+
+  // 如果通道数少于当前分屏数,不需要做额外处理,因为已经清空了超出部分
 }
+
 // 通知设备上传媒体流
 const sendDevicePush = (itemData, targetIndex = null) => {
   // 关键修改:允许从外部传入 targetIndex,默认使用当前激活的 playerIdx
@@ -349,25 +367,15 @@ const sendDevicePush = (itemData, targetIndex = null) => {
 let playInfoRes = ref('')
 // 设置播放URL
 const setPlayUrl = (url, idx) => {
+  // 确保数组长度足够
+  while (videoUrl.value.length <= idx) {
+    videoUrl.value.push('')
+  }
+
   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)
-
-  // console.log(
-  //   'xxxxxxxxxxxxxxxxxxxxx',
-  //   playerInfo.filter(
-  //     (item) => videoUrl[0].includes(item.id) && videoUrl[0].includes(item.deviceId)
-  //   )
-  // )
-
   setTimeout(() => {
     window.localStorage.setItem('videoUrl', JSON.stringify(videoUrl.value))
   }, 100)
@@ -410,6 +418,10 @@ const shot = (e) => {
 const save = (item, index) => {
   let dataStr = window.localStorage.getItem('playData') || '[]'
   let data = JSON.parse(dataStr)
+  // 确保数组长度足够
+  while (data.length <= index) {
+    data.push(null)
+  }
   data[index] = item
   window.localStorage.setItem('playData', JSON.stringify(data))
 }
@@ -418,7 +430,9 @@ const save = (item, index) => {
 const clear = (idx) => {
   let dataStr = window.localStorage.getItem('playData') || '[]'
   let data = JSON.parse(dataStr)
-  data[idx - 1] = null
+  if (data.length > idx - 1) {
+    data[idx - 1] = null
+  }
   console.log(data)
   window.localStorage.setItem('playData', JSON.stringify(data))
 }
@@ -452,6 +466,12 @@ const clear = (idx) => {
   border-radius: 5px;
 }
 
+.empty-box {
+  background-color: #333;
+  opacity: 0.5;
+  cursor: default;
+}
+
 .player-wrap {
   position: absolute;
   top: 0px;

+ 1 - 1
src/views/report-statistics/fault_report/index.vue

@@ -72,7 +72,7 @@
               "
             >
               <Icon icon="ep:more-filled" :size="40" />
-              <div class="card-title">未完成</div>
+              <div class="card-title">转工单</div>
               <div class="card-value pt-5">
                 <CountTo class="text-3xl" :end-val="statusCount.trans || 0" :decimals="0" />
               </div>