This commit is contained in:
parent
ffa6106b79
commit
d201e42309
|
|
@ -15,8 +15,10 @@
|
||||||
</div>
|
</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">
|
@cancel="handleCancel" @close="handleClose">
|
||||||
|
<!-- type === 8 时显示新样式(选择金额和支付方式) -->
|
||||||
|
<template v-if="rechangeForm.type === 8">
|
||||||
<!-- 步骤1:选择金额和支付方式 -->
|
<!-- 步骤1:选择金额和支付方式 -->
|
||||||
<template v-if="payStep === 1">
|
<template v-if="payStep === 1">
|
||||||
<!-- 渠道信息 -->
|
<!-- 渠道信息 -->
|
||||||
|
|
@ -108,16 +110,104 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</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>
|
||||||
|
</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" @click="handleOldSubmit">
|
||||||
|
确认充值
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</RechangeDialog>
|
</RechangeDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Check, Loading } from '@element-plus/icons-vue'
|
import { Check, Loading, Plus } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Rechange'
|
name: 'Rechange'
|
||||||
})
|
})
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules, UploadProps } from 'element-plus'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { nextTick, onMounted, ref, computed } from 'vue'
|
import { nextTick, onMounted, ref, computed } from 'vue'
|
||||||
import { useUserStore } from '@/stores/modules/user'
|
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 RechangeDialog from '@/components/common/Dialog.vue'
|
||||||
import { usePageLoading } from '@/composables/useLoading'
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import { rechangeTableColumns } from './options'
|
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 QRCode from 'qrcode'
|
||||||
import alipayIcon from '@/assets/images/zfb.png'
|
import alipayIcon from '@/assets/images/zfb.png'
|
||||||
import wechatIcon from '@/assets/images/wx.png'
|
import wechatIcon from '@/assets/images/wx.png'
|
||||||
import unionpayIcon from '@/assets/images/ylzf.png'
|
import unionpayIcon from '@/assets/images/ylzf.png'
|
||||||
|
|
||||||
|
// 上传凭证相关
|
||||||
|
const voucherUrl = ref('')
|
||||||
|
const uploadLoading = ref(false)
|
||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const userInfo = userStore.userInfo as any
|
const userInfo = userStore.userInfo as any
|
||||||
|
|
@ -213,11 +308,13 @@ const channelList = ref<ChannelRow[]>([])
|
||||||
// 弹窗表单数据
|
// 弹窗表单数据
|
||||||
interface RechangeFormData {
|
interface RechangeFormData {
|
||||||
id: number
|
id: number
|
||||||
|
type: number
|
||||||
channelName: string
|
channelName: string
|
||||||
channelCode: string
|
channelCode: string
|
||||||
currencySymbol: string
|
currencySymbol: string
|
||||||
channelFee: string
|
channelFee: string
|
||||||
depositAmount: string
|
depositAmount: string
|
||||||
|
voucherUrl: string
|
||||||
beneficiaryName: string
|
beneficiaryName: string
|
||||||
beneficiaryBankName: string
|
beneficiaryBankName: string
|
||||||
swiftBicCode: string
|
swiftBicCode: string
|
||||||
|
|
@ -228,11 +325,13 @@ interface RechangeFormData {
|
||||||
|
|
||||||
const createDefaultForm = (): RechangeFormData => ({
|
const createDefaultForm = (): RechangeFormData => ({
|
||||||
id: 0,
|
id: 0,
|
||||||
|
type: 0,
|
||||||
channelName: '',
|
channelName: '',
|
||||||
channelCode: '',
|
channelCode: '',
|
||||||
currencySymbol: '',
|
currencySymbol: '',
|
||||||
channelFee: '0',
|
channelFee: '0',
|
||||||
depositAmount: '',
|
depositAmount: '',
|
||||||
|
voucherUrl: '',
|
||||||
beneficiaryName: '',
|
beneficiaryName: '',
|
||||||
beneficiaryBankName: '',
|
beneficiaryBankName: '',
|
||||||
swiftBicCode: '',
|
swiftBicCode: '',
|
||||||
|
|
@ -249,6 +348,9 @@ const rechangeFormRules = ref<FormRules<RechangeFormData>>({
|
||||||
{ required: true, message: '请输入充值金额', trigger: ['blur', 'change'] },
|
{ required: true, message: '请输入充值金额', trigger: ['blur', 'change'] },
|
||||||
{ pattern: /^\d+$/, 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) => {
|
const handleOpenDialog = async (row: ChannelRow) => {
|
||||||
rechangeForm.value = {
|
rechangeForm.value = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
|
type: row.type,
|
||||||
channelName: row.name,
|
channelName: row.name,
|
||||||
channelCode: row.channel_code,
|
channelCode: row.channel_code,
|
||||||
currencySymbol: 'AUD',
|
currencySymbol: row.currency?.symbol || 'AUD',
|
||||||
channelFee: row.channel_fee || '0',
|
channelFee: row.channel_fee || '0',
|
||||||
depositAmount: '',
|
depositAmount: '',
|
||||||
|
voucherUrl: '',
|
||||||
beneficiaryName: row.beneficiary_name || '',
|
beneficiaryName: row.beneficiary_name || '',
|
||||||
beneficiaryBankName: row.beneficiary_bank_name || '',
|
beneficiaryBankName: row.beneficiary_bank_name || '',
|
||||||
swiftBicCode: row.swift_bic_code || '',
|
swiftBicCode: row.swift_bic_code || '',
|
||||||
|
|
@ -305,6 +409,7 @@ const handleOpenDialog = async (row: ChannelRow) => {
|
||||||
// 重置支付状态
|
// 重置支付状态
|
||||||
payStep.value = 1
|
payStep.value = 1
|
||||||
selectedMethod.value = ''
|
selectedMethod.value = ''
|
||||||
|
voucherUrl.value = ''
|
||||||
|
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
await nextTick()
|
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 = () => {
|
const handleCancel = () => {
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
|
@ -390,6 +546,7 @@ const handleCancel = () => {
|
||||||
qrcodeLoading.value = false
|
qrcodeLoading.value = false
|
||||||
payStep.value = 1
|
payStep.value = 1
|
||||||
selectedMethod.value = ''
|
selectedMethod.value = ''
|
||||||
|
voucherUrl.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
|
|
@ -660,4 +817,125 @@ onMounted(() => {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-top: 16px;
|
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>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue