1. 完成锁设置页UI

2. 完成基本信息相关功能
This commit is contained in:
范鹏 2025-02-18 18:35:24 +08:00
parent b1d7eca435
commit 1d1adaab0c
8 changed files with 1010 additions and 314 deletions

View File

@ -5,7 +5,52 @@ import request from '../utils/request'
// 获取锁设置
export function getLockSettingRequest(data) {
return request({
url: '/lockSetting/getLockSetting',
url: '/lock/getLockSettingData',
method: 'POST',
data
})
}
// 更新锁名称
export function updateLockNameRequest(data) {
return request({
url: '/lock/updateLockName',
method: 'POST',
data
})
}
// 修改管理员密码
export function updateAdminPasswordRequest(data) {
return request({
url: '/room/modifyPwd',
method: 'POST',
data
})
}
// 获取分组列表
export function getGroupListRequest(data) {
return request({
url: '/authorizedAdmin/listGroup',
method: 'POST',
data
})
}
// 创建分组
export function createGroupRequest(data) {
return request({
url: '/keyGroup/add',
method: 'POST',
data
})
}
// 设置分组
export function setGroupRequest(data) {
return request({
url: '/keyGroup/setGroup',
method: 'POST',
data
})

View File

@ -337,6 +337,27 @@
"navigationBarTitleText": "修改有效期",
"disableScroll": true
}
},
{
"path": "pages/lockInfo/lockInfo",
"style": {
"navigationBarTitleText": "基本信息",
"disableScroll": true
}
},
{
"path": "pages/syncElec/syncElec",
"style": {
"navigationBarTitleText": "电量",
"disableScroll": true
}
},
{
"path": "pages/selectGroup/selectGroup",
"style": {
"navigationBarTitleText": "选择分组",
"disableScroll": true
}
}
],
"globalStyle": {

269
pages/lockInfo/lockInfo.vue Normal file
View File

@ -0,0 +1,269 @@
<template>
<view class="break-all">
<view class="py-3 px-4 bg-white flex items-center justify-between text-base">
<view>锁编号</view>
<view>{{ $bluetooth.currentLockSetting.lockBasicInfo.lockName }}</view>
</view>
<view class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx">
<view>MAC/ID</view>
<view
>{{ $bluetooth.currentLockSetting.lockBasicInfo.mac }}/{{
$bluetooth.currentLockSetting.lockBasicInfo.lockId
}}</view
>
</view>
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-2.5"
@click="toJump('syncElec')"
>
<view>电量</view>
<view class="flex items-center">
<view class="mr-2"
>{{ $bluetooth.currentLockSetting.lockBasicInfo.electricQuantity }}%</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">
<view>有效期</view>
<view>
<view v-if="$bluetooth.currentLockSetting.lockBasicInfo.keyType === 4"
>{{ timeFormat($bluetooth.currentLockSetting.lockBasicInfo.startDate, 'yyyy-mm-dd') }}{{
timeFormat($bluetooth.currentLockSetting.lockBasicInfo.endDate, 'yyyy-mm-dd')
}}</view
>
<view v-else-if="$bluetooth.currentLockSetting.lockBasicInfo.keyType === 2">
<view>{{
timeFormat($bluetooth.currentLockSetting.lockBasicInfo.startDate, 'yyyy-mm-dd h:M')
}}</view>
<view>{{
timeFormat($bluetooth.currentLockSetting.lockBasicInfo.endDate, 'yyyy-mm-dd h:M')
}}</view>
</view>
<view v-else-if="$bluetooth.currentLockSetting.lockBasicInfo.keyType === 3">单次</view>
<view v-else>永久</view>
</view>
</view>
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
v-if="$bluetooth.currentLockSetting.lockBasicInfo.keyType === 4"
>
<view>有效日</view>
<view>
<view>{{
$lock.convertWeekDaysToChineseString($bluetooth.currentLockSetting.lockBasicInfo.weekDays)
}}</view>
</view>
</view>
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
v-if="$bluetooth.currentLockSetting.lockBasicInfo.keyType === 4"
>
<view>有效时间</view>
<view>
<view
>{{ timeFormat($bluetooth.currentLockSetting.lockBasicInfo.startDate, 'h:M') }}{{
timeFormat($bluetooth.currentLockSetting.lockBasicInfo.endDate, 'h:M')
}}</view
>
</view>
</view>
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-2.5"
@click="() => $refs.modalInput.open()"
>
<view>名称</view>
<view class="flex items-center">
<view class="mr-2 max-w-400">{{
$bluetooth.currentLockSetting.lockBasicInfo.lockAlias
}}</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('selectGroup')"
>
<view>锁分组</view>
<view class="flex items-center">
<view class="mr-2 max-w-400">{{
$bluetooth.currentLockSetting.lockBasicInfo.groupName
}}</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="() => $refs.modalPassword.open()"
>
<view>管理员开锁密码</view>
<view class="flex items-center">
<view class="mr-2">{{ $bluetooth.currentLockSetting.lockBasicInfo.adminPwd }}</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">
<view>位置信息</view>
<view class="flex items-center max-w-400">
<view>{{ $bluetooth.currentLockSetting.lockBasicInfo.address }}</view>
</view>
</view>
<ModalInput
ref="modalInput"
title="请输入名称"
:autoClose="false"
placeholder="请输入名称"
:value="$bluetooth.currentLockSetting.lockBasicInfo.lockAlias"
@confirm="changeName"
/>
<ModalInput
ref="modalPassword"
title="修改密码"
:autoClose="false"
:maxlength="9"
type="number"
placeholder="密码为6-9位数字"
:value="$bluetooth.currentLockSetting.lockBasicInfo.adminPwd"
@confirm="changePassword"
/>
</view>
</template>
<script setup>
import { timeFormat } from 'uview-plus'
import { ref } from 'vue'
import test from 'uview-plus/libs/function/test'
import { useBluetoothStore } from '@/stores/bluetooth'
import { useLockStore } from '@/stores/lock'
import { updateAdminPasswordRequest, updateLockNameRequest } from '@/api/setting'
import { useBasicStore } from '@/stores/basic'
import { useUserStore } from '@/stores/user'
const $bluetooth = useBluetoothStore()
const $lock = useLockStore()
const $basic = useBasicStore()
const $user = useUserStore()
const modalInput = ref(null)
const modalPassword = ref(null)
const pending = ref(false)
const changeName = async name => {
if (!name) {
uni.showToast({
title: '请输入名称',
icon: 'none'
})
return
}
if (pending.value) return
pending.value = true
const { code, message } = await updateLockNameRequest({
lockId: $bluetooth.currentLockInfo.lockId,
lockName: name
})
pending.value = false
if (code === 0) {
modalInput.value.close()
$lock.updateLockSearch({
...$lock.lockSearch,
pageNo: 1
})
$lock.getLockList($lock.lockSearch)
$bluetooth.updateCurrentLockSetting({
...$bluetooth.currentLockSetting,
lockBasicInfo: {
...$bluetooth.currentLockSetting.lockBasicInfo,
lockAlias: name
}
})
$bluetooth.updateCurrentLockInfo({
...$bluetooth.currentLockInfo,
lockAlias: name
})
uni.showToast({
title: '更新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
const changePassword = async password => {
if (!test.rangeLength(password, [6, 9])) {
uni.showToast({
title: '密码为6-9位纯数字',
icon: 'none'
})
return
}
if (pending.value) return
pending.value = true
uni.showLoading({
title: '更新中'
})
const params = {
keyId: $bluetooth.keyId.toString(),
uid: $user.userInfo.uid.toString(),
adminPwd: password,
userCountLimit: 0xffff,
startDate: Math.floor($bluetooth.currentLockSetting.lockBasicInfo.startDate / 1000),
endDate: Math.floor($bluetooth.currentLockSetting.lockBasicInfo.endDate / 1000)
}
const { code } = await $bluetooth.updateAdminPassword(params)
if (code === 0) {
const { code, message } = await updateAdminPasswordRequest({
password,
lockId: $bluetooth.currentLockInfo.lockId,
passwordType: '1'
})
uni.hideLoading()
pending.value = false
if (code === 0) {
modalPassword.value.close()
$bluetooth.updateCurrentLockSetting({
...$bluetooth.currentLockSetting,
lockBasicInfo: {
...$bluetooth.currentLockSetting.lockBasicInfo,
adminPwd: password
}
})
uni.showToast({
title: '更新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
} else {
uni.hideLoading()
pending.value = false
uni.showToast({
title: '更新失败,请保持在锁附近',
icon: 'none'
})
}
}
const toJump = name => {
$basic.routeJump({
name
})
}
</script>
<style lang="scss">
page {
background-color: $uni-bg-color-grey;
}
</style>

View File

@ -0,0 +1,140 @@
<template>
<view>
<scroll-view
v-if="deviceInfo"
:scroll-y="true"
:style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top + 'px' }"
>
<view class="pb-[calc(env(safe-area-inset-bottom)+250rpx)]">
<view
v-for="(item, index) in list"
:key="index"
:style="{ marginTop: index !== 0 ? '4rpx' : '0' }"
@click="changeGroup(item)"
class="flex items-center justify-between h-80 bg-white text-base"
>
<view class="ml-4 max-w-550 break-all">{{ item.keyGroupName }}</view>
<view
class="mr-4"
v-if="item.keyGroupId === $bluetooth.currentLockSetting.lockBasicInfo.groupId"
>
<up-icon name="checkbox-mark" color="#63b8af" size="40rpx"></up-icon>
</view>
</view>
</view>
</scroll-view>
<view
@click="() => $refs.modalInput.open()"
class="bg-#63b8af text-white pos-fixed bottom-[calc(env(safe-area-inset-bottom)+48rpx)] rounded-44rpx w-686 ml-4 h-88 line-height-88rpx text-lg font-bold text-center"
>创建新分组</view
>
<ModalInput
ref="modalInput"
title="创建新分组"
:autoClose="false"
placeholder="请输入名称"
@confirm="changeName"
/>
</view>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { useBasicStore } from '@/stores/basic'
import { createGroupRequest, getGroupListRequest, setGroupRequest } from '@/api/setting'
import { useBluetoothStore } from '@/stores/bluetooth'
const $basic = useBasicStore()
const $bluetooth = useBluetoothStore()
const deviceInfo = ref(null)
const modalInput = ref(null)
const list = ref([])
const pending = ref(false)
onMounted(async () => {
deviceInfo.value = await $basic.getDeviceInfo()
getList()
})
const getList = async () => {
const { code, data, message } = await getGroupListRequest({ type: 1 })
if (code === 0) {
list.value = data.list
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
const changeGroup = async item => {
if (pending.value) return
pending.value = true
uni.showLoading({
title: '设置中'
})
const { code, message } = await setGroupRequest({
lockId: $bluetooth.currentLockInfo.lockId,
groupId: item.keyGroupId
})
uni.hideLoading()
pending.value = false
if (code === 0) {
$bluetooth.updateCurrentLockSetting({
...$bluetooth.currentLockSetting,
lockBasicInfo: {
...$bluetooth.currentLockSetting.lockBasicInfo,
groupId: item.keyGroupId,
groupName: item.keyGroupName
}
})
uni.showToast({
title: '设置锁分组成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
const changeName = async name => {
if (!name) {
uni.showToast({
title: '请输入名称',
icon: 'none'
})
return
}
if (pending.value) return
pending.value = true
const { code, message } = await createGroupRequest({
groupName: name
})
pending.value = false
if (code === 0) {
modalInput.value.close()
getList()
uni.showToast({
title: '创建成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
</script>
<style lang="scss">
page {
background-color: $uni-bg-color-grey;
}
</style>

View File

@ -1,98 +1,153 @@
<template>
<view>
<view class="view">
<view class="view-button">
<view style="width: 150rpx">名称</view>
<view class="view-button" style="padding: 20rpx 0">
<view class="info" style="line-height: 40rpx; word-break: break-all">{{
currentLockInfo.lockAlias
}}</view>
</view>
</view>
<view class="view-line"></view>
<view class="view-button">
<view>锁编号</view>
<view class="view-button" style="padding: 0">
<view class="info">{{ currentLockInfo.name }}</view>
</view>
</view>
<view class="view-line"></view>
<view class="view-button">
<view>MAC/ID</view>
<view class="view-button" style="padding: 0">
<view class="info">{{ currentLockInfo.mac }}/{{ currentLockInfo.lockId }}</view>
</view>
</view>
<view class="view-line"></view>
<view class="view-button">
<view>电量</view>
<view class="view-button" style="padding: 0">
<view class="info">{{ currentLockInfo.electricQuantity }}%</view>
<view v-if="requestFinished" class="pb-100rpx">
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base"
@click="toJump('lockInfo')"
>
<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-2.5"
@click="toJump('lockInfo')"
>
<view class="item-title">自动闭锁</view>
<view class="flex items-center">
<view class="mr-2 max-w-400">
{{
$bluetooth.currentLockSetting.lockSettingInfo.autoLock === 1
? $bluetooth.currentLockSetting.lockSettingInfo.autoLockSecond + 's'
: '已关闭'
}}
</view>
<up-icon name="arrow-right"></up-icon>
</view>
</view>
<view class="view" v-if="currentLockInfo.userType === 110301">
<view class="view-button">
<view>开锁时是否需联网</view>
<view class="view-button" style="padding: 0">
<up-switch
v-model="unlockApp"
:size="40"
activeColor="#63b8af"
:asyncChange="true"
@change="changeUnlockApp"
:activeValue="1"
:inactiveValue="0"
></up-switch>
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
@click="toJump('lockInfo')"
>
<view class="item-title">锁声音</view>
<view class="flex items-center">
<view class="mr-2 max-w-400">
{{
$bluetooth.currentLockSetting.lockSettingInfo.lockSound === 1
? volumeList[$bluetooth.currentLockSetting.lockSettingInfo.lockSoundVolume - 1]
: '已关闭'
}}
</view>
<up-icon name="arrow-right"></up-icon>
</view>
</view>
<view class="view">
<view v-if="currentLockInfo.keyType === 4">
<view class="view-button">
<view>有效期</view>
<view class="view-button" style="padding: 0">
<view class="info"
>{{ timeFormat(currentLockInfo.startDate, 'yyyy-mm-dd') }}{{
timeFormat(currentLockInfo.endDate, 'yyyy-mm-dd')
}}</view
>
</view>
</view>
<view class="view-line"></view>
<view class="view-button">
<view>有效日</view>
<view class="view-button" style="padding: 0">
<view class="info">{{ convertWeekDaysToChineseString(currentLockInfo.weekDays) }}</view>
</view>
</view>
<view class="view-line"></view>
<view class="view-button">
<view>有效时间</view>
<view class="view-button" style="padding: 0">
<view class="info"
>{{ timeFormat(currentLockInfo.startDate, 'h:M') }}{{
timeFormat(currentLockInfo.endDate, 'h:M')
}}</view
>
</view>
</view>
</view>
<view v-else>
<view class="view-button">
<view>有效期</view>
<view class="view-button" style="padding: 10rpx 0">
<view class="info" v-if="currentLockInfo.keyType === 2" style="line-height: 40rpx">
<view>{{ timeFormat(currentLockInfo.startDate, 'yyyy-mm-dd h:M') }}</view>
<view>{{ timeFormat(currentLockInfo.endDate, 'yyyy-mm-dd h:M') }}</view>
</view>
<view class="info" v-if="currentLockInfo.keyType === 3">单次</view>
<view class="info" v-if="currentLockInfo.keyType === 1">永久</view>
</view>
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-4rpx"
@click="toJump('lockInfo')"
>
<view class="item-title">防撬报警</view>
<view class="flex items-center">
<view class="mr-2 max-w-400">
{{
$bluetooth.currentLockSetting.lockSettingInfo.antiPrySwitch === 1 ? '已开启' : '已关闭'
}}
</view>
<up-icon name="arrow-right"></up-icon>
</view>
</view>
<view class="button-logout" @click="deleteLock">删除</view>
<view
class="py-3 px-4 bg-white flex items-center justify-between text-base mt-2.5"
@click="toJump('lockInfo')"
>
<view class="item-title">远程开锁</view>
<view class="flex items-center">
<view class="mr-2 max-w-400">
{{
$bluetooth.currentLockSetting.lockSettingInfo.remoteUnlock === 1 ? '已开启' : '已关闭'
}}
</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('lockInfo')"
>
<view class="item-title">重置键</view>
<view class="flex items-center">
<view class="mr-2 max-w-400">
{{
$bluetooth.currentLockSetting.lockSettingInfo.resetSwitch === 1 ? '已开启' : '已关闭'
}}
</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-2.5"
@click="toJump('lockInfo')"
>
<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('lockInfo')"
>
<view class="item-title">消息提醒</view>
<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-2.5">
<view class="item-title">考勤</view>
<switch
:checked="$bluetooth.currentLockSetting.lockSettingInfo.attendance === 1"
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
:checked="$bluetooth.currentLockSetting.lockSettingInfo.unlockReminder === 1"
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
:checked="$bluetooth.currentLockSetting.lockSettingInfo.appUnlockOnline === 1"
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-2.5"
@click="toJump('lockInfo')"
>
<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('lockInfo')"
>
<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('lockInfo')"
>
<view class="item-title">锁升级</view>
<view><up-icon name="arrow-right"></up-icon></view>
</view>
<view
class="mt-4 rounded-3xl w-600 h-80 line-height-80rpx text-center mx-75rpx bg-#ec433c text-white text-xl font-bold"
@click="deleteLock"
>删除</view
>
<up-modal
:show="showModal"
title="是否删除授权管理员钥匙?"
@ -111,187 +166,167 @@
</view>
</template>
<script>
import { mapActions, mapState } from 'pinia'
import { timeFormat } from 'uview-plus'
<script setup>
import { onMounted, ref } from 'vue'
import { useBluetoothStore } from '@/stores/bluetooth'
import { useUserStore } from '@/stores/user'
import { deleteLockRequest } from '@/api/lock'
import { useLockStore } from '@/stores/lock'
import { updateLockSettingRequest } from '@/api/lockSetting'
import { deleteKeyRequest } from '@/api/key'
import { useBasicStore } from '@/stores/basic'
import { getLockSettingRequest } from '@/api/setting'
export default {
data() {
return {
unlockApp: 0,
showModal: false,
checked: false
}
},
computed: {
...mapState(useUserStore, ['userInfo']),
...mapState(useBluetoothStore, ['keyId', 'currentLockInfo']),
...mapState(useLockStore, ['lockSearch'])
},
onLoad() {
this.unlockApp = this.currentLockInfo.lockSetting.appUnlockOnline
},
methods: {
timeFormat,
...mapActions(useBluetoothStore, ['resetDevice', 'updateCurrentLockInfo']),
...mapActions(useLockStore, [
'getLockList',
'updateLockSearch',
'convertWeekDaysToChineseString'
]),
...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
changeRadio() {
this.checked = !this.checked
},
cancelModal() {
this.showModal = false
this.checked = false
},
async confirmModal() {
uni.showLoading({
title: '删除中',
mask: true
})
const that = this
const { code } = await deleteKeyRequest({
keyId: that.keyId,
includeUnderlings: that.checked ? 1 : 0
})
that.showModal = false
if (code === 0) {
uni.hideLoading()
that.updateLockSearch({
...that.lockSearch,
pageNo: 1
const $user = useUserStore()
const $bluetooth = useBluetoothStore()
const $lock = useLockStore()
const $basic = useBasicStore()
const showModal = ref(false)
const checked = ref(false)
const requestFinished = ref(false)
const volumeList = ['低', '较低', '中', '较高', '高']
onMounted(async () => {
uni.showLoading({
title: '加载中'
})
const { code, data, message } = await getLockSettingRequest({
lockId: $bluetooth.currentLockInfo.lockId
})
uni.hideLoading()
if (code === 0) {
requestFinished.value = true
$bluetooth.updateCurrentLockSetting(data)
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
})
const toJump = name => {
$basic.routeJump({
name
})
}
const changeRadio = () => {
checked.value = !checked.value
}
const cancelModal = () => {
showModal.value = false
checked.value = false
}
const confirmModal = async () => {
uni.showLoading({
title: '删除中',
mask: true
})
const { code } = await deleteKeyRequest({
keyId: $lock.keyId,
includeUnderlings: checked.value ? 1 : 0
})
showModal.value = false
if (code === 0) {
uni.hideLoading()
$lock.updateLockSearch({
...$lock.lockSearch,
pageNo: 1
})
$lock.getLockList($lock.lockSearch)
$basic.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
}
const deleteLock = async () => {
const netWork = await $basic.getNetworkType()
if (!netWork) {
return
}
if (
$bluetooth.currentLockInfo.userType !== 110301 &&
$bluetooth.currentLockInfo.keyRight === 1
) {
showModal.value = true
return
}
const message =
$bluetooth.currentLockInfo.userType === 110301
? '删除锁后,所有信息都会一起删除,确定删除锁吗?'
: '确定删除该钥匙吗?'
uni.showModal({
title: '提示',
content: message,
async success(res) {
if (res.confirm) {
uni.showLoading({
title: '删除中'
})
that.getLockList(that.lockSearch)
that.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
},
async changeUnlockApp(value) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
uni.showLoading({
title: '更新中',
mask: true
})
const { code, message } = await updateLockSettingRequest({
lockId: this.currentLockInfo.lockId,
appUnlockOnline: value
})
if (code === 0) {
this.unlockApp = value
const data = this.currentLockInfo
data.lockSetting.appUnlockOnline = value
this.updateCurrentLockInfo(data)
uni.hideLoading()
uni.showToast({
title: '更新成功',
icon: 'none'
})
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
},
async deleteLock() {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
const that = this
if (this.currentLockInfo.userType !== 110301 && this.currentLockInfo.keyRight === 1) {
this.showModal = true
return
}
const message =
that.currentLockInfo.userType === 110301
? '删除锁后,所有信息都会一起删除,确定删除锁吗?'
: '确定删除该钥匙吗?'
uni.showModal({
title: '提示',
content: message,
async success(res) {
if (res.confirm) {
uni.showLoading({
title: '删除中',
mask: true
if ($bluetooth.currentLockInfo.userType === 110301) {
const { code: resetDeviceCode } = await $bluetooth.resetDevice({
name: $bluetooth.currentLockInfo.name,
authUid: $user.userInfo.uid.toString(),
keyId: $bluetooth.keyId.toString()
})
if (resetDeviceCode === 0 || resetDeviceCode === -2) {
const { code } = await deleteLockRequest({
lockId: $bluetooth.currentLockInfo.lockId
})
if (that.currentLockInfo.userType === 110301) {
const { code: resetDeviceCode } = await that.resetDevice({
name: that.currentLockInfo.name,
authUid: that.userInfo.uid.toString(),
keyId: that.keyId.toString()
if (code === 0) {
uni.hideLoading()
$lock.updateLockSearch({
...$lock.lockSearch,
pageNo: 1
})
if (resetDeviceCode === 0 || resetDeviceCode === -2) {
const { code } = await deleteLockRequest({
lockId: that.currentLockInfo.lockId
})
if (code === 0) {
uni.hideLoading()
that.updateLockSearch({
...that.lockSearch,
pageNo: 1
})
that.getLockList(that.lockSearch)
that.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
} else if (resetDeviceCode === -1) {
uni.hideLoading()
uni.showToast({
title: '删除失败,请保持在锁附近',
icon: 'none'
})
}
$lock.getLockList($lock.lockSearch)
$basic.backAndToast('删除成功', 2)
} else {
const { code } = await deleteKeyRequest({
keyId: that.keyId
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
if (code === 0) {
uni.hideLoading()
that.updateLockSearch({
...that.lockSearch,
pageNo: 1
})
that.getLockList(that.lockSearch)
that.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
}
} else if (resetDeviceCode === -1) {
uni.hideLoading()
uni.showToast({
title: '删除失败,请保持在锁附近',
icon: 'none'
})
}
} else {
const { code } = await deleteKeyRequest({
keyId: $bluetooth.keyId
})
if (code === 0) {
uni.hideLoading()
$lock.updateLockSearch({
...$lock.lockSearch,
pageNo: 1
})
$lock.getLockList($lock.lockSearch)
$basic.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
}
})
}
}
}
})
}
</script>
@ -300,61 +335,3 @@
background-color: $uni-bg-color-grey;
}
</style>
<style lang="scss" scoped>
.button-logout {
position: absolute;
border-radius: 46rpx;
bottom: calc(env(safe-area-inset-bottom) + 30rpx);
width: 600rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
margin-left: 75rpx;
background: #ec433c;
color: #ffffff;
font-size: 40rpx;
font-weight: bold;
}
.view {
margin-top: 32rpx;
border-radius: 32rpx;
width: 710rpx;
margin-left: 20rpx;
background: #ffffff;
}
.view-button {
padding: 0 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
color: #292826;
font-size: 32rpx;
font-weight: bold;
line-height: 80rpx;
}
.view-line {
width: 100%;
height: 3rpx;
background: #ebebeb;
}
radio .wx-radio-input.wx-radio-input-checked {
border: none;
background: #c1885a;
}
radio .wx-radio-input.wx-radio-input-checked::before {
border-radius: 50%; /* 圆角 */
width: 28rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
height: 28rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
line-height: 28rpx;
text-align: center;
font-size: 20rpx; /* 对勾大小 30rpx */
color: #fff; /* 对勾颜色 白色 */
background: #c1885a;
transform: translate(-50%, -50%) scale(1);
}
</style>

108
pages/syncElec/syncElec.vue Normal file
View File

@ -0,0 +1,108 @@
<template>
<view>
<view class="mx-4 pt-5 text-base">
<view>电量信息可以通过网关远程更新或通过手机蓝牙在锁旁边更新</view>
<view class="mt-5"
>电池1电量{{ $bluetooth.currentLockSetting.lockBasicInfo.electricQuantity }}%</view
>
<view class="mt-2" v-if="$bluetooth.currentLockSetting?.lockFeature?.isSupportBackupBattery"
>电池2电量{{ $bluetooth.currentLockSetting.lockBasicInfo.electricQuantityStandby }}%</view
>
<view class="mt-2">
电量更新时间{{
timeFormat(
$bluetooth.currentLockSetting.lockBasicInfo.electricQuantityDate,
'yyyy-mm-dd h:M'
)
}}
</view>
<view
@click="updateElectricQuantity"
class="w-full bg-#63b8af text-white line-height-80rpx h-80 rounded-40rpx text-center mt-4 text-lg font-bold"
>更新</view
>
</view>
</view>
</template>
<script setup>
import { timeFormat } from 'uview-plus'
import { ref } from 'vue'
import { useBluetoothStore } from '@/stores/bluetooth'
import { useUserStore } from '@/stores/user'
import { updateElectricQuantityRequest } from '@/api/room'
const $bluetooth = useBluetoothStore()
const $user = useUserStore()
const pending = ref(false)
const updateElectricQuantity = async () => {
if (pending.value) return
uni.showLoading({
title: '更新中'
})
pending.value = true
const { code } = await $bluetooth.updateServerTimestamp()
if (code === 0) {
const date = new Date()
const timestamp = $bluetooth.serverTimestamp - date.getTimezoneOffset() * 60
const { code: lockStatus, data } = await $bluetooth.getLockStatus({
name: $bluetooth.currentLockInfo.lockId.toString(),
uid: $user.userInfo.uid.toString(),
nowTime: $bluetooth.serverTimestamp,
localTime: timestamp
})
$bluetooth.closeBluetoothConnection()
if (lockStatus === 0) {
const { code: resultCode, data: resultData } = await updateElectricQuantityRequest({
lockId: $bluetooth.currentLockInfo.lockId,
electricQuantity: data.lockConfig.electricQuantity,
electricQuantityStandby: data.lockConfig.electricQuantityStandby
})
uni.hideLoading()
pending.value = false
if (resultCode === 0) {
$bluetooth.updateCurrentLockInfo({
...$bluetooth.currentLockInfo,
electricQuantity: data.lockConfig.electricQuantity,
electricQuantityStandby: data.lockConfig.electricQuantityStandby,
electricQuantityDate: resultData.electricQuantityDate
})
$bluetooth.updateCurrentLockSetting({
...$bluetooth.currentLockSetting,
lockBasicInfo: {
...$bluetooth.currentLockSetting.lockBasicInfo,
electricQuantity: data.lockConfig.electricQuantity,
electricQuantityStandby: data.lockConfig.electricQuantityStandby,
electricQuantityDate: resultData.electricQuantityDate
}
})
uni.showToast({
title: '更新成功',
icon: 'none'
})
} else {
uni.showToast({
title: '更新失败',
icon: 'none'
})
}
} else {
uni.hideLoading()
pending.value = false
uni.showToast({
title: '更新失败',
icon: 'none'
})
}
} else {
uni.hideLoading()
pending.value = false
uni.showToast({
title: '更新失败',
icon: 'none'
})
}
}
</script>

View File

@ -251,6 +251,21 @@ const pages = [
name: 'temporaryDate',
path: '/pages/temporaryDate/temporaryDate',
tabBar: false
},
{
name: 'lockInfo',
path: '/pages/lockInfo/lockInfo',
tabBar: false
},
{
name: 'syncElec',
path: '/pages/syncElec/syncElec',
tabBar: false
},
{
name: 'selectGroup',
path: '/pages/selectGroup/selectGroup',
tabBar: false
}
]

View File

@ -84,7 +84,9 @@ const subCmdIds = {
// 注册掌纹取消
registerPalmVeinCancel: 44,
// 同步操作记录
syncRecord: 41
syncRecord: 41,
// 更新管理员密码
updateAdminPassword: 2
}
export const useBluetoothStore = defineStore('ble', {
@ -103,6 +105,8 @@ export const useBluetoothStore = defineStore('ble', {
deviceList: [],
// 当前锁信息
currentLockInfo: {},
// 当前锁设置信息
currentLockSetting: null,
// 消息序号
messageCount: 1,
// 是否初始化蓝牙
@ -354,11 +358,16 @@ export const useBluetoothStore = defineStore('ble', {
),
lockConfig
})
characteristicValueCallback({
code: decrypted[2],
data: { lockConfig }
})
console.log('获取锁状态成功', that.currentLockInfo.lockConfig)
} else {
characteristicValueCallback({
code: decrypted[2]
})
}
characteristicValueCallback({
code: decrypted[2]
})
break
case cmdIds.addUser:
that.updateCurrentLockInfo({
@ -505,6 +514,15 @@ export const useBluetoothStore = defineStore('ble', {
characteristicValueCallback({ code: decrypted[2] })
}
break
case subCmdIds.updateAdminPassword:
that.updateCurrentLockInfo({
...that.currentLockInfo,
token: decrypted.slice(5, 9)
})
characteristicValueCallback({
code: decrypted[2]
})
break
default:
break
}
@ -512,7 +530,9 @@ export const useBluetoothStore = defineStore('ble', {
case cmdIds.openDoor:
that.updateCurrentLockInfo({
...that.currentLockInfo,
token: decrypted.slice(2, 6)
token: decrypted.slice(2, 6),
electricQuantity: decrypted[7],
electricQuantityStandby: decrypted[9]
})
console.log('开门', decrypted[6], that.currentLockInfo.token)
log.info({
@ -884,6 +904,11 @@ export const useBluetoothStore = defineStore('ble', {
console.log('更新当前锁信息', lockInfo)
this.currentLockInfo = lockInfo
},
// 更新当前锁设置信息
updateCurrentLockSetting(lockSetting) {
console.log('更新当前锁设置信息', lockSetting)
this.currentLockSetting = lockSetting
},
// 订阅设备特征值改变
notifyBluetoothCharacteristicValueChange() {
const that = this
@ -2612,6 +2637,102 @@ export const useBluetoothStore = defineStore('ble', {
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.syncSingleRecord, data)
},
// 更新管理员密码
async updateAdminPassword(data) {
// 确认蓝牙状态正常
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
if (!this.currentLockInfo.connected) {
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
if (!result) {
return {
code: -1
}
}
}
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (!checkResult) {
return {
code: -1
}
}
let { keyId, uid, adminPwd, userCountLimit, startDate, endDate } = data
const length = 2 + 1 + 1 + 40 + 20 + 2 + 20 + 2 + 4 + 4 + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.expandCmd / 256
contentArray[1] = cmdIds.expandCmd % 256
contentArray[2] = subCmdIds.updateAdminPassword
contentArray[3] = length - 3
for (let i = 0; i < keyId.length; i++) {
contentArray[i + 4] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
contentArray[i + 44] = uid.charCodeAt(i)
}
contentArray[64] = 1 / 256
contentArray[65] = 1 % 256
for (let i = 0; i < adminPwd.length; i++) {
contentArray[i + 66] = adminPwd.charCodeAt(i)
}
contentArray[86] = (userCountLimit || 0xffff) / 256
contentArray[87] = (userCountLimit || 0xffff) % 256
contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 88)
contentArray.set(this.timestampToArray(startDate), 92)
contentArray.set(this.timestampToArray(endDate), 96)
contentArray[100] = 16
const md5Array = this.md5Encrypte(
keyId + uid,
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.currentLockInfo.signKey
)
contentArray.set(md5Array, 101)
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.updateAdminPassword, data)
}
}
})