吉安感知网项目-前端
罗广辉
2026-06-06 f81ab0dea14072cd89a198a13f2f7d184ffc97be
feat: m3u8播放
3 files modified
124 ■■■■ changed files
applications/task-work-order/src/components/VideoPlayDialog.vue 120 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/orderManage/outcomeData.vue 2 ●●● patch | view | raw | blame | history
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>
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue
@@ -632,8 +632,8 @@
let VideoShow = ref(false)
let currentVideo = ref({})
function videoClick(row) {
    VideoShow.value = true
    currentVideo.value = row
    VideoShow.value = true
}
// 初始化地图实例
applications/task-work-order/src/views/orderView/orderManage/orderManage/outcomeData.vue
@@ -252,8 +252,8 @@
let VideoShow = ref(false)
let currentVideo = ref({})
function videoClick(row) {
    currentVideo.value = row
    VideoShow.value = true
  currentVideo.value = row
}
// 监听 workOrderId 变化