2025-03-08 15:26:04 +08:00
|
|
|
|
<template>
|
2025-04-10 23:01:03 +08:00
|
|
|
|
<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>
|
2025-03-08 15:26:04 +08:00
|
|
|
|
|
2025-04-10 23:01:03 +08:00
|
|
|
|
<!-- 支付宝账号 -->
|
|
|
|
|
<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>
|
2025-03-08 15:26:04 +08:00
|
|
|
|
|
2025-04-10 23:01:03 +08:00
|
|
|
|
</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>
|
2025-03-08 15:26:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
2025-04-10 23:01:03 +08:00
|
|
|
|
<!-- 提交按钮 -->
|
|
|
|
|
<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>
|
2025-03-08 15:26:04 +08:00
|
|
|
|
</div>
|
2025-04-10 23:01:03 +08:00
|
|
|
|
<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>
|
2025-03-08 15:26:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-04-10 23:01:03 +08:00
|
|
|
|
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 = '';
|
|
|
|
|
};
|
2025-03-08 15:26:04 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
2025-04-10 23:01:03 +08:00
|
|
|
|
<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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-08 15:26:04 +08:00
|
|
|
|
</style>
|