qnc-webview-tob/src/views/Withdraw.vue
2025-04-10 23:01:03 +08:00

342 lines
12 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>
<div class="p-4 bg-gradient-to-b from-blue-50/30 to-gray-50 min-h-screen">
<div> <!-- 提现卡片 -->
<div class="rounded-xl shadow-lg bg-gradient-to-r from-blue-50/70 to-blue-100/50 p-6 mb-4">
<div class="flex items-center mb-6">
<van-icon name="alipay" class="text-blue-500 text-xl mr-2" />
<h1 class="text-xl font-bold text-gray-800">支付宝提现</h1>
</div>
<!-- 支付宝账号 -->
<div class="mb-6">
<label class="text-sm text-gray-600 mb-2 block">支付宝账号</label>
<van-field v-model="alipayAccount" placeholder="请输入支付宝账号"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm"
:rules="[{ required: true, message: ' ' }]">
<template #left-icon>
<van-icon name="phone-o" class="text-gray-500" />
</template>
</van-field>
<small class="text-gray-400 text-xs mt-1 block">可填写支付宝账户绑定的手机号</small>
</div>
<!-- 支付宝实名姓名 -->
<div class="mb-6">
<label class="text-sm text-gray-600 mb-2 block">实名姓名</label>
<van-field v-model="realName" placeholder="请输入支付宝认证姓名"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm" :rules="[{
required: true,
message: ' ',
validator: (val) => /^[\u4e00-\u9fa5]{2,4}$/.test(val)
}]">
<template #left-icon>
<van-icon name="contact-o" class="text-gray-500" />
</template>
</van-field>
<small class="text-gray-400 text-xs mt-1 block">请填写支付宝账户认证的真实姓名</small>
</div>
<!-- 提现金额 -->
<div class="mb-4">
<label class="text-sm text-gray-600 mb-2 block">提现金额</label>
<van-field v-model.number="amount" type="number" placeholder="请输入提现金额"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm"
:rules="[{ required: true, message: ' ' }, { validator: validateAmount, message: ' ' }]">
<template #left-icon>
<van-icon name="gold-coin-o" class="text-gray-500" />
</template>
<template #right-icon>
</template>
<template #button>
<van-button size="small" type="primary"
class="bg-gradient-to-r from-blue-500/20 to-blue-400/20 text-blue-600 rounded-full px-3 shadow-sm"
@click="fillMaxAmount">
全部提现
</van-button>
</template>
</van-field>
</div>
<!-- 金额提示 -->
<div class="text-sm text-gray-500 mb-6">
可提现金额:<span class="text-blue-600 font-semibold">¥{{ availableAmount }}</span>
</div>
<!-- 提现规则 -->
<div class="bg-blue-50/60 p-4 rounded-xl backdrop-blur-sm">
<div class="flex items-center text-sm text-blue-500 mb-2">
<van-icon name="warning" class="mr-1" />提现须知
</div>
<ul class="text-xs text-gray-600 space-y-1">
<li>· 每日限提现1次最低50元</li>
<li>· 超过800元需人工审核1-3个工作日</li>
<li>· 到账时间24小时内</li>
</ul>
</div>
</div>
<!-- 提交按钮 -->
<van-button type="primary" block :loading="isSubmitting"
class="bg-gradient-to-r from-blue-500 to-blue-400 text-white rounded-xl shadow-lg h-12 font-bold text-base"
@click="handleSubmit">
立即提现
</van-button>
</div>
<van-popup v-model:show="showStatusPopup" round position="center"
:style="{ width: '85%', borderRadius: '20px' }" :overlay-style="{ backgroundColor: 'rgba(0,0,0,0.4)' }">
<div class="p-8 bg-gradient-to-b from-white to-blue-50/30 relative">
<!-- 状态内容 -->
<div class="text-center space-y-5">
<!-- 状态图标 -->
<div class="relative inline-block">
<div class="absolute inset-0 bg-gradient-to-r opacity-20 rounded-full animate-pulse blur-sm"
:class="statusBg[status]"></div>
<van-icon :name="statusIcon[status]" size="56" class="p-1 rounded-full border-[3px]"
:class="statusIconClass[status]" />
</div>
<!-- 状态文案 -->
<div>
<h2 class="text-xl font-semibold mb-1" :class="statusTextColors[status]">
{{ statusMessages[status] }}
</h2>
<template v-if="status === 2">
<p class="text-sm text-gray-500">
已向 <span class="text-blue-500">{{ alipayAccount }}</span> 转账
</p>
<p class="text-2xl font-bold text-green-600 mt-2">¥{{ amount }}</p>
</template>
<template v-if="status === 3">
<p class="text-red-500 text-sm px-4">{{ failMsg }}</p>
</template>
</div>
<!-- 进度条(处理中状态) -->
<van-progress v-if="status === 1" :percentage="60" stroke-width="8"
color="linear-gradient(to right, #3b82f6, #60a5fa)" track-color="#e0f2fe"
class="!rounded-full" />
<!-- 辅助文案 -->
<div class="text-xs text-gray-400 space-y-1.5">
<template v-if="status === 2">
<p>预计24小时内到账</p>
<p>可在支付宝账单中查看详情</p>
</template>
<template v-if="status === 1">
<p>您的申请已进入处理队列</p>
<p>5分钟后结果在提现记录种查看</p>
</template>
</div>
<!-- 操作按钮 -->
<van-button block round size="small" :color="statusButtonColor[status]"
class="mt-4 h-11 font-medium shadow-sm" @click="handlePopupAction">
{{ status === 1 ? '知道了' : status === 2 ? '完成' : '重新提现' }}
</van-button>
</div>
</div>
</van-popup>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { showToast } from 'vant';
// 状态管理
const status = ref(null);
const failMsg = ref('');
const isSubmitting = ref(false);
const showStatusPopup = ref(false);
// 样式配置
const statusIcon = {
1: 'clock',
2: 'checked',
3: 'close'
};
const statusIconClass = {
1: 'text-blue-400 border-blue-100 bg-blue-50',
2: 'text-green-500 border-green-100 bg-green-50',
3: 'text-red-500 border-red-100 bg-red-50'
};
const statusBg = {
1: 'from-blue-100 to-blue-50',
2: 'from-green-100 to-green-50',
3: 'from-red-100 to-red-50'
};
const statusTextColors = {
1: 'text-blue-600',
2: 'text-green-600',
3: 'text-red-600'
};
const statusButtonColor = {
1: '#e0f2fe',
2: '#4ade80',
3: '#fca5a5'
};
const statusMessages = {
1: '提现申请处理中,请稍后再查询结果',
2: '提现成功',
3: '提现失败'
};
// 表单数据
const alipayAccount = ref('');
const amount = ref(null);
const availableAmount = ref(null);
const realName = ref('');
const getData = async () => {
const { data: res, error } = await useApiFetch("/agent/revenue")
.get()
.json();
if (res.value?.code === 200 && !error.value) {
availableAmount.value = res.value.data.balance;
}
};
onBeforeMount(() => {
getData();
});
// 表单验证
const validateAmount = (val) => {
const num = Number(val);
return num >= 50 && num <= availableAmount.value;
};
const validateForm = () => {
if (!realName.value.trim()) {
showToast('请输入账户实名姓名');
return false;
}
if (!/^[\u4e00-\u9fa5]{2,4}$/.test(realName.value)) {
showToast('请输入2-4位中文姓名');
return false;
}
if (!alipayAccount.value.trim()) {
showToast('请输入支付宝账号');
return false;
}
const amountNum = Number(amount.value);
if (!amount.value || isNaN(amountNum)) {
showToast('请输入有效金额');
return false;
}
if (amountNum < 50) {
showToast('提现金额不能低于50元');
return false;
}
if (amountNum > availableAmount.value) {
showToast('超过可提现金额');
return false;
}
return true;
};
const handleSubmit = async () => {
// 先进行表单验证
if (!validateForm()) return;
isSubmitting.value = true;
try {
const { data, error } = await useApiFetch("/agent/withdrawal")
.post({ payee_account: alipayAccount.value, amount: amount.value, payee_name: realName.value })
.json();
if (data.value?.code === 200) {
status.value = data.value.data.status;
showStatusPopup.value = true;
if (status.value === 3) {
failMsg.value = data.value.data.fail_msg;
}
}
} catch {
} finally {
isSubmitting.value = false;
}
};
// 弹窗操作
const handlePopupAction = () => {
if (status.value === 3) {
showStatusPopup.value = false;
resetForm();
} else {
showStatusPopup.value = false;
if (status.value === 2) resetPage();
}
};
// 填充最大金额
const fillMaxAmount = () => {
amount.value = availableAmount.value;
};
// 重置页面
const resetForm = () => {
status.value = null;
alipayAccount.value = '';
amount.value = '';
realName.value = '';
};
</script>
<style>
/* 自定义表单样式 */
.van-field__control {
@apply py-1 px-4 text-gray-800;
}
.van-field__error-message {
@apply mt-1;
}
.van-button--disabled {
@apply opacity-60 cursor-not-allowed;
}
/* 弹窗入场动画 */
.van-popup {
transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.3s ease;
}
.van-popup-enter-active,
.van-popup-leave-active {
transition: opacity 0.3s;
}
.van-popup-enter-from,
.van-popup-leave-to {
opacity: 0;
}
.van-popup-enter-active {
transform: scale(0.95);
}
.van-popup-enter-to {
transform: scale(1);
}
/* 状态图标动画 */
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
50% {
opacity: 0.5;
}
}
</style>