1. 完成消息提醒相关功能
This commit is contained in:
parent
a5b2018949
commit
7b34291570
@ -55,3 +55,12 @@ export function getFingerprintRequest(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取胁迫指纹列表
|
||||
export function getCoercedListRequest(data) {
|
||||
return request({
|
||||
url: '/fingerprint/getCoercedList',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
@ -37,3 +37,12 @@ export function deleteLockRequest(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 锁用户列表
|
||||
export function lockUserListRequest(data) {
|
||||
return request({
|
||||
url: '/lock/lockKeysList',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
@ -73,3 +73,57 @@ export function lockDataUploadRequest(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取锁通知设置
|
||||
export function getLockNoticeSettingRequest(data) {
|
||||
return request({
|
||||
url: '/lockSetting/getLockNoticeSetting',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新锁通知设置
|
||||
export function updateLockNoticeSettingRequest(data) {
|
||||
return request({
|
||||
url: '/lockSetting/updateLockNoticeSetting',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取通知列表
|
||||
export function getNoticeListRequest(data) {
|
||||
return request({
|
||||
url: '/lockNoticeSettingAccount/list',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新通知
|
||||
export function updateNoticeRequest(data) {
|
||||
return request({
|
||||
url: '/lockNoticeSettingAccount/update',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除通知
|
||||
export function deleteNoticeRequest(data) {
|
||||
return request({
|
||||
url: '/lockNoticeSettingAccount/delete',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 添加通知
|
||||
export function addNoticeRequest(data) {
|
||||
return request({
|
||||
url: '/lockNoticeSettingAccount/add',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
@ -101,3 +101,11 @@ export function updateTimezoneOffsetRequest(data) {
|
||||
})
|
||||
}
|
||||
|
||||
// 获取url
|
||||
export function getWebUrlRequest(data) {
|
||||
return request({
|
||||
url: '/v2/service/getPackageUrl',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
30
constant/keyType.js
Normal file
30
constant/keyType.js
Normal file
@ -0,0 +1,30 @@
|
||||
export const keysType = {
|
||||
1: {
|
||||
name: '电子钥匙',
|
||||
icon: '/static/images/icon_user.png'
|
||||
},
|
||||
2: {
|
||||
name: '密码',
|
||||
icon: '/static/images/icon_password.png'
|
||||
},
|
||||
3: {
|
||||
name: '指纹',
|
||||
icon: '/static/images/icon_fingerprint_white.png'
|
||||
},
|
||||
4: {
|
||||
name: '卡',
|
||||
icon: '/static/images/icon_card_white.png'
|
||||
},
|
||||
5: {
|
||||
name: '人脸',
|
||||
icon: '/static/images/icon_face_white.png'
|
||||
},
|
||||
6: {
|
||||
name: '掌静脉',
|
||||
icon: '/static/images/icon_palm_vein_white.png'
|
||||
},
|
||||
7: {
|
||||
name: '遥控',
|
||||
icon: '/static/images/icon_remote_white.png'
|
||||
}
|
||||
}
|
||||
70
pages.json
70
pages.json
@ -414,6 +414,76 @@
|
||||
"navigationBarTitleText": "电机功率设置",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/catEye/catEye",
|
||||
"style": {
|
||||
"navigationBarTitleText": "猫眼设置",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/messageReminder/messageReminder",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息提醒",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/openDoorNotice/openDoorNotice",
|
||||
"style": {
|
||||
"navigationBarTitleText": "家人到家",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/noticeDetail/noticeDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "家人详情",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/lockUser/lockUser",
|
||||
"style": {
|
||||
"navigationBarTitleText": "锁用户",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/noticeWay/noticeWay",
|
||||
"style": {
|
||||
"navigationBarTitleText": "提醒方式",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/notOpenDoor/notOpenDoor",
|
||||
"style": {
|
||||
"navigationBarTitleText": "N天未开门",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/lowElecNotice/lowElecNotice",
|
||||
"style": {
|
||||
"navigationBarTitleText": "低电量提醒",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/coercionOpenDoor/coercionOpenDoor",
|
||||
"style": {
|
||||
"navigationBarTitleText": "胁迫开门",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/coercionFingerprint/coercionFingerprint",
|
||||
"style": {
|
||||
"navigationBarTitleText": "指纹列表",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
11
pages/catEye/catEye.vue
Normal file
11
pages/catEye/catEye.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<view> </view>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
329
pages/coercionFingerprint/coercionFingerprint.vue
Normal file
329
pages/coercionFingerprint/coercionFingerprint.vue
Normal file
@ -0,0 +1,329 @@
|
||||
<template>
|
||||
<view>
|
||||
<scroll-view
|
||||
v-if="deviceInfo"
|
||||
scroll-y="true"
|
||||
:style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top + 'px' }"
|
||||
lower-threshold="100"
|
||||
@refresherrefresh="refresherList"
|
||||
:refresher-enabled="true"
|
||||
@scrolltolower="nextPage"
|
||||
:refresher-triggered="refresherTriggered"
|
||||
>
|
||||
<view class="search">
|
||||
<up-search
|
||||
shape="square"
|
||||
:searchIconSize="48"
|
||||
:inputStyle="{ fontSize: '32rpx' }"
|
||||
:height="80"
|
||||
placeholder="搜索"
|
||||
:clearabled="false"
|
||||
@change="changeSearch"
|
||||
v-model="searchStr"
|
||||
bgColor="#ffffff"
|
||||
:showAction="false"
|
||||
maxlength="50"
|
||||
></up-search>
|
||||
</view>
|
||||
<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="/static/images/background_empty_list.png"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view class="empty-list-text">暂无数据</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view v-for="(item, index) in list" :key="index">
|
||||
<view class="item" @click="change(item)">
|
||||
<image
|
||||
class="item-left"
|
||||
:src="keysType[item.openLockType].icon"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<view class="item-right">
|
||||
<view style="display: flex; align-items: center">
|
||||
<view class="item-right-top">{{ item?.name }}</view>
|
||||
</view>
|
||||
<view class="item-right-bottom">{{ item?.timeText }}</view>
|
||||
</view>
|
||||
<view class="ml-a mr-4">
|
||||
<image
|
||||
class="w-40 h-40"
|
||||
v-if="info?.id === item.id && info?.openLockType === item.openLockType"
|
||||
src="/static/images/icon_select.png"
|
||||
></image>
|
||||
<image v-else class="w-40 h-40" src="/static/images/icon_not_select.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view
|
||||
v-if="list.length > 0"
|
||||
@click="confirm"
|
||||
class="pos-fixed bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-88 line-height-88rpx text-center bg-#63b8af text-white rounded-3xl"
|
||||
>确定
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCurrentInstance, ref } from 'vue'
|
||||
import { timeFormat } from 'uview-plus'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { keysType } from '@/constant/keyType'
|
||||
import { getCoercedListRequest } from '@/api/fingerprint'
|
||||
|
||||
const instance = getCurrentInstance().proxy
|
||||
const eventChannel = instance.getOpenerEventChannel()
|
||||
|
||||
const $basic = useBasicStore()
|
||||
const $bluetooth = useBluetoothStore()
|
||||
|
||||
const searchStr = ref('')
|
||||
const list = ref([])
|
||||
const lockId = ref(null)
|
||||
|
||||
const deviceInfo = ref(null)
|
||||
const requestFinished = ref(false)
|
||||
|
||||
const info = ref(null)
|
||||
|
||||
const pageSize = 50
|
||||
const pageNo = ref(1)
|
||||
const total = ref(0)
|
||||
|
||||
const refresherTriggered = ref(false)
|
||||
|
||||
onLoad(async options => {
|
||||
if (JSON.parse(options.info)) {
|
||||
info.value = JSON.parse(options.info)
|
||||
info.value = {
|
||||
...info.value,
|
||||
name: info.value.remark,
|
||||
openLockType: info.value.openDoorType,
|
||||
id: info.value.openDoorId
|
||||
}
|
||||
}
|
||||
uni.showLoading({
|
||||
title: '加载中',
|
||||
mask: true
|
||||
})
|
||||
deviceInfo.value = await $basic.getDeviceInfo()
|
||||
lockId.value = $bluetooth.currentLockInfo.lockId
|
||||
const { code, message } = await getList({
|
||||
pageNo: pageNo.value,
|
||||
searchStr: searchStr.value
|
||||
})
|
||||
requestFinished.value = true
|
||||
uni.hideLoading()
|
||||
if (code !== 0) {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const refresherList = async () => {
|
||||
refresherTriggered.value = true
|
||||
pageNo.value = 1
|
||||
const { code } = await getList({
|
||||
pageNo: pageNo.value,
|
||||
searchStr: searchStr.value
|
||||
})
|
||||
if (code === 0) {
|
||||
uni.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
refresherTriggered.value = false
|
||||
}
|
||||
|
||||
const nextPage = async () => {
|
||||
if (total.value <= pageNo.value * pageSize) {
|
||||
return
|
||||
}
|
||||
const no = pageNo.value + 1
|
||||
const { code } = await getList(no, false)
|
||||
if (code === 0) {
|
||||
pageNo.value = no
|
||||
}
|
||||
}
|
||||
|
||||
const confirm = () => {
|
||||
if (info.value) {
|
||||
eventChannel.emit('confirm', {
|
||||
id: info.value.id,
|
||||
type: info.value.openLockType,
|
||||
name: info.value.name
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const getList = async params => {
|
||||
const { code, data, message } = await getCoercedListRequest({
|
||||
lockId: lockId.value,
|
||||
pageSize,
|
||||
...params
|
||||
})
|
||||
if (code === 0) {
|
||||
total.value = data.total
|
||||
for (let i = 0; i < data.list.length; i++) {
|
||||
data.list[i].openLockType = 3
|
||||
data.list[i].name = data.list[i].fingerprintName
|
||||
data.list[i].id = data.list[i].fingerprintId
|
||||
if (data.list[i].fingerprintType === 1) {
|
||||
data.list[i].timeText = timeFormat(data.list[i].createDate, 'yyyy-mm-dd hh:MM') + ' 永久'
|
||||
} else if (data.list[i].fingerprintType === 2) {
|
||||
data.list[i].timeText =
|
||||
timeFormat(data.list[i].startDate, 'yyyy-mm-dd hh:MM') +
|
||||
' - ' +
|
||||
timeFormat(data.list[i].endDate, 'yyyy-mm-dd hh:MM') +
|
||||
' 限时'
|
||||
} else {
|
||||
data.list[i].timeText =
|
||||
timeFormat(data.list[i].startDate, 'yyyy-mm-dd') +
|
||||
' - ' +
|
||||
timeFormat(data.list[i].endDate, 'yyyy-mm-dd') +
|
||||
' 循环'
|
||||
}
|
||||
}
|
||||
if (params.pageNo === 1) {
|
||||
list.value = data.list
|
||||
} else {
|
||||
list.value = list.value.concat(data.list)
|
||||
}
|
||||
return { code }
|
||||
}
|
||||
return { code, message }
|
||||
}
|
||||
|
||||
const changeSearch = async data => {
|
||||
pageNo.value = 1
|
||||
const { code, message } = await getList({
|
||||
pageNo: pageNo.value,
|
||||
searchStr: data
|
||||
})
|
||||
if (code !== 0) {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const change = item => {
|
||||
info.value = item
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
padding: 32rpx;
|
||||
width: 686rpx !important;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
bottom: calc(env(safe-area-inset-bottom) + 20rpx);
|
||||
font-weight: bold;
|
||||
|
||||
.button-reset {
|
||||
margin-left: 50rpx;
|
||||
width: 300rpx;
|
||||
height: 88rpx;
|
||||
background-color: #df282d;
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
}
|
||||
|
||||
.button-create {
|
||||
margin-left: 50rpx;
|
||||
width: 300rpx;
|
||||
height: 88rpx;
|
||||
background-color: #63b8af;
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
height: 120rpx;
|
||||
width: 750rpx;
|
||||
|
||||
.item-left {
|
||||
margin-left: 32rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
margin-right: 32rpx;
|
||||
margin-left: 32rpx;
|
||||
width: 574rpx;
|
||||
|
||||
.item-right-top {
|
||||
max-width: 400rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
padding-bottom: 6rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.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 {
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-left: auto;
|
||||
font-size: 26rpx;
|
||||
color: #df282d;
|
||||
}
|
||||
</style>
|
||||
159
pages/coercionOpenDoor/coercionOpenDoor.vue
Normal file
159
pages/coercionOpenDoor/coercionOpenDoor.vue
Normal file
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="text-sm h-80rpx py-3 mx-4">
|
||||
当被胁迫要求强行开锁时,使用胁迫指纹会触发报警,报警消息会推送给管理员,该功能需要锁联网
|
||||
</view>
|
||||
<scroll-view
|
||||
v-if="deviceInfo"
|
||||
scroll-y="true"
|
||||
:style="{
|
||||
height:
|
||||
deviceInfo.screenHeight -
|
||||
deviceInfo.safeArea.top -
|
||||
(deviceInfo.screenWidth / 750) * 128 +
|
||||
'px'
|
||||
}"
|
||||
lower-threshold="100"
|
||||
@refresherrefresh="refresherList"
|
||||
:refresher-enabled="true"
|
||||
@scrolltolower="nextPage"
|
||||
:refresher-triggered="refresherTriggered"
|
||||
>
|
||||
<view v-if="list.length === 0">
|
||||
<image
|
||||
class="w-150 h-150 transform-translate-x-[-50%] mt-300rpx mr-a mb-20rpx ml-50%"
|
||||
src="/static/images/background_empty_list.png"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view class="text-center text-base text-#999999">暂无数据</view>
|
||||
</view>
|
||||
<view v-else class="pb-[calc(env(safe-area-inset-bottom)+250rpx)]">
|
||||
<view
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
class="flex items-center bg-white px-4 py-2 mt-4rpx"
|
||||
@click="toJump(item)"
|
||||
>
|
||||
<image :src="keysType[item.settingValue.openDoorType].icon" class="w-80 h-80" />
|
||||
<view class="ml-3">
|
||||
<view class="break-all max-w-500 text-base">{{ item.settingValue.remark }}</view>
|
||||
<view class="text-sm text-gray-500">{{
|
||||
keysType[item.settingValue.openDoorType].name
|
||||
}}</view>
|
||||
</view>
|
||||
<view class="ml-a"> <up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view
|
||||
@click="toJump(null)"
|
||||
class="flex items-center justify-center bg-white shadow-sm rounded-md pos-fixed bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-100"
|
||||
><view class="flex items-center">
|
||||
<up-icon name="plus-circle-fill" color="#002ce5" size="50"></up-icon
|
||||
><view class="text-lg text-#63b8af ml-2 font-bold">胁迫指纹</view>
|
||||
</view></view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { getNoticeListRequest } from '@/api/setting'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { keysType } from '@/constant/keyType'
|
||||
|
||||
const $basic = useBasicStore()
|
||||
const $bluetooth = useBluetoothStore()
|
||||
|
||||
const deviceInfo = ref(null)
|
||||
|
||||
const refresherTriggered = ref(false)
|
||||
|
||||
const list = ref([])
|
||||
const pageSize = 50
|
||||
const pageNo = ref(1)
|
||||
const total = ref(0)
|
||||
|
||||
onMounted(async () => {
|
||||
uni.showLoading({
|
||||
title: '加载中'
|
||||
})
|
||||
deviceInfo.value = await $basic.getDeviceInfo()
|
||||
await getList(pageNo.value, true)
|
||||
})
|
||||
|
||||
const refresherList = async () => {
|
||||
refresherTriggered.value = true
|
||||
pageNo.value = 1
|
||||
const { code } = await getList(pageNo.value, false)
|
||||
if (code === 0) {
|
||||
uni.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
refresherTriggered.value = false
|
||||
}
|
||||
|
||||
const nextPage = async () => {
|
||||
if (total.value <= pageNo.value * pageSize) {
|
||||
return
|
||||
}
|
||||
const no = pageNo.value + 1
|
||||
const { code } = await getList(no, false)
|
||||
if (code === 0) {
|
||||
pageNo.value = no
|
||||
}
|
||||
}
|
||||
|
||||
const getList = async (no, flag) => {
|
||||
const { code, data, message } = await getNoticeListRequest({
|
||||
lockId: $bluetooth.currentLockInfo.lockId,
|
||||
noticeType: 20,
|
||||
pageSize,
|
||||
pageNo: no
|
||||
})
|
||||
if (flag) {
|
||||
uni.hideLoading()
|
||||
}
|
||||
|
||||
if (code === 0) {
|
||||
total.value = data.total
|
||||
if (no === 1) {
|
||||
list.value = data.list
|
||||
} else {
|
||||
list.value = list.value.concat(data.list)
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
return { code, message }
|
||||
}
|
||||
|
||||
const toJump = (data = null) => {
|
||||
$basic.routeJump({
|
||||
name: 'noticeDetail',
|
||||
params: {
|
||||
info: data ? JSON.stringify(data) : null,
|
||||
title: data ? '指纹详情' : '胁迫指纹',
|
||||
mode: 'coercion'
|
||||
},
|
||||
events: {
|
||||
refresherList() {
|
||||
pageNo.value = 1
|
||||
getList(pageNo.value, false)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
@ -441,7 +441,6 @@
|
||||
}
|
||||
const { code, data } = await $bluetooth.setLockPassword(params)
|
||||
if (code === 0 && data.status === 0) {
|
||||
console.log(1111, data)
|
||||
const { code: requestCode, message } = await addCustomPasswordRequest({
|
||||
lockId: $bluetooth.currentLockInfo.lockId,
|
||||
isCoerced: 2,
|
||||
|
||||
392
pages/lockUser/lockUser.vue
Normal file
392
pages/lockUser/lockUser.vue
Normal file
@ -0,0 +1,392 @@
|
||||
<template>
|
||||
<view>
|
||||
<scroll-view
|
||||
v-if="deviceInfo"
|
||||
scroll-y="true"
|
||||
:style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top + 'px' }"
|
||||
lower-threshold="100"
|
||||
>
|
||||
<view class="search">
|
||||
<up-search
|
||||
shape="square"
|
||||
:searchIconSize="48"
|
||||
:inputStyle="{ fontSize: '32rpx' }"
|
||||
:height="80"
|
||||
placeholder="搜索"
|
||||
:clearabled="false"
|
||||
@change="changeSearch"
|
||||
v-model="searchStr"
|
||||
bgColor="#ffffff"
|
||||
:showAction="false"
|
||||
maxlength="50"
|
||||
></up-search>
|
||||
</view>
|
||||
<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="/static/images/background_empty_list.png"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view class="empty-list-text">暂无数据</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view v-for="(item, index) in list" :key="index">
|
||||
<view class="item" @click="change(item)">
|
||||
<image
|
||||
class="item-left"
|
||||
:src="keysType[item.openLockType].icon"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<view class="item-right">
|
||||
<view style="display: flex; align-items: center">
|
||||
<view class="item-right-top">{{ item?.name }}</view>
|
||||
</view>
|
||||
<view class="item-right-bottom">{{ item?.timeText }}</view>
|
||||
</view>
|
||||
<view class="ml-a mr-4">
|
||||
<image
|
||||
class="w-40 h-40"
|
||||
v-if="info?.id === item.id && info?.openLockType === item.openLockType"
|
||||
src="/static/images/icon_select.png"
|
||||
></image>
|
||||
<image v-else class="w-40 h-40" src="/static/images/icon_not_select.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view
|
||||
v-if="list.length > 0"
|
||||
@click="confirm"
|
||||
class="pos-fixed bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-88 line-height-88rpx text-center bg-#63b8af text-white rounded-3xl"
|
||||
>确定
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCurrentInstance, ref } from 'vue'
|
||||
import { timeFormat } from 'uview-plus'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { lockUserListRequest } from '@/api/lock'
|
||||
import { keysType } from '@/constant/keyType'
|
||||
|
||||
const instance = getCurrentInstance().proxy
|
||||
const eventChannel = instance.getOpenerEventChannel()
|
||||
|
||||
const $basic = useBasicStore()
|
||||
const $bluetooth = useBluetoothStore()
|
||||
|
||||
const searchStr = ref('')
|
||||
const list = ref([])
|
||||
const lockId = ref(null)
|
||||
|
||||
const deviceInfo = ref(null)
|
||||
const requestFinished = ref(false)
|
||||
|
||||
const info = ref(null)
|
||||
|
||||
onLoad(async options => {
|
||||
if (JSON.parse(options.info)) {
|
||||
info.value = JSON.parse(options.info)
|
||||
info.value = {
|
||||
...info.value,
|
||||
name: info.value.remark,
|
||||
openLockType: info.value.openDoorType,
|
||||
id: info.value.openDoorId
|
||||
}
|
||||
}
|
||||
uni.showLoading({
|
||||
title: '加载中',
|
||||
mask: true
|
||||
})
|
||||
deviceInfo.value = await $basic.getDeviceInfo()
|
||||
lockId.value = $bluetooth.currentLockInfo.lockId
|
||||
const { code, message } = await getList({
|
||||
searchStr: searchStr.value
|
||||
})
|
||||
requestFinished.value = true
|
||||
uni.hideLoading()
|
||||
if (code !== 0) {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const confirm = () => {
|
||||
if (info.value) {
|
||||
eventChannel.emit('confirm', {
|
||||
id: info.value.id,
|
||||
type: info.value.openLockType,
|
||||
name: info.value.name
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const getList = async params => {
|
||||
const { code, data, message } = await lockUserListRequest({
|
||||
...params,
|
||||
lockId: lockId.value
|
||||
})
|
||||
if (code === 0) {
|
||||
const result = []
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].openLockType === 1) {
|
||||
for (let j = 0; j < data[i].keys.length; j++) {
|
||||
data[i].keys[j].openLockType = data[i].openLockType
|
||||
data[i].keys[j].name = data[i].keys[j].keyName
|
||||
if (data[i].keys[j].keyType === 1) {
|
||||
data[i].keys[j].timeText =
|
||||
`${timeFormat(new Date(data[i].keys[j].created_at), 'yyyy-mm-dd h:M')} 永久`
|
||||
} else if (data[i].keys[j].keyType === 2) {
|
||||
data[i].keys[j].timeText =
|
||||
`${timeFormat(new Date(data[i].keys[j].startDate), 'yyyy-mm-dd h:M')} - ${timeFormat(new Date(data[i].keys[j].endDate), 'yyyy-mm-dd h:M')} 限时`
|
||||
} else if (data[i].keys[j].keyType === 3) {
|
||||
data[i].keys[j].timeText =
|
||||
`${timeFormat(new Date(data[i].keys[j].created_at), 'yyyy-mm-dd h:M')} 单次`
|
||||
} else {
|
||||
data[i].keys[j].timeText = `循环`
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data[i].openLockType === 2) {
|
||||
for (let j = 0; j < data[i].keys.length; j++) {
|
||||
data[i].keys[j].openLockType = data[i].openLockType
|
||||
data[i].keys[j].name = data[i].keys[j].keyboardPwdName
|
||||
data[i].keys[j].id = data[i].keys[j].keyboardPwdId
|
||||
if (data[i].keys[j].keyboardPwdType === 2) {
|
||||
data[i].keys[j].timeText =
|
||||
`${timeFormat(new Date(data[i].keys[j].created_at), 'yyyy-mm-dd h:M')} 永久`
|
||||
} else if (data[i].keys[j].keyboardPwdType === 3) {
|
||||
data[i].keys[j].timeText = `${data[i].keys[j].validTimeStr} 限时`
|
||||
} else {
|
||||
let text = ''
|
||||
if (data[i].keys[j].keyboardPwdType === 5) {
|
||||
text = '周末'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 6) {
|
||||
text = '每日'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 7) {
|
||||
text = '工作日'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 8) {
|
||||
text = '周一'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 9) {
|
||||
text = '周二'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 10) {
|
||||
text = '周三'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 11) {
|
||||
text = '周四'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 12) {
|
||||
text = '周五'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 13) {
|
||||
text = '周六'
|
||||
} else if (data[i].keys[j].keyboardPwdType === 14) {
|
||||
text = '周日'
|
||||
}
|
||||
data[i].keys[j].timeText =
|
||||
`${text} ${data[i].keys[j].hoursStart}:00-${data[i].keys[j].hoursEnd}:00 循环`
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data[i].openLockType === 3) {
|
||||
for (let j = 0; j < data[i].keys.length; j++) {
|
||||
data[i].keys[j].openLockType = data[i].openLockType
|
||||
data[i].keys[j].name = data[i].keys[j].fingerprintName
|
||||
data[i].keys[j].id = data[i].keys[j].fingerprintId
|
||||
if (data[i].keys[j].fingerprintType === 1) {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].createDate, 'yyyy-mm-dd hh:MM') + ' 永久'
|
||||
} else if (data[i].keys[j].fingerprintType === 2) {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].startDate, 'yyyy-mm-dd hh:MM') +
|
||||
' - ' +
|
||||
timeFormat(data[i].keys[j].endDate, 'yyyy-mm-dd hh:MM') +
|
||||
' 限时'
|
||||
} else {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].startDate, 'yyyy-mm-dd') +
|
||||
' - ' +
|
||||
timeFormat(data[i].keys[j].endDate, 'yyyy-mm-dd') +
|
||||
' 循环'
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data[i].openLockType === 4) {
|
||||
for (let j = 0; j < data[i].keys.length; j++) {
|
||||
data[i].keys[j].openLockType = data[i].openLockType
|
||||
data[i].keys[j].name = data[i].keys[j].cardName
|
||||
data[i].keys[j].id = data[i].keys[j].cardId
|
||||
if (data[i].keys[j].cardType === 1) {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].createDate, 'yyyy-mm-dd hh:MM') + ' 永久'
|
||||
} else if (data[i].keys[j].cardType === 2) {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].startDate, 'yyyy-mm-dd hh:MM') +
|
||||
' - ' +
|
||||
timeFormat(data[i].keys[j].endDate, 'yyyy-mm-dd hh:MM') +
|
||||
' 限时'
|
||||
} else {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].startDate, 'yyyy-mm-dd') +
|
||||
' - ' +
|
||||
timeFormat(data[i].keys[j].endDate, 'yyyy-mm-dd') +
|
||||
' 循环'
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data[i].openLockType === 5) {
|
||||
for (let j = 0; j < data[i].keys.length; j++) {
|
||||
data[i].keys[j].openLockType = data[i].openLockType
|
||||
data[i].keys[j].id = data[i].keys[j].faceId
|
||||
if (data[i].keys[j].faceType === 1) {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].createDate, 'yyyy-mm-dd hh:MM') + ' 永久'
|
||||
} else if (data[i].keys[j].faceType === 2) {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].startDate, 'yyyy-mm-dd hh:MM') +
|
||||
' - ' +
|
||||
timeFormat(data[i].keys[j].endDate, 'yyyy-mm-dd hh:MM') +
|
||||
' 限时'
|
||||
} else {
|
||||
data[i].keys[j].timeText =
|
||||
timeFormat(data[i].keys[j].startDate, 'yyyy-mm-dd') +
|
||||
' - ' +
|
||||
timeFormat(data[i].keys[j].endDate, 'yyyy-mm-dd') +
|
||||
' 循环'
|
||||
}
|
||||
}
|
||||
}
|
||||
result.push(...data[i].keys)
|
||||
}
|
||||
console.log(result)
|
||||
list.value = result
|
||||
return { code }
|
||||
}
|
||||
return { code, message }
|
||||
}
|
||||
|
||||
const changeSearch = async data => {
|
||||
const { code, message } = await getList({
|
||||
searchStr: data
|
||||
})
|
||||
if (code !== 0) {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const change = item => {
|
||||
info.value = item
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
padding: 32rpx;
|
||||
width: 686rpx !important;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
bottom: calc(env(safe-area-inset-bottom) + 20rpx);
|
||||
font-weight: bold;
|
||||
|
||||
.button-reset {
|
||||
margin-left: 50rpx;
|
||||
width: 300rpx;
|
||||
height: 88rpx;
|
||||
background-color: #df282d;
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
}
|
||||
|
||||
.button-create {
|
||||
margin-left: 50rpx;
|
||||
width: 300rpx;
|
||||
height: 88rpx;
|
||||
background-color: #63b8af;
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
height: 120rpx;
|
||||
width: 750rpx;
|
||||
|
||||
.item-left {
|
||||
margin-left: 32rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
margin-right: 32rpx;
|
||||
margin-left: 32rpx;
|
||||
width: 574rpx;
|
||||
|
||||
.item-right-top {
|
||||
max-width: 400rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
padding-bottom: 6rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.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 {
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-left: auto;
|
||||
font-size: 26rpx;
|
||||
color: #df282d;
|
||||
}
|
||||
</style>
|
||||
135
pages/lowElecNotice/lowElecNotice.vue
Normal file
135
pages/lowElecNotice/lowElecNotice.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="text-sm h-80rpx py-3 mx-4">
|
||||
打开提醒后,当锁电量低于20%、10%、5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。
|
||||
</view>
|
||||
<view class="bg-white mx-4 rounded-md mt-4 text-base">
|
||||
<view class="flex items-center p-3">
|
||||
<view>低电量提醒</view>
|
||||
<switch
|
||||
@click="changeCheck()"
|
||||
:checked="check"
|
||||
class="transform-scale-90 ml-a"
|
||||
:disabled="true"
|
||||
color="#002ce5"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="check" class="bg-white mx-4 rounded-md mt-4 text-base" @click="toNoticeWay">
|
||||
<view class="flex items-center p-3">
|
||||
<view>提醒方式</view>
|
||||
<view class="ml-a"><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view class="pb-4">
|
||||
<view class="flex items-center bg-#f4f4f4 mx-4 py-1 px-2 rounded-md">
|
||||
<view>APP推送</view>
|
||||
<view class="text-gray-500 ml-a">管理员</view>
|
||||
</view>
|
||||
<view v-for="(list, index) in lowElecNoticeWayList" :key="index">
|
||||
<view
|
||||
v-if="list.accounts.length > 0"
|
||||
class="flex items-center bg-#f4f4f4 mx-4 py-1 px-2 rounded-md mt-4"
|
||||
>
|
||||
<view>{{ list.type === 'mail' ? '邮件提醒' : '短信提醒' }}</view>
|
||||
<view class="text-sm ml-a text-right">
|
||||
<view
|
||||
class="text-gray-500"
|
||||
v-for="(item, ListIndex) in list.accounts"
|
||||
:key="ListIndex"
|
||||
>
|
||||
{{ item.account }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
@click="update"
|
||||
class="pos-fixed bg-#63b8af bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-88 line-height-88rpx text-center text-white rounded-3xl"
|
||||
>保存
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { updateLockNoticeSettingRequest } from '@/api/setting'
|
||||
|
||||
const $bluetooth = useBluetoothStore()
|
||||
const $basic = useBasicStore()
|
||||
|
||||
const check = ref(false)
|
||||
const lowElecNoticeWayList = ref([])
|
||||
|
||||
const pending = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
check.value = $bluetooth.currentLockNoticeSetting.lowElecNoticeState === 1
|
||||
lowElecNoticeWayList.value = $bluetooth.currentLockNoticeSetting.lowElecNoticeWayList
|
||||
})
|
||||
|
||||
const update = async () => {
|
||||
if (pending.value) return
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '更新中'
|
||||
})
|
||||
const data = {
|
||||
lockId: $bluetooth.currentLockInfo.lockId,
|
||||
lowElecNoticeState: check.value ? 1 : 0,
|
||||
lowElecNoticeWayList: lowElecNoticeWayList.value
|
||||
}
|
||||
const { code, message } = await updateLockNoticeSettingRequest(data)
|
||||
pending.value = false
|
||||
uni.hideLoading()
|
||||
if (code === 0) {
|
||||
$bluetooth.updateCurrentLockNoticeSetting({
|
||||
...$bluetooth.currentLockNoticeSetting,
|
||||
...data
|
||||
})
|
||||
$basic.backAndToast('更新成功')
|
||||
} else if (code === 434) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: message,
|
||||
showCancel: false
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const changeCheck = () => {
|
||||
check.value = !check.value
|
||||
}
|
||||
|
||||
const toNoticeWay = () => {
|
||||
$basic.routeJump({
|
||||
name: 'noticeWay',
|
||||
params: {
|
||||
info:
|
||||
lowElecNoticeWayList.value.length === 0
|
||||
? null
|
||||
: JSON.stringify({ noticeWay: lowElecNoticeWayList.value })
|
||||
},
|
||||
events: {
|
||||
confirm(data) {
|
||||
lowElecNoticeWayList.value = data.noticeWay
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
140
pages/messageReminder/messageReminder.vue
Normal file
140
pages/messageReminder/messageReminder.vue
Normal file
@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<view>
|
||||
<view v-if="requestFinish">
|
||||
<view
|
||||
class="py-3 px-4 bg-white flex items-center justify-between text-base"
|
||||
@click="toJump('openDoorNotice')"
|
||||
>
|
||||
<view class="item-title">开门通知</view>
|
||||
<view><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view
|
||||
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
|
||||
@click="toJump('notOpenDoor')"
|
||||
>
|
||||
<view class="item-title">N天未开门</view>
|
||||
<view class="flex items-center">
|
||||
<view class="mr-2">{{
|
||||
$bluetooth.currentLockNoticeSetting.dayNotOpenDoorState ? '已启用' : '未启用'
|
||||
}}</view>
|
||||
<up-icon name="arrow-right"></up-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="py-3 px-4 bg-white !py-2 flex items-center justify-between text-base mt-4rpx">
|
||||
<view class="item-title">门未关好</view>
|
||||
<switch
|
||||
@click="
|
||||
updateSetting(
|
||||
'doorNotCloseState',
|
||||
$bluetooth.currentLockNoticeSetting.doorNotCloseState ? 0 : 1
|
||||
)
|
||||
"
|
||||
:checked="$bluetooth.currentLockNoticeSetting.doorNotCloseState"
|
||||
class="transform-scale-90"
|
||||
:disabled="true"
|
||||
color="#002ce5"
|
||||
/>
|
||||
</view>
|
||||
<view class="py-3 px-4 bg-white !py-2 flex items-center justify-between text-base mt-4rpx">
|
||||
<view class="item-title">防拆报警</view>
|
||||
<switch
|
||||
@click="
|
||||
updateSetting(
|
||||
'tamperAlarmState',
|
||||
$bluetooth.currentLockNoticeSetting.tamperAlarmState ? 0 : 1
|
||||
)
|
||||
"
|
||||
:checked="$bluetooth.currentLockNoticeSetting.tamperAlarmState"
|
||||
class="transform-scale-90"
|
||||
:disabled="true"
|
||||
color="#002ce5"
|
||||
/>
|
||||
</view>
|
||||
<view
|
||||
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
|
||||
@click="toJump('lowElecNotice')"
|
||||
>
|
||||
<view class="item-title">低电量提醒</view>
|
||||
<view class="flex items-center">
|
||||
<view class="mr-2">{{
|
||||
$bluetooth.currentLockNoticeSetting.lowElecNoticeState ? '已启用' : '未启用'
|
||||
}}</view>
|
||||
<up-icon name="arrow-right"></up-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
|
||||
@click="toJump('coercionOpenDoor')"
|
||||
>
|
||||
<view class="item-title">胁迫开门</view>
|
||||
<view><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view class="text-center text-sm mt-10">此模块功能需要锁联网后设置方可生效</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { getLockNoticeSettingRequest, updateLockNoticeSettingRequest } from '@/api/setting'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
|
||||
const $bluetooth = useBluetoothStore()
|
||||
const $basic = useBasicStore()
|
||||
|
||||
const requestFinish = ref(false)
|
||||
|
||||
const pending = ref(false)
|
||||
|
||||
onMounted(async () => {
|
||||
const { code, data, message } = await getLockNoticeSettingRequest({
|
||||
lockId: $bluetooth.currentLockInfo.lockId
|
||||
})
|
||||
if (code === 0) {
|
||||
requestFinish.value = true
|
||||
$bluetooth.updateCurrentLockNoticeSetting(data)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const updateSetting = async (type, value) => {
|
||||
if (pending.value) return
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '更新中'
|
||||
})
|
||||
const { code, message } = await updateLockNoticeSettingRequest({
|
||||
lockId: $bluetooth.currentLockInfo.lockId,
|
||||
[type]: value
|
||||
})
|
||||
uni.hideLoading()
|
||||
pending.value = false
|
||||
if (code === 0) {
|
||||
const info = $bluetooth.currentLockNoticeSetting
|
||||
info[type] = value
|
||||
$bluetooth.updateCurrentLockNoticeSetting(info)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const toJump = name => {
|
||||
$basic.routeJump({
|
||||
name
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
215
pages/notOpenDoor/notOpenDoor.vue
Normal file
215
pages/notOpenDoor/notOpenDoor.vue
Normal file
@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="text-sm h-80rpx py-3 mx-4">
|
||||
经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网。
|
||||
</view>
|
||||
<view class="bg-white mx-4 rounded-md mt-4 text-base">
|
||||
<view class="flex items-center p-3">
|
||||
<view>N天未开门提醒</view>
|
||||
<switch
|
||||
@click="changeCheck()"
|
||||
:checked="check"
|
||||
class="transform-scale-90 ml-a"
|
||||
:disabled="true"
|
||||
color="#002ce5"
|
||||
/>
|
||||
</view>
|
||||
<view
|
||||
v-if="check"
|
||||
@click="show = true"
|
||||
class="flex items-center p-3 border-t-1 border-t-solid border-t-gray-200"
|
||||
>
|
||||
<view>未开门时间</view>
|
||||
<view class="ml-a"> {{ value }}天 </view>
|
||||
<view class="ml-2"><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="check" class="bg-white mx-4 rounded-md mt-4 text-base" @click="toNoticeWay">
|
||||
<view class="flex items-center p-3">
|
||||
<view>提醒方式</view>
|
||||
<view class="ml-a"><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view class="pb-4">
|
||||
<view class="flex items-center bg-#f4f4f4 mx-4 py-1 px-2 rounded-md">
|
||||
<view>APP推送</view>
|
||||
<view class="text-gray-500 ml-a">管理员</view>
|
||||
</view>
|
||||
<view v-for="(list, index) in dayNotOpenDoorNoticeWayList" :key="index">
|
||||
<view
|
||||
v-if="list.accounts.length > 0"
|
||||
class="flex items-center bg-#f4f4f4 mx-4 py-1 px-2 rounded-md mt-4"
|
||||
>
|
||||
<view>{{ list.type === 'mail' ? '邮件提醒' : '短信提醒' }}</view>
|
||||
<view class="text-sm ml-a text-right">
|
||||
<view
|
||||
class="text-gray-500"
|
||||
v-for="(item, ListIndex) in list.accounts"
|
||||
:key="ListIndex"
|
||||
>
|
||||
{{ item.account }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
@click="update"
|
||||
class="pos-fixed bg-#63b8af bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-88 line-height-88rpx text-center text-white rounded-3xl"
|
||||
>保存
|
||||
</view>
|
||||
<up-picker
|
||||
:show="show"
|
||||
:columns="columns"
|
||||
:itemHeight="70"
|
||||
:visibleItemCount="5"
|
||||
:defaultIndex="[value - 1]"
|
||||
@close="show = false"
|
||||
@cancel="show = false"
|
||||
@confirm="changeValue"
|
||||
></up-picker>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { updateLockNoticeSettingRequest } from '@/api/setting'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
const $bluetooth = useBluetoothStore()
|
||||
const $basic = useBasicStore()
|
||||
const $user = useUserStore()
|
||||
|
||||
const check = ref(false)
|
||||
const value = ref(0)
|
||||
const dayNotOpenDoorNoticeWayList = ref([])
|
||||
|
||||
const show = ref(false)
|
||||
|
||||
const pending = ref(false)
|
||||
|
||||
const columns = ref([[]])
|
||||
|
||||
const flag = ref(false)
|
||||
|
||||
onShow(() => {
|
||||
if (flag.value) {
|
||||
$user.getUserInfo()
|
||||
flag.value = false
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
columns.value = [
|
||||
Array.from({ length: 15 }, (_, i) => ({
|
||||
text: `${i + 1}天`,
|
||||
value: i + 1
|
||||
}))
|
||||
]
|
||||
check.value = $bluetooth.currentLockNoticeSetting.dayNotOpenDoorState === 1
|
||||
value.value =
|
||||
$bluetooth.currentLockNoticeSetting.dayNotOpenDoorValue === 0
|
||||
? 3
|
||||
: $bluetooth.currentLockNoticeSetting.dayNotOpenDoorValue
|
||||
dayNotOpenDoorNoticeWayList.value =
|
||||
$bluetooth.currentLockNoticeSetting.dayNotOpenDoorNoticeWayList
|
||||
})
|
||||
|
||||
const changeValue = e => {
|
||||
value.value = columns.value[0][e.indexs[0]].value
|
||||
show.value = false
|
||||
}
|
||||
|
||||
const update = async () => {
|
||||
if (pending.value) return
|
||||
if ($user.userInfo.isVip === 0) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '该功能是高级功能,请开通后在使用',
|
||||
confirmText: '去开通',
|
||||
success: async res => {
|
||||
if (res.confirm) {
|
||||
const { code, data, message } = await $user.getWebUrl()
|
||||
if (code === 0) {
|
||||
$basic.routeJump({
|
||||
name: 'webview',
|
||||
params: {
|
||||
url: encodeURIComponent(data.vip_buy_url)
|
||||
}
|
||||
})
|
||||
flag.value = true
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '更新中'
|
||||
})
|
||||
const data = {
|
||||
lockId: $bluetooth.currentLockInfo.lockId,
|
||||
dayNotOpenDoorState: check.value ? 1 : 0,
|
||||
dayNotOpenDoorValue: value.value,
|
||||
dayNotOpenDoorNoticeWayList: dayNotOpenDoorNoticeWayList.value
|
||||
}
|
||||
const { code, message } = await updateLockNoticeSettingRequest(data)
|
||||
pending.value = false
|
||||
uni.hideLoading()
|
||||
if (code === 0) {
|
||||
$bluetooth.updateCurrentLockNoticeSetting({
|
||||
...$bluetooth.currentLockNoticeSetting,
|
||||
...data
|
||||
})
|
||||
$basic.backAndToast('更新成功')
|
||||
} else if (code === 434) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: message,
|
||||
showCancel: false
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const changeCheck = () => {
|
||||
check.value = !check.value
|
||||
}
|
||||
|
||||
const toNoticeWay = () => {
|
||||
$basic.routeJump({
|
||||
name: 'noticeWay',
|
||||
params: {
|
||||
info:
|
||||
dayNotOpenDoorNoticeWayList.value.length === 0
|
||||
? null
|
||||
: JSON.stringify({ noticeWay: dayNotOpenDoorNoticeWayList.value })
|
||||
},
|
||||
events: {
|
||||
confirm(data) {
|
||||
dayNotOpenDoorNoticeWayList.value = data.noticeWay
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
422
pages/noticeDetail/noticeDetail.vue
Normal file
422
pages/noticeDetail/noticeDetail.vue
Normal file
@ -0,0 +1,422 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="bg-white mx-4 rounded-md mt-4 text-base">
|
||||
<view class="flex items-center p-3" @click="toSelect">
|
||||
<view>{{ mode === 'all' ? '开门方式' : '胁迫指纹' }}</view>
|
||||
<view v-if="info?.settingValue?.openDoorType" class="ml-a">
|
||||
{{
|
||||
mode === 'all'
|
||||
? keysType[info.settingValue.openDoorType].name
|
||||
: info?.settingValue?.remark
|
||||
}}
|
||||
</view>
|
||||
<view v-else class="ml-a">请选择</view>
|
||||
<view class="ml-2"><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view
|
||||
v-if="mode === 'all'"
|
||||
class="flex items-center p-3 border-t-1 border-t-solid border-t-gray-200"
|
||||
@click="openModal"
|
||||
>
|
||||
<view>家人</view>
|
||||
<view class="ml-a break-all max-w-500">
|
||||
<view v-if="type === 'edit'">{{ info?.settingValue?.remark }}</view>
|
||||
<view v-else>
|
||||
<input
|
||||
class="w-450 h-60 text-right font-bold text-base"
|
||||
:value="remark"
|
||||
maxlength="50"
|
||||
placeholder="请输入"
|
||||
placeholder-class="text-base line-height-60rpx font-bold text-right"
|
||||
@input="updateName"
|
||||
/></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-white mx-4 rounded-md mt-4 text-base" @click="toNoticeWay">
|
||||
<view class="flex items-center p-3">
|
||||
<view>提醒方式</view>
|
||||
<view class="ml-a"><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view class="pb-4">
|
||||
<view class="flex items-center bg-#f4f4f4 mx-4 py-1 px-2 rounded-md">
|
||||
<view>APP推送</view>
|
||||
<view class="text-gray-500 ml-a">管理员</view>
|
||||
</view>
|
||||
<view
|
||||
class="flex items-center bg-#f4f4f4 mx-4 py-1 px-2 rounded-md mt-4"
|
||||
v-if="
|
||||
info?.settingValue?.noticeWay && info?.settingValue?.noticeWay[0]?.accounts.length > 0
|
||||
"
|
||||
>
|
||||
<view>邮件提醒</view>
|
||||
<view class="text-sm ml-a text-right">
|
||||
<view
|
||||
class="text-gray-500"
|
||||
v-for="(item, index) in info.settingValue.noticeWay[0].accounts"
|
||||
:key="index"
|
||||
>
|
||||
{{ item.account }}
|
||||
</view></view
|
||||
>
|
||||
</view>
|
||||
<view
|
||||
class="flex items-center bg-#f4f4f4 mx-4 py-1 px-2 rounded-md mt-4"
|
||||
v-if="
|
||||
info?.settingValue?.noticeWay && info?.settingValue?.noticeWay[1]?.accounts.length > 0
|
||||
"
|
||||
>
|
||||
<view>短信提醒</view>
|
||||
<view class="ml-a text-sm text-right">
|
||||
<view
|
||||
class="text-gray-500"
|
||||
v-for="(item, index) in info.settingValue.noticeWay[1].accounts"
|
||||
:key="index"
|
||||
>
|
||||
{{ item.account }}</view
|
||||
>
|
||||
</view></view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="type === 'edit'"
|
||||
@click="deleteData"
|
||||
class="pos-fixed bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-88 line-height-88rpx text-center bg-#df2a2c text-white rounded-3xl"
|
||||
>删除
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
@click="create"
|
||||
class="pos-fixed bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-88 line-height-88rpx text-center text-white rounded-3xl"
|
||||
:class="[canCreate ? 'bg-#63b8af' : 'bg-#9d9ca1']"
|
||||
>保存
|
||||
</view>
|
||||
<ModalInput
|
||||
v-if="info"
|
||||
ref="modalInput"
|
||||
title="修改名字"
|
||||
:autoClose="false"
|
||||
placeholder="请输入"
|
||||
:value="info?.settingValue?.remark"
|
||||
@confirm="changeName"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import { computed, getCurrentInstance, ref } from 'vue'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { keysType } from '@/constant/keyType'
|
||||
import { addNoticeRequest, deleteNoticeRequest, updateNoticeRequest } from '@/api/setting'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
const instance = getCurrentInstance().proxy
|
||||
const eventChannel = instance.getOpenerEventChannel()
|
||||
|
||||
const $basic = useBasicStore()
|
||||
const $bluetooth = useBluetoothStore()
|
||||
const $user = useUserStore()
|
||||
|
||||
const info = ref(null)
|
||||
|
||||
const remark = ref('')
|
||||
|
||||
const type = ref('add')
|
||||
|
||||
const modalInput = ref(null)
|
||||
|
||||
const pending = ref(false)
|
||||
|
||||
const mode = ref('all')
|
||||
|
||||
const flag = ref(false)
|
||||
|
||||
const canCreate = computed(() => {
|
||||
return info.value?.settingValue?.openDoorId
|
||||
})
|
||||
|
||||
onLoad(options => {
|
||||
if (options.title) {
|
||||
uni.setNavigationBarTitle({
|
||||
title: options.title
|
||||
})
|
||||
}
|
||||
if (JSON.parse(options.info)) {
|
||||
info.value = JSON.parse(options.info)
|
||||
type.value = 'edit'
|
||||
}
|
||||
|
||||
if (options.mode) {
|
||||
mode.value = options.mode
|
||||
}
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
if (flag.value) {
|
||||
$user.getUserInfo()
|
||||
flag.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const create = async () => {
|
||||
if (pending.value && canCreate) return
|
||||
if ($user.userInfo.isVip === 0) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '该功能是高级功能,请开通后在使用',
|
||||
confirmText: '去开通',
|
||||
success: async res => {
|
||||
if (res.confirm) {
|
||||
const { code, data, message } = await $user.getWebUrl()
|
||||
if (code === 0) {
|
||||
$basic.routeJump({
|
||||
name: 'webview',
|
||||
params: {
|
||||
url: encodeURIComponent(data.vip_buy_url)
|
||||
}
|
||||
})
|
||||
flag.value = true
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '保存中'
|
||||
})
|
||||
const { code, message } = await addNoticeRequest({
|
||||
lockId: $bluetooth.currentLockInfo.lockId,
|
||||
noticeType: mode.value === 'all' ? 10 : 20,
|
||||
settingValue: info.value.settingValue
|
||||
})
|
||||
uni.hideLoading()
|
||||
pending.value = false
|
||||
if (code === 0) {
|
||||
$basic.backAndToast('保存成功')
|
||||
eventChannel.emit('refresherList')
|
||||
} else if (code === 434) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: message,
|
||||
showCancel: false
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const openModal = () => {
|
||||
if (type.value !== 'edit') return
|
||||
modalInput.value.open()
|
||||
}
|
||||
|
||||
const updateName = e => {
|
||||
remark.value = e.detail.value
|
||||
info.value = {
|
||||
...info.value,
|
||||
settingValue: {
|
||||
...info.value.settingValue,
|
||||
remark: e.detail.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const deleteData = async () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定删除吗?',
|
||||
success: async res => {
|
||||
if (res.confirm) {
|
||||
if (pending.value) return
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '删除中'
|
||||
})
|
||||
const { code, message } = await deleteNoticeRequest({
|
||||
lockNoticeSettingAccountId: info.value.id
|
||||
})
|
||||
uni.hideLoading()
|
||||
pending.value = false
|
||||
if (code === 0) {
|
||||
$basic.backAndToast('删除成功')
|
||||
eventChannel.emit('refresherList')
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const toNoticeWay = () => {
|
||||
$basic.routeJump({
|
||||
name: 'noticeWay',
|
||||
params: {
|
||||
info: info.value?.settingValue ? JSON.stringify(info.value.settingValue) : null
|
||||
},
|
||||
events: {
|
||||
async confirm(data) {
|
||||
if (type.value === 'add') {
|
||||
info.value = {
|
||||
settingValue: {
|
||||
...(info.value?.settingValue || {}),
|
||||
noticeWay: data.noticeWay
|
||||
}
|
||||
}
|
||||
uni.navigateBack()
|
||||
return
|
||||
}
|
||||
|
||||
if (pending.value) return
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '更新中'
|
||||
})
|
||||
const params = {
|
||||
lockNoticeSettingAccountId: info.value.id,
|
||||
settingValue: {
|
||||
...info.value.settingValue,
|
||||
noticeWay: data.noticeWay
|
||||
}
|
||||
}
|
||||
const { code, message } = await updateNoticeRequest(params)
|
||||
uni.hideLoading()
|
||||
pending.value = false
|
||||
if (code === 0) {
|
||||
info.value = {
|
||||
...info.value,
|
||||
settingValue: params.settingValue
|
||||
}
|
||||
$basic.backAndToast('更新成功')
|
||||
eventChannel.emit('refresherList')
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const changeName = async name => {
|
||||
if (pending.value) return
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '更新中'
|
||||
})
|
||||
const params = {
|
||||
lockNoticeSettingAccountId: info.value.id,
|
||||
settingValue: {
|
||||
...info.value.settingValue,
|
||||
remark: name
|
||||
}
|
||||
}
|
||||
const { code, message } = await updateNoticeRequest(params)
|
||||
uni.hideLoading()
|
||||
pending.value = false
|
||||
if (code === 0) {
|
||||
modalInput.value.close()
|
||||
info.value = {
|
||||
...info.value,
|
||||
settingValue: params.settingValue
|
||||
}
|
||||
uni.showToast({
|
||||
title: '更新成功',
|
||||
icon: 'none'
|
||||
})
|
||||
eventChannel.emit('refresherList')
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const toSelect = () => {
|
||||
$basic.routeJump({
|
||||
name: mode.value === 'all' ? 'lockUser' : 'coercionFingerprint',
|
||||
params: {
|
||||
info: info.value?.settingValue ? JSON.stringify(info.value.settingValue) : null
|
||||
},
|
||||
events: {
|
||||
async confirm(data) {
|
||||
if (type.value === 'add') {
|
||||
info.value = {
|
||||
settingValue: {
|
||||
...(info.value?.settingValue || {}),
|
||||
openDoorId: data.id,
|
||||
openDoorType: data.type,
|
||||
remark: data.name
|
||||
}
|
||||
}
|
||||
remark.value = data.name
|
||||
uni.navigateBack()
|
||||
return
|
||||
}
|
||||
|
||||
if (pending.value) return
|
||||
pending.value = true
|
||||
uni.showLoading({
|
||||
title: '更新中'
|
||||
})
|
||||
const params = {
|
||||
lockNoticeSettingAccountId: info.value.id,
|
||||
settingValue: {
|
||||
...info.value.settingValue,
|
||||
openDoorId: data.id,
|
||||
openDoorType: data.type,
|
||||
remark: data.name
|
||||
}
|
||||
}
|
||||
const { code, message } = await updateNoticeRequest(params)
|
||||
uni.hideLoading()
|
||||
pending.value = false
|
||||
if (code === 0) {
|
||||
info.value = {
|
||||
...info.value,
|
||||
settingValue: params.settingValue
|
||||
}
|
||||
$basic.backAndToast('更新成功')
|
||||
eventChannel.emit('refresherList')
|
||||
} else if (code === 434) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: message,
|
||||
showCancel: false
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
191
pages/noticeWay/noticeWay.vue
Normal file
191
pages/noticeWay/noticeWay.vue
Normal file
@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="py-3 px-4 bg-white flex items-center justify-between text-base">
|
||||
<view>APP推送</view>
|
||||
<view class="ml-a">管理员</view>
|
||||
</view>
|
||||
|
||||
<view class="pt-2 px-4 bg-white text-base mt-20rpx">
|
||||
<view class="flex items-center w-full pb-2">
|
||||
<view>邮件提醒</view>
|
||||
<view class="ml-a h-50">
|
||||
<up-icon
|
||||
name="plus-circle-fill"
|
||||
color="#002ce5"
|
||||
size="50"
|
||||
v-if="emailList.length < 3"
|
||||
@click="addItem('email')"
|
||||
></up-icon
|
||||
></view>
|
||||
</view>
|
||||
<view v-if="emailList.length > 0">
|
||||
<view
|
||||
v-for="(item, index) in emailList"
|
||||
:key="index"
|
||||
class="flex items-center border-t-1 border-t-solid border-t-gray-200"
|
||||
>
|
||||
<up-icon
|
||||
name="close-circle-fill"
|
||||
color="#858585"
|
||||
size="40"
|
||||
@click="deleteItem('email', index)"
|
||||
></up-icon>
|
||||
<view class="ml-3">接收者</view>
|
||||
<view class="ml-a">
|
||||
<input
|
||||
class="py-2 w-450 h-60 text-right font-bold text-base"
|
||||
:value="item.account"
|
||||
maxlength="50"
|
||||
placeholder="请输入Email"
|
||||
placeholder-class="text-base line-height-60rpx font-bold text-right"
|
||||
@input="updateName('email', index, $event)"
|
||||
/>
|
||||
</view> </view
|
||||
></view>
|
||||
</view>
|
||||
|
||||
<view class="pt-2 px-4 bg-white text-base mt-20rpx">
|
||||
<view class="flex items-center w-full pb-2">
|
||||
<view>短信提醒</view>
|
||||
<view class="ml-a h-50">
|
||||
<up-icon
|
||||
name="plus-circle-fill"
|
||||
color="#002ce5"
|
||||
size="50"
|
||||
v-if="smsList.length < 3"
|
||||
@click="addItem('sms')"
|
||||
></up-icon
|
||||
></view>
|
||||
</view>
|
||||
<view v-if="smsList.length > 0">
|
||||
<view
|
||||
v-for="(item, index) in smsList"
|
||||
:key="index"
|
||||
class="flex items-center border-t-1 border-t-solid border-t-gray-200"
|
||||
>
|
||||
<up-icon
|
||||
name="close-circle-fill"
|
||||
color="#858585"
|
||||
size="40"
|
||||
@click="deleteItem('sms', index)"
|
||||
></up-icon>
|
||||
<view class="ml-3">接收者</view>
|
||||
<view class="ml-a">
|
||||
<input
|
||||
class="py-2 w-450 h-60 text-right font-bold text-base"
|
||||
:value="item.account"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
placeholder="请输入手机号"
|
||||
placeholder-class="text-base line-height-60rpx font-bold text-right"
|
||||
@input="updateName('sms', index, $event)"
|
||||
/>
|
||||
</view> </view
|
||||
></view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
@click="confirm"
|
||||
class="mt-10 w-686 mx-4 h-88 line-height-88rpx text-center bg-#63b8af text-white rounded-3xl"
|
||||
>确定
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getCurrentInstance, ref } from 'vue'
|
||||
import test from 'uview-plus/libs/function/test'
|
||||
|
||||
const instance = getCurrentInstance().proxy
|
||||
const eventChannel = instance.getOpenerEventChannel()
|
||||
|
||||
const info = ref(null)
|
||||
const emailList = ref([])
|
||||
const smsList = ref([])
|
||||
|
||||
onLoad(options => {
|
||||
info.value = JSON.parse(options.info)
|
||||
if (info.value?.noticeWay) {
|
||||
emailList.value = info.value.noticeWay[0].accounts
|
||||
smsList.value = info.value.noticeWay[1].accounts
|
||||
}
|
||||
})
|
||||
|
||||
const confirm = () => {
|
||||
for (let i = 0; i < emailList.value.length; i++) {
|
||||
if (test.email(emailList.value[i].account) === false) {
|
||||
uni.showToast({
|
||||
title: '含不符合规范的邮箱',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < smsList.value.length; i++) {
|
||||
if (test.mobile(smsList.value[i].account) === false) {
|
||||
uni.showToast({
|
||||
title: '含不符合规范的手机号',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
eventChannel.emit('confirm', {
|
||||
noticeWay: [
|
||||
{ type: 'mail', accounts: emailList.value },
|
||||
{ type: 'sms', accounts: smsList.value }
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
const addItem = type => {
|
||||
if (type === 'email') {
|
||||
emailList.value.push({ countryCode: 0, account: '' })
|
||||
} else {
|
||||
smsList.value.push({ countryCode: 86, account: '' })
|
||||
}
|
||||
}
|
||||
|
||||
const deleteItem = (type, index) => {
|
||||
if (type === 'email') {
|
||||
emailList.value.splice(index, 1)
|
||||
} else {
|
||||
smsList.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const updateName = (type, index, data) => {
|
||||
if (type === 'email') {
|
||||
emailList.value[index].account = data.detail.value
|
||||
} else {
|
||||
smsList.value[index].account = data.detail.value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.input {
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
margin-left: 35rpx;
|
||||
margin-top: 24rpx;
|
||||
height: 108rpx;
|
||||
width: 616rpx;
|
||||
padding-left: 32rpx;
|
||||
padding-right: 32rpx;
|
||||
}
|
||||
|
||||
.input-placeholder {
|
||||
height: 60rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
line-height: 108rpx;
|
||||
}
|
||||
</style>
|
||||
158
pages/openDoorNotice/openDoorNotice.vue
Normal file
158
pages/openDoorNotice/openDoorNotice.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="text-sm h-80rpx py-3 mx-4">
|
||||
若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择。
|
||||
</view>
|
||||
<scroll-view
|
||||
v-if="deviceInfo"
|
||||
scroll-y="true"
|
||||
:style="{
|
||||
height:
|
||||
deviceInfo.screenHeight -
|
||||
deviceInfo.safeArea.top -
|
||||
(deviceInfo.screenWidth / 750) * 128 +
|
||||
'px'
|
||||
}"
|
||||
lower-threshold="100"
|
||||
@refresherrefresh="refresherList"
|
||||
:refresher-enabled="true"
|
||||
@scrolltolower="nextPage"
|
||||
:refresher-triggered="refresherTriggered"
|
||||
>
|
||||
<view v-if="list.length === 0">
|
||||
<image
|
||||
class="w-150 h-150 transform-translate-x-[-50%] mt-300rpx mr-a mb-20rpx ml-50%"
|
||||
src="/static/images/background_empty_list.png"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view class="text-center text-base text-#999999">暂无数据</view>
|
||||
</view>
|
||||
<view v-else class="pb-[calc(env(safe-area-inset-bottom)+250rpx)]">
|
||||
<view
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
class="flex items-center bg-white px-4 py-2 mt-4rpx"
|
||||
@click="toJump(item)"
|
||||
>
|
||||
<image :src="keysType[item.settingValue.openDoorType].icon" class="w-80 h-80" />
|
||||
<view class="ml-3">
|
||||
<view class="break-all max-w-500 text-base">{{ item.settingValue.remark }}</view>
|
||||
<view class="text-sm text-gray-500">{{
|
||||
keysType[item.settingValue.openDoorType].name
|
||||
}}</view>
|
||||
</view>
|
||||
<view class="ml-a"> <up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view
|
||||
@click="toJump(null)"
|
||||
class="flex items-center justify-center bg-white shadow-sm rounded-md pos-fixed bottom-[calc(env(safe-area-inset-bottom)+48rpx)] w-686 mx-4 h-100"
|
||||
><view class="flex items-center">
|
||||
<up-icon name="plus-circle-fill" color="#002ce5" size="50"></up-icon
|
||||
><view class="text-lg text-#63b8af ml-2 font-bold">添加家人</view>
|
||||
</view></view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { getNoticeListRequest } from '@/api/setting'
|
||||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||
import { keysType } from '@/constant/keyType'
|
||||
|
||||
const $basic = useBasicStore()
|
||||
const $bluetooth = useBluetoothStore()
|
||||
|
||||
const deviceInfo = ref(null)
|
||||
|
||||
const refresherTriggered = ref(false)
|
||||
|
||||
const list = ref([])
|
||||
const pageSize = 50
|
||||
const pageNo = ref(1)
|
||||
const total = ref(0)
|
||||
|
||||
onMounted(async () => {
|
||||
uni.showLoading({
|
||||
title: '加载中'
|
||||
})
|
||||
deviceInfo.value = await $basic.getDeviceInfo()
|
||||
await getList(pageNo.value, true)
|
||||
})
|
||||
|
||||
const refresherList = async () => {
|
||||
refresherTriggered.value = true
|
||||
pageNo.value = 1
|
||||
const { code } = await getList(pageNo.value, false)
|
||||
if (code === 0) {
|
||||
uni.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
refresherTriggered.value = false
|
||||
}
|
||||
|
||||
const nextPage = async () => {
|
||||
if (total.value <= pageNo.value * pageSize) {
|
||||
return
|
||||
}
|
||||
const no = pageNo.value + 1
|
||||
const { code } = await getList(no, false)
|
||||
if (code === 0) {
|
||||
pageNo.value = no
|
||||
}
|
||||
}
|
||||
|
||||
const getList = async (no, flag) => {
|
||||
const { code, data, message } = await getNoticeListRequest({
|
||||
lockId: $bluetooth.currentLockInfo.lockId,
|
||||
noticeType: 10,
|
||||
pageSize,
|
||||
pageNo: no
|
||||
})
|
||||
if (flag) {
|
||||
uni.hideLoading()
|
||||
}
|
||||
|
||||
if (code === 0) {
|
||||
total.value = data.total
|
||||
if (no === 1) {
|
||||
list.value = data.list
|
||||
} else {
|
||||
list.value = list.value.concat(data.list)
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
return { code, message }
|
||||
}
|
||||
|
||||
const toJump = (data = null) => {
|
||||
$basic.routeJump({
|
||||
name: 'noticeDetail',
|
||||
params: {
|
||||
info: data ? JSON.stringify(data) : null,
|
||||
title: data ? '家人详情' : '添加家人'
|
||||
},
|
||||
events: {
|
||||
refresherList() {
|
||||
pageNo.value = 1
|
||||
getList(pageNo.value, false)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: $uni-bg-color-grey;
|
||||
}
|
||||
</style>
|
||||
@ -112,10 +112,25 @@
|
||||
<view class="item-title">面容开锁</view>
|
||||
<view><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<!-- <view class="py-3 px-4 bg-white flex items-center justify-between text-base">-->
|
||||
<!-- <view class="item-title">消息提醒</view>-->
|
||||
<!-- <view><up-icon name="arrow-right"></up-icon></view>-->
|
||||
<!-- </view>-->
|
||||
<view
|
||||
v-if="$bluetooth.currentLockSetting.lockBasicInfo.keyRight === 1"
|
||||
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
|
||||
@click="toJump('messageReminder')"
|
||||
>
|
||||
<view class="item-title">消息提醒</view>
|
||||
<view><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view
|
||||
v-if="
|
||||
$bluetooth.currentLockSetting.lockFeature.isSupportCatEye !== 1 &&
|
||||
$bluetooth.currentLockSetting.lockBasicInfo.keyRight === 1
|
||||
"
|
||||
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
|
||||
@click="toJump('catEye')"
|
||||
>
|
||||
<view class="item-title">猫眼设置</view>
|
||||
<view><up-icon name="arrow-right"></up-icon></view>
|
||||
</view>
|
||||
<view
|
||||
v-if="
|
||||
$bluetooth.currentLockSetting.lockFeature.openDirection === 1 &&
|
||||
|
||||
@ -15,27 +15,30 @@
|
||||
}
|
||||
},
|
||||
async onLoad(options) {
|
||||
this.env = await env[await getApp().globalData.getEnvConfig()]
|
||||
const officialAccounts = {
|
||||
default: {
|
||||
url: '/app/introduce',
|
||||
name: '介绍'
|
||||
},
|
||||
userAgreement: {
|
||||
url: '/app/userAgreement',
|
||||
name: '用户协议'
|
||||
},
|
||||
privacy: {
|
||||
url: '/app/privacy',
|
||||
name: '隐私政策'
|
||||
if (options.url) {
|
||||
this.url = decodeURIComponent(options.url)
|
||||
} else {
|
||||
this.env = await env[await getApp().globalData.getEnvConfig()]
|
||||
const officialAccounts = {
|
||||
default: {
|
||||
url: '/app/introduce',
|
||||
name: '介绍'
|
||||
},
|
||||
userAgreement: {
|
||||
url: '/app/userAgreement',
|
||||
name: '用户协议'
|
||||
},
|
||||
privacy: {
|
||||
url: '/app/privacy',
|
||||
name: '隐私政策'
|
||||
}
|
||||
}
|
||||
const item = officialAccounts[options?.type] || officialAccounts.default
|
||||
this.url = this.env.webviewBaseUrl + item.url
|
||||
uni.setNavigationBarTitle({
|
||||
title: item.name
|
||||
})
|
||||
}
|
||||
const item = officialAccounts[options?.type] || officialAccounts.default
|
||||
this.url = this.env.webviewBaseUrl + item.url
|
||||
console.log(this.url)
|
||||
uni.setNavigationBarTitle({
|
||||
title: item.name
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -306,6 +306,56 @@ const pages = [
|
||||
name: 'motorTorsion',
|
||||
path: '/pages/motorTorsion/motorTorsion',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'catEye',
|
||||
path: '/pages/catEye/catEye',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'messageReminder',
|
||||
path: '/pages/messageReminder/messageReminder',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'openDoorNotice',
|
||||
path: '/pages/openDoorNotice/openDoorNotice',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'noticeDetail',
|
||||
path: '/pages/noticeDetail/noticeDetail',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'lockUser',
|
||||
path: '/pages/lockUser/lockUser',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'noticeWay',
|
||||
path: '/pages/noticeWay/noticeWay',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'notOpenDoor',
|
||||
path: '/pages/notOpenDoor/notOpenDoor',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'lowElecNotice',
|
||||
path: '/pages/lowElecNotice/lowElecNotice',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'coercionOpenDoor',
|
||||
path: '/pages/coercionOpenDoor/coercionOpenDoor',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'coercionFingerprint',
|
||||
path: '/pages/coercionFingerprint/coercionFingerprint',
|
||||
tabBar: false
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@ -127,6 +127,8 @@ export const useBluetoothStore = defineStore('ble', {
|
||||
currentLockInfo: {},
|
||||
// 当前锁设置信息
|
||||
currentLockSetting: null,
|
||||
// 当前锁消息设置
|
||||
currentLockNoticeSetting: null,
|
||||
// 消息序号
|
||||
messageCount: 1,
|
||||
// 是否初始化蓝牙
|
||||
@ -140,6 +142,10 @@ export const useBluetoothStore = defineStore('ble', {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
// 更新锁消息设置
|
||||
updateCurrentLockNoticeSetting(lockNoticeSetting) {
|
||||
this.currentLockNoticeSetting = { ...this.currentLockNoticeSetting, ...lockNoticeSetting }
|
||||
},
|
||||
// 保存刚绑定的设备名称
|
||||
updateBindedDeviceName(name) {
|
||||
if (!this.bindedDeviceNameList.includes(name)) {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
* @description 用户信息数据持久化
|
||||
*/
|
||||
import { defineStore } from 'pinia'
|
||||
import { getUserInfoRequest, loginRequest, phoneLoginRequest } from '@/api/user'
|
||||
import { getUserInfoRequest, getWebUrlRequest, loginRequest, phoneLoginRequest } from '@/api/user'
|
||||
import { useLockStore } from '@/stores/lock'
|
||||
import { setStorage, getStorage } from '@/utils/storage'
|
||||
import { useNotificationStore } from '@/stores/notification'
|
||||
@ -13,7 +13,8 @@ export const useUserStore = defineStore('user', {
|
||||
// 用户信息
|
||||
userInfo: {},
|
||||
// 登录状态
|
||||
isLogin: false
|
||||
isLogin: false,
|
||||
webUrl: null
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@ -82,6 +83,17 @@ export const useUserStore = defineStore('user', {
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
async getWebUrl() {
|
||||
if (this.webUrl) {
|
||||
return { code: 0, data: this.webUrl }
|
||||
}
|
||||
const { code, data, message } = await getWebUrlRequest()
|
||||
if (code === 0) {
|
||||
this.webUrl = data
|
||||
return { code, data }
|
||||
}
|
||||
return { code, message }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user