424 lines
12 KiB
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>
|