wx-starlock/pages/feature/recordList.vue
2025-05-17 18:22:50 +08:00

481 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<view class="flex items-center h-[60px] mx-3 font-bold">
<view>日期</view>
<view class="bg-[rgba(0,0,0,0.35)] rounded-full px-2 py-1.5 mr-5">
<picker :value="timeText" mode="date" @change="changeDate">
<up-icon
:label="timeText"
color="#ffffff"
label-color="#ffffff"
labelPos="left"
name="arrow-down-fill"
size="32rpx"
space="16rpx"
></up-icon>
</picker>
</view>
<view>事件</view>
<view class="bg-[rgba(0,0,0,0.35)] rounded-full px-2 py-1.5 mr-1">
<picker
:value="index"
mode="selector"
:range="range"
range-key="name"
@change="changeEvent"
>
<up-icon
:label="range[index].name"
color="#ffffff"
label-color="#ffffff"
labelPos="left"
name="arrow-down-fill"
size="32rpx"
space="16rpx"
></up-icon>
</picker>
</view>
<view class="ml-a">
<up-icon
name="question-circle-fill"
@click="tip"
size="52rpx"
color="rgba(0,0,0,0.35)"
></up-icon>
</view>
</view>
<scroll-view
v-if="deviceInfo"
scroll-y="true"
:style="{ height: `calc(${deviceInfo.screenHeight - deviceInfo.safeArea.top - 60}px)` }"
lower-threshold="100"
@refresherrefresh="refresherList"
:refresher-enabled="true"
@scrolltolower="nextPage"
:refresher-triggered="refresherTriggered"
>
<view style="padding: 0 0 calc(env(safe-area-inset-bottom) + 250rpx) 0">
<view v-if="list.length === 0 && requestFinished">
<image
class="empty-list"
src="https://oss-lock.xhjcn.ltd/mp/background_empty_list.png"
mode="aspectFill"
></image>
<view class="empty-list-text">暂无数据</view>
</view>
<view v-else>
<div class="flex flex-col relative pl-5 text-base">
<div
v-for="(item, index) in list"
:key="index"
class="relative flex items-start pb-10 last:pb-0"
@click="toDetail(item)"
>
<div class="w-16 h-16 bg-#eeeeee rounded-full absolute left-0 top-2"></div>
<div
v-if="index !== list.length - 1"
class="absolute left-4 top-16 w-8 h-full bg-#eeeeee"
></div>
<div class="ml-5">
<div class="font-bold pb-3">{{ item.recordStr }}</div>
<view v-if="item.videoUrl !== ''" @click.stop="playFullScreen(index)">
<video
:id="`video${index}`"
class="w-300 h-225"
object-fit="cover"
:src="item.videoUrl"
></video>
</view>
<image
class="w-300 h-225"
v-else-if="item.imagesUrl"
:src="item.imagesUrl"
mode="aspectFill"
@click.stop="previewImage(item.imagesUrl)"
></image>
</div>
</div>
</div>
</view>
</view>
</scroll-view>
<view class="button" v-if="$bluetooth.currentLockInfo.keyRight === 1">
<view
class="button-reset"
@click="reset"
v-if="$bluetooth.currentLockInfo.userType === 110301"
>清空记录</view
>
<view
class="button-create"
:style="{ width: $bluetooth.currentLockInfo.userType === 110301 ? '300rpx' : '650rpx' }"
@click="syncRecord"
>
同步记录</view
>
</view>
</view>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { timeFormat } from 'uview-plus'
import { useBasicStore } from '@/stores/basic'
import { useBluetoothStore } from '@/stores/bluetooth'
import { clearRecordRequest, getEventRecordListRequest } from '@/api/record'
import { useUserStore } from '@/stores/user'
const $basic = useBasicStore()
const $bluetooth = useBluetoothStore()
const $user = useUserStore()
const list = ref([])
const pageNo = ref(1)
const pageSize = 50
const total = ref(0)
const lockId = ref(null)
const startDate = ref(0)
const endDate = ref(0)
const range = ref([
{ name: '全部事件', lockEventType: 0 },
{ name: '开锁事件', lockEventType: 10 },
{ name: '异常事件', lockEventType: 20 },
{ name: '门铃事件', lockEventType: 30 },
{ name: '视频事件', lockEventType: 40 }
])
const timeText = ref('今天')
const index = ref(0)
const deviceInfo = ref(null)
const requestFinished = ref(false)
const refresherTriggered = ref(false)
const playFullScreen = index => {
const videoContext = uni.createVideoContext(`video${index}`)
videoContext.requestFullScreen({ direction: 0 })
}
const tip = () => {
uni.showModal({
title: '操作记录未显示',
content: '锁未联网,开门记录无法实时上传,可以点击同步记录进行读取',
showCancel: false,
confirmText: '我知道了'
})
}
const previewImage = url => {
uni.previewImage({
urls: [url]
})
}
const changeDate = async value => {
if (value.detail.value === timeFormat(new Date(), 'yyyy-mm-dd')) {
timeText.value = '今天'
} else {
timeText.value = value.detail.value
}
startDate.value = new Date(value.detail.value).setHours(0, 0, 0, 0)
endDate.value = startDate.value + 24 * 60 * 60 * 1000 - 1
pageNo.value = 1
const { code, message } = await getList({
pageNo: pageNo.value
})
if (code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
}
const changeEvent = async value => {
index.value = Number(value.detail.value)
pageNo.value = 1
const { code, message } = await getList({
pageNo: pageNo.value
})
if (code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
}
onMounted(async () => {
uni.showLoading({
title: '加载中',
mask: true
})
deviceInfo.value = await $basic.getDeviceInfo()
lockId.value = $bluetooth.currentLockInfo.lockId
startDate.value = new Date().setHours(0, 0, 0, 0)
endDate.value = startDate.value + 24 * 60 * 60 * 1000 - 1
const { code, message } = await getList({
pageNo: pageNo.value
})
requestFinished.value = true
uni.hideLoading()
if (code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
})
const reset = async () => {
uni.showModal({
title: '是否要删除操作记录?',
content: '被删除的记录不能恢复',
async success(res) {
if (res.confirm) {
const netWork = await $basic.getNetworkType()
if (!netWork) {
return
}
await deleteData()
}
}
})
}
const deleteData = async () => {
uni.showLoading({
title: '删除中'
})
const { code: requestCode, message } = await clearRecordRequest({
lockId: lockId.value
})
if (requestCode === 0) {
uni.hideLoading()
uni.showToast({
title: `删除成功`,
icon: 'none'
})
pageNo.value = 1
await getList({
pageNo: pageNo.value
})
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
}
const refresherList = async () => {
refresherTriggered.value = true
pageNo.value = 1
const { code, message } = await getList({
pageNo: pageNo.value
})
if (code === 0) {
uni.showToast({
title: '刷新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
refresherTriggered.value = false
}
const nextPage = async () => {
if (total.value <= pageNo.value * pageSize) {
return
}
const page = pageNo.value + 1
const params = {
pageNo: page
}
const { code, message } = await getList(params)
if (code === 0) {
pageNo.value = page
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
const getList = async params => {
const { code, data, message } = await getEventRecordListRequest({
...params,
pageNo: params.pageNo,
lockId: lockId.value,
startDate: startDate.value,
endDate: endDate.value,
lockEventType: range.value[index.value].lockEventType,
pageSize
})
if (code === 0) {
total.value = data.total
if (params.pageNo === 1) {
list.value = data.list
} else {
list.value = list.value.concat(data.list)
}
return { code }
}
return { code, message }
}
const syncRecord = async () => {
const netWork = await $basic.getNetworkType()
if (!netWork) {
return
}
uni.showLoading({
title: '同步中'
})
const { code, message } = await $bluetooth.syncRecord({
keyId: $bluetooth.keyId.toString(),
uid: $user.userInfo.uid.toString()
})
$bluetooth.closeBluetoothConnection()
uni.hideLoading()
if (code === 0) {
uni.showToast({
title: '同步成功',
icon: 'none'
})
pageNo.value = 1
await getList({
pageNo: pageNo.value
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
const toDetail = item => {
$basic.routeJump({
name: 'recordDetail',
params: {
info: JSON.stringify({
operateDate: item.operateDate,
recordDetailStr: item.recordDetailStr
})
}
})
}
</script>
<style lang="scss">
page {
background-color: $uni-bg-color;
}
</style>
<style lang="scss" scoped>
.search {
width: 686rpx !important;
padding: 32rpx;
}
.button {
position: fixed;
bottom: calc(env(safe-area-inset-bottom) + 20rpx);
display: flex;
align-items: center;
font-weight: bold;
.button-reset {
width: 300rpx;
height: 88rpx;
margin-left: 50rpx;
line-height: 88rpx;
color: white;
text-align: center;
background-color: #df282d;
border-radius: 44rpx;
}
.button-create {
width: 300rpx;
height: 88rpx;
margin-left: 50rpx;
line-height: 88rpx;
color: white;
text-align: center;
background-color: #63b8af;
border-radius: 44rpx;
}
}
.item {
display: flex;
align-items: center;
width: 750rpx;
height: 120rpx;
background-color: #ffffff;
.item-left {
width: 80rpx;
height: 80rpx;
margin-left: 32rpx;
}
.item-right {
width: 574rpx;
margin-right: 32rpx;
margin-left: 32rpx;
.item-right-top {
max-width: 400rpx;
padding-bottom: 6rpx;
overflow: hidden;
text-overflow: ellipsis;
font-size: 32rpx;
font-weight: bold;
white-space: nowrap;
}
.item-right-bottom {
font-size: 24rpx;
color: #999999;
}
}
}
.line {
width: 100%;
height: 2rpx;
background: #ebebeb;
}
.empty-list {
width: 150rpx;
height: 150rpx;
margin: 300rpx auto 20rpx 50%;
transform: translateX(-50%);
}
.empty-list-text {
font-size: 32rpx;
color: #999999;
text-align: center;
}
.status {
margin-left: auto;
font-size: 26rpx;
color: #df282d;
}
</style>