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

892 lines
20 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.name }}</text>
<text class="bank-card">{{ selectedBank.cardNumber }}</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 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"
@close="showDeleteModal = false"
@success="onBankSuccess"
/>
</view>
</template>
<script>
import { commonEnum } from '@/enum/commonEnum.js'
import { getWithdrawInfo, submitWithdraw } from '@/api/user/user.js'
import { getBankAccountList } from '@/api/account.js'
import AddCard from './addCard.vue'
import DeleteCard from './deleteCar.vue'
export default {
components: {
AddCard,
DeleteCard,
},
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: '1',
},
selectedBank: {
id: '1',
name: '建设银行',
icon: commonEnum.CHINA_CONSTRUCTION_BANK,
cardNumber: '**** **** **** 1234',
},
banks: [
{
id: '1',
name: '建设银行',
icon: commonEnum.CHINA_CONSTRUCTION_BANK,
cardNumber: '**** **** **** 1234',
},
{
id: '2',
name: '工商银行',
icon: commonEnum.CHINA_CONSTRUCTION_BANK,
cardNumber: '**** **** **** 5678',
},
{
id: '3',
name: '农业银行',
icon: commonEnum.CHINA_CONSTRUCTION_BANK,
cardNumber: '**** **** **** 9012',
},
{
id: '4',
name: '中国银行',
icon: commonEnum.CHINA_CONSTRUCTION_BANK,
cardNumber: '**** **** **** 3456',
},
],
// 银行卡管理相关
showAddModal: false,
showDeleteModal: false,
bankList: [],
}
},
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.fetchBankList()
},
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 fetchBankList() {
try {
const response = await getBankAccountList()
if (response.code === 200 && response.data) {
this.bankList = response.data.map(item => ({
...item,
cardNumber: this.maskCardNumber(item.no),
}))
console.log('银行卡列表获取成功:', this.bankList)
}
} 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)
},
// 银行卡操作成功回调
onBankSuccess() {
this.fetchBankList()
},
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() {
uni.showActionSheet({
itemList: this.banks.map(bank => `${bank.name} ${bank.cardNumber}`),
success: res => {
const selectedBank = this.banks[res.tapIndex]
this.selectedBank = selectedBank
this.withdrawalData.bankId = selectedBank.id
},
})
},
async submitWithdrawal() {
if (!this.withdrawalData.amount || parseFloat(this.withdrawalData.amount) <= 0) {
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.name}吗?`,
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;
}
}
}
.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;
}
.debug-info {
background: #fff;
margin: 20rpx;
padding: 20rpx;
border-radius: 10rpx;
text {
display: block;
font-size: 24rpx;
color: #666;
margin-bottom: 10rpx;
}
}
@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;
}
}
}
/* 模态框样式 */
.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>