wx-starlock/pages/p2p/videoLog.vue

424 lines
12 KiB
Vue

<template>
<view>
<view class="m-4" v-if="info">
<swiper indicator-dots autoplay circular class="h-195" @click="toWebview">
<swiper-item>
<image
mode="widthFix"
src="https://xhj-starlock.oss-cn-shenzhen.aliyuncs.com/mp/swiper_video_ai.png"
class="w-full rounded-2xl"
/>
</swiper-item>
<swiper-item>
<image
mode="widthFix"
src="https://xhj-starlock.oss-cn-shenzhen.aliyuncs.com/mp/swiper_video_log.png"
class="w-full rounded-2xl"
/>
</swiper-item>
</swiper>
<view class="text-sm mt-2 flex mx-2" :style="{ color: color }">
<div class="i-solar:cloud-upload-linear size-40 mr-1"></div>
{{ info.desc }}
</view>
</view>
<scroll-view
v-if="deviceInfo"
scroll-y="true"
:lower-threshold="100"
:style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top - 145 + 'px' }"
:refresher-enabled="true"
@refresherrefresh="onRefresh"
@scrolltolower="onScrollToLower"
:refresher-triggered="refresherTriggered"
>
<view class="pb-40">
<view v-if="groupedList.length === 0 && requestFlag">
<image
class="w-[150rpx] h-[150rpx] mt-[300rpx] mx-auto mb-[20rpx] ml-[50%] -translate-x-1/2"
src="https://oss-lock.xhjcn.ltd/mp/background_empty_list.png"
mode="aspectFill"
></image>
<view class="text-[32rpx] text-[#999999] text-center">暂无数据</view>
</view>
<view v-else>
<view v-for="group in groupedList" :key="group.date" class="mb-2">
<view class="px-4 py-2 text-gray-600 text-sm font-medium font-bold">
{{ group.date }}
</view>
<view
v-for="item in group.items"
:key="item.event_id"
class="px-4 py-1 border-b border-gray-200 text-base"
>
<view class="mx-2">
<view class="flex items-start">
<view class="bg-#63b8af size-15 rounded-full mr-2 mt-1.5"></view>
<view class="w-full">
<view class="font-bold flex justify-between w-full">
<view>{{ item.event_type_name }}</view>
<view
class="i-material-symbols:more-horiz text-#999999 size-45 font-bold"
@click="operateEvent(item.event_id)"
></view>
</view>
<view class="text-sm text-#999999 mt-0.5">
{{ formatTime(item.event_time) }}
</view>
<view class="font-bold mt-1 text-#999999">
{{ item.text }}
</view>
<view v-if="item.video !== '' && item.video_expire_at > Date.now() / 1000">
<video
:id="`video-${item.event_id}`"
:src="item.video"
class="w-300"
@click="playVideoFullscreen(item.event_id)"
@fullscreenchange="onFullscreenChange(item.event_id, $event)"
@play="onVideoPlay(item.event_id)"
@pause="onVideoPause(item.event_id)"
controls
show-fullscreen-btn
></video>
<view class="text-sm text-#999999 mt-1">
{{ formatRemainingTime(item.video_expire_at) }}
</view>
</view>
<view v-else-if="item.preview_image !== ''">
<image :src="item.preview_image" class="w-300" mode="widthFix" />
<view v-if="item.video !== ''" class="text-sm text-#999999 mt-1">
{{ formatRemainingTime(item.video_expire_at) }}
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<view
v-if="list.length > 0"
class="fixed bottom-70 right-16 rounded-full bg-red p-2"
@click="resetLog"
>
<div class="i-material-symbols:delete-outline-rounded size-70 color-white"></div>
</view>
</view>
</template>
<script setup>
import { onMounted, ref, computed } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useBluetoothStore } from '@/stores/bluetooth'
import { passthrough } from '@/api/sdk'
import { useBasicStore } from '@/stores/basic'
const $bluetooth = useBluetoothStore()
const $basic = useBasicStore()
const info = ref()
const pageSize = 50
const list = ref([])
const pageNo = ref(1)
const total = ref(0)
const refresherTriggered = ref(false)
const requestFlag = ref(false)
const deviceInfo = ref(null)
const fullscreenVideoId = ref(null)
const isFullscreenChanging = ref(false)
const currentPlayingVideoId = ref(null)
onMounted(async () => {
deviceInfo.value = await $basic.getDeviceInfo()
await Promise.all([getInfo(), getList()])
requestFlag.value = true
})
onShow(() => {
if (requestFlag.value) {
getInfo()
}
})
const operateEvent = eventId => {
uni.showActionSheet({
itemList: ['删除'],
success: ({ tapIndex }) => {
if (tapIndex === 0) {
deleteEvent(eventId)
}
}
})
}
const toWebview = () => {
$basic.routeJump({
name: 'webview',
params: {
url: encodeURIComponent('https://www.baidu.com')
}
})
}
const resetLog = async () => {
uni.showModal({
title: '提示',
content: '确定删除所有记录吗?',
success: async ({ confirm }) => {
if (confirm) {
if (confirm) {
const { code, message } = await passthrough({
request_method: 'POST',
request_uri: '/api/v1/cloudStorage/clearStorageEvent',
post_args: { lockId: $bluetooth.currentLockInfo.lockId }
})
if (code === 0) {
uni.showToast({
title: '删除成功',
icon: 'none'
})
await getList()
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
}
})
}
const deleteEvent = async eventId => {
uni.showModal({
title: '提示',
content: '确定删除该记录吗?',
success: async ({ confirm }) => {
if (confirm) {
const { code, message } = await passthrough({
request_method: 'POST',
request_uri: '/api/v1/cloudStorage/delStorageEvent',
post_args: { eventId }
})
if (code === 0) {
uni.showToast({
title: '删除成功',
icon: 'none'
})
await getList()
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
}
const formatDate = timestamp => {
const date = new Date(timestamp * 1000)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
const formatTime = timestamp => {
const date = new Date(timestamp * 1000)
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${hours}:${minutes}:${seconds}`
}
const formatRemainingTime = expireTimestamp => {
const now = Math.floor(Date.now() / 1000)
const diff = expireTimestamp - now
if (diff <= 0) {
return '视频已过期'
}
const days = Math.floor(diff / (24 * 60 * 60))
const hours = Math.floor((diff % (24 * 60 * 60)) / (60 * 60))
const minutes = Math.floor((diff % (60 * 60)) / 60)
let result = '视频'
if (days > 0) {
result += `${days}`
}
if (hours > 0) {
result += `${hours}小时`
}
if (minutes > 0 && days === 0) {
result += `${minutes}分钟`
}
result += '后过期'
return result
}
const groupedList = computed(() => {
const groups = []
const dateMap = new Map()
list.value.forEach(item => {
const dateKey = formatDate(item.event_time)
if (!dateMap.has(dateKey)) {
const newGroup = {
date: dateKey,
items: []
}
groups.push(newGroup)
dateMap.set(dateKey, newGroup)
}
dateMap.get(dateKey).items.push(item)
})
return groups
})
const color = computed(() => {
if (info.value?.status === 1) {
return '#63b8af'
}
if (info.value?.status === 2) {
return 'red'
}
return '#999999'
})
const onRefresh = async () => {
refresherTriggered.value = true
pageNo.value = 1
await getList()
refresherTriggered.value = false
}
const onScrollToLower = async () => {
if (list.value.length < total.value) {
getList(pageNo.value + 1)
}
}
const getInfo = async () => {
const { code, data, message } = await passthrough({
request_method: 'POST',
request_uri: '/api/v1/cloudStorage/getStorageServiceInfo',
post_args: {
lockId: $bluetooth.currentLockInfo.lockId
}
})
if (code === 0) {
info.value = data
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
const getList = async (pageNo = 1) => {
if (pageNo > 1 && (pageNo - 1) * pageSize >= total.value) {
return
}
const { code, data, message } = await passthrough({
request_method: 'POST',
request_uri: '/api/v1/cloudStorage/getStorageEventList',
post_args: {
lockId: $bluetooth.currentLockInfo.lockId,
pageNo,
pageSize
}
})
if (code === 0) {
if (pageNo === 1) {
list.value = data.list
} else {
list.value = [...list.value, ...data.list]
}
total.value = data.total
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
return { code, data, message }
}
const playVideoFullscreen = eventId => {
if (fullscreenVideoId.value === eventId) {
return
}
if (isFullscreenChanging.value) {
return
}
if (currentPlayingVideoId.value && currentPlayingVideoId.value !== eventId) {
const currentVideoContext = uni.createVideoContext(`video-${currentPlayingVideoId.value}`)
currentVideoContext.pause()
}
const videoId = `video-${eventId}`
const videoContext = uni.createVideoContext(videoId)
isFullscreenChanging.value = true
currentPlayingVideoId.value = eventId
videoContext.play()
setTimeout(() => {
if (fullscreenVideoId.value !== eventId) {
videoContext.requestFullScreen({
direction: 0
})
}
setTimeout(() => {
isFullscreenChanging.value = false
}, 500)
}, 300)
}
const onFullscreenChange = (eventId, event) => {
if (event.detail.fullScreen) {
fullscreenVideoId.value = eventId
} else {
fullscreenVideoId.value = null
}
}
const onVideoPlay = eventId => {
if (currentPlayingVideoId.value && currentPlayingVideoId.value !== eventId) {
const currentVideoContext = uni.createVideoContext(`video-${currentPlayingVideoId.value}`)
currentVideoContext.pause()
}
currentPlayingVideoId.value = eventId
}
const onVideoPause = eventId => {
if (currentPlayingVideoId.value === eventId) {
currentPlayingVideoId.value = null
}
}
</script>