hejianhao
2025-04-29 426678e4c00df1321233896f5229532019cfdeef
订单记录去掉监控播放,车辆详情和监控回放修改监控播放
7个文件已修改
218 ■■■■ 已修改文件
src/components/PlayLive/index.vue 126 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/car-manage/components/detailOrderModal.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/car-manage/detail.vue 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/car-manage/service.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/order/component/detailModal.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/order/index.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/playback/index.vue 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PlayLive/index.vue
@@ -1,6 +1,9 @@
<template>
    <div style="height: 100%; position: relative;">
        <video id="video" style="height: 100%;width: 100%;" muted controls></video>
        <div style="width: 100%; height: 100%; border-radius: 9px; background: #f5f5f5; display: flex; justify-content: center; align-items: center; flex-direction: column">
            <video id="video" style="width: 100%; height: 100%; border-radius: 9px; display: none" muted controls></video>
            <el-empty description="暂无视频信息" :image-size="80"></el-empty>
        </div>
        <div v-if="showError" class="error-box" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.8); display: flex; justify-content: center; align-items: center; z-index: 9999;">
            <div class="error-content" style="text-align: center; color: #fff;">
                <i class="el-icon-warning" style="font-size: 48px; color: #E6A23C; margin-bottom: 16px;"></i>
@@ -37,11 +40,24 @@
        return {
            flvPlayer: null,
            timer: null,
            showError: false,
            showError: false
        }
    },
    watch: {
        urlLink: {
            handler(newUrl) {
                if (newUrl) {
                    this.destroyPlayer();
                    this.playDetection();
                }
            },
            immediate: true
        }
    },
    mounted() {
        this.playDetection()
        if (this.urlLink) {
            this.playDetection();
        }
    },
    beforeDestroy() {
        this.destroyPlayer();
@@ -49,16 +65,25 @@
    methods: {
        playDetection() {
            this.showError = false;
            if (flvjs.isSupported()) {
                playDetection(this.carId).then(res => {
            if (!flvjs.isSupported()) {
                this.showError = true;
                this.$emit('video-error');
                return;
            }
            playDetection(this.carId).then(res => {
                if (this.flvPlayer) {
                    this.destroyPlayer();
                }
                try {
                    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}`,  // 后端拿到的视频路径
                        url: this.urlLink,  // 后端拿到的视频路径
                        type: 'flv', //视频类型
                        isLive: true, //是否为直播
                        cors: true, //是否开启跨域
                        hasAudio: false, //是否开启音频
                        hasVideo: true, //是否开启视频
                        url: this.urlLink, // 后端拿到的视频路径
                        enableWorker: true, //启用 Web Worker 进程来加速视频的解码和处理过程
                        enableStashBuffer: false, // 启用数据缓存机制,提高视频的流畅度和稳定性。
                        stashInitialSize: 1024, // 初始缓存大小。单位:字节。建议针对直播:调整为1024kb
@@ -68,36 +93,83 @@
                        lazyLoadMaxDuration: 0.2, // 懒加载的最大时长。单位:秒。建议针对直播:调整为200毫秒
                        deferLoadAfterSourceOpen: false // 不预先加载视频数据,在 MSE(Media Source Extensions)打开后立即加载数据,提高视频的实时性。建议针对直播:调整为false
                    });
                    let video = document.getElementById('video');
                    this.flvPlayer.attachMediaElement(video); // video容器
                    if (!video) {
                        throw new Error('Video element not found');
                    }
                    this.flvPlayer.attachMediaElement(video);
                    this.flvPlayer.load();
                    this.flvPlayer.play().then(res => {
                    this.flvPlayer.play().then(() => {
                        // 显示视频元素
                        video.style.display = 'block';
                        // 隐藏空状态
                        const emptyElement = video.parentElement.querySelector('.el-empty');
                        if (emptyElement) {
                            emptyElement.style.display = 'none';
                        }
                        this.timer = setInterval(() => {
                            playDetection(this.carId)
                        }, 5000)
                            playDetection(this.carId);
                        }, 5000);
                    }).catch(err => {
                        console.error('视频播放失败:', err);
                        this.showError = true;
                        this.destroyPlayer();
                    })
                    // 错误监听
                    this.flvPlayer.on('error', (err) => {
                        this.showError = true;
                        this.destroyPlayer();
                        this.$emit('video-error');
                    });
                })
            }
                    this.flvPlayer.on('error', (err) => {
                        console.error('视频播放器错误:', err);
                        this.showError = true;
                        this.destroyPlayer();
                        this.$emit('video-error');
                    });
                } catch (err) {
                    console.error('创建播放器失败:', err);
                    this.showError = true;
                    this.destroyPlayer();
                    this.$emit('video-error');
                }
            }).catch(err => {
                console.error('获取视频流失败:', err);
                this.showError = true;
                this.destroyPlayer();
                this.$emit('video-error');
            });
        },
        destroyPlayer() {
            // 销毁播放器释放资源
            if (this.flvPlayer) {
                if (this.timer) clearInterval(this.timer)
                closeRealVideo(this.carId).then(res => {
                if (this.timer) {
                    clearInterval(this.timer);
                    this.timer = null;
                }
                try {
                    this.flvPlayer.pause();
                    this.flvPlayer.unload();
                    this.flvPlayer.detachMediaElement();
                    this.flvPlayer.destroy();
                } catch (err) {
                    console.error('销毁播放器失败:', err);
                } finally {
                    this.flvPlayer = null;
                })
                }
                closeRealVideo(this.carId).catch(err => {
                    console.error('关闭视频流失败:', err);
                });
                // 恢复空状态的显示
                const video = document.getElementById('video');
                if (video) {
                    video.style.display = 'none';
                    const emptyElement = video.parentElement.querySelector('.el-empty');
                    if (emptyElement) {
                        emptyElement.style.display = 'block';
                    }
                }
            }
        }
    }
src/view/car-manage/components/detailOrderModal.vue
@@ -5,7 +5,7 @@
            <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>
                <el-radio-button label="monitoring">行程监控</el-radio-button>
                <!-- <el-radio-button label="monitoring">行程监控</el-radio-button> -->
            </el-radio-group>
            <!-- 订单信息 -->
            <div v-show="tabPosition == 'order'">
@@ -32,10 +32,10 @@
                <div class="mapContainer" id="mapContainers"></div>
            </div>
            <!-- 行程监控 -->
            <div v-if="tabPosition == 'monitoring'">
            <!-- <div v-if="tabPosition == 'monitoring'">
                <PlayLive :serverIp="monitoringData.serverIp" :serverPort="monitoringData.serverPort"
                    :urlLink="monitoringData.url" :carId="orderData.carId" />
            </div>
            </div> -->
        </el-dialog>
    </div>
</template>
src/view/car-manage/detail.vue
@@ -27,19 +27,19 @@
                    </div> -->
                </div>
            </div>
            <div class="info-right flex2">
            <div class="info-right flex2" style="margin-top: 40px;">
                <div style="position: relative; width: 100%; height: 330px">
                    <div
                        style="width: 100%; height: 330px; border-radius: 9px; background: #f5f5f5; display: flex; justify-content: center; align-items: center; flex-direction: column">
                        <video style="width: 100%; height: 330px; border-radius: 9px; display: none" id="monitoringCard"
                            ref="monitoringCard" :controls="false" autoPlay width="620">
                        <video style="width: 100%;border-radius: 9px; display: none" id="monitoringCard"
                            ref="monitoringCard" :controls="false" autoplay>
                        </video>
                        <el-empty description="暂无视频信息" :image-size="80"></el-empty>
                    </div>
                    <canvas id="myCanvas" style="display:none"></canvas>
                    <el-button type="default" style="position: absolute; top: 10px;right: 60px;"
                    <el-button type="default" style="position: absolute; top: 20px;right: 60px;"
                        @click="goBack()">查看回放</el-button>
                    <div style="position: absolute; right: 11px; top: 10px">
                    <div style="position: absolute; right: 11px; top: 20px">
                        <div style="display: flex;flex-direction: column;align-items: center;justify-content: center;
              background: #ffffff; padding: 3px 10px; border-radius: 6px;margin-bottom: 10px;" @click="fullScreen()">
                            <img style="width: 20px; height: 20px" :src="require('../../assets//homeImg/full.png')" />
@@ -256,11 +256,13 @@
            showWarnDetail: false,
            info: {},
            activeInfo: {},
            map: null
            map: null,
            carId: null
        }
    },
    mounted() {
        if (this.$route.query.id) {
            this.carId = this.$route.query.id
            getCarDetail({ id: this.$route.query.id }).then(res => {
                this.detail = res;
                this.getList(res.vehicleNumber);
@@ -275,7 +277,7 @@
    },
    destroyed() {
    beforeDestroy() {
        this.destroyPlayer();
    },
    methods: {
@@ -300,7 +302,7 @@
            // 检查flv.js是否支持
            if (flvjs.isSupported()) {
                try {
                    playDetection(this.carId).then((res) => {
                    playDetection(this.$route.query.id).then((res) => {
                        this.flvPlayer = flvjs.createPlayer({
                            type: "flv", //视频类型
                            isLive: true, //是否为直播
@@ -333,7 +335,7 @@
                                }
                                this.videoTimer = setInterval(() => {
                                    playDetection(this.carId);
                                    playDetection(this.$route.query.id);
                                }, 5000);
                            })
                            .catch((err) => {
@@ -345,7 +347,7 @@
                        });
                    });
                } catch (error) {
                    console.error("创建播放器失败:", error);
                    console.log("创建播放器失败:", error);
                }
            } else {
                console.error("当前浏览器不支持flv.js");
@@ -432,13 +434,13 @@
        showDetails(row) {
            this.loading = true
            Promise.all([getOrderInfo(row.id), getOrderTravel({ id: row.id })]).then(res => {
                getOrderMonitoring({ id: row.id }).then(resp => {
                    this.$refs.detailOrder.initData(res[0], resp, res[1])
                    this.loading = false
                }).catch(err => {
                    this.$refs.detailOrder.initData(res[0], {}, res[1])
                    this.loading = false
                })
                // getOrderMonitoring({ id: row.id }).then(resp => {
                //     this.$refs.detailOrder.initData(res[0], resp, res[1])
                //     this.loading = false
                // }).catch(err => {
                this.$refs.detailOrder.initData(res[0], {}, res[1])
                this.loading = false
                // })
            }).catch(err => {
                this.loading = false
            })
@@ -663,6 +665,7 @@
.info-content {
    padding: 30px;
    margin-bottom: 30px;
}
::v-deep .el-descriptions-item__container {
src/view/car-manage/service.js
@@ -57,3 +57,12 @@
export const getOrderMonitoring = (params) => {
    return axios.get(`/system/order/getOrderMonitoring`, { params })
}
// 通知后端开始获取视频流
export const playDetection = (id) => {
    return axios.get(`/system/car/playDetection/${id}`)
}
// 通知后端开始关闭视频流
export const closeRealVideo = (id) => {
    return axios.get(`/system/car/closeRealVideo/${id}`)
}
src/view/order/component/detailModal.vue
@@ -5,7 +5,7 @@
            <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>
                <el-radio-button label="monitoring">行程监控</el-radio-button>
                <!-- <el-radio-button label="monitoring">行程监控</el-radio-button> -->
            </el-radio-group>
            <!-- 订单信息 -->
            <div v-show="tabPosition == 'order'">
@@ -32,10 +32,10 @@
                <div class="mapContainer" id="mapContainer"></div>
            </div>
            <!-- 行程监控 -->
            <div v-if="tabPosition == 'monitoring'">
            <!-- <div v-if="tabPosition == 'monitoring'">
                <PlayLive :serverIp="monitoringData.serverIp" :serverPort="monitoringData.serverPort"
                    :urlLink="monitoringData.url" :carId="orderData.carId" />
            </div>
            </div> -->
        </el-dialog>
    </div>
</template>
@@ -66,7 +66,7 @@
    methods: {
        initData(orderData = {}, monitoringData = {}, travelData = []) {
            this.orderData = orderData
            this.monitoringData = monitoringData
            // this.monitoringData = monitoringData
            this.travelData = travelData
            this.dialogVisible = true
        },
src/view/order/index.vue
@@ -158,13 +158,13 @@
        showDetail(row) {
            this.loading = true
            Promise.all([getOrderInfo(row.id), getOrderTravel({ id: row.id })]).then(res => {
                getOrderMonitoring({ id: row.id }).then(resp => {
                    this.$refs.detailModal.initData(res[0], resp, res[1])
                    this.loading = false
                }).catch(err => {
                // getOrderMonitoring({ id: row.id }).then(resp => {
                //     this.$refs.detailModal.initData(res[0], resp, res[1])
                //     this.loading = false
                // }).catch(err => {
                    this.$refs.detailModal.initData(res[0], {}, res[1])
                    this.loading = false
                })
                // })
            }).catch(err => {
                this.loading = false
            })
src/view/playback/index.vue
@@ -57,8 +57,11 @@
            </el-col>
            <el-col :span="20">
                <div class="grid-content" style="">
                    <PlayLive :serverPort="serverPort" :serverIp="serverIp" :carId="$route.query.id"
                        :urlLink="monitoringData.url" />
                    <PlayLive v-if="urlLink" :serverPort="serverPort" :serverIp="serverIp" :carId="$route.query.id"
                        :urlLink="urlLink" @video-error="handleVideoError" />
                    <div v-else class="empty-state">
                        <el-empty description="请选择时间范围并点击查询获取视频" :image-size="80"></el-empty>
                    </div>
                </div>
            </el-col>
        </el-row>
@@ -93,7 +96,8 @@
                }
            },
            serverIp: '',
            serverPort: ''
            serverPort: '',
            urlLink: ''
        }
    },
    created() {
@@ -144,6 +148,11 @@
                return;
            }
            // 重置视频链接
            this.urlLink = '';
            this.serverIp = '';
            this.serverPort = '';
            getPlaybackVideo({
                startTime: new Date(this.searchForm.startTime).getTime(),
                endTime: new Date(this.searchForm.endTime).getTime(),
@@ -152,7 +161,8 @@
                if (res && res.serverIp && res.serverPort) {
                    // 构建完整的视频流地址
                    this.serverIp = res.serverIp;
                    this.serverPort = res.serverPort
                    this.serverPort = res.serverPort;
                    this.urlLink = res.url;
                } else {
                    this.$message.error('未获取到视频地址');
                }
@@ -161,6 +171,10 @@
                this.$message.error('获取视频失败,请稍后重试');
            });
        },
        handleVideoError() {
            this.urlLink = '';
            this.$message.error('视频加载失败,请稍后重试');
        },
        resetForm() {
            this.searchForm.startTime = '';
            this.searchForm.endTime = '';