<template>
|
<view class="add-bank-card">
|
<!-- 银行卡表单 -->
|
<view class="form-card">
|
<!-- 选择银行 -->
|
<view class="form-item">
|
<text class="label required">发卡银行</text>
|
<picker
|
mode="selector"
|
:range="banks"
|
range-key="name"
|
:value="bankIndex"
|
@change="onBankChange"
|
>
|
<view class="picker">
|
<text>{{ bankIndex > -1 ? banks[bankIndex].name : '请选择发卡银行' }}</text>
|
<text class="iconfont icon-arrow-right"></text>
|
</view>
|
</picker>
|
</view>
|
|
<!-- 卡类型 -->
|
<view class="form-item">
|
<text class="label required">卡片类型</text>
|
<view class="card-types">
|
<view
|
class="type-item"
|
v-for="(type, index) in cardTypes"
|
:key="index"
|
:class="{ active: selectedCardType === type.value }"
|
@tap="selectedCardType = type.value"
|
>
|
<text class="radio"></text>
|
<text>{{ type.label }}</text>
|
</view>
|
</view>
|
</view>
|
|
<!-- 卡号 -->
|
<view class="form-item">
|
<text class="label required">银行卡号</text>
|
<input
|
type="number"
|
v-model="form.cardNumber"
|
placeholder="请输入银行卡号"
|
maxlength="19"
|
@input="formatCardNumber"
|
/>
|
</view>
|
|
<!-- 持卡人 -->
|
<view class="form-item">
|
<text class="label required">持卡人姓名</text>
|
<input
|
type="text"
|
v-model="form.holderName"
|
placeholder="请输入持卡人姓名"
|
maxlength="20"
|
/>
|
</view>
|
|
<!-- 手机号 -->
|
<view class="form-item">
|
<text class="label required">预留手机号</text>
|
<input
|
type="number"
|
v-model="form.phone"
|
placeholder="请输入银行预留手机号"
|
maxlength="11"
|
/>
|
</view>
|
|
<!-- 验证码 -->
|
<view class="form-item verify-code">
|
<text class="label required">验证码</text>
|
<input
|
type="number"
|
v-model="form.verifyCode"
|
placeholder="请输入验证码"
|
maxlength="6"
|
/>
|
<button
|
class="send-btn"
|
:disabled="!!countdown"
|
@tap="sendVerifyCode"
|
>
|
{{ countdown ? `${countdown}s` : '获取验证码' }}
|
</button>
|
</view>
|
</view>
|
|
<!-- 设为默认 -->
|
<view class="form-card">
|
<view class="switch-item">
|
<text>设为默认支付卡</text>
|
<switch
|
:checked="form.isDefault"
|
@change="e => form.isDefault = e.detail.value"
|
color="#0f95b0"
|
/>
|
</view>
|
</view>
|
|
<!-- 温馨提示 -->
|
<view class="notice-card">
|
<view class="section-title">温馨提示</view>
|
<view class="notice-list">
|
<view class="notice-item">
|
<text class="dot"></text>
|
<text class="content">请确保填写的是本人银行卡</text>
|
</view>
|
<view class="notice-item">
|
<text class="dot"></text>
|
<text class="content">储蓄卡需要开通网上银行功能</text>
|
</view>
|
<view class="notice-item">
|
<text class="dot"></text>
|
<text class="content">信用卡需要开通在线支付功能</text>
|
</view>
|
</view>
|
</view>
|
|
<!-- 底部按钮 -->
|
<view class="bottom-bar">
|
<button
|
class="submit-btn primary-btn"
|
:disabled="!canSubmit"
|
@tap="submitForm"
|
>确认添加</button>
|
</view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, computed } from 'vue'
|
|
// 银行列表
|
const banks = [
|
{
|
id: 1,
|
name: '中国银行(青岛)',
|
code: 'bocm',
|
logo: '/static/payment/bocm.png'
|
},
|
{
|
id: 2,
|
name: '工商银行(青岛)',
|
code: 'icbcm',
|
logo: '/static/payment/icbcm.png'
|
},
|
{
|
id: 3,
|
name: '大西洋银行',
|
code: 'bem',
|
logo: '/static/payment/bem.png'
|
},
|
{
|
id: 4,
|
name: '青岛商业银行',
|
code: 'bcm',
|
logo: '/static/payment/bcm.png'
|
}
|
]
|
const bankIndex = ref(-1)
|
|
// 卡类型
|
const cardTypes = [
|
{ value: 'debit', label: '储蓄卡' },
|
{ value: 'credit', label: '信用卡' }
|
]
|
const selectedCardType = ref('debit')
|
|
// 表单数据
|
const form = ref({
|
bankId: '',
|
cardType: 'debit',
|
cardNumber: '',
|
holderName: '',
|
phone: '',
|
verifyCode: '',
|
isDefault: false
|
})
|
|
// 验证码倒计时
|
const countdown = ref(0)
|
let timer = null
|
|
// 选择银行
|
const onBankChange = (e) => {
|
const index = parseInt(e.detail.value)
|
bankIndex.value = index
|
form.value.bankId = banks[index].id
|
}
|
|
// 格式化卡号
|
const formatCardNumber = (e) => {
|
let value = e.detail.value.replace(/\D/g, '')
|
value = value.replace(/(\d{4})(?=\d)/g, '$1 ')
|
form.value.cardNumber = value
|
}
|
|
// 验证手机号码
|
const validatePhone = (phone) => {
|
// 青岛手机号规则: 6开头的8位数字
|
const macauMobile = /^6\d{7}$/
|
// 内地手机号规则
|
const mainlandMobile = /^1[3-9]\d{9}$/
|
// 香港手机号规则: 5/6/9开头的8位数字
|
const hkMobile = /^[569]\d{7}$/
|
|
return macauMobile.test(phone) || mainlandMobile.test(phone) || hkMobile.test(phone)
|
}
|
|
// 发送验证码
|
const sendVerifyCode = () => {
|
if (countdown.value > 0) return
|
if (!form.value.phone) {
|
uni.showToast({
|
title: '请输入手机号码',
|
icon: 'none'
|
})
|
return
|
}
|
|
if (!validatePhone(form.value.phone)) {
|
uni.showToast({
|
title: '请输入正确的手机号码',
|
icon: 'none'
|
})
|
return
|
}
|
|
// 这里调用发送验证码API
|
countdown.value = 60
|
timer = setInterval(() => {
|
countdown.value--
|
if (countdown.value <= 0) {
|
clearInterval(timer)
|
timer = null
|
}
|
}, 1000)
|
}
|
|
// 是否可以提交
|
const canSubmit = computed(() => {
|
const { bankId, cardNumber, holderName, phone, verifyCode } = form.value
|
return bankId &&
|
cardNumber &&
|
holderName &&
|
phone &&
|
verifyCode &&
|
validatePhone(phone)
|
})
|
|
// 提交表单
|
const submitForm = () => {
|
if (!canSubmit.value) return
|
|
uni.showLoading({
|
title: '添加中...'
|
})
|
|
// 这里调用添加银行卡API
|
console.log('提交表单:', form.value)
|
|
setTimeout(() => {
|
uni.hideLoading()
|
uni.showToast({
|
title: '添加成功',
|
icon: 'success'
|
})
|
setTimeout(() => {
|
uni.navigateBack()
|
}, 1500)
|
}, 1000)
|
}
|
|
// 组件销毁时清除定时器
|
onUnmounted(() => {
|
if (timer) {
|
clearInterval(timer)
|
timer = null
|
}
|
})
|
</script>
|
|
<style lang="scss">
|
.add-bank-card {
|
min-height: 100vh;
|
background: $bg-color;
|
padding: 20rpx 20rpx 120rpx;
|
|
.form-card {
|
background: #fff;
|
border-radius: $radius-lg;
|
padding: 30rpx;
|
margin-bottom: 20rpx;
|
|
.form-item {
|
margin-bottom: 30rpx;
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
|
.label {
|
font-size: 28rpx;
|
color: $text-primary;
|
margin-bottom: 16rpx;
|
display: block;
|
|
&.required::before {
|
content: '*';
|
color: $danger;
|
margin-right: 4rpx;
|
}
|
}
|
|
input {
|
width: 100%;
|
height: 88rpx;
|
background: $bg-color;
|
border-radius: $radius-lg;
|
padding: 0 30rpx;
|
font-size: 28rpx;
|
color: $text-primary;
|
}
|
|
.picker {
|
height: 88rpx;
|
background: $bg-color;
|
border-radius: $radius-lg;
|
padding: 0 30rpx;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
|
text {
|
font-size: 28rpx;
|
color: $text-primary;
|
|
&.icon-arrow-right {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
}
|
}
|
|
.card-types {
|
display: flex;
|
gap: 30rpx;
|
|
.type-item {
|
flex: 1;
|
height: 88rpx;
|
background: $bg-color;
|
border-radius: $radius-lg;
|
display: flex;
|
align-items: center;
|
padding: 0 30rpx;
|
|
.radio {
|
width: 32rpx;
|
height: 32rpx;
|
border: 2rpx solid $text-secondary;
|
border-radius: 50%;
|
margin-right: 16rpx;
|
position: relative;
|
|
&::after {
|
content: '';
|
position: absolute;
|
left: 50%;
|
top: 50%;
|
transform: translate(-50%, -50%);
|
width: 16rpx;
|
height: 16rpx;
|
background: $primary-color;
|
border-radius: 50%;
|
opacity: 0;
|
transition: all 0.3s;
|
}
|
}
|
|
text {
|
font-size: 28rpx;
|
color: $text-regular;
|
}
|
|
&.active {
|
background: $primary-light;
|
|
.radio {
|
border-color: $primary-color;
|
|
&::after {
|
opacity: 1;
|
}
|
}
|
|
text {
|
color: $primary-color;
|
}
|
}
|
}
|
}
|
|
&.verify-code {
|
display: flex;
|
gap: 20rpx;
|
|
input {
|
flex: 1;
|
}
|
|
.send-btn {
|
width: 200rpx;
|
height: 88rpx;
|
line-height: 88rpx;
|
font-size: 26rpx;
|
color: $primary-color;
|
background: $primary-light;
|
border-radius: $radius-lg;
|
|
&[disabled] {
|
opacity: 0.5;
|
}
|
}
|
}
|
}
|
|
.switch-item {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
text {
|
font-size: 28rpx;
|
color: $text-primary;
|
}
|
}
|
}
|
|
.notice-card {
|
background: #fff;
|
border-radius: $radius-lg;
|
padding: 30rpx;
|
|
.section-title {
|
font-size: 30rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 20rpx;
|
}
|
|
.notice-list {
|
.notice-item {
|
display: flex;
|
align-items: flex-start;
|
margin-bottom: 16rpx;
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
|
.dot {
|
width: 12rpx;
|
height: 12rpx;
|
background: $primary-color;
|
border-radius: 50%;
|
margin-top: 8rpx;
|
margin-right: 12rpx;
|
flex-shrink: 0;
|
}
|
|
.content {
|
flex: 1;
|
font-size: 26rpx;
|
color: $text-regular;
|
line-height: 1.6;
|
}
|
}
|
}
|
}
|
|
.bottom-bar {
|
position: fixed;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
padding: 20rpx 30rpx;
|
background: #fff;
|
box-shadow: $shadow-lg;
|
|
.submit-btn {
|
width: 100%;
|
|
&[disabled] {
|
opacity: 0.6;
|
}
|
}
|
}
|
}
|
</style>
|