wx-starlock/pages/main/notificationList.vue
2025-07-29 11:07:43 +08:00

455 lines
11 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>
<scroll-view
v-if="deviceInfo"
scroll-y="true"
:style="{ height: deviceInfo.windowHeight + 'px' }"
lower-threshold="100"
@refresherrefresh="refresherList"
:refresher-enabled="true"
@scrolltolower="nextPage"
:refresher-triggered="refresherTriggered"
@scroll="scroll"
>
<view v-if="isLogin">
<view class="list" v-if="requestFinished">
<view v-if="notificationList.length === 0">
<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>
<up-swipe-action v-else>
<up-swipe-action-item
class="item"
ref="swipeItem"
:options="options"
v-for="(notification, index) in notificationList"
:key="notification.id"
:threshold="50"
@click="deleteNotification(notification, index)"
:index="index"
:name="index"
>
<view class="notification" @click="toDetail(index, notification)">
<view v-if="notification.readAt === 0">
<image
class="icon"
src="https://oss-lock.xhjcn.ltd/mp/icon_notification_unread.png"
mode="aspectFill"
></image>
<view class="point"></view>
</view>
<image
v-else
class="icon"
src="https://oss-lock.xhjcn.ltd/mp/icon_notification_read.png"
mode="aspectFill"
></image>
<view>
<view
class="content"
:style="{ color: notification.readAt === 0 ? '#000000' : '#6c6c6c' }"
>{{ notification.data }}</view
>
<view
class="time"
:style="{ color: notification.readAt === 0 ? '#000000' : '#6c6c6c' }"
>{{ timeFormat(notification.createdAt, 'yyyy-mm-dd h:M') }}</view
>
</view>
</view>
</up-swipe-action-item>
</up-swipe-action>
</view>
</view>
<view v-else>
<view class="tips">因智能门锁与账号绑定登录为手机号登录</view>
<label for="phone">
<view class="button-login">登录</view>
</label>
</view>
</scroll-view>
<view
class="delete"
@click="deleteAllNotification"
v-if="isLogin && requestFinished && notificationList.length !== 0"
>
<image
class="delete-image"
src="https://cos-lock.skychip.top/mp/icon_delete.png"
mode="aspectFill"
/>
</view>
<button
open-type="getPhoneNumber"
style="display: none"
id="phone"
@getphonenumber="getphonenumber"
></button>
</template>
<script>
import { mapActions, mapState } from 'pinia'
import { timeFormat } from 'uview-plus'
import { useNotificationStore } from '@/stores/notification'
import { useBasicStore } from '@/stores/basic'
import {
deleteAllNotification,
deleteNotification,
markAsReadNotification
} from '@/api/notification'
import { useUserStore } from '@/stores/user'
export default {
data() {
return {
refresherTriggered: false,
requestFinished: false,
deviceInfo: null,
options: [
{
text: '删除',
style: {
backgroundColor: '#f56c6c'
}
}
]
}
},
computed: {
...mapState(useNotificationStore, [
'notificationTotal',
'notificationList',
'notificationSearch'
]),
...mapState(useUserStore, ['isLogin'])
},
async onLoad() {
this.deviceInfo = await this.getDeviceInfo()
if (this.isLogin) {
await this.getList()
}
this.requestFinished = true
},
methods: {
timeFormat,
...mapActions(useNotificationStore, [
'getNotificationList',
'updateNotificationSearch',
'updateNotificationItem',
'deleteNotificationItem'
]),
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType']),
...mapActions(useUserStore, ['phoneLogin']),
async getList() {
uni.showLoading({
title: '加载中',
mask: true
})
const { code, message } = await this.getNotificationList(this.notificationSearch)
uni.hideLoading()
if (code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
},
async getphonenumber(data) {
if (data.detail.errMsg === 'getPhoneNumber:fail user deny') {
return
}
const that = this
uni.showLoading({
title: '登录中'
})
uni.login({
provider: 'weixin',
async success(loginRes) {
const result = await that.phoneLogin({
encryptedData: data.detail.encryptedData,
iv: data.detail.iv,
code: loginRes.code
})
uni.hideLoading()
if (!result) {
uni.showToast({
title: result.message,
icon: 'none'
})
}
},
fail() {
uni.hideLoading()
uni.showToast({
title: '登录失败,请重试'
})
}
})
},
scroll() {
this.$refs.swipeItem.forEach(item => {
if (item.show) {
item.closeHandler()
}
})
},
async deleteNotification(notification, index) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
this.$refs.swipeItem[index].closeHandler()
uni.showModal({
title: '提示',
content: '确定要删除该通知吗?',
success: async res => {
if (res.confirm) {
const { code, message } = await deleteNotification({
id: notification.id
})
if (code === 0) {
this.deleteNotificationItem(index)
uni.showToast({
title: '删除成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
},
deleteAllNotification() {
uni.showModal({
title: '提示',
content: '确定要删除所有通知吗?',
success: async res => {
if (res.confirm) {
const { code, message } = await deleteAllNotification()
if (code === 0) {
uni.showToast({
title: '删除成功',
icon: 'none'
})
this.updateNotificationSearch({
pageNo: 1
})
await this.getNotificationList(this.notificationSearch)
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
},
toDetail(index, notification) {
if (notification.readAt === 0) {
notification.readAt = 1
this.updateNotificationItem(index, notification)
markAsReadNotification({
id: notification.id
})
}
this.routeJump({
name: 'notificationDetail',
params: {
notification: JSON.stringify(notification)
}
})
},
async refresherList() {
this.refresherTriggered = true
this.updateNotificationSearch({
pageNo: 1
})
const { code, message } = await this.getNotificationList(this.notificationSearch)
if (code === 0) {
uni.showToast({
title: '刷新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.refresherTriggered = false
},
async nextPage() {
if (
this.notificationTotal <=
this.notificationSearch.pageNo * this.notificationSearch.pageSize
) {
return
}
const pageNo = this.notificationSearch.pageNo + 1
const params = {
...this.notificationSearch,
pageNo
}
const { code, message } = await this.getNotificationList(params)
if (code === 0) {
this.updateNotificationSearch({
pageNo
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss">
page {
background-color: $uni-bg-color-grey;
}
.u-swipe-action {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 700rpx;
padding-bottom: 140rpx !important;
overflow: inherit !important;
}
.u-swipe-action-item {
overflow: inherit !important;
background: transparent !important;
border-radius: 32rpx !important;
}
.u-swipe-action-item__right {
margin-top: 32rpx;
border-radius: 32rpx !important;
}
.u-swipe-action-item__content {
margin-left: 25rpx;
border-radius: 32rpx !important;
}
.u-swipe-action-item__right__button {
border-radius: 32rpx !important;
}
</style>
<style lang="scss" scoped>
.item {
border-radius: 32rpx;
}
.notification {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
width: 636rpx;
padding: 32rpx;
margin-top: 32rpx;
border-radius: 32rpx;
box-shadow: 2rpx 2rpx 10rpx rgba(0, 0, 0, 0.3);
.icon {
width: 50rpx;
height: 50rpx;
}
.point {
position: absolute;
top: 41rpx;
left: 72rpx;
width: 16rpx;
height: 16rpx;
background-color: #ff0000;
border-radius: 50%;
}
.content {
width: 550rpx;
overflow: hidden;
text-overflow: ellipsis;
font-size: 28rpx;
font-weight: bold;
color: #6c6c6c;
white-space: nowrap;
}
.time {
margin-top: 5rpx;
font-size: 24rpx;
font-weight: bold;
color: #6c6c6c;
}
}
.delete {
position: fixed;
right: 30rpx;
bottom: 80rpx;
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
background-color: #4777ee;
border-radius: 50%;
.delete-image {
width: 45rpx;
height: 45rpx;
}
}
.empty-list {
width: 150rpx;
height: 150rpx;
margin: 400rpx auto 20rpx 50%;
transform: translateX(-50%);
}
.empty-list-text {
font-size: 32rpx;
color: #999999;
text-align: center;
}
.tips {
padding: 32rpx 0;
margin-top: 40vh;
font-size: 28rpx;
color: #999999;
text-align: center;
}
.button-login {
width: 650rpx;
height: 120rpx;
margin-left: 50rpx;
font-size: 48rpx;
font-weight: bold;
line-height: 120rpx;
color: #ffffff;
text-align: center;
background: #4777ee;
border-radius: 46rpx;
}
</style>