2025-12-25 15:09:09 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<AppLayout title="">
|
|
|
|
|
|
<template #headerleft v-if="isMiniProgram">
|
|
|
|
|
|
<view >
|
|
|
|
|
|
<image class="btnback" src="@/static/icon/back.png" @click="navBack"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<view class="auth-container">
|
|
|
|
|
|
<view class="auth-header">
|
|
|
|
|
|
<view class="auth-title">身份认证</view>
|
|
|
|
|
|
<view class="auth-subtitle">请填写您的身份信息进行验证</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="auth-form">
|
|
|
|
|
|
<view class="form-item" >
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
身份证号
|
|
|
|
|
|
<text v-if="idCardError" class="error-text">{{ idCardError }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="form-input-wrapper" :class="{ 'error': idCardError }">
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
type="idcard"
|
|
|
|
|
|
v-model="formData.idCard"
|
|
|
|
|
|
placeholder="请输入18位身份证号码"
|
|
|
|
|
|
maxlength="18"
|
|
|
|
|
|
@input="onIdCardInput"
|
|
|
|
|
|
@blur="validateIdCard"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<view class="input-clear" v-if="formData.idCard" @click="clearField('idCard')">
|
|
|
|
|
|
<my-icons type="close-circle-filled" size="36" color="#ccc"></my-icons>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 手机号 -->
|
|
|
|
|
|
<view class="form-item" >
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
手机号
|
|
|
|
|
|
<text v-if="phoneError" class="error-text">{{ phoneError }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="form-input-wrapper" :class="{ 'error': phoneError }">
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
v-model="formData.phone"
|
|
|
|
|
|
placeholder="请输入11位手机号码"
|
|
|
|
|
|
maxlength="11"
|
|
|
|
|
|
@input="onPhoneInput"
|
|
|
|
|
|
@blur="validatePhone"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<view class="input-clear" v-if="formData.phone" @click="clearField('phone')">
|
|
|
|
|
|
<my-icons type="close-circle-filled" size="36" color="#ccc"></my-icons>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 验证码 -->
|
|
|
|
|
|
<view class="form-item" >
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
验证码
|
|
|
|
|
|
<text v-if="codeError" class="error-text">{{ codeError }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="form-input-wrapper" :class="{ 'error': codeError }">
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="form-input code-input"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
v-model="formData.code"
|
|
|
|
|
|
placeholder="请输入验证码"
|
|
|
|
|
|
maxlength="6"
|
|
|
|
|
|
@input="onCodeInput"
|
|
|
|
|
|
@blur="validateCode"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<view class="send-code-btn"
|
|
|
|
|
|
:class="{ 'disabled': !canSendCode }"
|
|
|
|
|
|
@click="sendCode">
|
|
|
|
|
|
{{ codeBtnText }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 认证按钮 -->
|
|
|
|
|
|
<view class="auth-btn-container">
|
|
|
|
|
|
<button class="auth-btn" :class="{ 'disabled': !canSubmit }" @click="submitAuth">
|
|
|
|
|
|
确认认证
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<view class="auth-tips">
|
|
|
|
|
|
认证信息仅用于身份验证,我们将严格保护您的隐私
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</AppLayout>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { reactive, ref, computed, onMounted ,onUnmounted ,inject} from 'vue';
|
|
|
|
|
|
import { onLoad } from '@dcloudio/uni-app';
|
|
|
|
|
|
import { storeToRefs } from 'pinia';
|
|
|
|
|
|
import useUserStore from '@/stores/useUserStore';
|
2025-12-25 15:15:02 +08:00
|
|
|
|
import { playTextDirectly } from '@/hook/useTTSPlayer-all-in-one';
|
2025-12-25 15:09:09 +08:00
|
|
|
|
const { $api ,navBack} = inject('globalFunction');
|
|
|
|
|
|
const { isMiniProgram } = storeToRefs(useUserStore());
|
|
|
|
|
|
|
|
|
|
|
|
// 表单数据
|
|
|
|
|
|
const formData = ref({
|
|
|
|
|
|
idCard: '',
|
|
|
|
|
|
phone: '',
|
|
|
|
|
|
code: ''
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 错误提示
|
|
|
|
|
|
const idCardError = ref('');
|
|
|
|
|
|
const phoneError = ref('');
|
|
|
|
|
|
const codeError = ref('');
|
|
|
|
|
|
|
|
|
|
|
|
// 验证码倒计时
|
|
|
|
|
|
const codeCountdown = ref(0);
|
|
|
|
|
|
const codeTimer = ref(null);
|
|
|
|
|
|
const codeBtnText = ref('发送验证码');
|
|
|
|
|
|
|
2025-12-25 15:18:55 +08:00
|
|
|
|
|
2025-12-25 15:09:09 +08:00
|
|
|
|
|
2025-12-25 15:15:02 +08:00
|
|
|
|
|
2025-12-25 15:09:09 +08:00
|
|
|
|
const canSendCode = computed(() => {
|
|
|
|
|
|
return codeCountdown.value === 0 && formData.value.phone.length === 11 && !phoneError.value;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const canSubmit = computed(() => {
|
|
|
|
|
|
return formData.value.idCard && formData.value.phone && formData.value.code &&
|
|
|
|
|
|
!idCardError.value && !phoneError.value && !codeError.value;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-25 15:15:02 +08:00
|
|
|
|
|
2025-12-25 15:09:09 +08:00
|
|
|
|
// 身份证输入处理
|
|
|
|
|
|
const onIdCardInput = (e) => {
|
|
|
|
|
|
formData.value.idCard = e.detail.value.toUpperCase();
|
|
|
|
|
|
idCardError.value = '';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 手机号输入处理
|
|
|
|
|
|
const onPhoneInput = (e) => {
|
|
|
|
|
|
formData.value.phone = e.detail.value.replace(/[^\d]/g, '');
|
|
|
|
|
|
phoneError.value = '';
|
|
|
|
|
|
// 如果手机号变化且验证码已发送,清空验证码
|
|
|
|
|
|
if (formData.value.code) {
|
|
|
|
|
|
formData.value.code = '';
|
|
|
|
|
|
codeError.value = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 验证码输入处理
|
|
|
|
|
|
const onCodeInput = (e) => {
|
|
|
|
|
|
formData.value.code = e.detail.value.replace(/[^\d]/g, '');
|
|
|
|
|
|
codeError.value = '';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 清空字段
|
|
|
|
|
|
const clearField = (field) => {
|
|
|
|
|
|
formData.value[field] = '';
|
|
|
|
|
|
switch(field) {
|
|
|
|
|
|
case 'idCard':
|
|
|
|
|
|
idCardError.value = '';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'phone':
|
|
|
|
|
|
phoneError.value = '';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'code':
|
|
|
|
|
|
codeError.value = '';
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 验证身份证号
|
|
|
|
|
|
const validateIdCard = () => {
|
|
|
|
|
|
if (!formData.value.idCard) {
|
|
|
|
|
|
idCardError.value = '请输入身份证号码';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const idCard = formData.value.idCard.trim();
|
|
|
|
|
|
if (idCard.length !== 18) {
|
|
|
|
|
|
idCardError.value = '身份证号码必须为18位';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 身份证号格式校验
|
|
|
|
|
|
const idCardPattern = /^\d{17}[\dXx]$/;
|
|
|
|
|
|
if (!idCardPattern.test(idCard)) {
|
|
|
|
|
|
idCardError.value = '身份证号码格式不正确';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 校验码验证
|
|
|
|
|
|
if (!validateIdCardCheckCode(idCard)) {
|
|
|
|
|
|
idCardError.value = '身份证号码校验失败';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
idCardError.value = '';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 身份证校验码验证
|
|
|
|
|
|
const validateIdCardCheckCode = (idCard) => {
|
|
|
|
|
|
if (idCard.length !== 18) return false;
|
|
|
|
|
|
|
|
|
|
|
|
const weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
|
|
|
|
|
const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
|
|
|
|
|
|
|
|
|
|
|
let sum = 0;
|
|
|
|
|
|
for (let i = 0; i < 17; i++) {
|
|
|
|
|
|
sum += parseInt(idCard[i]) * weight[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const checkCode = checkCodes[sum % 11];
|
|
|
|
|
|
return checkCode === idCard[17].toUpperCase();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 验证手机号
|
|
|
|
|
|
const validatePhone = () => {
|
|
|
|
|
|
if (!formData.value.phone) {
|
|
|
|
|
|
phoneError.value = '请输入手机号码';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const phone = formData.value.phone.trim();
|
|
|
|
|
|
if (phone.length !== 11) {
|
|
|
|
|
|
phoneError.value = '手机号码必须为11位';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 手机号格式校验
|
|
|
|
|
|
const phonePattern = /^1[3-9]\d{9}$/;
|
|
|
|
|
|
if (!phonePattern.test(phone)) {
|
|
|
|
|
|
phoneError.value = '手机号码格式不正确';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
phoneError.value = '';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 验证验证码
|
|
|
|
|
|
const validateCode = () => {
|
|
|
|
|
|
if (!formData.value.code) {
|
|
|
|
|
|
codeError.value = '请输入验证码';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (formData.value.code.length < 4) {
|
|
|
|
|
|
codeError.value = '请输入正确的验证码';
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
codeError.value = '';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送验证码
|
|
|
|
|
|
const sendCode = async () => {
|
|
|
|
|
|
if (!canSendCode.value) {
|
|
|
|
|
|
if (!formData.value.phone) {
|
|
|
|
|
|
phoneError.value = '请输入手机号码';
|
|
|
|
|
|
} else if (formData.value.phone.length !== 11) {
|
|
|
|
|
|
phoneError.value = '手机号码必须为11位';
|
|
|
|
|
|
} else if (phoneError.value) {
|
|
|
|
|
|
// 已有错误提示
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证手机号格式
|
|
|
|
|
|
if (!validatePhone()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 开始倒计时
|
|
|
|
|
|
codeCountdown.value = 60;
|
|
|
|
|
|
updateCodeBtnText();
|
|
|
|
|
|
|
|
|
|
|
|
codeTimer.value = setInterval(() => {
|
|
|
|
|
|
codeCountdown.value--;
|
|
|
|
|
|
updateCodeBtnText();
|
|
|
|
|
|
if (codeCountdown.value <= 0) {
|
|
|
|
|
|
clearInterval(codeTimer.value);
|
|
|
|
|
|
codeTimer.value = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 调用发送短信验证码接口
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
phone: formData.value.phone,
|
|
|
|
|
|
type: 'auth' // 身份认证类型
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await $api.createRequest('/app/auth/send-code', params, 'post');
|
|
|
|
|
|
|
2025-12-25 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
$api.msg('验证码已发送')
|
|
|
|
|
|
playTextDirectly('验证码已发送');
|
2025-12-25 15:15:02 +08:00
|
|
|
|
|
2025-12-25 15:09:09 +08:00
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
// 发送失败,重置倒计时
|
|
|
|
|
|
codeCountdown.value = 0;
|
|
|
|
|
|
clearInterval(codeTimer.value);
|
|
|
|
|
|
codeTimer.value = null;
|
|
|
|
|
|
updateCodeBtnText();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 更新验证码按钮文字
|
|
|
|
|
|
const updateCodeBtnText = () => {
|
|
|
|
|
|
if (codeCountdown.value > 0) {
|
|
|
|
|
|
codeBtnText.value = `${codeCountdown.value}s后重新发送`;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
codeBtnText.value = '发送验证码';
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-25 15:18:55 +08:00
|
|
|
|
|
2025-12-25 15:09:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 提交认证
|
|
|
|
|
|
const submitAuth = async () => {
|
|
|
|
|
|
if (!canSubmit.value) {
|
|
|
|
|
|
// 触发表单验证
|
|
|
|
|
|
validateIdCard();
|
|
|
|
|
|
validatePhone();
|
|
|
|
|
|
validateCode();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 调用身份认证接口
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
idCard: formData.value.idCard.toUpperCase(),
|
|
|
|
|
|
phone: formData.value.phone,
|
|
|
|
|
|
code: formData.value.code
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const result = await $api.createRequest('/app/auth/verify', params, 'post');
|
|
|
|
|
|
|
|
|
|
|
|
// 认证成功
|
2025-12-25 15:18:55 +08:00
|
|
|
|
$api.msg('身份认证成功')
|
2025-12-25 15:15:02 +08:00
|
|
|
|
playTextDirectly('身份认证成功');
|
2025-12-25 15:09:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 保存认证信息到store
|
|
|
|
|
|
useUserStore().getUserResume().then(()=>{
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
navBack()
|
|
|
|
|
|
}, 500);
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (error) {
|
2025-12-25 15:18:55 +08:00
|
|
|
|
|
2025-12-25 15:09:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-25 15:15:02 +08:00
|
|
|
|
|
2025-12-25 15:09:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 组件卸载时清理定时器
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
if (codeTimer.value) {
|
|
|
|
|
|
clearInterval(codeTimer.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.auth-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
padding: 20rpx 40rpx 40rpx;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.auth-header {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 60rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.auth-title {
|
|
|
|
|
|
font-size: 48rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #1677ff;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.auth-subtitle {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.auth-form {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-item {
|
|
|
|
|
|
margin-bottom: 48rpx;
|
|
|
|
|
|
animation: slideIn 0.3s ease-out;
|
|
|
|
|
|
animation-fill-mode: both;
|
|
|
|
|
|
|
|
|
|
|
|
&:nth-child(1) { animation-delay: 0.1s; }
|
|
|
|
|
|
&:nth-child(2) { animation-delay: 0.2s; }
|
|
|
|
|
|
&:nth-child(3) { animation-delay: 0.3s; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-label {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.error-text {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #ff4d4f;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
margin-left: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input-wrapper {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
height: 96rpx;
|
|
|
|
|
|
border: 2rpx solid #e8e8e8;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 0 30rpx;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
|
|
|
|
&:focus-within {
|
|
|
|
|
|
border-color: #1677ff;
|
|
|
|
|
|
box-shadow: 0 0 0 2rpx rgba(22, 119, 255, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
|
|
|
|
|
|
&::placeholder {
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-input {
|
|
|
|
|
|
padding-right: 220rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.input-clear {
|
|
|
|
|
|
width: 48rpx;
|
|
|
|
|
|
height: 48rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin-left: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.send-code-btn {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
right: 20rpx;
|
|
|
|
|
|
top: 50%;
|
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
|
min-width: 120rpx;
|
|
|
|
|
|
padding: 0 20rpx;
|
|
|
|
|
|
background: #1677ff;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
background: #0958d9;
|
|
|
|
|
|
transform: translateY(-50%) scale(0.98);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.disabled {
|
|
|
|
|
|
background: #d9d9d9;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.auth-btn-container {
|
|
|
|
|
|
margin-top: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.auth-btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100rpx;
|
|
|
|
|
|
background: #1677ff;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
background: #0958d9;
|
|
|
|
|
|
transform: scale(0.98);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.disabled {
|
|
|
|
|
|
background: #d9d9d9;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.auth-tips {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-top: 24rpx;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.auth-status {
|
|
|
|
|
|
margin-top: 40rpx;
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
&.success {
|
|
|
|
|
|
background: #f6ffed;
|
|
|
|
|
|
border: 1rpx solid #b7eb8f;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.error {
|
|
|
|
|
|
background: #fff2f0;
|
|
|
|
|
|
border: 1rpx solid #ffccc7;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.loading {
|
|
|
|
|
|
background: #f0f5ff;
|
|
|
|
|
|
border: 1rpx solid #adc6ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 动画效果 */
|
|
|
|
|
|
@keyframes slideIn {
|
|
|
|
|
|
from {
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
transform: translateY(20rpx);
|
|
|
|
|
|
}
|
|
|
|
|
|
to {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.btnback{
|
|
|
|
|
|
width: 64rpx;
|
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="stylus" scoped>
|
|
|
|
|
|
|
|
|
|
|
|
.back-button {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: 40rpx;
|
|
|
|
|
|
top: 40rpx;
|
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.05);
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading-spin {
|
|
|
|
|
|
animation: spin 1s linear infinite;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes spin {
|
|
|
|
|
|
0% {
|
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
100% {
|
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.form-input:focus {
|
|
|
|
|
|
outline: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.code-input-container {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
&:after {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
right: 200rpx;
|
|
|
|
|
|
top: 20rpx;
|
|
|
|
|
|
bottom: 20rpx;
|
|
|
|
|
|
width: 1rpx;
|
|
|
|
|
|
background: #e8e8e8;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input-wrapper.error {
|
|
|
|
|
|
border-color: #ff4d4f;
|
|
|
|
|
|
animation: shake 0.5s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes shake {
|
|
|
|
|
|
0%, 100% { transform: translateX(0); }
|
|
|
|
|
|
10%, 30%, 50%, 70%, 90% { transform: translateX(-10rpx); }
|
|
|
|
|
|
20%, 40%, 60%, 80% { transform: translateX(10rpx); }
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|