|
|
@@ -0,0 +1,260 @@
|
|
|
+<template>
|
|
|
+ <div class="nvr-camera-view">
|
|
|
+ <div class="nvr-tips">
|
|
|
+ <el-icon size="18" color="#409eff" style="margin: 11px 8px 11px 16px"><InfoFilled /></el-icon>
|
|
|
+ 可以回看和下载三个月内的视频回放数据;默认显示直播画面</div
|
|
|
+ >
|
|
|
+ <div class="nvr-date-picker">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="dateRange"
|
|
|
+ type="datetimerange"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ range-separator="至"
|
|
|
+ format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ :prefix-icon="Calendar"
|
|
|
+ :disabled-date="disableDate"
|
|
|
+ :clearable="false"
|
|
|
+ @change="judgeDate"
|
|
|
+ />
|
|
|
+ <el-button style="margin-left: 10px" type="primary" @click="handleNvrUrl(null)"
|
|
|
+ >查看回放</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <LiveVideo v-if="videoUrl" :url="videoUrl" @time-update="handleTimeUpdate" />
|
|
|
+ </div>
|
|
|
+ <div class="nvr-slider">
|
|
|
+ <NvrSlider
|
|
|
+ ref="nvrSliderRef"
|
|
|
+ v-if="confirmDate"
|
|
|
+ :start-time="dateRange[0]"
|
|
|
+ :end-time="dateRange[1]"
|
|
|
+ :start-position="100"
|
|
|
+ :violations="violationsList"
|
|
|
+ @update-nvr="handleNvrUrl"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="nvr-setting-bar">
|
|
|
+ <NvrVioCheckbox :available="confirmDate" :camera-id="cameraId" @check-tags="handleVioTags" />
|
|
|
+ <NvrTimeSelect
|
|
|
+ ref="nvrTimeSelectRef"
|
|
|
+ @set-Time="handleSetTime"
|
|
|
+ @download-nvr="handleDownloadNvr"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <a ref="downloadRef" style="display: none" :href="downloadUrl" download />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+ import NvrVioCheckbox from './NvrCheckbox.vue';
|
|
|
+ import NvrTimeSelect from './NvrTimeSelect.vue';
|
|
|
+ import NvrSlider from './NvrSlider.vue';
|
|
|
+ // import CameraLiveVideo from '@/views/cameras/preview/components/CameraLiveVideo/CameraLiveVideo.vue';
|
|
|
+ import { ref } from 'vue';
|
|
|
+ import LiveVideo from '@/components/LiveVideo/LiveVideo.vue';
|
|
|
+ import useCameraDetailStore from '@/views/cameras/preview/store/useCameraDetailStore';
|
|
|
+ import { dayjs, ElMessage } from 'element-plus';
|
|
|
+ import { computed } from 'vue';
|
|
|
+ import { InfoFilled, Calendar } from '@element-plus/icons-vue';
|
|
|
+ import {
|
|
|
+ getReplayNvr,
|
|
|
+ GetReplayNvrBody,
|
|
|
+ getRecordByTime,
|
|
|
+ GetRecordByTimeBody,
|
|
|
+ ViolationRecordItem,
|
|
|
+ getNvrDownloadUrl,
|
|
|
+ } from '@/api/datamanagement/playback';
|
|
|
+
|
|
|
+ defineProps<{ cameraId: number }>();
|
|
|
+ const cameraDetailStore = useCameraDetailStore();
|
|
|
+
|
|
|
+ // 日期范围
|
|
|
+ const dateRange = ref();
|
|
|
+ // 确认查看回放
|
|
|
+ const confirmDate = ref(false);
|
|
|
+ // 回放nvr地址
|
|
|
+ const nvrUrl = ref();
|
|
|
+ // 违例点列表
|
|
|
+ const violationsList = ref<ViolationRecordItem[]>([]);
|
|
|
+ // nvr滑动组件引用
|
|
|
+ const nvrSliderRef = ref();
|
|
|
+ // nvr下载组件引用
|
|
|
+ const nvrTimeSelectRef = ref();
|
|
|
+ // 下载
|
|
|
+ const downloadRef = ref();
|
|
|
+ const downloadUrl = ref();
|
|
|
+
|
|
|
+ const judgeDate = (date: Date[]) => {
|
|
|
+ // 判断日期范围大于半小时小于三个月
|
|
|
+ if (date && date.length === 2) {
|
|
|
+ const startTime = new Date(date[0]);
|
|
|
+ const endTime = new Date(date[1]);
|
|
|
+ if ((endTime.getTime() - startTime.getTime()) / (1000 * 60) < 1) {
|
|
|
+ ElMessage({
|
|
|
+ message: `选择回放时间范围不小于1分钟`,
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ dateRange.value = undefined;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // if (startTime.diff(endTime, 'month') > 3) {
|
|
|
+ // ElMessage({
|
|
|
+ // message: `选择回放时间范围不大于三个月`,
|
|
|
+ // type: 'error',
|
|
|
+ // });
|
|
|
+ // dateRange.value = undefined;
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+
|
|
|
+ confirmDate.value = false;
|
|
|
+ nvrUrl.value = undefined;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const handleNvrUrl = (nowTime?: Date | null) => {
|
|
|
+ if (!dateRange.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (cameraDetailStore.detail?.pushstreamIp) {
|
|
|
+ cameraDetailStore.clear();
|
|
|
+ }
|
|
|
+ const nvrParams: GetReplayNvrBody = {
|
|
|
+ cameraId: cameraDetailStore.cameraId,
|
|
|
+ startTime: dayjs(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ endTime: dayjs(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ };
|
|
|
+ confirmDate.value = true;
|
|
|
+ if (nowTime) {
|
|
|
+ nvrParams.startTime = dayjs(nowTime).format('YYYY-MM-DD HH:mm:ss');
|
|
|
+ }
|
|
|
+ getReplayNvr(nvrParams).then((res) => {
|
|
|
+ nvrUrl.value = res.data;
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleVioTags = (tags: string[]) => {
|
|
|
+ if (tags.length === 0) {
|
|
|
+ violationsList.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const violationsParams: GetRecordByTimeBody = {
|
|
|
+ algoList: tags.map((tag) => Number(tag)),
|
|
|
+ cameraId: cameraDetailStore.cameraId,
|
|
|
+ startTime: dayjs(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ endTime: dayjs(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ };
|
|
|
+ getRecordByTime(violationsParams).then((res) => {
|
|
|
+ violationsList.value = res;
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSetTime = (isStart: boolean) => {
|
|
|
+ if (!confirmDate.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (isStart) {
|
|
|
+ const end = nvrTimeSelectRef.value.endTime;
|
|
|
+ if (end.length > 0 && new Date(end) <= new Date(nvrSliderRef.value.onTime)) {
|
|
|
+ ElMessage({
|
|
|
+ message: `结束时间不早于开始时间`,
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ nvrTimeSelectRef.value.startTime = dayjs(nvrSliderRef.value.onTime).format(
|
|
|
+ 'YYYY-MM-DD HH:mm:ss',
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ const start = nvrTimeSelectRef.value.startTime;
|
|
|
+ if (start.length > 0 && new Date(start) >= new Date(nvrSliderRef.value.onTime)) {
|
|
|
+ ElMessage({
|
|
|
+ message: `开始时间不晚于结束时间`,
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ nvrTimeSelectRef.value.endTime = dayjs(nvrSliderRef.value.onTime).format(
|
|
|
+ 'YYYY-MM-DD HH:mm:ss',
|
|
|
+ );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleTimeUpdate = () => {
|
|
|
+ nvrSliderRef.value.pushTime();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDownloadNvr = () => {
|
|
|
+ if (
|
|
|
+ !confirmDate.value ||
|
|
|
+ nvrTimeSelectRef.value.startTime.length === 0 ||
|
|
|
+ nvrTimeSelectRef.value.endTime.length === 0
|
|
|
+ ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const nvrParams: GetReplayNvrBody = {
|
|
|
+ cameraId: cameraDetailStore.cameraId,
|
|
|
+ startTime: dayjs(nvrTimeSelectRef.value.startTime).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ endTime: dayjs(nvrTimeSelectRef.value.endTime).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ };
|
|
|
+ getNvrDownloadUrl(nvrParams).then((res) => {
|
|
|
+ downloadUrl.value = res;
|
|
|
+ downloadRef.value.click();
|
|
|
+
|
|
|
+ // const link = document.createElement('a');
|
|
|
+ // link.href = res;
|
|
|
+ // link.setAttribute('download', 'nvr.mp4');
|
|
|
+ // link.style.display = 'none';
|
|
|
+ // document.body.appendChild(link);
|
|
|
+ // link.click();
|
|
|
+ // document.body.removeChild(link);
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const disableDate = (time: Date) => {
|
|
|
+ const now = new Date();
|
|
|
+ return time > now || time < new Date(now.setDate(now.getDate() - 90));
|
|
|
+ };
|
|
|
+
|
|
|
+ const videoUrl = computed(() => {
|
|
|
+ return nvrUrl.value
|
|
|
+ ? nvrUrl.value
|
|
|
+ : cameraDetailStore.detail?.pushstreamIp
|
|
|
+ ? cameraDetailStore.detail?.pushstreamIp
|
|
|
+ : '';
|
|
|
+ });
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+ .nvr-tips {
|
|
|
+ margin: 5px 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ background: #ecf5ff;
|
|
|
+ border-radius: 2px;
|
|
|
+ font-family: 'PingFangSC', 'PingFang SC';
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 40px;
|
|
|
+ text-align: left;
|
|
|
+ font-style: normal;
|
|
|
+ text-transform: none;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nvr-date-picker {
|
|
|
+ margin: 10px 0 10px 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nvr-slider {
|
|
|
+ height: 80px;
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nvr-setting-bar {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+</style>
|