HomeLease/pages/requestWithdrawal/addCard.vue
2025-08-20 15:32:16 +08:00

413 lines
8.3 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 v-if="visible" class="modal-overlay" @click="handleClose">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">添加银行卡</text>
<text class="modal-close" @click="handleClose">×</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="form-label">账户类型</text>
<picker
:range="typeOptions"
:value="typeIndex"
range-key="label"
@change="onTypeChange"
>
<view class="picker-value">{{ typeOptions[typeIndex].label }}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">{{ typeOptions[typeIndex].noLabel }}</text>
<input
v-model="bankForm.no"
:placeholder="typeOptions[typeIndex].noPlaceholder"
class="form-input"
maxlength="30"
/>
</view>
<view class="form-item">
<text class="form-label">收款人姓名</text>
<input
v-model="bankForm.name"
class="form-input"
maxlength="20"
placeholder="请输入收款人姓名"
/>
</view>
<view class="form-item">
<text class="form-label">身份证号</text>
<input
v-model="bankForm.idCard"
class="form-input"
maxlength="18"
placeholder="请输入身份证号"
/>
</view>
<view class="form-item">
<text class="form-label">手机号</text>
<input
v-model="bankForm.mobile"
class="form-input"
maxlength="11"
placeholder="请输入手机号"
type="number"
/>
</view>
</view>
<view class="modal-footer">
<view class="modal-btn cancel-btn" @click="handleClose">取消</view>
<view
:class="{ 'loading-btn': loading }"
class="modal-btn confirm-btn"
@click="handleSubmit"
>
{{ loading ? '添加中...' : '确认添加' }}
</view>
</view>
</view>
</view>
</template>
<script>
import { addBankAccount } from '@/api/account.js'
export default {
name: 'AddCard',
props: {
visible: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false,
typeIndex: 0,
typeOptions: [
{
label: '银行卡',
value: 'BANK',
noLabel: '银行卡号',
noPlaceholder: '请输入银行卡号',
},
{
label: '收款二维码',
value: 'QR',
noLabel: '收款码图片',
noPlaceholder: '请输入收款码图片URL',
},
],
bankForm: {
type: 'BANK',
no: '',
name: '',
idCard: '',
mobile: '',
},
}
},
watch: {
visible(newVal) {
if (newVal) {
this.resetForm()
}
}
},
methods: {
// 重置表单
resetForm() {
this.bankForm = {
type: 'BANK',
no: '',
name: '',
idCard: '',
mobile: '',
}
this.typeIndex = 0
},
// 关闭弹窗
handleClose() {
this.$emit('close')
},
// 类型选择变化
onTypeChange(e) {
this.typeIndex = e.detail.value
this.bankForm.type = this.typeOptions[this.typeIndex].value
},
// 验证表单
validateForm() {
if (!this.bankForm.no.trim()) {
uni.showToast({
title: '请输入' + this.typeOptions[this.typeIndex].noLabel,
icon: 'none',
})
return false
}
if (!this.bankForm.name.trim()) {
uni.showToast({
title: '请输入收款人姓名',
icon: 'none',
})
return false
}
if (!this.bankForm.idCard.trim()) {
uni.showToast({
title: '请输入身份证号',
icon: 'none',
})
return false
}
if (!this.bankForm.mobile.trim()) {
uni.showToast({
title: '请输入手机号',
icon: 'none',
})
return false
}
// 验证身份证号格式
const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
if (!idCardRegex.test(this.bankForm.idCard)) {
uni.showToast({
title: '身份证号格式不正确',
icon: 'none',
})
return false
}
// 验证手机号格式
const mobileRegex = /^1[3-9]\d{9}$/
if (!mobileRegex.test(this.bankForm.mobile)) {
uni.showToast({
title: '手机号格式不正确',
icon: 'none',
})
return false
}
return true
},
// 提交表单
async handleSubmit() {
if (!this.validateForm()) {
return
}
this.loading = true
try {
const response = await addBankAccount(this.bankForm)
if (response.code === 200) {
uni.showToast({
title: '银行卡添加成功',
icon: 'success',
})
this.$emit('success')
this.handleClose()
} else {
uni.showToast({
title: response.msg || '添加失败',
icon: 'none',
})
}
} catch (error) {
console.error('添加银行卡失败:', error)
uni.showToast({
title: '添加失败,请重试',
icon: 'none',
})
} finally {
this.loading = false
}
},
},
}
</script>
<style lang="scss" scoped>
/* 模态框样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
animation: fadeIn 0.3s ease-out;
}
.modal-content {
width: 90%;
max-width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
animation: slideUp 0.3s ease-out;
}
.modal-header {
padding: 30rpx;
text-align: center;
border-bottom: 1rpx solid #f0f0f0;
position: relative;
.modal-title {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
.modal-close {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 40rpx;
color: #999;
cursor: pointer;
}
}
.modal-body {
padding: 30rpx;
.form-item {
margin-bottom: 30rpx;
.form-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 500;
}
.form-input {
width: 100%;
height: 80rpx;
border: 1rpx solid #e0e0e0;
border-radius: 10rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
background: #fafafa;
&:focus {
border-color: #ff803a;
background: #fff;
}
}
.picker-value {
width: 100%;
height: 80rpx;
border: 1rpx solid #e0e0e0;
border-radius: 10rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
background: #fafafa;
display: flex;
align-items: center;
}
}
}
.modal-footer {
display: flex;
border-top: 1rpx solid #f0f0f0;
.modal-btn {
flex: 1;
padding: 30rpx;
text-align: center;
font-size: 30rpx;
font-weight: 500;
&.cancel-btn {
color: #666;
border-right: 1rpx solid #f0f0f0;
}
&.confirm-btn {
color: #ff803a;
}
&.loading-btn {
position: relative;
color: transparent !important;
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 30rpx;
height: 30rpx;
margin: -15rpx 0 0 -15rpx;
border: 3rpx solid transparent;
border-top: 3rpx solid #ff803a;
border-radius: 50%;
animation: spin 1s linear infinite;
}
}
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
transform: translateY(100rpx);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.modal-content {
width: 95%;
margin: 20rpx;
}
}
</style>