13404089107
2025-04-23 641a31ba3f142272396c517961e45f6d567df2cf
修改bug
1个文件已修改
210 ■■■■■ 已修改文件
src/view/car-manage/detail.vue 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/car-manage/detail.vue
@@ -28,7 +28,34 @@
                </div>
            </div>
            <div class="info-right flex2">
                <PlayLive></PlayLive>
                <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>
                        <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;"
                        @click="goBack()">查看回放</el-button>
                    <div style="position: absolute; right: 11px; top: 10px">
                        <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')" />
                            <div
                                style="font-size: 12px;font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);">
                                全屏</div>
                        </div>
                        <div style="display: flex;flex-direction: column;align-items: center; justify-content: center;
              background: #ffffff;padding: 3px 10px;border-radius: 6px;" @click="shotScreen()">
                            <img style="width: 20px; height: 20px" :src="require('../../assets//homeImg/slot.png')" />
                            <div
                                style="font-size: 12px; font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);">
                                截屏</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="tab-content ml--100 mr--30">
@@ -131,7 +158,7 @@
                <!-- 使用 Tailwind CSS 的内联十六进制颜色类 -->
                <div>{{ info.vehicleNumber }}<span v-if="info.warnList && info.warnList.length > 0">({{
                    info.warnList.length
                }})</span></div><i @click="closeDrawer" class="el-icon-s-unfold color1 pointer"></i>
                        }})</span></div><i @click="closeDrawer" class="el-icon-s-unfold color1 pointer"></i>
            </div>
            <hr class="mt--10" />
            <div class="pl--15 pr--15">
@@ -203,13 +230,12 @@
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
import DetailModal from "./components/detailModal.vue";
import PlayLive from '@/components/PlayLive/index.vue'
import DetailOrderModal from "./components/detailOrderModal.vue";
import { getCarDetail, getCarOrder, getCarWarning, getCarTrack, getCarVideo,getDetail,getOrderInfo,getOrderTravel,getOrderMonitoring} from './service'
import { getCarDetail, getCarOrder, getCarWarning, getCarTrack, getCarVideo, getDetail, getOrderInfo, getOrderTravel, getOrderMonitoring, playDetection, closeRealVideo } from './service'
import moment from "moment";
export default {
    name: "detail",
    components: { DetailModal,DetailOrderModal,PlayLive },
    components: { DetailModal, DetailOrderModal },
    data() {
        return {
            id: '',
@@ -224,7 +250,7 @@
            activeName: 'first',
            routeList: [],
            videoObj: {},
            loading:false,
            loading: false,
            drawer: false,
            showWarnDetail: false,
            info: {},
@@ -240,11 +266,167 @@
            })
            getCarVideo({ id: this.$route.query.id }).then(res => {
                this.videoObj = res;
                this.initVideoPlayer();
            })
        }
    },
    destroyed() {
        this.destroyPlayer();
    },
    methods: {
        goBack() {
            this.$router.push('/car-playback?id=' + this.$route.query.id)
        },
        // 初始化视频播放器
        initVideoPlayer() {
            // 先销毁之前的播放器
            if (this.flvPlayer) {
                this.flvPlayer.destroy();
                this.flvPlayer = null;
            }
            // 获取video元素
            const video = document.getElementById("monitoringCard");
            if (!video) {
                console.error("Video element not found");
                return;
            }
            // 检查flv.js是否支持
            if (flvjs.isSupported()) {
                try {
                    playDetection(this.carId).then((res) => {
                        this.flvPlayer = flvjs.createPlayer({
                            type: "flv", //视频类型
                            isLive: true, //是否为直播
                            cors: true, //是否开启跨域
                            hasAudio: false, //是否开启音频
                            hasVideo: true, //是否开启视频
                            url: `http://${this.videoObj.serverIp}:${this.videoObj.serverPort}/live?port=1935&app=flv&stream=${this.$route.query.id}`, // 后端拿到的视频路径
                            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("monitoringCard");
                        this.flvPlayer.attachMediaElement(video); // video容器
                        this.flvPlayer.load();
                        this.flvPlayer
                            .play()
                            .then((res) => {
                                // 显示视频元素
                                video.style.display = 'block';
                                // 隐藏空状态
                                const emptyElement = video.parentElement.querySelector('.el-empty');
                                if (emptyElement) {
                                    emptyElement.style.display = 'none';
                                }
                                this.videoTimer = setInterval(() => {
                                    playDetection(this.carId);
                                }, 5000);
                            })
                            .catch((err) => {
                                this.destroyPlayer();
                            });
                        // 错误监听
                        this.flvPlayer.on("error", (err) => {
                            this.destroyPlayer();
                        });
                    });
                } catch (error) {
                    console.error("创建播放器失败:", error);
                }
            } else {
                console.error("当前浏览器不支持flv.js");
            }
        },
        destroyPlayer() {
            // 销毁播放器释放资源
            if (this.flvPlayer) {
                if (this.videoTimer) clearInterval(this.videoTimer);
                closeRealVideo(this.carId).then((res) => {
                    this.flvPlayer.pause();
                    this.flvPlayer.unload();
                    this.flvPlayer.detachMediaElement();
                    this.flvPlayer.destroy();
                    this.flvPlayer = null;
                    // 恢复空状态的显示
                    const video = document.getElementById("monitoringCard");
                    if (video) {
                        video.style.display = 'none';
                        const emptyElement = video.parentElement.querySelector('.el-empty');
                        if (emptyElement) {
                            emptyElement.style.display = 'block';
                        }
                    }
                });
            }
        },
        // 处理视频错误
        handleVideoError(event) {
            console.error("视频加载失败", event);
            if (this.flvPlayer) {
                this.flvPlayer.destroy();
                this.flvPlayer = null;
            }
            this.infoWindow.setContent(
                '<div style="padding: 20px;text-align: center;color: red;">视频加载失败,请稍后重试</div>'
            );
        },
        shotScreen() {
            // 获取video和canvas元素
            const video = document.getElementById("monitoringCard");
            const canvas = document.getElementById("myCanvas");
            // 设置canvas的宽度和高度与video相同
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            // 获取canvas的2d绘图上下文
            const context = canvas.getContext("2d");
            // 将当前video帧绘制到canvas上
            context.drawImage(video, 0, 0, canvas.width, canvas.height);
            setTimeout(() => {
                // 将canvas内容转换为图片
                let dataURL = canvas.toDataURL("image/png");
                this.downloadImage(dataURL);
            }, 100);
        },
        downloadImage(base64) {
            const link = document.createElement("a");
            link.href = base64;
            link.download = "screenshot.png"; // 你希望下载的文件名
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        },
        fullScreen() {
            const video = document.getElementById("monitoringCard");
            if (video.requestFullscreen) {
                video.requestFullscreen();
            } else if (video.mozRequestFullScreen) {
                // Firefox
                video.mozRequestFullScreen();
            } else if (video.webkitRequestFullscreen) {
                // Chrome, Safari and Opera
                video.webkitRequestFullscreen();
            } else if (video.msRequestFullscreen) {
                // IE/Edge
                video.msRequestFullscreen();
            }
        },
        showDetails(row) {
            this.loading = true
            Promise.all([getOrderInfo(row.id), getOrderTravel({ id: row.id })]).then(res => {
@@ -262,7 +444,7 @@
        closeDrawer() {
            this.drawer = false
            this.showWarnDetail = false
        },
        // 查看详情
        viewDetail(row) {
@@ -280,7 +462,7 @@
                    securityJsCode: this.$secretKey,
                };
                AMapLoader.load({
                    key:this.$mapKey,
                    key: this.$mapKey,
                    version: "2.0",
                    plugins: [
                        "AMap.ToolBar",
@@ -315,7 +497,7 @@
                    pageSize: 10,
                    total: 0,
                }
                this.getList(this.detail.vehicleNumber)
                //销毁地图
                if (this.map) {
@@ -351,10 +533,10 @@
        },
        reset() {
            this.searchForm = {
               pageCurr: 1,
               pageSize: 10,
               total: 0,
               date: undefined,
                pageCurr: 1,
                pageSize: 10,
                total: 0,
                date: undefined,
            }
        },
        getList(vehicleNumber) {
@@ -529,6 +711,7 @@
    width: 100%;
    height: 600px;
}
#mapContainers {
    width: 100%;
    height: 500px;
@@ -554,6 +737,7 @@
        }
    }
}
.color1 {
    color: #0E6EFD;
}