officialAccount/pages/login/code.vue

524 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="login-container">
<view class="title">
<image class="title-imge" src="/static/index/nu.png" />
<view class="title-font">
<view class="">您好</view>
<view class="">欢迎使用护理单元~</view>
</view>
</view>
<image class="photo-imge" src="/static/index/bgc.png" />
<image class="old-imge" src="/static/index/old.png" />
<view class="under-container">
<view class="under-container-title">
<view class="code-title">
请输入验证码
</view>
<view class="code-number">
验证码已发送至{{ mobile }}
</view>
</view>
<view class="captcha-container">
<view class="captcha-box">
<view v-for="(digit, index) in captcha" :key="index" class="captcha-item">
<input v-model="captcha[index]" class="captcha-input" type="number" maxlength="4"
:placeholder="index < 3 ? '' : ' '" @input="handleInput(index, $event)"
@keydown="handleKeydown(index, $event)" :focus="focusedIndex === index" />
</view>
</view>
</view>
<view class="under-view">
<view class="right-blue" v-show="!countdown" @click="getcode">
重新发送
</view>
<view class="right-white" v-show="countdown">
{{countdown}}S后重新发送
</view>
<view class="right-black" @click="isFadingOut=true">
收不到验证码
</view>
</view>
</view>
<!-- 遮罩 -->
<transition name="fade">
<view v-if="isFadingOut" class="overlay" @click="closeModal" :style="{ backgroundColor: maskColor }" />
</transition>
<!-- 底部弹窗 -->
<transition name="slide-up">
<view v-if="isFadingOut" class="modal">
<view class="modal-title">收不到验证码</view>
<view class="model-p">
<view class="text-view" style="font-weight: 600;">手机号可正常使用:</view>
<view class="text-view">1 是否输错手机号</view>
<view class="text-view">2 手机是否设置短信拦截/欠费/信号不好</view>
<view class="text-view">3 手机内存是否满了</view>
<view class="text-view">4 手机卡是否为物联卡而非SIM卡</view>
</view>
</view>
</transition>
</view>
</template>
<script setup>
import {
nextTick,
reactive,
ref,
onUnmounted
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
smsCode,
checkPhoneCode
} from "@/api/loginApi.js"
const mobile = ref("")
const hkcode = ref("")
const captcha = ref(['', '', '', '']); // 用来存储4个小方块的验证码输入
const focusedIndex = ref(-1); // 当前聚焦的小方块索引
const isFadingOut = ref(false);
// 遮罩色rgba 可调透明度
const maskColor = ref('rgba(0, 0, 0, 0.5)')
function closeModal() {
isFadingOut.value = false
}
function filterToSingleDigit(number) {
if (typeof number === 'number') {
return number % 10; // 只保留个位数
}
return number; // 如果不是 number原样返回
}
// 输入框输入时的处理函数
const handleInput = (index, event) => {
const val = event.detail.value || ''
console.log("??????", event)
if (val.length == 4) {
// 1. 转成字符串,并补足前导 0 到 4 位
const codeStr = event.detail.value.toString().padStart(4, '0') // "0123"
captcha.value = codeStr.split('')
focusedIndex.value = 3
nextTick(() => {
submitCaptcha()
})
} else if (val.length == 2) {
captcha.value[index] = filterToSingleDigit(captcha.value[index])
if (captcha.value[index]) {
if (index < 3) {
focusedIndex.value = index + 1; // 输入后自动聚焦到下一个小方块
}
}
let isFour = true;
captcha.value.forEach(number => {
if (!number) {
isFour = false;
}
})
nextTick(() => {
if (isFour) {
submitCaptcha()
}
})
} else {
if (captcha.value[index]) {
if (index < 3) {
focusedIndex.value = index + 1; // 输入后自动聚焦到下一个小方块
}
}
let isFour = true;
captcha.value.forEach(number => {
if (!number) {
isFour = false;
}
})
nextTick(() => {
if (isFour) {
submitCaptcha()
}
})
}
};
// 处理删除键
const handleKeydown = (index, event) => {
if (event.key === 'Backspace' && !captcha.value[index]) {
if (index > 0) {
focusedIndex.value = index - 1; // 如果当前小方块为空,则聚焦到前一个小方块
}
}
};
const rightCode = ref("")
// 提交验证码
const submitCaptcha = () => {
const code = captcha.value.join('');
if (code.length === 4) {
console.log('提交验证码:', code);
if (rightCode.value != code) {
rightCode.value = code;
checkPhoneCode({
mobile: mobile.value,
openId : uni.getStorageSync('openid').openid,
smscode: code
}).then(res => {
if (res.success) {
uni.redirectTo({
url: `/pages/index/index`
});
} else {
uni.showToast({
title: '验证码错误',
icon: 'none', // 不显示图标(提示信息)
duration: 2000 // 显示时长(毫秒)
})
}
})
}
// 执行验证码提交的逻辑
} else {
console.log('验证码未输入完整');
}
};
const getcode = () => {
smsCode({
mobile: mobile.value,
hkcode: hkcode.value,
smsmode:1
}).then(res => {
if (res.success) {
uni.showToast({
title: '发送成功',
icon: 'none', // 不显示图标(提示信息)
duration: 2000 // 显示时长(毫秒)
})
focusedIndex.value = 0;
// 倒计时逻辑
countdown.value = 60;
timerId = setInterval(() => {
if (countdown.value > 0) {
countdown.value--;
} else {
clearInterval(timerId);
timerId = null;
}
}, 1000);
} else {
uni.showToast({
title: res.message,
icon: 'none', // 不显示图标(提示信息)
duration: 2000 // 显示时长(毫秒)
})
}
})
}
// 新增:倒计时相关
const countdown = ref(0);
let timerId = null;
// 页面卸载时清除定时器
onUnmounted(() => {
if (timerId) {
clearInterval(timerId);
}
});
onLoad((options) => {
mobile.value = options.mobile;
hkcode.value = options.hkcode;
getcode()
});
</script>
<style lang="scss" scoped>
.login-container {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
background-color: rgb(239, 241, 252);
position: relative;
.title {
margin-top: 70rpx;
align-items: center;
.title-imge {
width: 100rpx;
height: 105rpx;
margin-left: 100rpx;
}
.title-font {
font-size: 35rpx;
font-weight: 600;
margin-left: 105rpx;
margin-top: 10rpx;
}
}
.photo-imge {
position: absolute;
top: 120rpx;
left: 0;
width: 100%;
height: 1100rpx;
}
.old-imge {
position: absolute;
right: 30rpx;
top: 400rpx;
width: 400rpx;
height: 400rpx;
}
.under-container {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 45vh;
background-color: #fff;
border-top-left-radius: 50rpx;
border-top-right-radius: 50rpx;
box-shadow: 10rpx 10rpx 20rpx rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
color: #5A607F;
.radio-circle {
position: relative;
margin-top: 2rpx;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid #C0C5D9;
background-color: transparent;
}
.radio-circle-target {
position: relative;
margin-top: 2rpx;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid #C0C5D9;
background-color: transparent;
}
.radio-circle-target::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 30rpx;
height: 30rpx;
background-color: #00C9FF;
border-radius: 50%;
}
}
}
.under-container-title {
margin-top: 50rpx;
margin-bottom: 20rpx;
font-size: 25rpx;
font-weight: 500;
width: 100%;
.code-title {
margin-left: 80rpx;
font-size: 35rpx;
color: black;
font-weight: 500;
margin-bottom: 20rpx;
}
.code-number {
margin-left: 80rpx;
font-size: 28rpx;
margin-bottom: 20rpx;
}
}
.captcha-container {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20rpx;
}
.captcha-box {
display: flex;
justify-content: space-between;
margin-bottom: 20rpx;
}
.captcha-item {
display: flex;
justify-content: center;
align-items: center;
}
.captcha-input {
width: 110rpx;
height: 110rpx;
border: 3rpx solid #C0C5D9;
border-radius: 30rpx;
font-size: 50rpx;
font-weight: 700;
text-align: center;
margin-right: 40rpx;
outline: none;
}
.captcha-input:focus {
border-color: #00C9FF;
}
.right-blue {
// float: right;
color: #0083FF;
margin-left: 60rpx;
}
.right-white {
color: rgb(194, 198, 211);
margin-left: 60rpx;
}
.right-black {
// float: right;
// color: #0083FF;
margin-right: 80rpx;
color: black;
}
.under-view {
width: 100%;
margin-top: 10rpx;
display: flex;
justify-content: space-between;
}
/* 遮罩 */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 998;
}
/* 弹窗 */
.modal {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #fff;
z-index: 999;
border-top-left-radius: 50rpx;
border-top-right-radius: 50rpx;
width: 100%;
height: 500rpx;
display: flex;
flex-direction: column;
align-items: center;
.modal-title {
font-size: 32rpx;
font-weight: 700;
margin: 50rpx 0;
margin-bottom: 30rpx;
}
.model-p {
padding: 0 50rpx;
width: 100%;
font-size: 30rpx;
}
.model-down {
display: flex;
width: 100%;
justify-content: space-between;
padding: 0 50rpx;
margin-top: 40rpx;
.model-white {
border-radius: 50rpx;
width: 300rpx;
height: 95rpx;
border: 5rpx solid rgb(0, 141, 255);
color: rgb(0, 141, 255);
font-size: 35rpx;
display: flex;
justify-content: center;
align-items: center;
}
.model-blue {
border-radius: 50rpx;
width: 300rpx;
height: 95rpx;
background: linear-gradient(to right, #00C9FF, #0076FF);
color: #fff;
font-size: 35rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
}
/* 动画:遮罩淡入淡出 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.fade-enter-to,
.fade-leave-from {
opacity: 1;
}
/* 动画:弹窗上滑 */
.slide-up-enter-active,
.slide-up-leave-active {
transition: transform 0.3s;
}
.slide-up-enter-from,
.slide-up-leave-to {
transform: translateY(100%);
}
.slide-up-enter-to,
.slide-up-leave-from {
transform: translateY(0);
}
.text-view {
margin-bottom: 20rpx;
}
</style>