This commit is contained in:
parent
ffa6106b79
commit
d201e42309
|
|
@ -319,7 +319,7 @@ const handleLogout = () => {
|
|||
.logo-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
height: 100%;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
padding: 4px 0 ;
|
||||
|
|
|
|||
|
|
@ -15,109 +15,199 @@
|
|||
</div>
|
||||
|
||||
<!-- 存款弹窗 -->
|
||||
<RechangeDialog class="rechange-pay-dialog" :visible="dialogVisible" title="存款" width="500px" :show-footer="false"
|
||||
<RechangeDialog class="rechange-pay-dialog" :visible="dialogVisible" title="存款" width="600px" :show-footer="false"
|
||||
@cancel="handleCancel" @close="handleClose">
|
||||
<!-- 步骤1:选择金额和支付方式 -->
|
||||
<template v-if="payStep === 1">
|
||||
<!-- 渠道信息 -->
|
||||
<div class="channel-card">
|
||||
<div class="channel-info">
|
||||
<div class="channel-name">{{ rechangeForm.channelName }}</div>
|
||||
<!-- type === 8 时显示新样式(选择金额和支付方式) -->
|
||||
<template v-if="rechangeForm.type === 8">
|
||||
<!-- 步骤1:选择金额和支付方式 -->
|
||||
<template v-if="payStep === 1">
|
||||
<!-- 渠道信息 -->
|
||||
<div class="channel-card">
|
||||
<div class="channel-info">
|
||||
<div class="channel-name">{{ rechangeForm.channelName }}</div>
|
||||
</div>
|
||||
<div class="channel-meta">支持货币: AUD (澳元)</div>
|
||||
</div>
|
||||
<div class="channel-meta">支持货币: AUD (澳元)</div>
|
||||
</div>
|
||||
|
||||
<!-- 快捷金额选择 -->
|
||||
<div class="quick-amount">
|
||||
<div class="section-title">选择充值金额</div>
|
||||
<div class="amount-list">
|
||||
<div v-for="(amount, index) in quickAmounts" :key="index" class="amount-item"
|
||||
:class="{ active: rechangeForm.depositAmount === amount.toString() }"
|
||||
@click="handleQuickAmount(amount)">
|
||||
{{ amount }} AUD
|
||||
<!-- 快捷金额选择 -->
|
||||
<div class="quick-amount">
|
||||
<div class="section-title">选择充值金额</div>
|
||||
<div class="amount-list">
|
||||
<div v-for="(amount, index) in quickAmounts" :key="index" class="amount-item"
|
||||
:class="{ active: rechangeForm.depositAmount === amount.toString() }"
|
||||
@click="handleQuickAmount(amount)">
|
||||
{{ amount }} AUD
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自定义金额 -->
|
||||
<el-form-item label="自定义金额">
|
||||
<el-input v-model="rechangeForm.depositAmount" placeholder="请输入充值金额" size="large"
|
||||
@input="handleAmountInput">
|
||||
<template #suffix>
|
||||
<span class="currency-suffix">AUD</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<!-- 自定义金额 -->
|
||||
<el-form-item label="自定义金额">
|
||||
<el-input v-model="rechangeForm.depositAmount" placeholder="请输入充值金额" size="large"
|
||||
@input="handleAmountInput">
|
||||
<template #suffix>
|
||||
<span class="currency-suffix">AUD</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 支付方式选择 -->
|
||||
<div class="payment-methods">
|
||||
<div class="section-title">选择支付方式</div>
|
||||
<div class="method-list">
|
||||
<div v-for="method in paymentMethods" :key="method.code" class="method-item"
|
||||
:class="{ active: selectedMethod === method.code }" @click="handleSelectMethod(method.code)">
|
||||
<div class="method-icon">
|
||||
<img :src="method.icon" :alt="method.name" />
|
||||
<!-- 支付方式选择 -->
|
||||
<div class="payment-methods">
|
||||
<div class="section-title">选择支付方式</div>
|
||||
<div class="method-list">
|
||||
<div v-for="method in paymentMethods" :key="method.code" class="method-item"
|
||||
:class="{ active: selectedMethod === method.code }" @click="handleSelectMethod(method.code)">
|
||||
<div class="method-icon">
|
||||
<img :src="method.icon" :alt="method.name" />
|
||||
</div>
|
||||
<span class="method-name">{{ method.name }}</span>
|
||||
<div class="method-check" v-if="selectedMethod === method.code">
|
||||
<el-icon>
|
||||
<Check />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<span class="method-name">{{ method.name }}</span>
|
||||
<div class="method-check" v-if="selectedMethod === method.code">
|
||||
<el-icon>
|
||||
<Check />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 按钮区 -->
|
||||
<div class="dialog-actions">
|
||||
<el-button size="large" @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" size="large" :loading="submitLoading"
|
||||
:disabled="!rechangeForm.depositAmount || !selectedMethod" @click="handleCreateOrder">
|
||||
确认支付
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 步骤2:支付中/跳转 -->
|
||||
<template v-else-if="payStep === 2">
|
||||
<!-- 移动端:直接跳转 -->
|
||||
<template v-if="isMobileDevice">
|
||||
<div class="loading-section">
|
||||
<el-icon class="is-loading" size="48">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<div class="loading-text">正在跳转支付页面...</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 桌面端:显示二维码 -->
|
||||
<template v-else>
|
||||
<div class="qrcode-section">
|
||||
<div class="section-title">请使用{{ getMethodName(selectedMethod) }}扫码支付</div>
|
||||
<div class="qrcode-container">
|
||||
<div v-show="qrcodeLoading">
|
||||
<el-icon class="is-loading" size="48">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div v-show="!qrcodeLoading">
|
||||
<img v-if="qrcodeImageUrl" :src="qrcodeImageUrl" alt="支付二维码" class="qrcode-image" />
|
||||
<div v-else ref="qrcodeRef" class="qrcode"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qrcode-tip">请使用{{ getMethodName(selectedMethod) }}扫描上方二维码完成支付</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- type !== 8 时显示老样式(银行卡信息 + 上传凭证) -->
|
||||
<template v-else>
|
||||
<el-form ref="rechangeFormRef" :model="rechangeForm" :rules="rechangeFormRules" label-position="top">
|
||||
<!-- 渠道信息 -->
|
||||
<div class="channel-card">
|
||||
<div class="channel-info">
|
||||
<div class="channel-name">{{ rechangeForm.channelName }}</div>
|
||||
<div class="channel-meta">
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="channel-meta">支持货币: {{ rechangeForm.currencySymbol }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 银行卡信息(channel_code = BANK 时显示) -->
|
||||
<template v-if="rechangeForm.channelCode === 'BANK'">
|
||||
<div class="info-section">
|
||||
<div class="section-title">收款信息</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="label">账户持有人姓名</span>
|
||||
<span class="value">{{ rechangeForm.beneficiaryName }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">银行名称</span>
|
||||
<span class="value">{{ rechangeForm.beneficiaryBankName }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">银行识别代码</span>
|
||||
<span class="value">{{ rechangeForm.swiftBicCode }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">收款人银行账号</span>
|
||||
<span class="value">{{ rechangeForm.beneficiaryBankAccount }}</span>
|
||||
</div>
|
||||
<div class="info-item full-width">
|
||||
<span class="label">银行地址</span>
|
||||
<span class="value">{{ rechangeForm.beneficiaryBankAddress }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 钱包地址信息(其他渠道显示) -->
|
||||
<template v-else>
|
||||
<div class="info-section">
|
||||
<div class="section-title">收款信息</div>
|
||||
<div class="info-item full-width">
|
||||
<span class="label">钱包收款地址</span>
|
||||
<span class="value address-value">{{ rechangeForm.address }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 充值金额 -->
|
||||
<el-form-item label="充值金额" prop="depositAmount">
|
||||
<el-input v-model="rechangeForm.depositAmount" placeholder="请输入充值金额" size="large" @input="handleAmountInput">
|
||||
<template #suffix>
|
||||
<span class="currency-suffix">{{ rechangeForm.currencySymbol }}</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 上传凭证 -->
|
||||
<el-form-item label="上传凭证" prop="voucherUrl">
|
||||
<el-upload class="voucher-uploader" action="" :show-file-list="false"
|
||||
:http-request="handleUpload" :before-upload="beforeAvatarUpload" :loading="uploadLoading">
|
||||
<img v-if="voucherUrl" :src="voucherUrl" class="voucher-image" />
|
||||
<div v-else class="upload-placeholder">
|
||||
<el-icon class="upload-icon">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
<span class="upload-text">点击上传凭证</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 按钮区 -->
|
||||
<div class="dialog-actions">
|
||||
<el-button size="large" @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" size="large" :loading="submitLoading"
|
||||
:disabled="!rechangeForm.depositAmount || !selectedMethod" @click="handleCreateOrder">
|
||||
确认支付
|
||||
<el-button type="primary" size="large" :loading="submitLoading" @click="handleOldSubmit">
|
||||
确认充值
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 步骤2:支付中/跳转 -->
|
||||
<template v-else-if="payStep === 2">
|
||||
<!-- 移动端:直接跳转 -->
|
||||
<template v-if="isMobileDevice">
|
||||
<div class="loading-section">
|
||||
<el-icon class="is-loading" size="48">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<div class="loading-text">正在跳转支付页面...</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 桌面端:显示二维码 -->
|
||||
<template v-else>
|
||||
<div class="qrcode-section">
|
||||
<div class="section-title">请使用{{ getMethodName(selectedMethod) }}扫码支付</div>
|
||||
<div class="qrcode-container">
|
||||
<div v-show="qrcodeLoading">
|
||||
<el-icon class="is-loading" size="48">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div v-show="!qrcodeLoading">
|
||||
<img v-if="qrcodeImageUrl" :src="qrcodeImageUrl" alt="支付二维码" class="qrcode-image" />
|
||||
<div v-else ref="qrcodeRef" class="qrcode"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qrcode-tip">请使用{{ getMethodName(selectedMethod) }}扫描上方二维码完成支付</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</RechangeDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Check, Loading } from '@element-plus/icons-vue'
|
||||
import { Check, Loading, Plus } from '@element-plus/icons-vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'Rechange'
|
||||
})
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { FormInstance, FormRules, UploadProps } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { nextTick, onMounted, ref, computed } from 'vue'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
|
|
@ -125,12 +215,17 @@ import RechangeTable from '@/components/common/Table.vue'
|
|||
import RechangeDialog from '@/components/common/Dialog.vue'
|
||||
import { usePageLoading } from '@/composables/useLoading'
|
||||
import { rechangeTableColumns } from './options'
|
||||
import { getRechargeChannelList, getApplyCustomerRef, getKycDetail, createBuyEx } from '@/api/modules/capital/rechangeChanl'
|
||||
import { getRechargeChannelList, getApplyCustomerRef, getKycDetail, createBuyEx, rechargeApi } from '@/api/modules/capital/rechangeChanl'
|
||||
import { uploadImageApi } from '@/api/modules/upload'
|
||||
import QRCode from 'qrcode'
|
||||
import alipayIcon from '@/assets/images/zfb.png'
|
||||
import wechatIcon from '@/assets/images/wx.png'
|
||||
import unionpayIcon from '@/assets/images/ylzf.png'
|
||||
|
||||
// 上传凭证相关
|
||||
const voucherUrl = ref('')
|
||||
const uploadLoading = ref(false)
|
||||
|
||||
// 获取用户信息
|
||||
const userStore = useUserStore()
|
||||
const userInfo = userStore.userInfo as any
|
||||
|
|
@ -213,11 +308,13 @@ const channelList = ref<ChannelRow[]>([])
|
|||
// 弹窗表单数据
|
||||
interface RechangeFormData {
|
||||
id: number
|
||||
type: number
|
||||
channelName: string
|
||||
channelCode: string
|
||||
currencySymbol: string
|
||||
channelFee: string
|
||||
depositAmount: string
|
||||
voucherUrl: string
|
||||
beneficiaryName: string
|
||||
beneficiaryBankName: string
|
||||
swiftBicCode: string
|
||||
|
|
@ -228,11 +325,13 @@ interface RechangeFormData {
|
|||
|
||||
const createDefaultForm = (): RechangeFormData => ({
|
||||
id: 0,
|
||||
type: 0,
|
||||
channelName: '',
|
||||
channelCode: '',
|
||||
currencySymbol: '',
|
||||
channelFee: '0',
|
||||
depositAmount: '',
|
||||
voucherUrl: '',
|
||||
beneficiaryName: '',
|
||||
beneficiaryBankName: '',
|
||||
swiftBicCode: '',
|
||||
|
|
@ -249,6 +348,9 @@ const rechangeFormRules = ref<FormRules<RechangeFormData>>({
|
|||
{ required: true, message: '请输入充值金额', trigger: ['blur', 'change'] },
|
||||
{ pattern: /^\d+$/, message: '请输入整数金额', trigger: ['blur', 'change'] },
|
||||
],
|
||||
voucherUrl: [
|
||||
{ required: true, message: '请上传充值凭证', trigger: ['change'] },
|
||||
],
|
||||
})
|
||||
|
||||
// 渠道数据接口
|
||||
|
|
@ -290,11 +392,13 @@ const fetchChannelList = async () => {
|
|||
const handleOpenDialog = async (row: ChannelRow) => {
|
||||
rechangeForm.value = {
|
||||
id: row.id,
|
||||
type: row.type,
|
||||
channelName: row.name,
|
||||
channelCode: row.channel_code,
|
||||
currencySymbol: 'AUD',
|
||||
currencySymbol: row.currency?.symbol || 'AUD',
|
||||
channelFee: row.channel_fee || '0',
|
||||
depositAmount: '',
|
||||
voucherUrl: '',
|
||||
beneficiaryName: row.beneficiary_name || '',
|
||||
beneficiaryBankName: row.beneficiary_bank_name || '',
|
||||
swiftBicCode: row.swift_bic_code || '',
|
||||
|
|
@ -305,6 +409,7 @@ const handleOpenDialog = async (row: ChannelRow) => {
|
|||
// 重置支付状态
|
||||
payStep.value = 1
|
||||
selectedMethod.value = ''
|
||||
voucherUrl.value = ''
|
||||
|
||||
dialogVisible.value = true
|
||||
await nextTick()
|
||||
|
|
@ -381,6 +486,57 @@ const handleCreateOrder = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
// 上传凭证相关
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
if (rawFile.type !== 'image/jpeg' && rawFile.type !== 'image/png') {
|
||||
ElMessage.error('图片格式必须为 JPG 或 PNG!')
|
||||
return false
|
||||
} else if (rawFile.size / 1024 / 1024 > 2) {
|
||||
ElMessage.error('图片大小不能超过 2MB!')
|
||||
return false
|
||||
}
|
||||
uploadLoading.value = true
|
||||
return true
|
||||
}
|
||||
|
||||
// 自定义上传方法
|
||||
const handleUpload = async (options: any) => {
|
||||
const { file, onSuccess, onError } = options
|
||||
try {
|
||||
const res: any = await uploadImageApi(file)
|
||||
voucherUrl.value = res.url
|
||||
rechangeForm.value.voucherUrl = res.url
|
||||
onSuccess(res)
|
||||
// 上传成功后手动清除该字段的验证状态
|
||||
nextTick(() => {
|
||||
rechangeFormRef.value?.clearValidate('voucherUrl')
|
||||
})
|
||||
} catch (error) {
|
||||
onError(error)
|
||||
uploadLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 老表单提交(type !== 8 时使用)
|
||||
const handleOldSubmit = async () => {
|
||||
try {
|
||||
await rechangeFormRef.value?.validate()
|
||||
submitLoading.value = true
|
||||
await rechargeApi({
|
||||
channel_id: rechangeForm.value.id,
|
||||
amount: rechangeForm.value.depositAmount,
|
||||
img: rechangeForm.value.voucherUrl,
|
||||
})
|
||||
ElMessage.success('充值提交成功')
|
||||
dialogVisible.value = false
|
||||
fetchChannelList()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.msg || '充值提交失败')
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 取消弹窗
|
||||
const handleCancel = () => {
|
||||
dialogVisible.value = false
|
||||
|
|
@ -390,6 +546,7 @@ const handleCancel = () => {
|
|||
qrcodeLoading.value = false
|
||||
payStep.value = 1
|
||||
selectedMethod.value = ''
|
||||
voucherUrl.value = ''
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
|
|
@ -660,4 +817,125 @@ onMounted(() => {
|
|||
font-size: 14px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
// info-section 样式
|
||||
.info-section {
|
||||
background: #f5f7fa;
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
||||
&.full-width {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
word-break: break-all;
|
||||
|
||||
&.address-value {
|
||||
font-family: monospace;
|
||||
background: #fff;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-item.full-width {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
||||
.label {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
word-break: break-all;
|
||||
|
||||
&.address-value {
|
||||
font-family: monospace;
|
||||
background: #fff;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 上传凭证样式
|
||||
.voucher-uploader {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
:deep(.el-upload) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.voucher-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.upload-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
color: #909399;
|
||||
|
||||
.upload-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.upload-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue