2024-06-21 11:40:32 +08:00
|
|
|
<script setup lang="ts">
|
|
|
|
import { defineProps, defineEmits, ref, watch, computed } from 'vue';
|
|
|
|
const props = defineProps({
|
|
|
|
visible: { type: Boolean, default: () => true },
|
|
|
|
random: { type: Boolean, default: () => true },
|
|
|
|
num: { type: Number, default: () => 6 },
|
|
|
|
title: { type: String }
|
|
|
|
});
|
|
|
|
const emits = defineEmits<{
|
|
|
|
(event : 'update:visible', value : boolean);
|
|
|
|
(event : 'complete', value : string);
|
|
|
|
(event : 'close');
|
|
|
|
}>();
|
|
|
|
const tplInputs = computed(() => {
|
|
|
|
return Array(props.num).fill(0);
|
|
|
|
});
|
|
|
|
const refKeys = ref([]);
|
|
|
|
const makeKeys = () => {
|
|
|
|
refKeys.value = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'].sort(() => (props.random ? 0.5 - Math.random() : 0)).concat('删除');
|
|
|
|
refKeys.value.splice(9, 0, '清空');
|
|
|
|
};
|
|
|
|
watch(
|
|
|
|
() => props.visible,
|
|
|
|
newValue => {
|
|
|
|
if (newValue) {
|
|
|
|
makeKeys();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{ immediate: true }
|
|
|
|
);
|
|
|
|
const refValue = ref([]);
|
|
|
|
const handleKeyClick = (key : string | number) => {
|
|
|
|
switch (key.toLowerCase()) {
|
|
|
|
case '清空':
|
|
|
|
refValue.value = [];
|
|
|
|
break;
|
|
|
|
case '删除':
|
|
|
|
refValue.value.pop();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (refValue.value.length < props.num) {
|
|
|
|
refValue.value.push(key);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2024-06-26 14:32:27 +08:00
|
|
|
uni.vibrateShort();
|
2024-06-21 11:40:32 +08:00
|
|
|
if (refValue.value.length === props.num) {
|
|
|
|
emits('complete', refValue.value.join(''));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleClose = $event => {
|
|
|
|
handleKeyClick('c');
|
|
|
|
emits('update:visible', false);
|
|
|
|
emits('close');
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<uni-transition :show="props.visible">
|
|
|
|
<view class="zy-passwordboard" @click="handleClose">
|
|
|
|
<uni-transition :show="props.visible">
|
|
|
|
<view class="zy-passwordboard__board" @click.stop>
|
|
|
|
<uni-transition :mode-class="['slide-bottom']" :show="props.visible">
|
|
|
|
<view class="title" v-if="props.title">{{ props.title }}</view>
|
|
|
|
<view class="inputs">
|
|
|
|
<view class="input" v-for="(input, inputi) in tplInputs" :key="inputi"><text class="text"
|
|
|
|
:class="{ filled: refValue[inputi] }"></text></view>
|
|
|
|
</view>
|
|
|
|
<view class="keys">
|
|
|
|
<view class="key" v-for="key in refKeys" :key="key">
|
|
|
|
<text class="text" :class="[`key-${key}`]" @click="handleKeyClick(key)">{{ key }}</text>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</uni-transition>
|
|
|
|
</view>
|
|
|
|
</uni-transition>
|
|
|
|
</view>
|
|
|
|
</uni-transition>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
view,
|
|
|
|
text {
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
|
|
|
|
.zy-passwordboard {
|
|
|
|
box-sizing: border-box;
|
|
|
|
position: fixed;
|
|
|
|
z-index: 999;
|
|
|
|
top: 0;
|
|
|
|
bottom: 0;
|
|
|
|
bottom: constant(safe-area-inset-bottom);
|
|
|
|
bottom: env(safe-area-inset-bottom);
|
|
|
|
left: 0;
|
|
|
|
right: 0;
|
|
|
|
background-color: var(--bg-color, rgba(0, 0, 0, 0.3));
|
|
|
|
|
|
|
|
&__board {
|
|
|
|
position: absolute;
|
|
|
|
left: 0;
|
|
|
|
right: 0;
|
|
|
|
bottom: 0;
|
|
|
|
// padding: 10rpx;
|
|
|
|
background-color: white;
|
|
|
|
backdrop-filter: blur(2rpx);
|
|
|
|
border-radius: 30rpx 30rpx 0 0;
|
|
|
|
|
|
|
|
.title {
|
|
|
|
padding: 20rpx;
|
|
|
|
text-align: center;
|
|
|
|
color: #000000;
|
|
|
|
font-size: 35rpx;
|
|
|
|
padding-bottom: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.inputs {
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
padding-top: 40rpx;
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.input {
|
|
|
|
padding: 10rpx;
|
|
|
|
|
|
|
|
.text {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
width: 80rpx;
|
|
|
|
height: 80rpx;
|
|
|
|
background-color: #ffffff;
|
|
|
|
border-radius: 20rpx;
|
|
|
|
background-color: #E6E6E6;
|
|
|
|
|
|
|
|
&.filled:before {
|
|
|
|
content: '';
|
|
|
|
width: 30%;
|
|
|
|
height: 30%;
|
|
|
|
border-radius: 50%;
|
|
|
|
background-color: #000000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.keys {
|
|
|
|
width: 101vw;
|
|
|
|
display: flex;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
background-color: white;
|
|
|
|
|
|
|
|
.key {
|
|
|
|
flex: 0 1 33%;
|
|
|
|
padding: 10rpx;
|
|
|
|
border: 1px solid #E6E6E6;
|
|
|
|
|
|
|
|
.text {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
padding: 20rpx 10rpx;
|
|
|
|
background-color: #ffffff;
|
|
|
|
border-radius: 20rpx;
|
|
|
|
font-size: 34rpx;
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
|
|
&.key- {
|
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|