| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- <!-- 远程回放 -->
- <template>
- <div class="remote-playback">
- <div class="remote-playback-wrapper" mb-15px>
- <div class="remote-playback-l">
- <Calendar
- expanded
- :attributes="attrs"
- borderless
- color="#8ac5ff"
- :disabled-dates="disabledDates"
- :locale="useSystem.language"
- @dayclick="calendarChange"
- @did-move="updateView"
- @update:pages="tempUpdateView"
- />
- </div>
- <div class="remote-playback-r">
- <div class="remote-playback-video-box h-full relative bg-#00000080">
- <pub-video-new newClass="playback-video" class="h-full" />
- <div
- v-if="loading"
- class="absolute top-50% left-50% transform-translate--50% flex justify-center items-center"
- >
- <NSpin />
- </div>
- </div>
- </div>
- </div>
- <div class="time-line-box" h="150px" w-full overflow-hidden relative bottom-0>
- <div
- class="timeShow"
- absolute
- bottom="30px"
- left="50%"
- translate-x="-50%"
- color="#fff"
- pointer-events-none
- select-none
- >
- {{ showTime2 }}
- </div>
- <TimeLine
- ref="TimeLineRef"
- backgroundColor="rgba(94, 141, 255, 0.2)"
- multiSegmentActiveColor="transparent"
- :initTime="initTime"
- :timeSegments="timeSegments"
- :initZoomIndex="7"
- :extendZOOM="[
- {
- zoom: 15,
- zoomHourGrid: 0.5
- }
- ]"
- @timeChange="timeChange"
- @click_timeSegments="click_timeSegments"
- @click_timeline="onClickTimeLine"
- @dragTimeChange="onDragTimeChange"
- ></TimeLine>
- </div>
- </div>
- </template>
- <script setup>
- import dayjs from 'dayjs'
- import { NSpin } from 'naive-ui'
- import { omatVideoPlayer } from '@/assets/js/video-lib/flv/omatVideoPlayer'
- import { Calendar } from 'v-calendar'
- import 'v-calendar/style.css'
- import TimeLine from './components/TimeLine/index.vue'
- // import PartBox from './components/PartBox.vue'
- import { dialogFn } from '@/utils'
- import { useOutsideSystemStore } from '@/stores/modules/system.js'
- defineOptions({ name: 'RemotePlayback' })
- const props = defineProps({
- device_id: String
- })
- const { API_SR_GET } = useRequest()
- const useSystem = useOutsideSystemStore()
- const date = ref(+new Date())
- const disabledDates = ref([
- {
- repeat: {
- days: []
- }
- }
- ])
- const attrs = ref([
- {
- key: 'today',
- highlight: true,
- dates: date
- }
- ])
- const timeSegments = ref([
- // {
- // name: '时间段1',
- // beginTime: new Date('2023-01-13 10:00:00').getTime(),
- // endTime: new Date('2023-01-14 23:00:00').getTime(),
- // color: '#0f59a4',
- // startRatio: 0.65,
- // endRatio: 0.9
- // },
- // {
- // name: '时间段2',
- // beginTime: new Date('2023-01-15 02:00:00').getTime(),
- // endTime: new Date('2023-01-15 18:00:00').getTime(),
- // color: '#0f59a4',
- // startRatio: 0.65,
- // endRatio: 0.9
- // }
- ])
- let playerObj = null
- let timer = null
- let interval = 1000 // 间隔时间
- let startTime = 0 // 起始时间
- let endTime = 0 // 结束时间
- let current = 0
- let monthDays = []
- let currentDay = null
- let switchDay = ref(false)
- const TimeLineRef = ref(null)
- const formatT = (t) => dayjs(t).format('YYYY-MM-DD HH:mm:ss')
- const calendarChange = async (v) => {
- console.log(v)
- if (v.isDisabled || currentDay?.day === v.day) return
- if (timer) {
- dialogFn(
- 'warning',
- '警告',
- '当前正在播放,切换会停止,是否继续?',
- () => {
- clearInterval(timer)
- switchDay.value = true
- timer = null
- calendarChange(v)
- },
- () => {},
- '确定',
- '取消'
- )
- return
- }
- let promises = []
- let params = []
- currentDay = v
- // 找出当前点击天的前一天和后一天
- for (let i = 0; i < monthDays.length; i++) {
- if (
- monthDays[i].id ===
- `${v.year}-${v.month < 10 ? '0' + v.month : v.month}-${v.day < 10 ? '0' + v.day : v.day}`
- ) {
- if (monthDays[i - 1] && monthDays[i + 1]) {
- params.push(monthDays[i - 1].id, monthDays[i].id, monthDays[i + 1].id)
- } else {
- if (!monthDays[i - 1]) {
- params.push(monthDays[i].id, monthDays[i + 1].id)
- } else if (!monthDays[i + 1]) {
- params.push(monthDays[i - 1].id, monthDays[i].id)
- }
- }
- break
- }
- }
- params.forEach((p) => {
- const [form, to] = [dayjs(p + ' 00:00:00').unix(), dayjs(p + ' 23:59:59').unix()]
- promises.push(
- new Promise((resolve) => {
- API_SR_GET({
- device_id: props.device_id,
- from: form,
- to
- }).then((res) => {
- resolve(res)
- })
- })
- )
- })
- Promise.all(promises)
- .then((ress) => {
- console.log(ress)
- timeSegments.value = []
- ress.forEach((res) => {
- if (!res) return
- let list = res.map((item, i) => ({
- index: timeSegments.value.length + i,
- device_id: item.device_id,
- name: '时间段' + (timeSegments.value.length + i + 1),
- beginTime: `${item.begin}`.padEnd(13, '0'),
- endTime: `${item.end}`.padEnd(13, '0'),
- color: '#0f59a4',
- startRatio: 0.65,
- endRatio: 0.9
- }))
- timeSegments.value.push(...list)
- })
- const ressI = ress[1]?.length ? 1 : ress.findIndex((r) => r.length)
- let bool = ressI >= 0 ? true : false
- initTime.value = formatT(
- +(bool
- ? `${ress[ressI][0].begin}`.padEnd(13, '0')
- : `${new Date().getTime()}`.padEnd(13, '0'))
- )
- clearInterval(timer)
- })
- .catch(() => {
- timeSegments.value = []
- })
- }
- const updateView = (v) => {
- // API_NVR_MONTH_GET({ Year: v[0].year, Month: v[0].month }, { NvrId: useSystem.nvrId })
- // .then((res) => {
- // let temp = []
- // v[0].days.forEach((item) => {
- // if (!res.day?.includes(item.day)) {
- // temp.push(item.day)
- // }
- // })
- // disabledDates.value[0].repeat.days = temp
- // })
- // .catch(() => {
- // disabledDates.value[0].repeat.days = v[0].days.map((item) => item.day)
- // })
- }
- // 初始化日历
- let flag = 0
- const tempUpdateView = async (v) => {
- monthDays = v[0].days
- if (flag) return
- updateView(v)
- flag = 1
- }
- const currentTime = ref(0)
- let initTime = ref(formatT(+new Date()))
- const showTime2 = computed({
- get: () => formatT(initTime.value)
- })
- const timeChange = (time) => {
- initTime.value = formatT(time)
- currentTime.value = time
- }
- const timeSegmentsObj = ref({})
- const click_timeSegments = (arr, ...args) => {
- console.log('onClickTimeSegments', arr, args)
- console.log('点击了:' + arr[0].name)
- date.value = arr[0]
- timeSegmentsObj.value = arr[0]
- }
- const onClickTimeLine = (...args) => {
- console.log('onClickTimeLine', args)
- }
- const onDragTimeChange = (...args) => {
- console.log('onDragTimeChange', args)
- const segments = getEndTime(args[0])
- if (!segments.length) return
- let temp = { ...segments[0] }
- temp.beginTime = args[0] + ''
- timeSegmentsObj.value = temp
- }
- const getEndTime = (time) => {
- // 8:12:43 8:22:50
- return timeSegments.value.filter((item, i) => {
- let beginTime = +item.beginTime.padEnd(13, '0')
- let endTime = +item.endTime.padEnd(13, '0')
- if (time > beginTime && time < endTime) {
- current = i
- return true
- }
- })
- }
- const toStrOrNum = (value) => {
- return typeof value === 'number' ? value + '' : value
- }
- // 定义定时器函数
- const incrementTime = () => {
- // 执行递增操作(示例中是每秒加1秒)
- startTime += interval
- TimeLineRef.value.setTime(startTime)
- if (toStrOrNum(startTime).slice(0, 10) >= toStrOrNum(endTime).slice(0, 10)) {
- if (current >= timeSegments.value.length - 1) {
- clearInterval(timer) // 结束定时器
- console.log('已经到达结束时间')
- return
- }
- const item = timeSegments.value.find(
- (item) => toStrOrNum(startTime).slice(0, 10) <= toStrOrNum(item.beginTime).slice(0, 10)
- )
- if (!item) return clearInterval(timer)
- startTime = +item.beginTime
- endTime = +item.endTime
- console.log('切换到下一个时间段', item)
- clearInterval(timer)
- timer = setInterval(incrementTime, interval)
- }
- }
- const successOpen = () => {
- timer && clearInterval(timer)
- // 启动定时器
- timer = setInterval(incrementTime, interval)
- }
- const loading = ref(false)
- const playVideo = async (device_id) => {
- loading.value = true
- return new Promise(async (resolve) => {
- const { url } = await useSystem.getStream({ device_id })
- playerObj = omatVideoPlayer(
- '.playback-video',
- url,
- () => {
- loading.value = false
- resolve()
- },
- {
- enableZoom: false,
- enableDrag: false
- }
- )
- })
- }
- watch(
- () => timeSegmentsObj,
- (newV) => {
- playVideo(newV.value.device_id).then(() => {
- startTime = +newV.value.beginTime
- endTime = +newV.value.endTime
- current = newV.value.index
- successOpen()
- })
- },
- { deep: true }
- )
- onMounted(() => {
- let date = new Date()
- calendarChange({
- id: initTime.value.split(' ')[0],
- year: date.getFullYear(),
- month: date.getMonth() + 1,
- day: date.getDate(),
- isDisabled: false
- })
- setTimeout(() => {
- TimeLineRef.value.onResize()
- }, 200)
- })
- onUnmounted(() => {
- clearInterval(timer)
- timer = null
- playerObj?.destroyed()
- })
- </script>
- <style scoped lang="scss">
- .remote-playback {
- &-wrapper {
- display: flex;
- }
- &-l {
- border: 1px solid #5e8dff;
- background-color: rgba(94, 141, 255, 0.2);
- display: flex;
- justify-content: center;
- align-items: center;
- }
- &-r {
- flex: 1 0 auto;
- margin-left: 15px;
- }
- @mixin vcHeader() {
- background: rgba(94, 141, 255, 0.2);
- border-radius: 0;
- color: #fff;
- }
- :deep(.vc-container) {
- border: 0px solid #5e8dff;
- background-color: rgba(94, 141, 255, 0);
- color: #8ac5ff;
- .vc-pane-header-wrapper {
- .vc-header .vc-arrow {
- @include vcHeader();
- }
- }
- .vc-pane-layout {
- .vc-title-wrapper .vc-title {
- @include vcHeader();
- }
- }
- .vc-highlight-bg-solid {
- background-color: #5e8dff;
- }
- }
- :deep(.vc-popover-content-wrapper) {
- .vc-popover-content {
- border: 1px solid #5e8dff;
- backdrop-filter: blur(10px);
- @include vcHeader();
- .vc-nav-title,
- .vc-nav-arrow,
- .vc-nav-item {
- background: transparent;
- color: #8ac5ff;
- }
- .vc-nav-item.is-active {
- @include vcHeader();
- }
- }
- }
- }
- </style>
|