HomeLease/pages/requestWithdrawal/requestWithdrawal.vue
2025-08-20 16:42:14 +08:00

949 lines
22 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="page">
<!-- 加载状态 -->
<view v-if="loading" class="loading-overlay">
<view class="loading-content">
<view class="loading-spinner"></view>
<text class="loading-text">加载中...</text>
</view>
</view>
<!-- 提现容器 -->
<!-- 账户余额卡片 -->
<view class="balance-card">
<view class="balance-item">
<view class="balance-label">账户余额 (元)</view>
<view class="balance-value">{{ withdrawInfo.balance }}</view>
</view>
<view class="balance-item">
<view class="balance-label">未结算金额 (元)</view>
<view class="balance-value">{{ withdrawInfo.unsettled }}</view>
</view>
</view>
<view class="withdrawal-container">
<!-- 提现金额输入 -->
<view class="withdrawal-section">
<view class="section-title">提现金额</view>
<view class="amount-input">
<text class="currency-symbol">¥</text>
<input
v-model="withdrawalData.amount"
class="amount-field"
placeholder="请输入金额"
type="text"
@input="onAmountInput"
/>
<view class="withdraw-all-btn" @click="withdrawAll">全部提现</view>
</view>
</view>
<!-- 提现至银行 -->
<view class="bank-section">
<view class="section-title">提现至</view>
<view class="bank-selector" @click="selectBank">
<view class="bank-info">
<image :src="selectedBank.icon" class="bank-icon" mode="aspectFit"></image>
<view class="bank-details">
<text class="bank-name">{{ selectedBank.displayName || '请选择银行卡' }}</text>
<text class="bank-card">{{ selectedBank.cardNumber || '暂无银行卡' }}</text>
<text v-if="selectedBank.name" class="bank-owner"
>收款人: {{ selectedBank.name }}
</text>
</view>
</view>
<text class="arrow-icon"></text>
</view>
<!-- 银行卡管理按钮 -->
</view>
<view class="bank-management">
<view class="bank-btn add-btn" @click="showAddModal = true">添加银行卡</view>
<view class="bank-btn delete-btn" @click="showDeleteModal = true">删除银行卡</view>
</view>
<!-- 银行卡状态提示 -->
<view v-if="userBankList.length === 0" class="bank-status-tip">
<text class="tip-text">您还没有添加银行卡,请先添加银行卡</text>
</view>
<!-- 提现按钮 -->
<view class="withdraw-btn" @click="submitWithdrawal">立即提现</view>
</view>
<!-- 可提现金额提示 -->
<view class="available-amount"> 可提现金额: {{ withdrawInfo.available }}元</view>
<!-- 提现说明 -->
<view class="withdrawal-explanation">
<view class="explanation-title">提现说明:</view>
<view class="explanation-item">
<text>提现金额: {{ withdrawalData.amount ? withdrawalData.amount + '元' : '0.00元' }}</text>
</view>
<view class="explanation-item">
<text>实际到账: {{ actualAmount }}元</text>
</view>
<view class="explanation-item">
<text>提现手续费: {{ fee }}元</text>
</view>
<view class="explanation-item">
<text>最小提现金额: {{ withdrawInfo.minAmount }}元</text>
</view>
<view class="explanation-item">
<text>最大提现金额: {{ withdrawInfo.maxAmount }}</text>
</view>
</view>
<!-- 添加银行卡组件 -->
<add-card :visible="showAddModal" @close="showAddModal = false" @success="onBankSuccess" />
<!-- 删除银行卡组件 -->
<delete-card
:visible="showDeleteModal"
:bank-list="userBankList"
@close="showDeleteModal = false"
@success="onBankSuccess"
/>
</view>
</template>
<script>
import { commonEnum } from '@/enum/commonEnum.js'
import { getWithdrawInfo, submitWithdraw } from '@/api/user/user.js'
import { getUserBankList } from '@/api/account.js'
import AddCard from './addCard.vue'
import DeleteCardd from './deleteCard.vue'
export default {
components: {
AddCard,
DeleteCard: DeleteCardd,
},
data() {
return {
loading: false,
withdrawInfo: {
balance: '10000.00',
unsettled: '0.00',
available: '10000.00',
fee: 1.0,
minAmount: 100.0,
maxAmount: 50000.0,
},
withdrawalData: {
amount: '',
bankId: '',
},
selectedBank: {
id: '',
name: '',
icon: commonEnum.CHINA_CONSTRUCTION_BANK,
cardNumber: '',
type: 'BANK',
},
// 用户银行卡列表
userBankList: [],
// 银行卡管理相关
showAddModal: false,
showDeleteModal: false,
}
},
computed: {
fee() {
const amount = parseFloat(this.withdrawalData.amount) || 0
return this.withdrawInfo.fee || 1 // 使用API返回的手续费或默认1元
},
actualAmount() {
const amount = parseFloat(this.withdrawalData.amount) || 0
const fee = parseFloat(this.fee)
const result = amount - fee
return result > 0 ? result.toFixed(2) : '0.00'
},
},
onLoad() {
this.fetchWithdrawInfo()
this.fetchUserBankList()
},
methods: {
// 获取提现信息
async fetchWithdrawInfo() {
this.loading = true
try {
const response = await getWithdrawInfo()
if (response.code === 200 && response.data) {
this.withdrawInfo = {
...this.withdrawInfo,
...response.data,
}
console.log('提现信息获取成功:', this.withdrawInfo)
}
} catch (error) {
console.error('获取提现信息失败:', error)
uni.showToast({
title: '获取提现信息失败',
icon: 'none',
})
} finally {
this.loading = false
}
},
// 获取用户银行卡列表
async fetchUserBankList() {
try {
console.log('开始获取用户银行卡列表...123')
const response = await getUserBankList()
console.log('API响应123:', response)
console.log('row:')
if (response.code === 200 && response.rows) {
this.userBankList = response.rows || []
console.log('用户银行卡列表获取成功:')
// 处理银行卡数据
this.userBankList = this.userBankList.map(item => ({
...item,
cardNumber: this.maskCardNumber(item.no),
icon: this.getBankIcon(item.type),
displayName: this.getDisplayName(item),
}))
console.log('用户银行卡列表获取成功:', this.userBankList)
// 如果有银行卡,设置默认选中的银行卡
if (this.userBankList.length > 0) {
this.selectedBank = this.userBankList[0]
this.withdrawalData.bankId = this.selectedBank.id
console.log('设置默认银行卡:', this.selectedBank)
} else {
console.log('没有找到银行卡,显示空状态')
}
} else {
console.log('API返回错误:', response)
uni.showToast({
title: response.msg || '获取银行卡列表失败',
icon: 'none',
})
}
} catch (error) {
console.error('获取用户银行卡列表失败:', error)
uni.showToast({
title: '获取银行卡列表失败',
icon: 'none',
})
}
},
// 掩码银行卡号
maskCardNumber(cardNumber) {
if (!cardNumber) return ''
if (cardNumber.length <= 8) return cardNumber
return '**** **** **** ' + cardNumber.slice(-4)
},
// 获取银行图标
getBankIcon(type) {
// 根据type字段判断类型B和BAN都表示银行卡
if (type === 'B' || type === 'BAN') {
return commonEnum.CHINA_CONSTRUCTION_BANK
} else if (type === 'QR') {
return '/static/icons/qr-code.png' // 收款二维码图标
}
return commonEnum.CHINA_CONSTRUCTION_BANK
},
// 获取显示名称
getDisplayName(item) {
// 根据type字段判断类型
if (item.type === 'B' || item.type === 'BAN') {
return '银行卡'
} else if (item.type === 'QR') {
return '收款二维码'
}
return '银行卡'
},
// 银行卡操作成功回调
onBankSuccess() {
this.fetchUserBankList()
},
goBack() {
uni.navigateBack()
},
onAmountInput(e) {
const value = e.detail.value
console.log('输入值:', value)
// 只允许数字和小数点
const filteredValue = value.replace(/[^\d.]/g, '')
// 确保只有一个小数点
const parts = filteredValue.split('.')
if (parts.length > 2) {
this.withdrawalData.amount = parts[0] + '.' + parts.slice(1).join('')
} else {
// 限制小数点后最多2位数字
if (parts.length === 2 && parts[1].length > 2) {
this.withdrawalData.amount = parts[0] + '.' + parts[1].substring(0, 2)
} else {
this.withdrawalData.amount = filteredValue
}
}
},
withdrawAll() {
const available = parseFloat(this.withdrawInfo.available) || 0
this.withdrawalData.amount = available.toString()
console.log('全部提现,设置金额:', this.withdrawalData.amount)
},
selectBank() {
if (this.userBankList.length === 0) {
uni.showToast({
title: '请先添加银行卡',
icon: 'none',
})
return
}
uni.showActionSheet({
itemList: this.userBankList.map(
bank => `${bank.displayName} ${bank.cardNumber} (${bank.name})`
),
success: res => {
const selectedBank = this.userBankList[res.tapIndex]
this.selectedBank = selectedBank
this.withdrawalData.bankId = selectedBank.id
console.log('选择银行卡:', selectedBank)
},
})
},
async submitWithdrawal() {
if (!this.withdrawalData.amount || parseFloat(this.withdrawalData.amount) <= 0) {
uni.showToast({
title: '请输入提现金额',
icon: 'none',
})
return
}
if (!this.withdrawalData.bankId) {
uni.showToast({
title: '请选择提现银行卡',
icon: 'none',
})
return
}
const amount = parseFloat(this.withdrawalData.amount)
const available = parseFloat(this.withdrawInfo.available)
const minAmount = parseFloat(this.withdrawInfo.minAmount)
const maxAmount = parseFloat(this.withdrawInfo.maxAmount)
if (amount > available) {
uni.showToast({
title: '提现金额超过可提现余额',
icon: 'none',
})
return
}
if (amount < minAmount) {
uni.showToast({
title: `提现金额不能少于${minAmount}`,
icon: 'none',
})
return
}
if (amount > maxAmount) {
uni.showToast({
title: `提现金额不能超过${maxAmount}`,
icon: 'none',
})
return
}
uni.showModal({
title: '确认提现',
content: `确认提现${this.withdrawalData.amount}元到${this.selectedBank.displayName}吗?`,
success: async res => {
if (res.confirm) {
this.loading = true
try {
const response = await submitWithdraw({
amount: amount,
bankId: this.withdrawalData.bankId,
})
if (response.code === 200) {
uni.showToast({
title: '提现申请已提交',
icon: 'success',
})
// 刷新提现信息
await this.fetchWithdrawInfo()
// 返回上一页
setTimeout(() => {
uni.navigateBack()
}, 1500)
} 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>
.page {
min-height: 90vh;
background: #f7f7f7;
padding-top: 20rpx;
padding-bottom: 40rpx;
}
.loading-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: 9999;
.loading-content {
background: #fff;
padding: 40rpx;
border-radius: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.loading-spinner {
width: 80rpx;
height: 80rpx;
border: 8rpx solid #f3f3f3;
border-top: 8rpx solid #ff803a;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20rpx;
}
.loading-text {
font-size: 32rpx;
color: #333;
}
}
}
.withdrawal-container {
background: #fff;
border-radius: 20rpx;
margin: 20rpx;
padding-bottom: 54rpx;
overflow: hidden;
}
.balance-card {
display: flex;
justify-content: space-between;
margin: 20rpx;
padding: 40rpx;
background: linear-gradient(135deg, #ff803a, #ff6b35);
border-radius: 20rpx;
color: white;
.balance-item {
text-align: center;
.balance-label {
font-size: 24rpx;
margin-bottom: 10rpx;
opacity: 0.9;
}
.balance-value {
font-size: 36rpx;
font-weight: bold;
}
}
}
.withdrawal-section {
padding: 30rpx;
//border-bottom: 1rpx solid #f0f0f0;
.section-title {
font-size: 28rpx;
color: #3d3d3d;
margin-bottom: 20rpx;
font-weight: 500;
}
.amount-input {
display: flex;
align-items: center;
border-bottom: 1rpx solid #f0f0f0;
padding-bottom: 20rpx;
.currency-symbol {
font-size: 80rpx;
color: #333;
margin-right: 20rpx;
font-weight: bold;
}
.amount-field {
height: 90rpx;
//border: #4cd964 1px solid;
flex: 1;
font-size: 80rpx;
color: #333;
}
.withdraw-all-btn {
padding: 10rpx 20rpx;
color: #ff803a;
font-size: 30rpx;
}
}
}
.bank-section {
display: flex;
padding: 30rpx;
align-items: center;
justify-content: space-between;
//border-bottom: 1rpx solid #f0f0f0;
.section-title {
font-size: 28rpx;
color: #7c7c7c;
font-weight: 500;
}
.bank-selector {
display: flex;
align-items: center;
justify-content: space-between;
.bank-info {
display: flex;
align-items: center;
gap: 20rpx;
.bank-icon {
width: 40rpx;
height: 40rpx;
}
.bank-details {
display: flex;
flex-direction: column;
.bank-name {
font-size: 28rpx;
color: #333;
margin-bottom: 5rpx;
}
.bank-card {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.bank-owner {
font-size: 22rpx;
color: #666;
margin-top: 4rpx;
}
}
}
.arrow-icon {
font-size: 32rpx;
color: #999;
}
}
}
.withdraw-btn {
margin: 17rpx;
padding: 30rpx;
background: #ffeee4;
color: #ff803a;
text-align: center;
font-size: 36rpx;
font-weight: 500;
border-radius: 46rpx;
box-shadow: rgba(0, 0, 0, 0.1) 0 5px 10px 0;
}
.available-amount {
padding-left: 66rpx;
text-align: left;
font-size: 24rpx;
color: #666;
margin-bottom: 30rpx;
}
.withdrawal-explanation {
margin: 30rpx;
padding: 30rpx;
background: #fff;
border-radius: 20rpx;
.explanation-title {
font-size: 34rpx;
color: #3d3d3d;
margin-bottom: 20rpx;
font-weight: 500;
}
.explanation-item {
padding: 10rpx 0;
font-size: 26rpx;
color: #3d3d3d;
}
}
view {
//border: red solid 1px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 银行卡管理样式 */
.bank-management {
margin-top: 20rpx;
display: flex;
gap: 20rpx;
.bank-btn {
flex: 1;
padding: 20rpx;
text-align: center;
border-radius: 10rpx;
font-size: 28rpx;
font-weight: 500;
&.add-btn {
background: #ff803a;
color: #fff;
}
&.delete-btn {
background: #ff4757;
color: #fff;
}
}
}
/* 银行卡状态提示 */
.bank-status-tip {
margin: 20rpx 30rpx;
padding: 20rpx;
background: #fff5f0;
border-radius: 10rpx;
border-left: 4rpx solid #ff803a;
.tip-text {
font-size: 26rpx;
color: #ff803a;
text-align: center;
}
}
/* 模态框样式 */
.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;
.modal-content {
width: 90%;
max-width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
.modal-header {
padding: 30rpx;
text-align: center;
border-bottom: 1rpx solid #f0f0f0;
.modal-title {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
}
.modal-body {
padding: 30rpx;
.form-group {
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;
}
}
.form-select {
width: 100%;
height: 80rpx;
border: 1rpx solid #e0e0e0;
border-radius: 10rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
background: #fafafa;
}
.upload-area {
border: 2rpx dashed #e0e0e0;
border-radius: 10rpx;
padding: 40rpx;
text-align: center;
background: #fafafa;
&.has-image {
border-color: #ff803a;
background: #fff;
}
.upload-icon {
font-size: 60rpx;
color: #999;
margin-bottom: 20rpx;
}
.upload-text {
font-size: 26rpx;
color: #666;
margin-bottom: 20rpx;
}
.upload-btn {
display: inline-block;
padding: 15rpx 30rpx;
background: #ff803a;
color: #fff;
border-radius: 8rpx;
font-size: 24rpx;
}
.preview-image {
width: 200rpx;
height: 200rpx;
border-radius: 10rpx;
margin: 20rpx auto;
}
}
}
}
.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;
}
}
}
}
}
/* 银行卡列表样式 */
.bank-list-modal {
.modal-content {
.bank-list {
max-height: 600rpx;
overflow-y: auto;
.bank-item {
display: flex;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.bank-icon {
width: 60rpx;
height: 60rpx;
margin-right: 20rpx;
border-radius: 8rpx;
}
.bank-info {
flex: 1;
.bank-name {
font-size: 30rpx;
color: #333;
margin-bottom: 8rpx;
font-weight: 500;
}
.bank-number {
font-size: 26rpx;
color: #666;
}
.bank-type {
font-size: 24rpx;
color: #999;
margin-top: 5rpx;
}
}
.delete-icon {
width: 40rpx;
height: 40rpx;
color: #ff4757;
}
}
}
}
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.modal-content {
width: 95%;
margin: 20rpx;
}
.bank-management {
flex-direction: column;
.bank-btn {
margin-bottom: 15rpx;
}
}
}
/* 动画效果 */
.modal-overlay {
animation: fadeIn 0.3s ease-out;
}
.modal-content {
animation: slideUp 0.3s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
transform: translateY(100rpx);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
/* 加载状态样式 */
.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 currentColor;
border-radius: 50%;
animation: spin 1s linear infinite;
}
}
</style>