You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
duoji-frontend/src/views/videoPlayback/index.vue

550 lines
20 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<a-row
type="flex"
:gutter="30"
>
<a-col :flex="1">
时间<a-date-picker
v-model="date"
format="YYYY-MM-DD"
placeholder="请选择时间"
@change="cameraRecord"
/>
<section style="height: 80vh;overflow: hidden;
overflow-y: scroll;">
<a-tree
:tree-data="treeData"
:check-strictly="true"
@select="handleCheck"
>
</a-tree>
</section>
</a-col>
<a-col :flex="13">
<div>
<div class="time-display">
<!-- 视频 -->
<video
ref="videoPlayer"
muted
style=" display: flex;"
width="60%"
>
<source
:src="'http://192.168.1.110:8007'+currentVideoUrl"
type="video/mp4"
/>
</video>
</div>
<!-- 滑动轴 'http://192.168.1.110:8007'+currentVideoUrl -->
<div
class="zoom-buttons"
width="100%"
>
<!-- <a-button-group>
<a-button icon="arrows-alt" :disabled="zoom" @click="handleZoomIn"></a-button>
<a-button icon="shrink" :disabled="shrink" @click="handleZoomOut"></a-button>
</a-button-group> -->
</div>
<a-slider
ref="slider"
:marks="marks"
class="progress-bar"
:max="totalDuration"
:tip-formatter="formatter"
:value="currentTime"
:disabled="Object.keys(urls).length === 0"
@change="onSliderChange"
/>
<div class="time-display">
<a-button-group>
<a-button
icon="step-backward"
:disabled="Object.keys(urls).length === 0"
@click="moveForward(-5)"
/>
<a-button
v-if="isPlaying"
:disabled="Object.keys(urls).length === 0"
icon="pause"
@click="pauseVideo"
/>
<a-button
v-else
icon="play-circle"
:disabled="Object.keys(urls).length === 0"
@click="playVideo"
/>
<a-button
icon="step-forward"
:disabled="Object.keys(urls).length === 0"
@click="moveForward(5)"
/>
</a-button-group>
</div>
</div>
</a-col>
</a-row>
</template>
<script>
import { Slider, Button, ButtonGroup } from "ant-design-vue";
import moment from "moment";
import { message } from "ant-design-vue";
export default {
components: {
ASlider: Slider,
AButton: Button,
AButtonGroup: ButtonGroup,
},
data() {
return {
totalDuration: 24 * 60 * 60, // 假设视频总时长为60s
//数据轴上的数值
currentTime: 0,
//数据轴上的开始时间
startTimeLong: 0,
//数据轴上的结束时间
endTimeLong: 24 * 60 * 60,
//当天记录的结束的时间绝对值
maxTimeLong: 24 * 60 * 60,
//当天记录的开始的时间绝对值
minTimeLong: 0 * 60 * 60,
date: this.getYesterday(),
currentVideoUrl: "", // 当前视频的 URL
value1: "2023-10-11",
urls: {},
mapByTime: {},
URLStartTime: 0,
isPlaying: false, // 视频是否正在播放
marks: {},
zoom: false,
shrink: true,
treeData: [],
cameraId: "",
playObject: {},
getSuccessUrl: [],
};
},
mounted() {
const video = this.$refs.videoPlayer;
video.addEventListener("timeupdate", this.onVideoTimeUpdate);
video.addEventListener("ended", this.playNextVideo);
console.log(this.getTimeMap());
this.totalDuration = this.endTimeLong - this.startTimeLong;
this.marks = this.getTimeMap();
console.log(this.date);
this.getTree();
this.cameraRecord();
},
beforeDestroy() {
const video = this.$refs.videoPlayer;
video.removeEventListener("timeupdate", this.onVideoTimeUpdate);
video.removeEventListener("ended", this.playNextVideo);
},
methods: {
videoControl(seconds) {
//获取playObject参数
this.binarySearchMax(seconds);
//后台获取资源
if (!this.getSuccessUrl.includes(this.currentVideoUrl)) {
//加载视频
this.$api.httpApi
.cameraRecordConvetor({
data: {
url: this.currentVideoUrl,
},
})
.then((res) => {
this.getSuccessUrl.push(this.currentVideoUrl);
});
}
//读取MP4文件
const video = this.$refs.videoPlayer;
this.isPlaying = true;
video.load(); // 重新加载视频资源
//计算时间
video.currentTime =
this.currentTime - this.playObject.startTimeLong;
//播放或停止
if (this.isPlaying) {
video.play();
} else {
video.pause();
}
},
//获取前一天
getYesterday() {
const now = moment();
return now.subtract(1, "days");
},
//放大缩小轴所用
scaleTime(rate) {
const middle = this.startTimeLong + this.currentTime;
// 计算开始时间到中间时间的毫秒数
const startToMiddleMs = middle - this.startTimeLong;
// 计算结束时间到中间时间的毫秒数
const endToMiddleMs = this.endTimeLong - middle;
// 缩小或放大开始时间
const scaledStart = middle - Math.floor(startToMiddleMs * rate);
console.log("开始缩小时间" + scaledStart);
// 缩小或放大结束时间
const scaledEnd = middle + Math.floor(endToMiddleMs * rate);
console.log("结束缩小时间" + scaledEnd);
// 检查是否超出当天时间的范围并赋值
this.startTimeLong =
this.minTimeLong > scaledStart ? this.minTimeLong : scaledStart;
this.endTimeLong =
this.maxTimeLong < scaledEnd ? this.maxTimeLong : scaledEnd;
//时间修改
if (
this.minTimeLong < scaledStart ||
this.maxTimeLong > scaledEnd
) {
this.shrink = false;
} else {
this.shrink = true;
}
console.log("zhou" + middle);
this.updateslider(middle);
},
//获取当前时间
formatTime(seconds) {
seconds = seconds % (60 * 60 * 24);
const hour = Math.floor(seconds / 3600);
const minute = Math.floor((seconds % 3600) / 60);
const second = seconds % 60;
return `${hour.toString().padStart(2, "0")}:${minute
.toString()
.padStart(2, "0")}:${second.toString().padStart(2, "0")}`;
},
// 点击放大按钮触发的方法
handleZoomIn() {
this.scaleTime(0.5);
},
// 点击缩小按钮触发的方法
handleZoomOut() {
this.scaleTime(2);
},
//根据开始时间修改时间轴(轴位置不变,请在外部修改)
updateslider(middle) {
this.totalDuration = this.endTimeLong - this.startTimeLong;
console.log("轴上数值为:" + (middle - this.startTimeLong));
this.currentTime = middle - this.startTimeLong;
this.marks = this.getTimeMap();
},
//巷道列表
getTree() {
this.$api.httpApi
.getAllStreet({})
.then((res) => {
console.log("update data");
for (let i = 0; i < res.data.length; i++) {
// 创建空对象
const obj = {};
// 添加属性和值
obj["title"] = res.data[i].name;
obj["key"] = res.data[i].id;
obj["type"] = 0;
obj["children"] = [];
if (res.data[i].camera1Id != "") {
const obj1 = {};
obj1["title"] = res.data[i].camera1Name;
obj1["key"] = res.data[i].camera1Id;
obj1["type"] = 1;
obj["children"].push(obj1);
}
if (res.data[i].camera2Id != "") {
const obj1 = {};
obj1["title"] = res.data[i].camera2Name;
obj1["key"] = res.data[i].camera2Id;
obj1["type"] = 1;
obj["children"].push(obj1);
}
this.treeData.push(obj);
}
console.log(this.treeData);
})
.catch((err) => {});
},
//根据时间间隔调整横轴时间片段
getTimeMap() {
const diff = this.endTimeLong - this.startTimeLong; // 计算时间差,单位为秒
console.log(diff + " qqq");
const map = {};
if (diff >= 60 * 60 * 3) {
this.TimeMapErgodic(60 * 60, map);
} else if (diff >= 60 * 60) {
// 如果大于等于1小时小于3小时每15分钟一个标识
this.TimeMapErgodic(15 * 60, map);
} else if (diff >= 60 * 20) {
this.zoom = false;
// 如果大于等于20分钟小于1小时每5分钟一个标识
this.TimeMapErgodic(5 * 60, map);
} else if (diff >= 5 * 60) {
this.zoom = false;
// 如果大于等于5分钟小于20分钟每分钟一个标识
this.TimeMapErgodic(60, map);
} else if (diff >= 30) {
this.zoom = false;
// 如果小于5分钟大于1m每30s一个标识
console.log("如果小于5分钟大于1m每30s一个标识");
console.log(startTime + " " + endTime);
this.TimeMapErgodic(30, map);
} else if (diff >= 10) {
this.zoom = true;
// 如果小于1m大于10s 5s标识
this.TimeMapErgodic(5, map);
} else {
this.zoom = true;
// 如果小于10s 1s标识
this.TimeMapErgodic(1, map);
}
return map;
},
//遍历获取time映射
TimeMapErgodic(interval, map) {
const startTime =
Math.ceil(this.startTimeLong / interval) * interval;
const endTime = Math.floor(this.endTimeLong / interval) * interval;
for (let i = startTime; i <= endTime; i += interval) {
const minuteDiff = i - this.startTimeLong;
map[minuteDiff] = `${String(Math.floor(i / (60 * 60))).padStart(
2,
"0"
)}:${String(Math.floor((i % (60 * 60)) / 60)).padStart(
2,
"0"
)}:${String(i % 60).padStart(2, "0")}`;
}
return map;
},
//将秒数转为 时分秒
formatter(value) {
const i = this.startTimeLong + value;
// 格式化输出新的时间
const hours = String(Math.floor(i / (60 * 60))).padStart(2, "0");
const minutes = String(Math.floor((i % (60 * 60)) / 60)).padStart(
2,
"0"
);
const seconds = String(Math.floor(i % 60)).padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
},
//当改变横轴时获取视频开始时间和url
binarySearchMax(target) {
var maxSmaller = null;
let nums = Object.keys(this.mapByTime);
//console.log(nums);
let num = 0;
for (let numString of nums) {
num = parseInt(this.mapByTime[numString].endTimeLong);
if (target < num) {
this.playObject = this.mapByTime[numString];
if (
!(
target >
parseInt(this.mapByTime[numString].startTimeLong)
)
) {
this.currentTime = parseInt(
this.mapByTime[numString].startTimeLong
);
} else {
this.currentTime = target;
}
this.currentVideoUrl = this.playObject.url;
console.log(this.currentVideoUrl);
break;
}
}
return maxSmaller;
},
//横轴改变
onSliderChange(value) {
this.videoControl(value);
},
//视频时间改变
onVideoTimeUpdate() {
const video = this.$refs.videoPlayer;
console.log(
"视频时间" + (this.playObject.startTimeLong + video.currentTime)
);
this.currentTime =
this.playObject.startTimeLong +
video.currentTime -
this.startTimeLong;
},
//左右调整
moveForward(duration) {
console.log("111");
this.videoControl(this.currentTime + duration)
},
playVideo() {
console.log(this.currentVideoUrl);
if (this.currentVideoUrl == null || this.currentVideoUrl == "") {
this.binarySearchMax(0);
}
//加载视频
console.log(this.getSuccessUrl.includes(this.currentVideoUrl));
if (!this.getSuccessUrl.includes(this.currentVideoUrl)) {
//加载视频
this.$api.httpApi
.cameraRecordConvetor({
data: {
url: this.currentVideoUrl,
},
})
.then((res) => {
this.getSuccessUrl.push(this.currentVideoUrl);
});
}
const video = this.$refs.videoPlayer;
this.isPlaying = true;
video.load(); // 重新加载视频资源
video.currentTime =
this.currentTime - this.playObject.startTimeLong;
video.play();
},
pauseVideo() {
const video = this.$refs.videoPlayer;
this.isPlaying = false;
video.pause();
},
playNextVideo() {
let nextKey = this.URLStartTime;
const keys = Object.keys(this.urls);
// 找到当前键的索引
const currentIndex = keys.indexOf(this.URLStartTime.toString());
console.log(keys);
if (currentIndex !== -1 && currentIndex < keys.length - 1) {
nextKey = Number(keys[currentIndex + 1]);
const video = this.$refs.videoPlayer;
this.URLStartTime = nextKey;
this.currentVideoUrl = this.urls[nextKey];
video.load(); // 重新加载视频资源
this.currentTime = this.URLStartTime;
video.currentTime = 0;
video.play();
}
},
handleCheck(selectedKeys, e) {
if (e.selectedNodes[0].data.props.type == 1) {
this.cameraId = e.selectedNodes[0].data.key;
console.log(e.selectedNodes[0].data);
this.cameraRecord();
}
console.log(e.selectedNodes[0].data.props);
},
cameraRecord() {
this.$api.httpApi
.cameraRecord({
data: {
date:
this.date._d.getFullYear() +
"-" +
(this.date._d.getMonth() + 1) +
"-" +
this.date._d.getDate(),
cameraId: this.cameraId,
},
})
.then((res) => {
console.log("update data");
if (
(res.data.startTimeLong !== null &&
res.data.startTimeLong !== undefined &&
res.data.startTimeLong !== "") ||
(res.data.endTimeLong !== null &&
res.data.endTimeLong !== undefined &&
res.data.endTimeLong !== "")
) {
}
if (
res.data.urls !== null &&
res.data.urls !== undefined &&
Object.keys(res.data.urls).length > 0
) {
this.startTimeLong = res.data.startTimeLong;
this.endTimeLong = res.data.endTimeLong;
this.minTimeLong = res.data.startTimeLong;
this.maxTimeLong = res.data.endTimeLong;
this.currentTime = 0;
this.totalDuration =
res.data.endTimeLong - res.data.startTimeLong;
const map = {};
const mapByTime = {};
for (let i = 0; i < res.data.urls.length; i++) {
map[res.data.urls[i].startTimeLong] =
res.data.urls[i].url;
}
for (let i = 0; i < res.data.urls.length; i++) {
mapByTime[res.data.urls[i].startTimeLong] =
res.data.urls[i];
}
this.urls = map;
this.mapByTime = mapByTime;
this.marks = this.getTimeMap();
console.log(map);
} else {
if (
this.cameraId !== null &&
this.cameraId !== undefined &&
this.cameraId !== ""
) {
message.info("此摄像头该日期未录像");
}
}
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
<style>
.progress-bar .ant-slider-rail {
background-color: lightgray;
}
.progress-bar .ant-slider-track {
background-color: dodgerblue;
}
.time-display {
margin-top: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.zoom-buttons {
text-align: right;
margin-bottom: 16px;
}
</style>