662 lines
19 KiB
Vue
662 lines
19 KiB
Vue
<template>
|
||
<view>
|
||
<view class="tabs">
|
||
<up-tabs
|
||
:list="tabs"
|
||
lineWidth="40rpx"
|
||
lineHeight="5rpx"
|
||
:current="currentIndex"
|
||
lineColor="#63b8af"
|
||
@click="clickTab"
|
||
:inactiveStyle="{ color: '#a3a3a3', fontSize: '32rpx', fontWeight: 'bold' }"
|
||
:activeStyle="{ color: '#63b8af', fontSize: '32rpx', fontWeight: 'bold' }"
|
||
>
|
||
</up-tabs>
|
||
</view>
|
||
<swiper
|
||
:style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top - 44 + 'px' }"
|
||
v-if="deviceInfo"
|
||
:list="tabs"
|
||
:autoplay="false"
|
||
:circular="true"
|
||
:current="currentIndex"
|
||
@change="changeSwiper"
|
||
>
|
||
<swiper-item>
|
||
<LockInput
|
||
:value="permanentName"
|
||
title="姓名"
|
||
placeholder="请给密码命名"
|
||
@change-input="changeName('permanent', $event)"
|
||
></LockInput>
|
||
<view class="text">{{ text }}</view>
|
||
<view class="button" @click="createPassword('permanent')">获取密码</view>
|
||
</swiper-item>
|
||
<swiper-item>
|
||
<LockInput
|
||
:value="temporaryName"
|
||
title="姓名"
|
||
placeholder="请给密码命名"
|
||
@change-input="changeName('temporary', $event)"
|
||
></LockInput>
|
||
<view style="margin-top: 20rpx">
|
||
<LockDateHourPicker
|
||
title="失效时间"
|
||
:value="temporaryTime"
|
||
:minDate="minDate"
|
||
:maxDate="maxDate"
|
||
type="datehour"
|
||
@change-time="changeTemporaryTime"
|
||
></LockDateHourPicker>
|
||
</view>
|
||
<view class="text">{{ text }}</view>
|
||
<view class="button" @click="createPassword('temporary')">获取密码</view>
|
||
</swiper-item>
|
||
<swiper-item>
|
||
<LockInput
|
||
:value="singleName"
|
||
title="姓名"
|
||
placeholder="请给密码命名"
|
||
@change-input="changeName('single', $event)"
|
||
></LockInput>
|
||
<view class="text">密码有效期为6个小时,只能使用一次</view>
|
||
<view class="button" @click="createPassword('single')">获取密码</view>
|
||
</swiper-item>
|
||
<swiper-item>
|
||
<LockInput
|
||
:value="customName"
|
||
title="姓名"
|
||
placeholder="请给密码命名"
|
||
@change-input="changeName('custom', $event)"
|
||
></LockInput>
|
||
<LockInput
|
||
:value="customPassword"
|
||
title="密码"
|
||
placeholder="请输入6-9位数字"
|
||
:maxlength="9"
|
||
type="number"
|
||
@change-input="changePassword('custom', $event)"
|
||
></LockInput>
|
||
<view class="mt-3 border-b-2 border-b-solid border-b-gray-200">
|
||
<LockSwitch
|
||
:value="customPermanent"
|
||
title="永久"
|
||
@change="changePermanent('custom', $event)"
|
||
></LockSwitch>
|
||
</view>
|
||
<view v-if="!customPermanent" class="border-b-2 border-b-solid border-b-gray-200">
|
||
<LockDatetimePicker
|
||
title="生效时间"
|
||
:value="customStartTime"
|
||
@change-time="changeDate('customStartTime', $event)"
|
||
></LockDatetimePicker>
|
||
</view>
|
||
<view v-if="!customPermanent">
|
||
<LockDatetimePicker
|
||
title="失效时间"
|
||
:value="customEndTime"
|
||
@change-time="changeDate('customEndTime', $event)"
|
||
></LockDatetimePicker>
|
||
</view>
|
||
<view class="mt-3">
|
||
<LockSwitch
|
||
:value="customAdmin"
|
||
title="是否为管理员"
|
||
@change="changeAdmin('custom', $event)"
|
||
></LockSwitch>
|
||
</view>
|
||
<view class="text">
|
||
手动输入6-9位数字作为密码。可在锁旁边通过手机蓝牙添加,也可通过网关远程添加
|
||
</view>
|
||
<view class="button" @click="createPassword('custom')">获取密码</view>
|
||
</swiper-item>
|
||
<swiper-item>
|
||
<LockInput
|
||
:value="cycleName"
|
||
title="姓名"
|
||
placeholder="请给密码命名"
|
||
@change-input="changeName('cycle', $event)"
|
||
></LockInput>
|
||
<view style="margin-top: 20rpx" class="border-b-2 border-b-solid border-b-gray-200">
|
||
<view
|
||
@click="showCycle = true"
|
||
class="flex items-center bg-white font-bold text-base h-100 w-full"
|
||
>
|
||
<view class="w-168 ml-4 leading-[100rpx]">有效日</view>
|
||
<view class="ml-a mr-2 flex items-center">
|
||
<view class="mr-2 text-right w-[518rpx] h-100 leading-[100rpx]"
|
||
>{{ cycleOptions[0][defaultIndex].name }}
|
||
</view>
|
||
<up-icon name="arrow-right"></up-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="border-b-2 border-b-solid border-b-gray-200">
|
||
<view
|
||
@click="showHoursStart = true"
|
||
class="flex items-center bg-white font-bold text-base h-100 w-full"
|
||
>
|
||
<view class="w-168 ml-4 leading-[100rpx]">生效时间</view>
|
||
<view class="ml-a mr-2 flex items-center">
|
||
<view class="mr-2 text-right w-[518rpx] h-100 leading-[100rpx]"
|
||
>{{ hoursStart }}:00
|
||
</view>
|
||
<up-icon name="arrow-right"></up-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view>
|
||
<view
|
||
@click="showHoursEnd = true"
|
||
class="flex items-center bg-white font-bold text-base h-100 w-full"
|
||
>
|
||
<view class="w-168 ml-4 leading-[100rpx]">失效时间</view>
|
||
<view class="ml-a mr-2 flex items-center">
|
||
<view class="mr-2 text-right w-[518rpx] h-100 leading-[100rpx]">
|
||
{{ hoursEnd }}:00</view
|
||
>
|
||
<up-icon name="arrow-right"></up-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="text">{{ text }}</view>
|
||
<view class="button" @click="createPassword('cycle')">获取密码</view>
|
||
</swiper-item>
|
||
<swiper-item>
|
||
<LockInput
|
||
:value="emptyName"
|
||
title="姓名"
|
||
placeholder="请给密码命名"
|
||
@change-input="changeName('empty', $event)"
|
||
></LockInput>
|
||
<view class="text">
|
||
<view>清空密码当日23:59前有效</view>
|
||
<view>
|
||
清空内容1:当日0点前生成的所有密码(当日0点后生成的密码,不受清空密码影响,可继续使用)
|
||
</view>
|
||
<view>清空内容2:清空密码使用后,立即清除所有自定义密码(含使用过和未使用过的)</view>
|
||
<view>如需彻底清除所有密码,请使用重置所有密码功能</view></view
|
||
>
|
||
<view class="button" @click="createPassword('empty')">获取密码</view>
|
||
</swiper-item>
|
||
</swiper>
|
||
<up-picker
|
||
:show="showCycle"
|
||
:columns="cycleOptions"
|
||
keyName="name"
|
||
:defaultIndex="[defaultIndex]"
|
||
@close="showCycle = false"
|
||
closeOnClickOverlay
|
||
@cancel="showCycle = false"
|
||
@confirm="selectCycle"
|
||
></up-picker>
|
||
<up-picker
|
||
:show="showHoursStart"
|
||
:columns="hours"
|
||
:defaultIndex="[hoursStart]"
|
||
closeOnClickOverlay
|
||
@close="showHoursStart = false"
|
||
@cancel="showHoursStart = false"
|
||
@confirm="selectHours('start', $event)"
|
||
></up-picker>
|
||
<up-picker
|
||
:show="showHoursEnd"
|
||
:columns="hours"
|
||
:defaultIndex="[hoursEnd]"
|
||
closeOnClickOverlay
|
||
@close="showHoursEnd = false"
|
||
@cancel="showHoursEnd = false"
|
||
@confirm="selectHours('end', $event)"
|
||
></up-picker>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { timeFormat } from 'uview-plus'
|
||
import { onMounted, ref } from 'vue'
|
||
import test from 'uview-plus/libs/function/test'
|
||
import { useBasicStore } from '@/stores/basic'
|
||
import LockInput from '@/components/LockInput/LockInput.vue'
|
||
import LockDateHourPicker from '@/components/LockDateHourPicker/LockDateHourPicker.vue'
|
||
import { addCustomPasswordRequest, createPsaawordRequest } from '@/api/keyboardPwd'
|
||
import { useBluetoothStore } from '@/stores/bluetooth'
|
||
import { useLockStore } from '@/stores/lock'
|
||
import { useUserStore } from '@/stores/user'
|
||
|
||
const $lock = useLockStore()
|
||
const $basic = useBasicStore()
|
||
const $bluetooth = useBluetoothStore()
|
||
const $user = useUserStore()
|
||
|
||
const tabs = [
|
||
{
|
||
name: '永久'
|
||
},
|
||
{
|
||
name: '限时'
|
||
},
|
||
{
|
||
name: '单次'
|
||
},
|
||
{
|
||
name: '自定义'
|
||
},
|
||
{
|
||
name: '循环'
|
||
},
|
||
{
|
||
name: '清空'
|
||
}
|
||
]
|
||
const cycleOptions = ref([
|
||
[
|
||
{ type: 5, name: '周末' },
|
||
{ type: 6, name: '每日' },
|
||
{ type: 7, name: '工作日' },
|
||
{ type: 8, name: '星期一' },
|
||
{ type: 9, name: '星期二' },
|
||
{ type: 10, name: '星期三' },
|
||
{ type: 11, name: '星期四' },
|
||
{ type: 12, name: '星期五' },
|
||
{ type: 13, name: '星期六' },
|
||
{ type: 14, name: '星期日' }
|
||
]
|
||
])
|
||
const defaultIndex = ref(0)
|
||
const showCycle = ref(false)
|
||
const showHoursStart = ref(false)
|
||
const showHoursEnd = ref(false)
|
||
const hours = ref([Array.from({ length: 25 }, (v, k) => `${k}时`)])
|
||
const permanentName = ref('')
|
||
const temporaryName = ref('')
|
||
const singleName = ref('')
|
||
const customName = ref('')
|
||
const cycleName = ref('')
|
||
const emptyName = ref('')
|
||
const temporaryTime = ref(Number(new Date()))
|
||
const customPermanent = ref(true)
|
||
const customStartTime = ref(0)
|
||
const customEndTime = ref(0)
|
||
const customAdmin = ref(false)
|
||
const customPassword = ref('')
|
||
const hoursStart = ref(0)
|
||
const hoursEnd = ref(0)
|
||
const minDate = ref(Number(new Date()))
|
||
const maxDate = ref(Number(4133951940000))
|
||
const currentIndex = ref(0)
|
||
const deviceInfo = ref(null)
|
||
const pending = ref(false)
|
||
const text = ref(
|
||
'密码生成后,请在当日23:59前使用一次进行激活,否则过0点后未激活则失效。密码激活后,有效期内不限次数使用。'
|
||
)
|
||
|
||
onMounted(async () => {
|
||
deviceInfo.value = await $basic.getDeviceInfo()
|
||
temporaryTime.value = Number(getNextFullHour())
|
||
hoursStart.value = Number(timeFormat(getNextFullHour(), 'h')) - 1
|
||
hoursEnd.value = Number(timeFormat(getNextFullHour(), 'h'))
|
||
minDate.value = Number(getNextFullHour())
|
||
maxDate.value = Number(getFutureTimestamp())
|
||
})
|
||
|
||
const changePassword = (type, e) => {
|
||
if (type === 'custom') {
|
||
customPassword.value = e
|
||
}
|
||
}
|
||
|
||
const selectCycle = e => {
|
||
showCycle.value = false
|
||
defaultIndex.value = e.indexs[0]
|
||
}
|
||
|
||
const changePermanent = (type, e) => {
|
||
if (type === 'custom') {
|
||
customPermanent.value = e.detail.value
|
||
if (customPermanent.value) {
|
||
customStartTime.value = 0
|
||
customEndTime.value = 0
|
||
} else {
|
||
customStartTime.value = new Date().getTime()
|
||
customEndTime.value = new Date().getTime()
|
||
}
|
||
}
|
||
}
|
||
|
||
const changeAdmin = (type, e) => {
|
||
if (type === 'custom') {
|
||
customAdmin.value = e.detail.value
|
||
}
|
||
}
|
||
|
||
const changeDate = (type, e) => {
|
||
if (type === 'customStartTime') {
|
||
customStartTime.value = e
|
||
} else {
|
||
customEndTime.value = e
|
||
}
|
||
}
|
||
|
||
const selectHours = (type, e) => {
|
||
if (type === 'start') {
|
||
showHoursStart.value = false
|
||
hoursStart.value = e.indexs[0]
|
||
} else {
|
||
showHoursEnd.value = false
|
||
hoursEnd.value = e.indexs[0]
|
||
}
|
||
}
|
||
|
||
const getNextFullHour = () => {
|
||
const now = new Date()
|
||
const currentHour = now.getHours() + 1
|
||
now.setHours(currentHour)
|
||
now.setMinutes(0)
|
||
now.setSeconds(0)
|
||
now.setMilliseconds(0)
|
||
|
||
return now
|
||
}
|
||
|
||
const getFutureTimestamp = () => {
|
||
const currentDate = new Date()
|
||
|
||
const year = currentDate.getFullYear()
|
||
const month = currentDate.getMonth()
|
||
const day = currentDate.getDate()
|
||
|
||
const futureDate = new Date(year + 3, month, day, 23, 0, 0)
|
||
|
||
return futureDate.getTime()
|
||
}
|
||
|
||
const createPassword = async type => {
|
||
if (
|
||
(type === 'temporary' && temporaryName.value === '') ||
|
||
(type === 'permanent' && permanentName.value === '') ||
|
||
(type === 'single' && singleName.value === '') ||
|
||
(type === 'cycle' && cycleName.value === '') ||
|
||
(type === 'empty' && emptyName.value === '') ||
|
||
(type === 'custom' && customName.value === '')
|
||
) {
|
||
uni.showToast({
|
||
title: '名称不能为空',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
if (type === 'custom' && !test.rangeLength(customPassword.value, [6, 9])) {
|
||
uni.showToast({
|
||
title: '密码为6-9位纯数字',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
if (
|
||
type === 'custom' &&
|
||
customPermanent.value === false &&
|
||
customStartTime.value >= customEndTime.value
|
||
) {
|
||
uni.showToast({
|
||
title: '失效时间需晚于生效时间',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
if (type === 'cycle' && hoursStart.value >= hoursEnd.value) {
|
||
uni.showToast({
|
||
title: '失效时间需晚于生效时间',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
const netWork = await $basic.getNetworkType()
|
||
if (!netWork) {
|
||
return
|
||
}
|
||
|
||
if (pending.value) {
|
||
return
|
||
}
|
||
pending.value = true
|
||
|
||
if (type === 'custom') {
|
||
uni.showLoading({
|
||
title: '生成中'
|
||
})
|
||
const params = {
|
||
keyId: $bluetooth.keyId.toString(),
|
||
uid: $user.userInfo.uid.toString(),
|
||
pwdNo: 0,
|
||
operate: 0,
|
||
isAdmin: customAdmin.value ? 1 : 0,
|
||
pwd: customPassword.value,
|
||
userCountLimit: 0xffff,
|
||
startTime: Math.floor(customStartTime.value / 1000),
|
||
endTime: Math.floor(customEndTime.value / 1000)
|
||
}
|
||
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,
|
||
addType: 1,
|
||
pwdUserNo: data.no,
|
||
pwdRight: customAdmin.value ? 1 : 0,
|
||
keyboardPwdType: customPermanent.value ? 2 : 3,
|
||
keyboardPwdName: customName.value,
|
||
keyboardPwd: customPassword.value,
|
||
startDate: customStartTime.value,
|
||
endDate: customEndTime.value
|
||
})
|
||
uni.hideLoading()
|
||
if (requestCode === 0) {
|
||
uni.reportEvent('create_password', {})
|
||
$lock.updatePasswordSearch({
|
||
...$lock.passwordSearch,
|
||
pageNo: 1
|
||
})
|
||
$lock.getPasswordList($lock.passwordSearch)
|
||
uni.showModal({
|
||
title: '密码生成成功',
|
||
content: `密码:${customPassword.value}`,
|
||
cancelText: '复制',
|
||
success: res => {
|
||
if (res.confirm) {
|
||
uni.navigateBack()
|
||
} else {
|
||
uni.setClipboardData({
|
||
data: customPassword.value,
|
||
success: () => {
|
||
$basic.backAndToast('复制成功')
|
||
}
|
||
})
|
||
}
|
||
}
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: message,
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} else {
|
||
uni.hideLoading()
|
||
if (data.status === 0xff) {
|
||
uni.showToast({
|
||
title: '创建失败',
|
||
icon: 'none'
|
||
})
|
||
} else if (data.status === 0xfe) {
|
||
uni.showToast({
|
||
title: '管理员已满',
|
||
icon: 'none'
|
||
})
|
||
} else if (data.status === 0xfd) {
|
||
uni.showToast({
|
||
title: '用户已满',
|
||
icon: 'none'
|
||
})
|
||
} else if (data.status === 0xfc) {
|
||
uni.showToast({
|
||
title: '密码已满',
|
||
icon: 'none'
|
||
})
|
||
} else if (data.status === 0xfb) {
|
||
uni.showToast({
|
||
title: '密码已存在',
|
||
icon: 'none'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: '创建失败,请保持在锁附近',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
} else {
|
||
let params = {
|
||
lockId: $bluetooth.currentLockInfo.lockId,
|
||
isCoerced: 2,
|
||
pwdRight: 0
|
||
}
|
||
if (type === 'temporary') {
|
||
params.keyboardPwdName = temporaryName.value
|
||
params.keyboardPwdType = 3
|
||
params.startDate = new Date().setHours(0, 0, 0, 0)
|
||
params.endDate = temporaryTime.value
|
||
params.hoursStart = 0
|
||
params.hoursEnd = 0
|
||
} else if (type === 'permanent') {
|
||
params.startDate = 0
|
||
params.endDate = 0
|
||
params.keyboardPwdName = permanentName.value
|
||
params.keyboardPwdType = 2
|
||
params.hoursStart = 0
|
||
params.hoursEnd = 0
|
||
} else if (type === 'single') {
|
||
params.startDate = 0
|
||
params.endDate = 0
|
||
params.keyboardPwdName = singleName.value
|
||
params.keyboardPwdType = 1
|
||
params.hoursStart = 0
|
||
params.hoursEnd = 0
|
||
} else if (type === 'cycle') {
|
||
params.startDate = new Date().getTime()
|
||
params.endDate = new Date().getTime()
|
||
params.keyboardPwdName = cycleName.value
|
||
params.keyboardPwdType = cycleOptions.value[0][defaultIndex.value].type
|
||
params.hoursStart = hoursStart.value
|
||
params.hoursEnd = hoursEnd.value
|
||
} else {
|
||
params.startDate = 0
|
||
params.endDate = 0
|
||
params.keyboardPwdName = emptyName.value
|
||
params.keyboardPwdType = 4
|
||
params.hoursStart = 0
|
||
params.hoursEnd = 0
|
||
}
|
||
const { code, data, message } = await createPsaawordRequest(params)
|
||
if (code === 0) {
|
||
uni.reportEvent('create_password', {})
|
||
$lock.updatePasswordSearch({
|
||
...$lock.passwordSearch,
|
||
pageNo: 1
|
||
})
|
||
$lock.getPasswordList($lock.passwordSearch)
|
||
uni.showModal({
|
||
title: '密码生成成功',
|
||
content: `密码:${data.keyboardPwd}`,
|
||
cancelText: '复制',
|
||
success: res => {
|
||
if (res.confirm) {
|
||
uni.navigateBack()
|
||
} else {
|
||
uni.setClipboardData({
|
||
data: data.keyboardPwd,
|
||
success: () => {
|
||
$basic.backAndToast('复制成功')
|
||
}
|
||
})
|
||
}
|
||
}
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: message,
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
|
||
pending.value = false
|
||
}
|
||
|
||
const changeName = (type, e) => {
|
||
if (type === 'temporary') {
|
||
temporaryName.value = e
|
||
} else if (type === 'permanent') {
|
||
permanentName.value = e
|
||
} else if (type === 'single') {
|
||
singleName.value = e
|
||
} else if (type === 'cycle') {
|
||
cycleName.value = e
|
||
} else if (type === 'custom') {
|
||
customName.value = e
|
||
} else if (type === 'empty') {
|
||
emptyName.value = e
|
||
}
|
||
}
|
||
|
||
const changeTemporaryTime = e => {
|
||
temporaryTime.value = e
|
||
}
|
||
|
||
const clickTab = data => {
|
||
currentIndex.value = data.index
|
||
}
|
||
|
||
const changeSwiper = e => {
|
||
currentIndex.value = e.detail.current
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
background-color: $uni-bg-color-grey;
|
||
}
|
||
</style>
|
||
|
||
<style lang="scss" scoped>
|
||
.tabs {
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.text {
|
||
margin-top: 40rpx;
|
||
margin-bottom: 50rpx;
|
||
color: #262626;
|
||
font-size: 26rpx;
|
||
padding: 0 32rpx;
|
||
}
|
||
|
||
.button {
|
||
border-radius: 64rpx;
|
||
width: 686rpx;
|
||
margin-left: 32rpx;
|
||
height: 100rpx;
|
||
line-height: 100rpx;
|
||
text-align: center;
|
||
background-color: #63b8af;
|
||
color: #fff;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
}
|
||
</style>
|