吉安感知网项目-前端
罗广辉
2026-06-06 f81ab0dea14072cd89a198a13f2f7d184ffc97be
applications/task-work-order/src/components/VideoPlayDialog.vue
@@ -1,56 +1,130 @@
<script setup>
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
import videojs from 'video.js'
const props = defineProps({
   width: {
      type: String,
      default: '800'
      default: '800',
   },
   modelValue: {
      type: Boolean,
      default: false
      default: false,
   },
   playUrl: {
      type: String,
      default: ''
      default: '',
   },
   title:{
   title: {
      type: String,
      default: '视频播放'
   }
      default: '视频播放',
   },
})
const emit = defineEmits(['update:modelValue'])
const handleClose = () => {
   emit('update:modelValue', false)
const videoRefs = ref(null)
let player = null
const dialogVisible = computed({
   get: () => props.modelValue,
   set: value => emit('update:modelValue', value),
})
function getVideoType(url) {
   const path = (url || '').split('?')[0].toLowerCase()
   if (path.endsWith('.m3u8')) return 'application/x-mpegURL'
   if (path.endsWith('.mp4')) return 'video/mp4'
   if (path.endsWith('.webm')) return 'video/webm'
   if (path.endsWith('.ogg') || path.endsWith('.ogv')) return 'video/ogg'
   if (path.endsWith('.mov')) return 'video/quicktime'
   return ''
}
function destroyPlayer() {
   if (!player) return
   player.dispose()
   player = null
}
function getSource() {
   const type = getVideoType(props.playUrl)
   return {
      src: props.playUrl,
      ...(type ? { type } : {}),
   }
}
async function initPlayer() {
   if (!props.modelValue || !props.playUrl) return
   await nextTick()
   if (!videoRefs.value) return
   if (player) {
      player.src(getSource())
      player.load()
      return
   }
   player = videojs(videoRefs.value, {
      controls: true,
      preload: 'auto',
      autoplay: false,
      fluid: false,
      width: '100%',
      height: '600px',
      sources: [getSource()],
   })
   player.on('error', () => {
      console.error('视频播放失败:', player?.error(), props.playUrl)
   })
}
watch(
   () => props.playUrl,
   () => {
      if (!props.modelValue || !props.playUrl) return
      initPlayer()
   }
)
onBeforeUnmount(destroyPlayer)
</script>
<template>
   <el-dialog
      class="gd-dialog"
      class="gd-dialog video-dialog"
      :title="props.title"
      append-to-body
      v-model="props.modelValue"
      v-model="dialogVisible"
      width="60%"
      destroy-on-close
      :close-on-click-modal="false"
      @close="handleClose"
      @opened="initPlayer"
      @closed="destroyPlayer"
   >
      <video ref="videoRefs" controls preload="auto"  :src="props.playUrl">
         <source :src="props.playUrl" type="video/mp4" />
      </video>
      <!--         <el-carousel trigger="click" :autoplay="false" @change="handleCarouselChange">-->
      <!--            <el-carousel-item v-for="(item, index) in videoList" :key="index">-->
      <!--               <video ref="videoRefs" controls preload="auto"  :src="currentVideoUrl" @play="handleVideoPlay" @ended="handleVideoEnded(index)">-->
      <!--                  <source :src="item.smallUrl" type="video/mp4" />-->
      <!--               </video>-->
      <!--            </el-carousel-item>-->
      <!--         </el-carousel>-->
      <video
         ref="videoRefs"
         id="videoPlayDialogPlayer"
         class="video-js vjs-default-skin vjs-big-play-centered"
         controls
         preload="auto"
         playsinline
      ></video>
   </el-dialog>
</template>
<style lang="scss">
.video-dialog {
   .video-js {
      height: 600px;
      width: 100%;
   }
}
</style>
<style scoped lang="scss">
video {
   height: 600px;
:deep(.video-js .vjs-tech) {
   height: 100%;
   width: 100%;
}
</style>