Compare commits
9 Commits
19d27194e2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 70f4f97d53 | |||
| 013dfb4bee | |||
| f02f3f5c04 | |||
| adde209c57 | |||
| 104e04a8cc | |||
| 11bc49d1e0 | |||
| 3639e10a11 | |||
| 3f0be7575c | |||
| 63d40b3e76 |
@@ -176,7 +176,7 @@ const videoRef = ref<HTMLVideoElement | null>(null)
|
|||||||
const openVideoModal = () => {
|
const openVideoModal = () => {
|
||||||
videoModalVisible.value = true
|
videoModalVisible.value = true
|
||||||
}
|
}
|
||||||
|
// console.log('11')
|
||||||
const handleVideoModalClose = () => {
|
const handleVideoModalClose = () => {
|
||||||
if (videoRef.value) {
|
if (videoRef.value) {
|
||||||
videoRef.value.pause()
|
videoRef.value.pause()
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 176 KiB |
@@ -17,12 +17,23 @@
|
|||||||
<!-- Right Column -->
|
<!-- Right Column -->
|
||||||
<div class="flex h-full w-[345px] flex-col gap-[20px]">
|
<div class="flex h-full w-[345px] flex-col gap-[20px]">
|
||||||
<ProxyData />
|
<ProxyData />
|
||||||
<div class="flex-1">
|
<div class="">
|
||||||
<SalesData @show-history="orderDetailsModalRef?.show()" />
|
<SalesData @show-history="orderDetailsModalRef?.show()" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<RefundData @show-history="refundDetailsModalRef?.show()" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<OrderDetailsModal ref="orderDetailsModalRef" />
|
<OrderDetailsModal ref="orderDetailsModalRef" />
|
||||||
|
<WithdrawalLogDialog
|
||||||
|
ref="refundDetailsModalRef"
|
||||||
|
title="退费记录"
|
||||||
|
biz-type="commission_refund"
|
||||||
|
amount-label="退费金额"
|
||||||
|
empty-text="暂无退费记录"
|
||||||
|
show-content
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -33,9 +44,12 @@ import DownloadStats from '@/pages/UserCenter/components/DownloadStats/index.vue
|
|||||||
import QuickTools from '@/pages/UserCenter/components/QuickTools/index.vue'
|
import QuickTools from '@/pages/UserCenter/components/QuickTools/index.vue'
|
||||||
import ProxyData from '@/pages/UserCenter/components/ProxyData/index.vue'
|
import ProxyData from '@/pages/UserCenter/components/ProxyData/index.vue'
|
||||||
import SalesData from '@/pages/UserCenter/components/SalesData/index.vue'
|
import SalesData from '@/pages/UserCenter/components/SalesData/index.vue'
|
||||||
|
import RefundData from '@/pages/UserCenter/components/RefundData/index.vue'
|
||||||
import OrderDetailsModal from '@/pages/UserCenter/components/OrderDetails/index.vue'
|
import OrderDetailsModal from '@/pages/UserCenter/components/OrderDetails/index.vue'
|
||||||
|
import WithdrawalLogDialog from '@/pages/UserCenter/components/UserInfo/components/WithdrawalLogDialog.vue'
|
||||||
|
|
||||||
const orderDetailsModalRef = ref<InstanceType<typeof OrderDetailsModal> | null>(null)
|
const orderDetailsModalRef = ref<InstanceType<typeof OrderDetailsModal> | null>(null)
|
||||||
|
const refundDetailsModalRef = ref<InstanceType<typeof WithdrawalLogDialog> | null>(null)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ function statusText(status: number) {
|
|||||||
function formatTime(timestamp: number) {
|
function formatTime(timestamp: number) {
|
||||||
if (!timestamp) return '-'
|
if (!timestamp) return '-'
|
||||||
const date = new Date(timestamp > 10000000000 ? timestamp : timestamp * 1000)
|
const date = new Date(timestamp > 10000000000 ? timestamp : timestamp * 1000)
|
||||||
return date.toLocaleString('en-US', {
|
return date.toLocaleString('zh-CN', {
|
||||||
month: 'numeric',
|
month: 'numeric',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="relative ml-1 pb-2 text-base font-bold text-white">本月链接转化</div>
|
<div class="relative ml-1 pb-2 text-base font-bold text-white">本月链接转化</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-2 flex flex-col gap-2">
|
<div class="flex flex-col">
|
||||||
<div
|
<div
|
||||||
v-for="item in data"
|
v-for="item in data"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-2 text-xs text-white/40">相比前一个月 {{ growthRate }}</div>
|
<div class="mt-1 text-xs text-white/40">相比前一个月 {{ growthRate }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ import request from '@/utils/request'
|
|||||||
const data = ref([
|
const data = ref([
|
||||||
{ label: '点击量', value: 0, key: 'clicks' },
|
{ label: '点击量', value: 0, key: 'clicks' },
|
||||||
{ label: '浏览量', value: 0, key: 'views' },
|
{ label: '浏览量', value: 0, key: 'views' },
|
||||||
{ label: '付费数量', value: 0, key: 'paid_count' },
|
{ label: '付费用户数', value: 0, key: 'paid_count' },
|
||||||
])
|
])
|
||||||
|
|
||||||
const growthRate = ref('N/A')
|
const growthRate = ref('N/A')
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="lucid-glass-bar flex h-full w-full flex-col rounded-4xl! border-1 border-white px-6 py-7"
|
||||||
|
>
|
||||||
|
<div class="mb-[20px] flex justify-between border-b-1 border-dashed pb-4">
|
||||||
|
<div>
|
||||||
|
<div class="mb-1 text-base font-bold text-white">退费数据</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="h-auto p-0 text-sm font-medium text-white/60 underline hover:text-white"
|
||||||
|
@click="$emit('show-history')"
|
||||||
|
>
|
||||||
|
查看全部
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 overflow-y-auto pr-1">
|
||||||
|
<div v-if="loading" class="flex h-10 items-center justify-center">
|
||||||
|
<div
|
||||||
|
class="h-6 w-6 animate-spin rounded-full border-2 border-[#ADFF5B] border-t-transparent"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in salesPage.list"
|
||||||
|
:key="index"
|
||||||
|
class="mb-3 flex items-center justify-between last:mb-0"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-semibold text-white">{{ item.id }}</span>
|
||||||
|
<span class="text-[10px] text-white/40">{{ formatTime(item.created_at) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-lg font-bold text-white tabular-nums">
|
||||||
|
$ {{ formatAmount(item.amount) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="!salesPage.list.length">暂无数据</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
defineEmits(['show-history'])
|
||||||
|
|
||||||
|
const salesPage = ref({
|
||||||
|
total: 0,
|
||||||
|
list: [] as any[],
|
||||||
|
})
|
||||||
|
function formatAmount(amount: number) {
|
||||||
|
return ((amount || 0) / 100).toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(timestamp: number) {
|
||||||
|
if (!timestamp) return '-'
|
||||||
|
const date = new Date(timestamp > 10000000000 ? timestamp : timestamp * 1000)
|
||||||
|
return date.toLocaleString('zh-CN', {
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
async function fetchSales() {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res: any = await request.get('/api/v1/public/user/withdrawal_log', {
|
||||||
|
page: 1,
|
||||||
|
size: 2,
|
||||||
|
biz_type: 'commission_refund',
|
||||||
|
})
|
||||||
|
salesPage.value = res
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fetch sales error:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchSales()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
<div
|
<div
|
||||||
class="lucid-glass-bar flex h-full w-full flex-col rounded-4xl! border-1 border-white px-6 py-7"
|
class="lucid-glass-bar flex h-full w-full flex-col rounded-4xl! border-1 border-white px-6 py-7"
|
||||||
>
|
>
|
||||||
<div class="mb-[20px] flex justify-between border-b-1 border-dashed pb-4">
|
<div class="mb-[10px] flex justify-between border-b-1 border-dashed pb-4">
|
||||||
<div>
|
<div>
|
||||||
<div class="mb-1 text-base font-bold text-white">本月销售数据</div>
|
<div class="mb-1 text-base font-bold text-white">本月销售数据</div>
|
||||||
<div class="text-sm text-white/40">本月已成交订单{{ salesPage.total }}人/次</div>
|
<div class="text-sm text-white/40">本月已成交{{ salesPage.total }}单</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="link"
|
variant="link"
|
||||||
@@ -17,10 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-1 overflow-y-auto pr-1">
|
<div class="flex-1 overflow-y-auto pr-1">
|
||||||
<div
|
<div v-if="loading" class="flex h-[100px] items-center justify-center">
|
||||||
v-if="loading && salesPage.list.length === 0"
|
|
||||||
class="flex h-20 items-center justify-center"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="h-6 w-6 animate-spin rounded-full border-2 border-[#ADFF5B] border-t-transparent"
|
class="h-6 w-6 animate-spin rounded-full border-2 border-[#ADFF5B] border-t-transparent"
|
||||||
></div>
|
></div>
|
||||||
@@ -29,14 +26,15 @@
|
|||||||
<div
|
<div
|
||||||
v-for="(item, index) in salesPage.list"
|
v-for="(item, index) in salesPage.list"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="mb-5 flex items-center justify-between last:mb-0"
|
class="mb-3 flex items-center justify-between last:mb-0"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-sm font-semibold text-white">{{ item.user_hash }}</span>
|
<span class="text-sm font-semibold text-white">{{ item.user_hash }}</span>
|
||||||
<span class="text-[10px] text-white/40">{{ formatTime(item.update_at) }}</span>
|
<span class="text-[10px] text-white/40">{{ formatTime(item.updated_at) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-lg font-bold text-white tabular-nums">$ {{ item.amount }}</div>
|
<div class="text-lg font-bold text-white tabular-nums">$ {{ item.amount }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="!salesPage.list.length">暂无数据</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -69,7 +67,7 @@ async function fetchSales() {
|
|||||||
const end_time = Math.floor(endOfMonth.getTime() / 1000)
|
const end_time = Math.floor(endOfMonth.getTime() / 1000)
|
||||||
const res: any = await request.get('/api/v1/public/user/invite/sales', {
|
const res: any = await request.get('/api/v1/public/user/invite/sales', {
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 8,
|
size: 3,
|
||||||
start_time,
|
start_time,
|
||||||
end_time,
|
end_time,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
:value="t"
|
:value="t"
|
||||||
class="py-3 text-sm focus:bg-[#ADFF5B] focus:text-black"
|
class="py-3 text-sm focus:bg-[#ADFF5B] focus:text-black"
|
||||||
>
|
>
|
||||||
{{ t === 'USDT(TRC20)' ? 'USDT' : t }}
|
{{ t }}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
@@ -129,7 +129,10 @@
|
|||||||
@click="fileInputRef?.click()"
|
@click="fileInputRef?.click()"
|
||||||
>
|
>
|
||||||
<template v-if="values.avatar">
|
<template v-if="values.avatar">
|
||||||
<img :src="values.avatar" class="max-h-[300px] w-full rounded-2xl object-contain" />
|
<img
|
||||||
|
:src="receiptPreviewUrl || values.avatar"
|
||||||
|
class="max-h-[300px] w-full rounded-2xl object-contain"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 flex items-center justify-center bg-black/60 opacity-0 transition-opacity group-hover:opacity-100"
|
class="absolute inset-0 flex items-center justify-center bg-black/60 opacity-0 transition-opacity group-hover:opacity-100"
|
||||||
>
|
>
|
||||||
@@ -140,6 +143,13 @@
|
|||||||
<Upload class="mb-3 h-12 w-12 text-white/20" />
|
<Upload class="mb-3 h-12 w-12 text-white/20" />
|
||||||
<span class="text-base font-medium text-white/30">点击上传高清收款二维码</span>
|
<span class="text-base font-medium text-white/30">点击上传高清收款二维码</span>
|
||||||
</template>
|
</template>
|
||||||
|
<div
|
||||||
|
v-if="isUploadingReceipt"
|
||||||
|
class="absolute inset-0 flex items-center justify-center bg-black/70"
|
||||||
|
>
|
||||||
|
<Loader2 class="mr-2 h-6 w-6 animate-spin text-[#ADFF5B]" />
|
||||||
|
<span class="text-sm font-bold text-white">上传中</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FormMessage class="ml-4 text-red-400" />
|
<FormMessage class="ml-4 text-red-400" />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@@ -148,7 +158,7 @@
|
|||||||
<div class="flex justify-center pt-2">
|
<div class="flex justify-center pt-2">
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
:disabled="isPending"
|
:disabled="isPending || isUploadingReceipt"
|
||||||
class="h-[30px] w-[100px] rounded-full bg-[#ADFF5B] text-sm font-black text-black shadow-[0_10px_30px_rgba(173,255,91,0.3)] transition-all hover:scale-105 hover:bg-[#9ded4e] active:scale-95 disabled:opacity-50"
|
class="h-[30px] w-[100px] rounded-full bg-[#ADFF5B] text-sm font-black text-black shadow-[0_10px_30px_rgba(173,255,91,0.3)] transition-all hover:scale-105 hover:bg-[#9ded4e] active:scale-95 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isPending" class="mr-2 h-7 w-7 animate-spin" />
|
<Loader2 v-if="isPending" class="mr-2 h-7 w-7 animate-spin" />
|
||||||
@@ -189,64 +199,88 @@ const emit = defineEmits(['confirm'])
|
|||||||
|
|
||||||
const open = ref(false)
|
const open = ref(false)
|
||||||
const isPending = ref(false) // 手动管理加载状态
|
const isPending = ref(false) // 手动管理加载状态
|
||||||
|
const isUploadingReceipt = ref(false)
|
||||||
|
const receiptPreviewUrl = ref('')
|
||||||
const fileInputRef = ref<HTMLInputElement | null>(null)
|
const fileInputRef = ref<HTMLInputElement | null>(null)
|
||||||
const ACCOUNT_TYPE = ['USDT(TRC20)', '微信', '支付宝'] as const
|
const ACCOUNT_TYPE = ['USDT(TRC20)', '微信', '支付宝'] as const
|
||||||
|
const RECEIPT_UPLOAD_BIZ_TYPE = 'app-package'
|
||||||
|
const WITHDRAW_METHOD = {
|
||||||
|
支付宝: 1,
|
||||||
|
微信: 2,
|
||||||
|
'USDT(TRC20)': 3,
|
||||||
|
} as const
|
||||||
|
|
||||||
const compressImage = (file: File, quality = 0.7, maxWidth = 1024): Promise<string> => {
|
type FileUploadResponse =
|
||||||
return new Promise((resolve, reject) => {
|
| string
|
||||||
const reader = new FileReader()
|
| {
|
||||||
reader.readAsDataURL(file)
|
url?: string
|
||||||
reader.onload = (e) => {
|
file_url?: string
|
||||||
const img = new Image()
|
full_url?: string
|
||||||
img.src = e.target?.result as string
|
path?: string
|
||||||
img.onload = () => {
|
uri?: string
|
||||||
const canvas = document.createElement('canvas')
|
file?: string
|
||||||
let width = img.width
|
src?: string
|
||||||
let height = img.height
|
|
||||||
|
|
||||||
if (width > maxWidth) {
|
|
||||||
height = (maxWidth / width) * height
|
|
||||||
width = maxWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.width = width
|
|
||||||
canvas.height = height
|
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d')
|
|
||||||
ctx?.drawImage(img, 0, 0, width, height)
|
|
||||||
|
|
||||||
const compressedBase64 = canvas.toDataURL('image/jpeg', quality)
|
|
||||||
resolve(compressedBase64)
|
|
||||||
}
|
|
||||||
img.onerror = reject
|
|
||||||
}
|
}
|
||||||
reader.onerror = reject
|
|
||||||
})
|
const revokeReceiptPreview = () => {
|
||||||
|
if (receiptPreviewUrl.value) {
|
||||||
|
URL.revokeObjectURL(receiptPreviewUrl.value)
|
||||||
|
receiptPreviewUrl.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUploadedFileUrl = (data: FileUploadResponse) => {
|
||||||
|
if (typeof data === 'string') return data
|
||||||
|
|
||||||
|
return (
|
||||||
|
data.url ||
|
||||||
|
data.file_url ||
|
||||||
|
data.full_url ||
|
||||||
|
data.path ||
|
||||||
|
data.uri ||
|
||||||
|
data.file ||
|
||||||
|
data.src ||
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadReceiptCode = async (file: File) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('biz_type', RECEIPT_UPLOAD_BIZ_TYPE)
|
||||||
|
formData.append('file', file, file.name)
|
||||||
|
|
||||||
|
const data = await request.post<FormData, FileUploadResponse>(
|
||||||
|
'/api/v1/public/file/upload',
|
||||||
|
formData,
|
||||||
|
)
|
||||||
|
return getUploadedFileUrl(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onFileChange = async (e: Event) => {
|
const onFileChange = async (e: Event) => {
|
||||||
const file = (e.target as HTMLInputElement).files?.[0]
|
const file = (e.target as HTMLInputElement).files?.[0]
|
||||||
if (!file) return
|
if (!file) return
|
||||||
|
|
||||||
|
if (!file.type.startsWith('image/')) {
|
||||||
|
toast.error('请上传图片文件')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 压缩图片
|
isUploadingReceipt.value = true
|
||||||
const compressedBase64 = await compressImage(file)
|
const uploadedUrl = await uploadReceiptCode(file)
|
||||||
|
if (!uploadedUrl) {
|
||||||
// 计算压缩后的大小
|
toast.error('上传失败,请重试')
|
||||||
const base64Length = compressedBase64.split(',')[1].length
|
|
||||||
const sizeInBytes = base64Length * (3 / 4)
|
|
||||||
|
|
||||||
if (sizeInBytes > 2 * 1024 * 1024) {
|
|
||||||
// 限制 2MB
|
|
||||||
toast.error('图片过大,压缩后仍超过 2MB')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setFieldValue('avatar', compressedBase64)
|
revokeReceiptPreview()
|
||||||
|
receiptPreviewUrl.value = URL.createObjectURL(file)
|
||||||
|
setFieldValue('avatar', uploadedUrl)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('图片处理失败:', err)
|
console.error('收款码上传失败:', err)
|
||||||
toast.error('图片处理失败,请重试')
|
toast.error('上传失败,请重试')
|
||||||
} finally {
|
} finally {
|
||||||
|
isUploadingReceipt.value = false
|
||||||
// 重置 input,允许重新选择同一张图
|
// 重置 input,允许重新选择同一张图
|
||||||
if (e.target) {
|
if (e.target) {
|
||||||
;(e.target as HTMLInputElement).value = ''
|
;(e.target as HTMLInputElement).value = ''
|
||||||
@@ -282,6 +316,7 @@ const { handleSubmit, resetForm, values, setFieldValue } = useForm({
|
|||||||
|
|
||||||
// --- 暴露给父组件的方法 ---
|
// --- 暴露给父组件的方法 ---
|
||||||
const show = () => {
|
const show = () => {
|
||||||
|
revokeReceiptPreview()
|
||||||
resetForm()
|
resetForm()
|
||||||
open.value = true
|
open.value = true
|
||||||
}
|
}
|
||||||
@@ -307,29 +342,16 @@ const onSubmit = handleSubmit(async (val) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 检查是否有未完成工单
|
|
||||||
const data = await request.get<any>('/api/v1/public/ticket/list', {
|
|
||||||
page: 1,
|
|
||||||
size: 1,
|
|
||||||
issue_type: 1,
|
|
||||||
})
|
|
||||||
if (data?.list?.length > 0) {
|
|
||||||
toast.info('已有待处理申请')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 执行提现请求
|
// 3. 执行提现请求
|
||||||
const description =
|
await request.post('/api/v1/public/user/commission_withdraw', {
|
||||||
val.type === 'USDT(TRC20)' ? `${val.type}-${val.account}` : `${val.type}-${val.avatar}`
|
amount: Math.round(amount * 100),
|
||||||
|
method: WITHDRAW_METHOD[val.type],
|
||||||
await request.post('/api/v1/public/ticket/', {
|
account: val.type === 'USDT(TRC20)' ? val.account : '',
|
||||||
title: `提现-${val.money}`,
|
qr_code_url: val.type === 'USDT(TRC20)' ? '' : val.avatar,
|
||||||
description,
|
|
||||||
issue_type: 1,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 4. 成功后处理
|
// 4. 成功后处理
|
||||||
toast.success('提交成功')
|
toast.success('提现申请已提交,请等待审核')
|
||||||
open.value = false
|
open.value = false
|
||||||
emit('confirm') // 触发父组件刷新 info 接口
|
emit('confirm') // 触发父组件刷新 info 接口
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog :open="isOpen" @update:open="setOpen">
|
||||||
|
<DialogContent
|
||||||
|
class="top-[94px] flex h-[calc(100vh-94px-50px)] w-[386px] translate-y-0 flex-col items-center justify-center border-none bg-transparent p-0 shadow-none outline-none focus:ring-0"
|
||||||
|
:showCloseButton="false"
|
||||||
|
>
|
||||||
|
<div class="relative flex h-[628px] w-full flex-col rounded-[32px] bg-[#DDDDDD] px-4 py-6">
|
||||||
|
<button
|
||||||
|
@click="hide"
|
||||||
|
class="absolute top-6 right-6 z-10 flex size-8 items-center justify-center rounded-lg transition-colors hover:bg-black/5"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="3"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="text-black"
|
||||||
|
>
|
||||||
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||||
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h2 class="mb-2 px-4 pt-8 text-center text-[20px] font-bold text-black">{{ title }}</h2>
|
||||||
|
|
||||||
|
<WithdrawalLogList
|
||||||
|
ref="logListRef"
|
||||||
|
:biz-type="bizType"
|
||||||
|
:amount-label="amountLabel"
|
||||||
|
:empty-text="emptyText"
|
||||||
|
:show-content="showContent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { nextTick, ref } from 'vue'
|
||||||
|
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||||
|
import WithdrawalLogList from './WithdrawalLogList.vue'
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
title?: string
|
||||||
|
bizType?: string
|
||||||
|
amountLabel?: string
|
||||||
|
emptyText?: string
|
||||||
|
showContent?: boolean
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
title: '提现记录',
|
||||||
|
bizType: '',
|
||||||
|
amountLabel: '提现金额',
|
||||||
|
emptyText: '暂无提现记录',
|
||||||
|
showContent: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const isOpen = ref(false)
|
||||||
|
const logListRef = ref<InstanceType<typeof WithdrawalLogList> | null>(null)
|
||||||
|
|
||||||
|
const setOpen = (value: boolean) => {
|
||||||
|
isOpen.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
const show = () => {
|
||||||
|
isOpen.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
logListRef.value?.refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const hide = () => {
|
||||||
|
isOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
hide,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-1 flex-col overflow-hidden">
|
||||||
|
<div class="h-[430px] overflow-y-auto pr-1">
|
||||||
|
<div v-if="loading" class="flex h-40 items-center justify-center">
|
||||||
|
<div
|
||||||
|
class="h-8 w-8 animate-spin rounded-full border-4 border-[#ADFF5B] border-t-transparent"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="list.length === 0"
|
||||||
|
class="flex h-40 items-center justify-center text-gray-500"
|
||||||
|
>
|
||||||
|
{{ emptyText }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="space-y-[10px]">
|
||||||
|
<div
|
||||||
|
v-for="item in list"
|
||||||
|
:key="item.id"
|
||||||
|
class="rounded-[20px] bg-[#CECECF] py-2 text-[14px] font-normal text-black"
|
||||||
|
>
|
||||||
|
<div v-if="showContent" class="grid grid-cols-2 gap-y-2">
|
||||||
|
<div class="pl-4">
|
||||||
|
<div class="text-xs text-gray-500">{{ amountLabel }}</div>
|
||||||
|
<div class="font-bold text-[#222]">${{ formatAmount(item.amount) }}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-xs text-gray-500">退费时间</div>
|
||||||
|
<div class="whitespace-nowrap">{{ formatTime(item.created_at) }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-2 px-4">
|
||||||
|
<div class="text-xs text-gray-500">说明</div>
|
||||||
|
<div class="break-words leading-snug">{{ item.content || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="grid grid-cols-2 gap-y-1">
|
||||||
|
<div class="pl-4">
|
||||||
|
<div class="text-xs text-gray-500">{{ amountLabel }}</div>
|
||||||
|
<div class="font-bold text-[#222]">${{ formatAmount(item.amount) }}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-xs text-gray-500">状态</div>
|
||||||
|
<div class="font-medium">{{ statusText(item.status) }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pl-4">
|
||||||
|
<div class="text-xs text-gray-500">提现方式</div>
|
||||||
|
<div>{{ methodText(item.method) }}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-xs text-gray-500">申请时间</div>
|
||||||
|
<div class="whitespace-nowrap">{{ formatTime(item.created_at) }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="item.reason" class="col-span-2 pl-4">
|
||||||
|
<div class="text-xs text-gray-500">拒绝原因</div>
|
||||||
|
<div class="break-all">{{ item.reason }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="total > 0" class="flex flex-col items-center pt-[18px]">
|
||||||
|
<div class="mb-2 flex items-center gap-[10px]">
|
||||||
|
<button
|
||||||
|
@click="changePage(1)"
|
||||||
|
:disabled="page === 1"
|
||||||
|
class="flex h-[30px] min-w-[30px] items-center justify-center rounded-full bg-[#EAEAEA] transition-opacity disabled:opacity-30"
|
||||||
|
>
|
||||||
|
<span class="text-lg font-bold text-[#848484]"><<</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="changePage(page - 1)"
|
||||||
|
:disabled="page === 1"
|
||||||
|
class="flex h-[30px] min-w-[30px] items-center justify-center rounded-full bg-[#EAEAEA] transition-opacity disabled:opacity-30"
|
||||||
|
>
|
||||||
|
<span class="text-lg font-bold text-[#848484]"><</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex h-[30px] min-w-[65px] items-center justify-center rounded-full bg-[#EAEAEA] px-2"
|
||||||
|
>
|
||||||
|
<span class="text-base text-[#848484]">{{ page }}</span>
|
||||||
|
<span class="ml-1 text-base text-[#848484]">v</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click="changePage(page + 1)"
|
||||||
|
:disabled="page >= totalPages"
|
||||||
|
class="flex h-[30px] min-w-[30px] items-center justify-center rounded-full bg-[#EAEAEA] transition-opacity disabled:opacity-30"
|
||||||
|
>
|
||||||
|
<span class="text-lg font-bold text-[#848484]">></span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="changePage(totalPages)"
|
||||||
|
:disabled="page >= totalPages"
|
||||||
|
class="flex h-[30px] min-w-[30px] items-center justify-center rounded-full bg-[#EAEAEA] transition-opacity disabled:opacity-30"
|
||||||
|
>
|
||||||
|
<span class="text-lg font-bold text-[#848484]">>></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="text-xs font-[300] text-[#848484]">第 {{ page }} / {{ totalPages }} 页</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
bizType?: string
|
||||||
|
amountLabel?: string
|
||||||
|
emptyText?: string
|
||||||
|
showContent?: boolean
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
bizType: '',
|
||||||
|
amountLabel: '提现金额',
|
||||||
|
emptyText: '暂无提现记录',
|
||||||
|
showContent: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
interface WithdrawalLog {
|
||||||
|
id: number
|
||||||
|
amount: number
|
||||||
|
status: number
|
||||||
|
method: number
|
||||||
|
content?: string
|
||||||
|
reason?: string
|
||||||
|
created_at: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const page = ref(1)
|
||||||
|
const size = ref(4)
|
||||||
|
const total = ref(0)
|
||||||
|
const list = ref<WithdrawalLog[]>([])
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const totalPages = computed(() => Math.ceil(total.value / size.value) || 1)
|
||||||
|
|
||||||
|
async function fetchLogs() {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res: any = await request.get('/api/v1/public/user/withdrawal_log', {
|
||||||
|
page: page.value,
|
||||||
|
size: size.value,
|
||||||
|
...(props.bizType ? { biz_type: props.bizType } : {}),
|
||||||
|
})
|
||||||
|
list.value = res.list || []
|
||||||
|
total.value = res.total || 0
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fetch withdrawal logs error:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
page.value = 1
|
||||||
|
fetchLogs()
|
||||||
|
}
|
||||||
|
|
||||||
|
function changePage(p: number) {
|
||||||
|
if (p < 1 || p > totalPages.value) return
|
||||||
|
page.value = p
|
||||||
|
fetchLogs()
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusText(status: number) {
|
||||||
|
const map: Record<number, string> = {
|
||||||
|
0: '待审核',
|
||||||
|
1: '已通过',
|
||||||
|
2: '已拒绝',
|
||||||
|
3: '已取消',
|
||||||
|
}
|
||||||
|
return map[status] || '未知'
|
||||||
|
}
|
||||||
|
|
||||||
|
function methodText(method: number) {
|
||||||
|
const map: Record<number, string> = {
|
||||||
|
0: '其他',
|
||||||
|
1: '支付宝',
|
||||||
|
2: '微信',
|
||||||
|
3: 'USDT(TRC20)',
|
||||||
|
}
|
||||||
|
return map[method] || '未知'
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAmount(amount: number) {
|
||||||
|
return ((amount || 0) / 100).toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(timestamp: number) {
|
||||||
|
if (!timestamp) return '-'
|
||||||
|
const date = new Date(timestamp > 10000000000 ? timestamp : timestamp * 1000)
|
||||||
|
return date.toLocaleString('zh-CN', {
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
refresh,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -12,13 +12,21 @@
|
|||||||
<div class="ml-2 flex flex-col justify-center text-white">
|
<div class="ml-2 flex flex-col justify-center text-white">
|
||||||
<div class="text-base font-semibold">{{ userInfo.email }}</div>
|
<div class="text-base font-semibold">{{ userInfo.email }}</div>
|
||||||
<div class="flex items-center text-base font-semibold">
|
<div class="flex items-center text-base font-semibold">
|
||||||
<span class="mr-0.5 text-3xl">🌞</span> 超级合伙人 返佣比例{{
|
<span class="mr-0.5 text-3xl">🌞</span> {{ referralText }}
|
||||||
userInfo.referral_percentage
|
|
||||||
}}%
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-7 mb-1 ml-[18px] font-semibold text-[#ADFF5B]">专属代理链接</div>
|
<div class="mt-7 mb-1 ml-[18px] flex justify-between font-semibold text-[#ADFF5B]">
|
||||||
|
专属代理链接
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="mr-6 h-auto p-0 text-sm font-bold text-[#999] underline outline-none hover:text-[#666]"
|
||||||
|
@click="withdrawalLogDialogRef?.show()"
|
||||||
|
>
|
||||||
|
提现记录
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="mb-[10px] flex h-[50px] w-full items-center justify-between rounded-[32px] bg-[#ADFF5B] px-4 font-medium text-black"
|
class="mb-[10px] flex h-[50px] w-full items-center justify-between rounded-[32px] bg-[#ADFF5B] px-4 font-medium text-black"
|
||||||
>
|
>
|
||||||
@@ -29,13 +37,18 @@
|
|||||||
class="flex min-h-[90px] w-full items-center justify-between rounded-[25px] bg-[#ADFF5B] px-4 font-medium text-black"
|
class="flex min-h-[90px] w-full items-center justify-between rounded-[25px] bg-[#ADFF5B] px-4 font-medium text-black"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-xl font-semibold">佣金账户余额</div>
|
<div class="flex items-center text-xl font-semibold">佣金账户余额</div>
|
||||||
<div class="text-3xl font-black">
|
<div class="text-3xl font-black">
|
||||||
$ {{ (userInfo.commission / 100 || 0).toFixed(2) }}
|
$ {{ (userInfo.commission / 100 || 0).toFixed(2) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="ghost" class="hover:bg-transparent" @click="walletDialogRef?.show()">
|
<Button
|
||||||
点击提现
|
variant="ghost"
|
||||||
|
class="hover:bg-transparent"
|
||||||
|
:disabled="isCheckingWithdrawal"
|
||||||
|
@click="handleWithdrawClick"
|
||||||
|
>
|
||||||
|
{{ hasPendingWithdrawal ? '审核中' : '点击提现' }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -43,14 +56,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<WalletDialog ref="walletDialogRef" :commission="userInfo.commission || 0" @confirm="init" />
|
<WalletDialog ref="walletDialogRef" :commission="userInfo.commission || 0" @confirm="init" />
|
||||||
|
<WithdrawalLogDialog ref="withdrawalLogDialogRef" />
|
||||||
<div>
|
<div>
|
||||||
<div class="flex flex-col gap-[10px] px-6 pt-8 pb-9">
|
<div class="flex flex-col gap-[10px] px-6 pt-8 pb-4">
|
||||||
<div
|
<div
|
||||||
class="flex h-[50px] w-full items-center justify-between rounded-[32px] bg-[#222222] px-4 pr-6 leading-[50px] font-medium"
|
class="flex h-[50px] w-full items-center justify-between rounded-[32px] bg-[#222222] px-4 pr-6 leading-[50px] font-medium"
|
||||||
>
|
>
|
||||||
我的邀请码:{{ userInfo.refer_code }}
|
我的邀请码:{{ userInfo.refer_code }}
|
||||||
<CopyIcon class="size-5 cursor-pointer text-white" @click="copy(userInfo.refer_code)" />
|
<CopyIcon class="size-5 cursor-pointer text-white" @click="copy(userInfo.refer_code)" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mt-[-2px] mb-1 px-2 text-[11px] leading-snug text-[#ADFF5B]">
|
||||||
|
*
|
||||||
|
提醒:如果客户没有海外苹果ID,使用官方提供的ID会导致绑定失败,用户可以手动输入此邀请码绑定代理。
|
||||||
|
</div>
|
||||||
<div class="h-[50px] w-full rounded-[32px] bg-[#222222] px-4 leading-[50px] font-medium">
|
<div class="h-[50px] w-full rounded-[32px] bg-[#222222] px-4 leading-[50px] font-medium">
|
||||||
历史佣金总计:$ {{ (inviteStats.friendly_count / 100).toFixed(2) }}
|
历史佣金总计:$ {{ (inviteStats.friendly_count / 100).toFixed(2) }}
|
||||||
</div>
|
</div>
|
||||||
@@ -74,6 +92,7 @@
|
|||||||
import UserCenterSkeleton from '@/components/user-center/UserCenterSkeleton.vue'
|
import UserCenterSkeleton from '@/components/user-center/UserCenterSkeleton.vue'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import WalletDialog from './components/WalletDialog.vue'
|
import WalletDialog from './components/WalletDialog.vue'
|
||||||
|
import WithdrawalLogDialog from './components/WithdrawalLogDialog.vue'
|
||||||
import CopyIcon from './copy.svg?component'
|
import CopyIcon from './copy.svg?component'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
@@ -82,17 +101,21 @@ import { toast } from 'vue-sonner'
|
|||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const walletDialogRef = ref<InstanceType<typeof WalletDialog> | null>(null)
|
const walletDialogRef = ref<InstanceType<typeof WalletDialog> | null>(null)
|
||||||
|
const withdrawalLogDialogRef = ref<InstanceType<typeof WithdrawalLogDialog> | null>(null)
|
||||||
const userInfo = ref({
|
const userInfo = ref({
|
||||||
email: '',
|
email: '',
|
||||||
created_at: '',
|
created_at: '',
|
||||||
share_link: '',
|
share_link: '',
|
||||||
commission: 0,
|
commission: 0,
|
||||||
|
referral_percentage: 0,
|
||||||
})
|
})
|
||||||
const inviteStats = ref({
|
const inviteStats = ref({
|
||||||
friendly_count: 0,
|
friendly_count: 0,
|
||||||
history_count: 0,
|
history_count: 0,
|
||||||
})
|
})
|
||||||
const isUserLoading = ref(true)
|
const isUserLoading = ref(true)
|
||||||
|
const isCheckingWithdrawal = ref(false)
|
||||||
|
const hasPendingWithdrawal = ref(false)
|
||||||
async function init() {
|
async function init() {
|
||||||
// 1. 用户信息 & 设备列表
|
// 1. 用户信息 & 设备列表
|
||||||
isUserLoading.value = true
|
isUserLoading.value = true
|
||||||
@@ -114,6 +137,8 @@ async function init() {
|
|||||||
request.get('/api/v1/public/user/invite/stats').then((res: any) => {
|
request.get('/api/v1/public/user/invite/stats').then((res: any) => {
|
||||||
inviteStats.value = res
|
inviteStats.value = res
|
||||||
})
|
})
|
||||||
|
|
||||||
|
checkPendingWithdrawal()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -137,6 +162,51 @@ const formattedDate = computed(() => {
|
|||||||
}).format(date)
|
}).format(date)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const referralText = computed(() => {
|
||||||
|
const percentage = Number(userInfo.value.referral_percentage || 0)
|
||||||
|
if (percentage <= 0) return '暂未激活比例,请联系客服激活'
|
||||||
|
if (percentage <= 20) return `初级合伙人 返佣比例${percentage}%`
|
||||||
|
if (percentage <= 39) return `高级合伙人 返佣比例${percentage}%`
|
||||||
|
return `超级合伙人 返佣比例${percentage}%`
|
||||||
|
})
|
||||||
|
|
||||||
|
async function handleWithdrawClick() {
|
||||||
|
if (hasPendingWithdrawal.value) {
|
||||||
|
toast.info('已有提现申请审核中,请勿重复提交')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isCheckingWithdrawal.value) return
|
||||||
|
|
||||||
|
const canWithdraw = await checkPendingWithdrawal(true)
|
||||||
|
if (canWithdraw) {
|
||||||
|
walletDialogRef.value?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkPendingWithdrawal(showErrorToast = false) {
|
||||||
|
try {
|
||||||
|
isCheckingWithdrawal.value = true
|
||||||
|
const res: any = await request.get('/api/v1/public/user/withdrawal_log', {
|
||||||
|
page: 1,
|
||||||
|
size: 20,
|
||||||
|
})
|
||||||
|
hasPendingWithdrawal.value = (res?.list || []).some((item: any) => item.status === 0)
|
||||||
|
if (hasPendingWithdrawal.value) {
|
||||||
|
toast.info('已有提现申请审核中,请勿重复提交')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Check withdrawal logs error:', error)
|
||||||
|
if (showErrorToast) {
|
||||||
|
toast.error('提现记录检查失败,请稍后重试')
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} finally {
|
||||||
|
isCheckingWithdrawal.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function copy(text: string) {
|
function copy(text: string) {
|
||||||
navigator.clipboard.writeText(text).then(() => {
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
toast.success('已复制到剪贴板')
|
toast.success('已复制到剪贴板')
|
||||||
|
|||||||
Reference in New Issue
Block a user