2025-04-22 13:05:32 +08:00
|
|
|
<template>
|
|
|
|
|
<page-meta :page-font-size="fontValue+'px'" :root-font-size="fontValue+'px'"></page-meta>
|
|
|
|
|
<view class="container">
|
|
|
|
|
<!-- 顶部导航栏 -->
|
|
|
|
|
<!-- <view class="header">-->
|
|
|
|
|
<!-- <view class="back-icon" @click="goBack">-->
|
|
|
|
|
<!-- <image class="icon" :src="require('@/static/images/icons/back.png')" mode="aspectFit"></image>-->
|
|
|
|
|
<!-- </view>-->
|
|
|
|
|
<!-- </view>-->
|
|
|
|
|
|
|
|
|
|
<!-- 主要内容区域 -->
|
|
|
|
|
<view class="content">
|
|
|
|
|
<view class="title-section">
|
|
|
|
|
<text class="title">输入6位验证码</text>
|
|
|
|
|
<text class="subtitle">验证码已发至 {{ formatPhone(phone) }}</text>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 验证码输入框 -->
|
|
|
|
|
<view class="code-input-wrapper">
|
|
|
|
|
<input
|
|
|
|
|
v-for="(digit, index) in 6"
|
|
|
|
|
:key="index"
|
|
|
|
|
:ref="`codeInput${index}`"
|
|
|
|
|
v-model="verificationCode[index]"
|
|
|
|
|
type="number"
|
|
|
|
|
maxlength="1"
|
|
|
|
|
class="code-input"
|
|
|
|
|
:class="{ active: currentFocus === index }"
|
|
|
|
|
@input="handleInput($event, index)"
|
|
|
|
|
@focus="currentFocus = index"
|
|
|
|
|
/>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 重新获取验证码 -->
|
|
|
|
|
<view class="resend-wrapper" v-if="!showSuccessModal">
|
|
|
|
|
<text v-if="resendCountdown > 0" class="countdown">重新获取 {{ resendCountdown }}s</text>
|
|
|
|
|
<text v-else class="resend-btn" @click="handleResendCode">重新获取</text>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 完成按钮 -->
|
|
|
|
|
<button
|
|
|
|
|
class="submit-btn"
|
|
|
|
|
:disabled="!isComplete"
|
|
|
|
|
@click="handleSubmit"
|
|
|
|
|
>
|
|
|
|
|
完成
|
|
|
|
|
</button>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 成功弹窗 -->
|
|
|
|
|
<view class="modal" v-if="showSuccessModal">
|
|
|
|
|
<view class="modal-content">
|
|
|
|
|
<view class="success-icon">
|
|
|
|
|
<image class="icon" :src="require('@/static/images/my/success.png')" mode="aspectFit"></image>
|
|
|
|
|
</view>
|
|
|
|
|
<text class="success-title">手机号更新成功</text>
|
|
|
|
|
<text class="success-subtitle">{{ redirectCountdown }}秒后自动返回界面</text>
|
|
|
|
|
<text class="relogin-btn" @click="handleRelogin">重新登录</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import { getTextCode } from '@/api/login';
|
|
|
|
|
import { rebindMobileApi } from '@/api/mine/index.js';
|
2025-04-27 15:58:51 +08:00
|
|
|
|
2025-04-22 13:05:32 +08:00
|
|
|
export default {
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
2025-04-27 15:58:51 +08:00
|
|
|
fontValue:uni.getStorageSync('fontSize') || 8,
|
2025-04-22 13:05:32 +08:00
|
|
|
phone: '',
|
|
|
|
|
verificationCode: ['', '', '', '', '', ''],
|
|
|
|
|
currentFocus: 0,
|
|
|
|
|
resendCountdown: 60,
|
|
|
|
|
redirectCountdown: 5,
|
|
|
|
|
resendTimer: null,
|
|
|
|
|
redirectTimer: null,
|
|
|
|
|
showSuccessModal: false
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
isComplete() {
|
|
|
|
|
return this.verificationCode.every(digit => digit !== '')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onLoad(options) {
|
|
|
|
|
this.phone = options.phone || ''
|
|
|
|
|
this.getCode()
|
|
|
|
|
this.startResendCountdown()
|
|
|
|
|
},
|
|
|
|
|
onUnload() {
|
|
|
|
|
this.clearTimers()
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
//获取验证码
|
|
|
|
|
getCode(){
|
|
|
|
|
let param = {
|
|
|
|
|
"username": this.phone,
|
|
|
|
|
"verificationCodeType": "LOGIN"
|
|
|
|
|
}
|
|
|
|
|
getTextCode(param).then(res => {
|
|
|
|
|
if(res.code==200){
|
|
|
|
|
uni.$u.toast('验证码已发送')
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
formatPhone(phone) {
|
|
|
|
|
if (!phone) return ''
|
|
|
|
|
return phone.replace(/(\d{3})(\d{4})(\d{4})/, '$1 $2 $3')
|
|
|
|
|
},
|
|
|
|
|
goBack() {
|
|
|
|
|
uni.navigateBack()
|
|
|
|
|
},
|
|
|
|
|
handleInput(event, index) {
|
|
|
|
|
const value = event.detail.value
|
|
|
|
|
// Ensure the input is a single digit
|
|
|
|
|
this.verificationCode[index] = value.slice(0, 1)
|
|
|
|
|
|
|
|
|
|
// Move to next input if a digit was entered and it's not the last input
|
|
|
|
|
if (value && index < 5) {
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
// Focus the next input
|
|
|
|
|
const nextInput = this.$refs[`codeInput${index + 1}`][0]
|
|
|
|
|
if (nextInput && typeof nextInput.focus === 'function') {
|
|
|
|
|
nextInput.focus()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
startResendCountdown() {
|
|
|
|
|
this.clearTimers()
|
|
|
|
|
this.resendTimer = setInterval(() => {
|
|
|
|
|
if (this.resendCountdown > 0) {
|
|
|
|
|
this.resendCountdown--
|
|
|
|
|
} else {
|
|
|
|
|
clearInterval(this.resendTimer)
|
|
|
|
|
this.resendTimer = null
|
|
|
|
|
}
|
|
|
|
|
}, 1000)
|
|
|
|
|
},
|
|
|
|
|
startRedirectCountdown() {
|
|
|
|
|
this.redirectTimer = setInterval(() => {
|
|
|
|
|
if (this.redirectCountdown > 0) {
|
|
|
|
|
this.redirectCountdown--
|
|
|
|
|
} else {
|
|
|
|
|
clearInterval(this.redirectTimer)
|
|
|
|
|
this.redirectTimer = null
|
|
|
|
|
this.handleRelogin()
|
|
|
|
|
}
|
|
|
|
|
}, 1000)
|
|
|
|
|
},
|
|
|
|
|
clearTimers() {
|
|
|
|
|
if (this.resendTimer) {
|
|
|
|
|
clearInterval(this.resendTimer)
|
|
|
|
|
this.resendTimer = null
|
|
|
|
|
}
|
|
|
|
|
if (this.redirectTimer) {
|
|
|
|
|
clearInterval(this.redirectTimer)
|
|
|
|
|
this.redirectTimer = null
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
handleResendCode() {
|
|
|
|
|
if (this.resendCountdown > 0) return
|
|
|
|
|
this.resendCountdown = 60
|
|
|
|
|
this.startResendCountdown()
|
|
|
|
|
this.getCode()
|
|
|
|
|
// 这里添加重新发送验证码的逻辑
|
|
|
|
|
},
|
|
|
|
|
async handleSubmit() {
|
|
|
|
|
if (!this.isComplete) return
|
|
|
|
|
|
|
|
|
|
let param = {
|
2025-04-27 15:58:51 +08:00
|
|
|
"oldMobile": uni.getStorageSync('username') ,
|
2025-04-22 13:05:32 +08:00
|
|
|
"newMobile": this.phone,
|
|
|
|
|
"code": this.verificationCode.join("")
|
|
|
|
|
}
|
|
|
|
|
console.log(param)
|
|
|
|
|
const res = await rebindMobileApi(param)
|
|
|
|
|
if(res.code==200){
|
|
|
|
|
// 显示成功弹窗并开始重定向倒计时
|
|
|
|
|
this.showSuccessModal = true
|
|
|
|
|
this.redirectCountdown = 5
|
|
|
|
|
this.startRedirectCountdown()
|
|
|
|
|
}else{
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: res.msg,
|
|
|
|
|
icon: 'none'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
handleRelogin() {
|
|
|
|
|
// 这里添加重新登录的逻辑
|
|
|
|
|
uni.reLaunch({
|
|
|
|
|
url: '/pages/login'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
.container {
|
2025-06-17 16:19:23 +08:00
|
|
|
height: 100vh;
|
|
|
|
|
overflow-y: auto;
|
2025-04-22 13:05:32 +08:00
|
|
|
background-color: #fff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header {
|
|
|
|
|
padding: 44px 32rpx 0;
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
.back-icon {
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
margin-left: -20rpx;
|
|
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
|
width: 40rpx;
|
|
|
|
|
height: 40rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.title-section {
|
|
|
|
|
margin-bottom: 48rpx;
|
|
|
|
|
|
|
|
|
|
.title {
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
color: #333;
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
display: block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.subtitle {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #999;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.code-input-wrapper {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
|
|
|
|
.code-input {
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
background: #F5F5F5;
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
color: #333;
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
background: #fff;
|
|
|
|
|
border: 2rpx solid #FF8126;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.resend-wrapper {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin-bottom: 48rpx;
|
|
|
|
|
|
|
|
|
|
.countdown {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #999;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.resend-btn {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #FF8126;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.submit-btn {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
background: #FF8126;
|
|
|
|
|
color: #fff;
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
border-radius: 44rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
border: none;
|
|
|
|
|
|
|
|
|
|
&:disabled {
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.modal {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
background: rgba(0, 0, 0, 0.5);
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
z-index: 1000;
|
|
|
|
|
|
|
|
|
|
.modal-content {
|
|
|
|
|
width: 560rpx;
|
|
|
|
|
background: #fff;
|
|
|
|
|
border-radius: 24rpx;
|
|
|
|
|
padding: 48rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
.success-icon {
|
|
|
|
|
width: 120rpx;
|
|
|
|
|
height: 120rpx;
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.success-title {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
color: #333;
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.success-subtitle {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #999;
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.relogin-btn {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #FF8126;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|