hejianhao
2025-04-11 ebc8abe2133e671617e6a8b2b292d41cb28592fa
实时视频监控播放
4个文件已修改
2个文件已添加
128 ■■■■■ 已修改文件
src/components/PlayLive/index.vue 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PlayLive/service.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/order/component/detailModal.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/order/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PlayLive/index.vue
New file
@@ -0,0 +1,91 @@
<template>
    <div>
        <video id="video" width="100%" height="100%" muted controls></video>
    </div>
</template>
<script>
import { playDetection, closeRealVideo } from './service'
import flvjs from 'flv.js'
export default {
    props: {
        serverIp: {
            type: String,
            required: ''
        },
        serverPort: {
            type: Number,
            required: null
        },
        carId: {
            type: Number,
            required: null
        },
    },
    data() {
        return {
            flvPlayer: null,
            timer: null,
        }
    },
    mounted() {
        this.playDetection()
    },
    beforeDestroy() {
        this.destroyPlayer();
    },
    methods: {
        playDetection() {
            if (flvjs.isSupported()) {
                playDetection(this.carId).then(res => {
                    this.flvPlayer = flvjs.createPlayer({
                        type: 'flv',//视频类型
                        isLive: true,//是否为直播
                        cors: true,//是否开启跨域
                        hasAudio: false,//是否开启音频
                        hasVideo: true,//是否开启视频
                        url: `http://${this.serverIp}:${this.serverPort}/live?port=1935&app=flv&stream=${this.carId}`,  // 后端拿到的视频路径
                        enableWorker: true, //启用 Web Worker 进程来加速视频的解码和处理过程
                        enableStashBuffer: false, // 启用数据缓存机制,提高视频的流畅度和稳定性。
                        stashInitialSize: 1024, // 初始缓存大小。单位:字节。建议针对直播:调整为1024kb
                        stashInitialTime: 0.2, // 缓存初始时间。单位:秒。建议针对直播:调整为200毫秒
                        seekType: 'range', // 建议将其设置为“range”模式,以便更快地加载视频数据,提高视频的实时性。
                        lazyLoad: false, //关闭懒加载模式,从而提高视频的实时性。建议针对直播:调整为false
                        lazyLoadMaxDuration: 0.2, // 懒加载的最大时长。单位:秒。建议针对直播:调整为200毫秒
                        deferLoadAfterSourceOpen: false // 不预先加载视频数据,在 MSE(Media Source Extensions)打开后立即加载数据,提高视频的实时性。建议针对直播:调整为false
                    });
                    let video = document.getElementById('video');
                    this.flvPlayer.attachMediaElement(video); // video容器
                    this.flvPlayer.load();
                    this.flvPlayer.play().then(res => {
                        this.timer = setInterval(() => {
                            playDetection(this.carId)
                        }, 5000)
                    }).catch(err => {
                        this.destroyPlayer();
                    })
                    // 错误监听
                    this.flvPlayer.on('error', (err) => {
                        this.destroyPlayer();
                    });
                })
            }
        },
        destroyPlayer() {
            // 销毁播放器释放资源
            if (this.flvPlayer) {
                if (this.timer) clearInterval(this.timer)
                closeRealVideo(this.carId).then(res => {
                    this.flvPlayer.pause();
                    this.flvPlayer.unload();
                    this.flvPlayer.detachMediaElement();
                    this.flvPlayer.destroy();
                    this.flvPlayer = null;
                })
            }
        }
    }
}
</script>
<style></style>
src/components/PlayLive/service.js
New file
@@ -0,0 +1,11 @@
import axios from '@/utils/request';
// 通知后端开始获取视频流
export const playDetection = (id) => {
    return axios.get(`/system/car/playDetection/${id}`)
}
// 通知后端开始关闭视频流
export const closeRealVideo = (id) => {
    return axios.get(`/system/car/closeRealVideo/${id}`)
}
src/main.js
@@ -9,6 +9,7 @@
import {
  Message
} from 'element-ui'
import PlayLive from '@/components/PlayLive'
Vue.use(ElementUI)
Vue.prototype.$cookies = cookies;
@@ -17,6 +18,7 @@
Vue.prototype.$secretKey = apiConfig.secretKey
Vue.prototype.$store = store
Vue.config.productionTip = false
Vue.component('PlayLive', PlayLive)
/* 全局TableHeight */
Vue.prototype.$baseTableHeight = (formType) => {
  let height = window.innerHeight
src/utils/request.js
@@ -10,7 +10,7 @@
const service = axios.create({
  baseURL: apiConfig.baseURL,
  withCredentials: false, // 当跨域请求时发送cookie
  timeout: 30000, // request timeout
  timeout: 60000, // request timeout
})
// 对 POST 请求参数进行排序
const sortPostParams = (params) => {
src/view/order/component/detailModal.vue
@@ -1,6 +1,7 @@
<template>
    <div>
        <el-dialog title="订单详情" :visible.sync="dialogVisible" width="50%" :modal-append-to-body="false">
        <el-dialog title="订单详情" :visible.sync="dialogVisible" width="50%" :modal-append-to-body="false"
            @close="closeClick">
            <el-radio-group v-model="tabPosition" style="margin-bottom: 30px;">
                <el-radio-button label="order">订单信息</el-radio-button>
                <el-radio-button label="track">行程轨迹</el-radio-button>
@@ -27,11 +28,14 @@
                </el-descriptions>
            </div>
            <!-- 行程轨迹 -->
            <div v-show="tabPosition == 'track'">
            <div v-if="tabPosition == 'track'">
                <div class="mapContainer" id="mapContainer"></div>
            </div>
            <!-- 行程监控 -->
            <div v-show="tabPosition == 'monitoring'"></div>
            <div v-if="tabPosition == 'monitoring'">
                <PlayLive :serverIp="monitoringData.serverIp" :serverPort="monitoringData.serverPort"
                    :carId="orderData.carId" />
            </div>
        </el-dialog>
    </div>
</template>
@@ -45,7 +49,7 @@
            tabPosition: 'order',
            orderData: {},
            monitoringData: {},
            travelData: []
            travelData: [],
        };
    },
    computed: {},
@@ -55,12 +59,12 @@
                this.$nextTick(() => {
                    this.initMap();
                })
                return
            }
        }
    },
    created() { },
    methods: {
        initData(orderData = {}, monitoringData = {}, travelData = {},) {
        initData(orderData = {}, monitoringData = {}, travelData = []) {
            this.orderData = orderData
            this.monitoringData = monitoringData
            this.travelData = travelData
@@ -127,7 +131,7 @@
            this.orderData = {}
            this.monitoringData = {}
            this.travelData = []
        }
        },
    },
};
</script>
src/view/order/index.vue
@@ -87,7 +87,7 @@
<script>
import DetailModal from "./component/detailModal"
import { exportExcell } from '@/utils/utils'
import { getOrderList, getOrderInfo, getOrderMonitoring, getOrderTravel } from './service'
import { getOrderList, getOrderInfo, getOrderMonitoring, getOrderTravel, } from './service'
import moment from "moment/moment";
export default {
@@ -160,7 +160,7 @@
            this.loading = true
            Promise.all([getOrderInfo(row.id), getOrderMonitoring({ id: row.id }), getOrderTravel({ id: row.id })]).then(res => {
                // Promise.all([getOrderInfo(row.id), getOrderTravel({ id: row.id })]).then(res => {
                this.$refs.detailModal.initData(res[0], {}, res[2])
                this.$refs.detailModal.initData(res[0], res[1], res[2])
                this.loading = false
            }).catch(err => {
                this.loading = false