2026-03-05 17:08:18 +08:00

696 lines
16 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="idcard-auth-page">
<!-- 顶部导航栏 -->
<view class="navbox">
<view class="status_bar"></view>
<uni-nav-bar
left-icon="left"
:title="currentStep === 1 ? '身份验证' : '添加银行卡'"
@clickLeft="goBack"
color="#8B2316"
:border="false"
backgroundColor="#eeeeee"
>
</uni-nav-bar>
</view>
<!-- 内容区域 -->
<view class="content-area">
<!-- 进度指示器 -->
<view class="progress-bar">
<view class="barbox">
<view class="imgbox">
<up-image :src="currentStep >= 1 ? stepActiveImg : stepImg" width="46rpx" height="46rpx"></up-image>
<view class="desc" :class="{ active: currentStep >= 1 }">身份信息</view>
</view>
<view class="line" :class="{ active: currentStep >= 2 }"></view>
<view class="imgbox">
<up-image :src="currentStep >= 2 ? stepActiveImg : stepImg" width="46rpx" height="46rpx"></up-image>
<view class="desc" :class="{ active: currentStep >= 2 }">添加银行卡</view>
</view>
<view class="line" :class="{ active: currentStep >= 3 }"></view>
<view class="imgbox">
<up-image :src="currentStep >= 3 ? stepActiveImg : stepImg" width="46rpx" height="46rpx"></up-image>
<view class="desc" :class="{ active: currentStep >= 3 }">完成</view>
</view>
</view>
<!-- <view class="progress-step active">
<view class="step-icon">
<uni-icons type="checkmarkempty" color="#ff0000" size="20"></uni-icons>
</view>
<text class="step-text">身份信息</text>
</view>
<view class="progress-line active"></view>
<view class="progress-step">
<view class="step-icon">
<uni-icons type="checkmarkempty" color="#cccccc" size="20"></uni-icons>
</view>
<text class="step-text">添加银行卡</text>
</view>
<view class="progress-line"></view>
<view class="progress-step">
<view class="step-icon">
<uni-icons type="checkmarkempty" color="#cccccc" size="20"></uni-icons>
</view>
<text class="step-text">完成</text>
</view> -->
</view>
<!-- 输入表单 -->
<view class="form-section">
<!-- 第一步身份信息 -->
<view v-if="currentStep === 1">
<view class="form-item">
<text class="form-label">姓名</text>
<input
class="form-input"
placeholder="请输入您的姓名"
v-model="formData.name"
placeholder-style="color: #cccccc"
/>
</view>
<view class="form-item">
<text class="form-label">身份证号</text>
<input
class="form-input"
placeholder="请输入您的身份证号"
v-model="formData.idNumber"
placeholder-style="color: #cccccc"
/>
</view>
</view>
<!-- 第二步:添加银行卡 -->
<view v-if="currentStep === 2">
<view class="form-item">
<text class="form-label">银行卡号</text>
<view class="input-container">
<input
class="form-input"
placeholder="仅限借记卡"
v-model="formData.cardNumber"
placeholder-style="color: #cccccc"
/>
</view>
<view class="info-icon" @click="showInfo('card')">
<text class="icon-text">!</text>
</view>
</view>
<view class="form-item">
<text class="form-label">手机号</text>
<view class="input-container">
<input
class="form-input"
placeholder="银行预留手机号"
v-model="formData.mobile"
placeholder-style="color: #cccccc"
/>
</view>
<view class="info-icon" @click="showInfo('phone')">
<text class="icon-text">!</text>
</view>
</view>
</view>
</view>
<!-- 提示文字 -->
<view class="warning-text">
平台不支持绑定多人银行卡,请务必绑定本人卡,实名认证信息,谨慎填写!
</view>
<!-- 下一步按钮 -->
<view class="bottom-actions">
<button class="next-btn" :class="{ loading: isLoading }" @click="onNextStep" :disabled="isLoading">
<text v-if="!isLoading">下一步</text>
<text v-else>验证中...</text>
</button>
</view>
<!-- 短信验证码弹框 -->
<view v-if="showSmsDialog" class="sms-mask">
<view class="sms-dialog">
<view class="sms-title">短信验证码</view>
<view class="sms-subtitle">请输入手机{{ maskedMobile }}收到的验证码</view>
<view class="sms-input-row">
<input class="sms-input" v-model="smsCode" placeholder="请输入验证码" placeholder-style="color: #cccccc" />
<button class="sms-code-btn" :disabled="countdown > 0 || sendingCode" @click="onGetSmsCode">
<text v-if="countdown === 0">获取验证码</text>
<text v-else>{{ countdown }}s</text>
</button>
</view>
<view class="sms-actions">
<button class="sms-cancel" @click="onCancelSms">取消</button>
<button class="sms-confirm" @click="onConfirmSms">确定</button>
</view>
</view>
</view>
</view>
</view>
<unidialog
:visible="cardVisible"
:showCancel="false"
:title="cardTitle"
:content="cardContent"
:showConfirm="true"
:confirmText="'知道了'"
@close="cardVisible=false"
@confirm="cardVisible=false"
>
</unidialog>
</template>
<script setup>
import { ref, computed } from 'vue';
import stepImg from "@/static/add_card_no.png"
import stepActiveImg from "@/static/add_card_yes.png"
import navTo from '@/utils/navTo';
import api from '@/api/api';
import unidialog from '@/components/dialog/dialog.vue';
const cardContent = ref('暂支持以下银行:农业银行、建设银行、光大银行、平安银行、兴业银行、中信银行、邮政储蓄银行、民生银行、中国银行、工商银行、交通银行、浦发银行、广发银行、华夏银行、招商银行、北京银行、上海银行。');
const cardTitle = ref('银行卡说明');
const cardVisible = ref(false);
const formData = ref({
name: '',
idNumber: '',
cardNumber: '',
mobile: ''
});
const isLoading = ref(false);
const currentStep = ref(1); // 当前步骤1表示身份信息2表示添加银行卡
const showInfo = (type) => {
if (type === 'card') {
cardTitle.value = '银行卡说明';
cardContent.value = '暂支持以下银行:农业银行、建设银行、光大银行、平安银行、兴业银行、中信银行、邮政储蓄银行、民生银行、中国银行、工商银行、交通银行、浦发银行、广发银行、华夏银行、招商银行、北京银行、上海银行。';
} else if (type === 'phone') {
cardTitle.value = '手机号说明';
cardContent.value = '银行预留的手机号码是办理银行卡时所填写的手机号码。没有预留,手机号码已经忘记或者已经停用,请联系银行客服更新处理';
}
cardVisible.value = true;
};
// 短信弹框相关
const showSmsDialog = ref(false);
const smsCode = ref('');
const sendingCode = ref(false);
const countdown = ref(0);
let countdownTimer = null;
const maskedMobile = computed(() => {
const m = formData.value.mobile || '';
if (m && m.length >= 7) {
return `${m.slice(0,3)}****${m.slice(-4)}`;
}
return m || '***********';
});
const goBack = () => {
uni.navigateBack();
};
// 身份证号格式验证
const validateIdNumber = (idNumber) => {
const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
return reg.test(idNumber);
};
// 姓名格式验证
const validateName = (name) => {
const reg = /^[\u4e00-\u9fa5]{2,10}$/;
return reg.test(name);
};
// 银行卡号验证
const validateCardNumber = (cardNumber) => {
const reg = /^\d{16,19}$/;
return reg.test(cardNumber);
};
// 手机号验证
const validateMobile = (mobile) => {
const reg = /^1[3-9]\d{9}$/;
return reg.test(mobile);
};
const onNextStep = async () => {
if (currentStep.value === 1) {
// 第一步:身份信息验证
if (!formData.value.name.trim()) {
uni.showToast({ title: '请输入姓名', icon: 'none' });
return;
}
if (!validateName(formData.value.name)) {
uni.showToast({ title: '请输入正确的姓名2-10个汉字', icon: 'none' });
return;
}
if (!formData.value.idNumber.trim()) {
uni.showToast({ title: '请输入身份证号', icon: 'none' });
return;
}
if (!validateIdNumber(formData.value.idNumber)) {
uni.showToast({ title: '请输入正确的身份证号', icon: 'none' });
return;
}
// 显示加载状态
isLoading.value = true;
try {
// 调用身份验证API
const res = {code:200}
if (res.code === 200) {
uni.showToast({ title: '身份验证成功', icon: 'none' });
currentStep.value = 2;
isLoading.value = false;
} else {
uni.showToast({ title: res.msg || '身份验证失败', icon: 'none' });
isLoading.value = false;
}
} catch (error) {
console.error('身份验证失败:', error);
uni.showToast({ title: '网络错误,请重试', icon: 'none' });
isLoading.value = false;
}
} else if (currentStep.value === 2) {
// 第二步:银行卡信息验证
if (!formData.value.cardNumber.trim()) {
uni.showToast({ title: '请输入银行卡号', icon: 'none' });
return;
}
if (!validateCardNumber(formData.value.cardNumber)) {
uni.showToast({ title: '请输入正确的银行卡号', icon: 'none' });
return;
}
if (!formData.value.mobile.trim()) {
uni.showToast({ title: '请输入手机号', icon: 'none' });
return;
}
if (!validateMobile(formData.value.mobile)) {
uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
return;
}
// 弹出短信验证码弹框
showSmsDialog.value = true;
}
};
const onGetSmsCode = async () => {
if (countdown.value > 0) return;
const res = await api.smsSend({
mobile: formData.value.mobile,
type: 3
});
if (res.code === 200) {
uni.showToast({ title: '短信验证码发送成功', icon: 'none' });
// 开始60秒倒计时
countdown.value = 60;
if (countdownTimer) clearInterval(countdownTimer);
countdownTimer = setInterval(() => {
if (countdown.value > 0) {
countdown.value -= 1;
} else {
clearInterval(countdownTimer);
countdownTimer = null;
}
}, 1000);
} else {
uni.showToast({ title: res.msg || '短信验证码发送失败', icon: 'none' });
}
};
const onConfirmSms = async () => {
if (!smsCode.value) {
uni.showToast({ title: '请输入短信验证码', icon: 'none' });
return;
}
const res = await api.identificationBankCardNew({
phone_number: formData.value.mobile,
sms: smsCode.value,
id_number: formData.value.idNumber,
card_number: formData.value.cardNumber,
id_name: formData.value.name
});
if (res.code === 200) {
uni.showToast({ title: '银行卡添加成功', icon: 'none' });
navTo({
url: '/pages_app/idcardAuth/bankCardList'
});
} else {
uni.showToast({ title: res.msg || '银行卡添加失败', icon: 'none' });
}
};
const onCancelSms = () => {
showSmsDialog.value = false;
};
</script>
<style lang="scss" scoped>
.idcard-auth-page {
min-height: 100vh;
background: #f5f5f5;
}
.content-area {
margin-top: calc(var(--status-bar-height) + 44px);
padding: 0rpx 0rpx 0;
}
.progress-bar {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #ffffff;
padding: 80rpx 20rpx 120rpx;
border-radius: 16rpx;
margin-bottom: 30rpx;
.barbox{
display: flex;
align-items: center;
justify-content: center;
.imgbox{
flex:1;
position: relative;
.desc{
position: absolute;
left:-50%;
color:#d0d0d0;
top:80rpx;
font-size: 28rpx;
margin-left: -10rpx;
white-space: nowrap;
transform: translateY(-50%);
&.active{
color:#8B2316;
}
}
}
.imgbox:last-child{
.desc{
margin-left: 15rpx;
}
}
.line{
width:240rpx;
margin:0 -2rpx;
height: 16rpx;
background:#cccccc;
&.active{
background:#8B2316;
}
}
}
.steptext{
margin:0 30rpx;
display: flex;
width:900rpx;
justify-content: space-between;
align-items:center ;
}
.progress-step {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
.step-icon {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
&.active {
background: #ff0000;
}
}
.step-text {
font-size: 24rpx;
color: #666666;
&.active {
color: #000000;
}
}
&.active {
.step-icon {
background: #ff0000;
}
.step-text {
color: #000000;
}
}
}
.progress-line {
flex: 1;
height: 4rpx;
background: #f0f0f0;
margin: 0 20rpx;
&.active {
background: #ff0000;
}
}
}
.form-section {
background: #ffffff;
border-radius: 16rpx;
padding: 0;
.form-item {
margin-bottom: 30rpx;
display: flex;
align-items: center;
border-bottom: 2rpx solid #eee;
padding: 0 30rpx 20rpx;
&:last-child {
margin-bottom: 0;
padding-bottom: 0;
}
.form-label {
display: block;
font-size: 28rpx;
color: #000000;
width: 120rpx;
font-weight: 500;
}
.form-input {
flex: 1;
height: 80rpx;
padding: 0 20rpx;
font-size: 28rpx;
background: #ffffff;
border: none;
outline: none;
&:focus {
border-color: #8B2316;
}
}
.info-icon {
flex:1;
position: absolute;
right: 20rpx;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
border: 2rpx solid #8B2316;
.icon-text {
font-size: 20rpx;
color: #8B2316;
font-weight: bold;
}
}
.input-container {
display: flex;
align-items: center;
position: relative;
width: 80%;
.form-input {
flex: 9;
height: 80rpx;
padding: 0 20rpx;
font-size: 28rpx;
background: #ffffff;
border: none;
border-radius: 0;
outline: none;
&:focus {
/* 去除边框后无需变更边框颜色 */
}
}
}
}
}
.warning-text {
background: #fff3cd;
border: 2rpx solid #ffeaa7;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 60rpx;
font-size: 26rpx;
color: #856404;
line-height: 1.6;
position: relative;
&::before {
content: "⚠️";
position: absolute;
left: 30rpx;
top: 30rpx;
font-size: 32rpx;
}
padding-left: 80rpx;
}
.bottom-actions {
padding: 0 30rpx 40rpx;
.next-btn {
width: 100%;
height: 88rpx;
background: #8B2316;
color: #ffffff;
border: none;
border-radius: 8rpx;
font-size: 32rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&:active {
background: #6B1A0F;
}
&.loading {
background: #cccccc;
opacity: 0.7;
}
&:disabled {
background: #cccccc;
opacity: 0.7;
}
}
}
/* 短信弹框样式 */
.sms-mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
.sms-dialog {
width: 680rpx;
background: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
}
.sms-title {
text-align: center;
font-size: 34rpx;
color: #000000;
font-weight: 600;
margin-bottom: 20rpx;
}
.sms-subtitle {
text-align: center;
font-size: 28rpx;
color: #333333;
margin-bottom: 24rpx;
}
.sms-input-row {
display: flex;
align-items: center;
gap: 16rpx;
margin: 10rpx 0 30rpx;
}
.sms-input {
flex: 1;
height: 88rpx;
border: 2rpx solid #eeeeee;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
}
.sms-code-btn {
width: 200rpx;
height: 88rpx;
border-radius: 8rpx;
background: #eeeeee;
color: #8B2316;
font-size: 26rpx;
}
.sms-actions {
display: flex;
justify-content: space-between;
margin-top: 10rpx;
}
.sms-cancel,
.sms-confirm {
flex: 1;
height: 88rpx;
border-radius: 8rpx;
font-size: 32rpx;
}
.sms-cancel { background: #f5f5f5; color: #000000; margin-right: 20rpx; }
.sms-confirm { background: #8B2316; color: #ffffff; margin-left: 20rpx; }
</style>