aslan-h5/src/views/Wallet/CashOut/CashWithdraw.vue

834 lines
24 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.

// src/views/Wallet/CashOut/CashOut.vue
<template>
<div class="fullPage">
<GeneralHeader :title="t('cash_withdraw')" style="width: 100%" color="rgba(0, 0, 0, 0.80)">
<template #extraFunction>
<img
v-smart-img
src="@/assets/icon/history.png"
alt=""
style=""
class="extra-icon-btn"
@click="lookDetails"
/>
</template>
</GeneralHeader>
<!-- 主体内容 -->
<div style="padding: 16px; display: flex; flex-direction: column; gap: 2vw">
<!-- 提现部分 -->
<div style="display: flex; flex-direction: column; gap: 2vw">
<!-- 收入金额 -->
<div style="display: flex; justify-content: space-between; align-items: center">
<div style="font-weight: 600">{{ t('salary_balance', { amount: currentAmount }) }}</div>
</div>
<!-- 输入框 -->
<div
style="
background-color: white;
padding: 16px;
border-radius: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
"
>
<input
name=""
id=""
placeholder="50"
style="
width: 100%;
outline: none;
border: none;
background-color: transparent;
color: black;
"
:value="cashOutAmount"
@input="handleCashOutAmountInput"
dir="ltr"
inputmode="decimal"
/>
</div>
<!-- 规则 -->
<div style="color: #f00; font-weight: 500; font-size: 0.8em">
{{ t('withdrawal_rule_1') }}
<br />
{{ t('withdrawal_rule_2') }}
</div>
</div>
<!-- 使用的银行卡 -->
<div style="display: flex; flex-direction: column; gap: 2vw">
<!-- 标题 -->
<div style="display: flex; justify-content: space-between; align-items: center">
<div style="font-weight: 600">{{ t('currently_in_use') }}</div>
<!-- 跳转按钮 -->
<img
v-smart-img
src="/src/assets/icon/arrow.png"
alt=""
style="width: 6vw"
class="flipImg"
@click="gotoselectBank"
/>
</div>
<!-- 银行卡信息 -->
<div
style="
border-radius: 8px;
background: #fff;
padding: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
"
:style="
usedBankCard
? `border-radius: 11.75px;border: 0.5px solid rgba(255, 255, 255, 0.08);`
: ''
"
@click="cashOutTypeShow = true"
>
<!-- 无使用银行卡 -->
<div v-if="!usedBankCard" style="font-weight: 510; color: rgba(0, 0, 0, 0.4)">
{{ t('no_bank_cards_in_use') }}
</div>
<!-- 银行卡信息 -->
<div v-else style="display: flex; align-items: center; gap: 2vw">
<!-- 银行图标 -->
<div style="width: 4.5em">
<img
v-smart-img
v-if="usedBankCard?.cardType == 'BANK'"
src="@/assets/icon/bank/BANK.png"
alt=""
style="width: 100%; display: block"
/>
<img
v-smart-img
v-if="usedBankCard?.cardType == 'USDT'"
src="@/assets/icon/bank/USDT.png"
alt=""
style="width: 100%; display: block"
/>
</div>
<!-- 银行卡信息 -->
<div
style="
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div
style="
font-weight: 510;
color: rgba(0, 0, 0, 0.8);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
{{ t('payee') }}: {{ usedBankCard?.payee }}
</div>
<div style="font-weight: 510; color: rgba(0, 0, 0, 0.4)">
{{ t('card_number') }}: {{ usedBankCard?.cardNo }}
</div>
</div>
</div>
</div>
</div>
<!-- 个人信息 -->
<div style="display: flex; flex-direction: column; gap: 2vw">
<!-- 标题 -->
<div style="display: flex; align-items: center">
<div style="font-weight: 600">{{ t('kyc') }}</div>
<!-- 申请状态 -->
<div v-if="hasKYC" style="font-weight: 600; margin: 0 4px">:</div>
<!-- 通过 -->
<div
v-if="bankCardInfo?.status === 'PASS'"
style="
font-weight: 510;
font-size: 0.9em;
background: linear-gradient(248deg, #75ff98 5.66%, #3dff54 42.49%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
"
>
{{ t('review_passed') }}
</div>
<!-- 未通过 -->
<div
v-if="bankCardInfo?.status === 'NOT_PASS'"
style="
font-weight: 510;
font-size: 0.9em;
background: linear-gradient(248deg, #ff7578 5.66%, #ff3d40 42.49%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
"
>
{{ t('review_failed') }}
</div>
<!-- 审核中 -->
<div
v-if="bankCardInfo?.status === 'PENDING'"
style="
font-weight: 510;
font-size: 0.9em;
background: linear-gradient(248deg, #ffe675 5.66%, #ffc53d 42.49%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
"
>
{{ t('awaiting_review') }}
</div>
</div>
<!-- 资料内容 -->
<div
style="
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
"
>
<!-- 未上传 -->
<div
v-if="!hasKYC"
style="display: flex; justify-content: space-between; align-items: center"
@click="gotoKYC"
>
<span style="font-weight: 510; font-size: 1em">{{ t('complete_information') }}</span>
<img
v-smart-img
src="/src/assets/icon/arrow.png"
alt=""
style="width: 6vw"
class="flipImg"
/>
</div>
<!-- 获取到上传的资料 -->
<div v-else style="width: 100%; display: flex; flex-direction: column; gap: 8px">
<!-- 资料 -->
<div style="display: flex; justify-content: space-between; align-items: center">
<!-- 图片数量 -->
<span style="font-weight: 510; font-size: 1em">{{
t('passport_id_card', { current: bankCardInfo.previewUrls.length })
}}</span>
<!-- 跳转按钮 -->
<img
v-smart-img
src="/src/assets/icon/arrow.png"
alt=""
style="width: 6vw"
@click="gotoKYC"
class="flipImg"
/>
</div>
<!-- 资料图片列表 -->
<div style="display: flex; align-items: center; gap: 4px">
<img
:src="imgUrl"
alt=""
v-for="imgUrl in bankCardInfo.previewUrls"
style="width: 10vw; aspect-ratio: 1/1; border-radius: 4px"
/>
</div>
<!-- 联系方式 -->
<div style="font-weight: 500">{{ t('contact_number') }}:</div>
<div style="color: rgba(0, 0, 0, 0.4); font-weight: 600; font-size: 0.8em">
{{ bankCardInfo.contactNumber }}
</div>
<!-- 备注信息 -->
<div style="font-weight: 500">{{ t('other_description') }}:</div>
<div style="color: rgba(0, 0, 0, 0.4); font-weight: 600; font-size: 0.8em">
{{ bankCardInfo.otherDescription }}
</div>
</div>
</div>
</div>
<!-- 提现按钮 -->
<div style="display: flex; justify-content: center; align-items: center">
<div
style="
margin-top: 10px;
width: 80%;
border-radius: 32px;
padding: 12px;
color: #fff;
font-weight: 590;
text-align: center;
"
:style="{
background: checkStatus
? 'linear-gradient(135deg, #BB92FF 2.82%, #8B45FF 99.15%), linear-gradient(135deg, #D1CED6 2.82%, #7C7882 99.15%)'
: 'linear-gradient(135deg, #D1CED6 2.82%, #7C7882 99.15%)',
}"
@click="Receive"
>
{{ t('cash_out') }}
</div>
</div>
</div>
<!-- 弹窗遮罩层 -->
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
<!-- 资料不足提示弹窗 -->
<div
v-if="cashOutTipShow"
style="
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
"
@click="closedPopup"
>
<div
style="
width: 80%;
border-radius: 12px;
background: #fff;
padding: 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
"
@click.stop
>
<div style="color: rgba(0, 0, 0, 0.8); font-weight: 800">{{ t('tips') }}</div>
<div style="color: rgba(0, 0, 0, 0.4); font-weight: 600; font-size: 0.8em">
{{ t('fill_info_tips') }}
</div>
<div style="color: rgba(0, 0, 0, 0.4); font-weight: 600; font-size: 0.6em">
{{ t('card_issue_tips') }}
</div>
<div
style="
display: flex;
justify-content: center;
align-items: center;
border-radius: 12px;
background: linear-gradient(
152deg,
rgba(198, 112, 255, 0.8) 7.01%,
rgba(119, 38, 255, 0.8) 92.99%
);
color: #fff;
font-weight: 800;
padding: 8px 12px;
width: 50%;
"
@click="gotoKYC"
>
{{ t('receive') }}
</div>
</div>
</div>
<!-- 选择提现方式抽屉 -->
<div
v-if="cashOutTypeShow"
style="position: fixed; bottom: 0; width: 100%"
@click="closedPopup"
>
<div
style="
background: white;
border-radius: 16px 16px 0 0;
max-height: 80vh;
display: flex;
flex-direction: column;
gap: 2vw;
padding: 20px 0;
"
@click.stop
>
<!-- 标题 -->
<div style="display: flex; justify-content: center; align-items: center">
<div style="margin: 0; font-size: 18px; font-weight: 600; color: #333">
{{ t('bd_salary') }}
</div>
</div>
<!-- 银行卡列表 -->
<div
style="
width: 100%;
height: 80vw;
padding: 16px;
display: flex;
flex-direction: column;
gap: 3vw;
"
class="overflow-y-auto"
>
<!-- 列表为空 -->
<div
v-if="bankCardList.length === 0"
style="
border-radius: 8px;
background: #fff;
padding: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
"
>
<div style="font-weight: 510; color: rgba(0, 0, 0, 0.4)">
{{ t('no_bank_cards_added') }}
</div>
</div>
<!-- 列表不为空 -->
<div
v-else
v-for="card in bankCardList"
:key="card.id"
style="
border-radius: 8px;
background: #fff;
padding: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
display: flex;
flex-direction: column;
gap: 2vw;
"
@click="setDefaultBankCard(card.id)"
>
<!-- 银行卡信息 -->
<div style="display: flex; align-items: center; gap: 2vw">
<!-- 银行图 -->
<div style="width: 4.5em">
<img
v-smart-img
v-if="card.cardType == 'BANK'"
src="@/assets/icon/bank/BANK.png"
alt=""
style="width: 100%; display: block"
/>
<img
v-smart-img
v-if="card.cardType == 'USDT'"
src="@/assets/icon/bank/USDT.png"
alt=""
style="width: 100%; display: block"
/>
</div>
<!-- 信息 -->
<div style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px">
<div
style="
font-weight: 510;
color: rgba(0, 0, 0, 0.8);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
{{ t('payee') }}: {{ card.payee }}
</div>
<div style="font-weight: 510; color: rgba(0, 0, 0, 0.4)">
{{ t('card_number') }}: {{ card.cardNo }}
</div>
</div>
<div
style="
width: 1.5em;
aspect-ratio: 1/1;
border-radius: 50%;
border: 1px solid gray;
box-sizing: border-box;
position: relative;
display: flex;
justify-content: center;
align-items: center;
"
>
<div
v-if="card.use"
style="
width: 0.9em;
aspect-ratio: 1/1;
border-radius: 50%;
background-color: #3dff54;
"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 等待审核提示弹窗 -->
<div
v-if="cashOutShow"
style="
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
"
@click="closedPopup"
>
<div
style="
width: 80%;
border-radius: 12px;
background: #fff;
padding: 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
"
@click.stop
>
<div style="color: rgba(0, 0, 0, 0.8); font-weight: 800">{{ t('tips') }}</div>
<div style="color: rgba(0, 0, 0, 0.8); font-weight: 600; font-size: 0.8em">
{{ t('cash_withdrawal_tips') }}
</div>
<div
style="
display: flex;
justify-content: center;
align-items: center;
border-radius: 999999px;
background:
linear-gradient(180deg, #d3acff 0%, rgba(222, 172, 255, 0) 58.38%),
linear-gradient(152deg, #c670ff 7.01%, #7726ff 92.99%), #ff4768;
box-shadow:
-1px 0 5px 0 rgba(255, 255, 255, 0.7) inset,
-3.5px 0 7.5px 0 rgba(255, 255, 255, 0.2) inset,
1px 0 5px 0 rgba(255, 255, 255, 0.7) inset,
3.5px 0 7.5px 0 rgba(255, 255, 255, 0.2) inset;
color: #fff;
font-weight: 700;
padding: 8px 12px;
width: 50%;
"
@click="closedPopup"
>
{{ t('receive') }}
</div>
</div>
</div>
</maskLayer>
</div>
</template>
<script setup>
import { useI18n } from 'vue-i18n'
import { setApplyInfo, getApplyInfo } from '@/utils/applyStore.js'
import { ref, onMounted, computed, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { setDocumentDirection } from '@/locales/i18n'
import {
withdrawableAmount, // 获取可提现金额
withdrawApply, // 提交提现申请
} from '@/api/lottery'
import {
getBankBalance, // 获取余额
getBankCardList, // 获取正在使用的银行卡
getWithdrawInfoList, // 获取申请提现信息
useBankCard, // 设置默认银行卡
} from '@/api/wallet.js'
import GeneralHeader from '@/components/GeneralHeader.vue'
import maskLayer from '@/components/MaskLayer.vue'
const { t, locale } = useI18n()
const router = useRouter()
const route = useRoute()
// 监听语言变化并设置文档方向
locale.value && setDocumentDirection(locale.value)
const cashOutTipShow = ref(false)
const cashOutTypeShow = ref(false)
const cashOutShow = ref(false)
const cashOutAmount = ref(null)
const maskLayerShow = computed(() => {
return cashOutTipShow.value || cashOutShow.value || cashOutTypeShow.value
})
const bankCardList = ref([]) // 银行卡列表
const usedBankCard = ref(null) //正在使用的银行卡
const closedPopup = () => {
cashOutTipShow.value = false
cashOutShow.value = false
cashOutTypeShow.value = false
}
const activityId = route.query.activityId || ''
const currentAmount = ref(0) //可提现金额
const bankCardInfo = ref(null)
const hasKYC = computed(() => {
return bankCardInfo.value != null
})
// 前往选择提交方式
const gotoselectBank = () => {
router.push('/bank-card')
}
// 查看历史提现信息
const lookDetails = () => {
router.push({ path: '/cash-out-details', query: { activityId: activityId } })
}
// 查看历史提现信息
const gotoKYC = () => {
router.push('/KYC')
}
// 是否可以提现
const checkStatus = computed(() => {
return bankCardInfo.value?.status == 'PASS' && usedBankCard.value?.id && cashOutAmount.value >= 50
})
// 确认提现
const Receive = async () => {
// 资料不足
if (!hasKYC.value) {
cashOutTipShow.value = true
return
}
// 资料填写完成 + 银行卡信息通过
else if (checkStatus.value) {
try {
const resApply = await withdrawApply({
activityId: activityId,
amount: cashOutAmount.value,
contactNumber: bankCardInfo.value.contactNumber,
cardImages: JSON.stringify(bankCardInfo.value.previewUrls),
description: bankCardInfo.value.otherDescription,
})
if (resApply.status) {
closedPopup()
await getDrawableAmount() // 刷新银行余额
cashOutShow.value = true
}
} catch (error) {
closedPopup()
console.log('提现失败:', error.response?.errorMsg)
showError(t('something_went_wrong'))
}
}
}
//获取可提现金额
const getDrawableAmount = async () => {
try {
const response = await getBankBalance()
if (response.status && typeof response.body === 'number') {
// 格式化余额显示保留2位小数
currentAmount.value = response.body.toFixed(2)
} else {
currentAmount.value = 0
}
} catch (error) {
console.error('Failed to fetch bank balance:', error)
currentAmount.value = 0
// 可以显示错误提示
showError(t('failed_to_load_balance'))
}
}
// 数字处理
const handleCashOutAmountInput = (event) => {
let value = event.target.value
// 只保留数字和小数点
value = value.replace(/[^\d.]/g, '')
// 防止多个小数点
const parts = value.split('.')
if (parts.length > 2) {
value = parts[0] + '.' + parts.slice(1).join('')
}
// 如果输入值超过可用余额,则限制为最大值
const numericValue = parseFloat(value)
if (numericValue > currentAmount.value) {
value = currentAmount.value.toString()
}
// 更新输入框的值
event.target.value = value
// 更新 cashOutAmount 的值
cashOutAmount.value = parseFloat(value) || 0
}
// 获取提现信息列表
const getWithdrawInfoListData = async () => {
try {
const resWithdrawInfoList = await getWithdrawInfoList()
console.log('提现信息列表:', resWithdrawInfoList)
if (resWithdrawInfoList.status && resWithdrawInfoList.body?.length > 0) {
let imgList = JSON.parse(resWithdrawInfoList.body[0].passportFrontUrl)
let previewUrls = imgList.map((item) => item)
bankCardInfo.value = { previewUrls, ...resWithdrawInfoList.body[0] }
}
} catch (error) {
console.error('获取提现信息列表失败:', error)
showError(error.response?.errorMsg)
}
}
// 获取银行卡列表
const getBankCards = async () => {
try {
const resBankCards = await getBankCardList()
console.log('银行卡列表:', resBankCards)
if (resBankCards.status && resBankCards.body) {
// 处理银行卡列表数据
bankCardList.value = resBankCards.body
const usedCard = bankCardList.value.find((card) => card.use)
if (usedCard) {
usedBankCard.value = usedCard
} else {
// 没有使用中的银行卡
usedBankCard.value = null
}
}
} catch (error) {
console.error('获取银行卡列表失败:', error)
}
}
// 设置默认银行卡
const setDefaultBankCard = async (cardId) => {
if (usedBankCard.value?.id === cardId) {
return
}
try {
const resUseCard = await useBankCard({ id: cardId })
if (resUseCard.status) {
getBankCards() // 重新获取银行卡列表
}
} catch (error) {
showError(error.response?.errorMsg || '')
}
}
onMounted(() => {
getDrawableAmount() //获取可提现金额
getWithdrawInfoListData() // 获取提现信息列表
getBankCards() // 获取正在使用的银行卡
})
onUnmounted(() => {
setApplyInfo()
})
</script>
<style lang="scss" scoped>
* {
color: rgba(0, 0, 0, 0.8);
}
.fullPage {
width: 100vw;
min-height: 100vh;
background-color: #fff;
background-image: url(/src/assets/images/secondBg.png);
background-size: 100% auto;
background-repeat: no-repeat;
position: relative;
}
.extra-icon-btn {
width: 1.2em;
display: block;
object-fit: cover;
cursor: pointer;
transition: all 0.2s ease;
}
.extra-icon-btn:active {
transform: scale(0.9);
}
input[type='number'] {
font-family: 'Arial', sans-serif; /* 使用支持西方数字的字体 */
direction: ltr; /* 强制从左到右 */
}
.overflow-y-auto {
overflow-y: auto;
}
.overflow-y-auto::-webkit-scrollbar {
display: none;
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 12px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
}
@media screen and (min-width: 1024px) {
* {
font-size: 32px;
}
}
/* RTL支持 */
[dir='rtl'] .flipImg {
transform: scaleX(-1);
}
</style>