Files
bdrp-app/src/pages/subordinate-detail.vue

354 lines
11 KiB
Vue
Raw Normal View History

2026-04-20 16:42:28 +08:00
<script setup>
import { onMounted, ref } from 'vue'
import { useRoute } from '@/composables/uni-router'
import useApiFetch from '@/composables/useApiFetch'
definePage({ layout: 'default', auth: true })
const route = useRoute()
const loading = ref(false)
const page = ref(1)
const pageSize = 8
const total = ref(0)
const rewardDetails = ref([])
const userInfo = ref({})
const summary = ref({})
const statistics = ref([])
// 获取收益列表
async function fetchRewardDetails() {
if (loading.value)
return
loading.value = true
const { data, error } = await useApiFetch(
`/agent/subordinate/contribution/detail?subordinate_id=${route.params.id}&page=${page.value}&page_size=${pageSize}`,
)
.get()
.json()
if (data.value && !error.value) {
if (data.value.code === 200) {
if (page.value === 1) {
// 更新用户信息
userInfo.value = {
createTime: data.value.data.create_time,
level: data.value.data.level_name || '普通',
mobile: data.value.data.mobile,
}
// 更新汇总数据
summary.value = {
totalReward: data.value.data.total_earnings,
totalContribution: data.value.data.total_contribution,
totalOrders: data.value.data.total_orders,
}
// 设置默认的统计类型
statistics.value = [
{
type: 'descendant_promotion',
amount: 0,
count: 0,
description: '推广奖励',
},
{
type: 'cost',
amount: 0,
count: 0,
description: '成本贡献',
},
{
type: 'pricing',
amount: 0,
count: 0,
description: '定价贡献',
},
{
type: 'descendant_withdraw',
amount: 0,
count: 0,
description: '提现收益',
},
{
type: 'descendant_upgrade_vip',
amount: 0,
count: 0,
description: '转化VIP奖励',
},
{
type: 'descendant_upgrade_svip',
amount: 0,
count: 0,
description: '转化SVIP奖励',
},
]
// 如果有统计数据,更新对应的值
if (data.value.data.stats) {
const stats = data.value.data.stats
// 更新推广奖励
const platformStat = statistics.value.find(s => s.type === 'descendant_promotion')
if (platformStat) {
platformStat.amount = stats.descendant_promotion_amount || 0
platformStat.count = stats.descendant_promotion_count || 0
}
// 更新成本贡献
const costStat = statistics.value.find(s => s.type === 'cost')
if (costStat) {
costStat.amount = stats.cost_amount || 0
costStat.count = stats.cost_count || 0
}
// 更新定价贡献
const pricingStat = statistics.value.find(s => s.type === 'pricing')
if (pricingStat) {
pricingStat.amount = stats.pricing_amount || 0
pricingStat.count = stats.pricing_count || 0
}
// 更新提现收益
const withdrawStat = statistics.value.find(s => s.type === 'descendant_withdraw')
if (withdrawStat) {
withdrawStat.amount = stats.descendant_withdraw_amount || 0
withdrawStat.count = stats.descendant_withdraw_count || 0
}
// 更新转化VIP奖励
const conversionVipStat = statistics.value.find(s => s.type === 'descendant_upgrade_vip')
if (conversionVipStat) {
conversionVipStat.amount = stats.descendant_upgrade_vip_amount || 0
conversionVipStat.count = stats.descendant_upgrade_vip_count || 0
}
// 更新转化SVIP奖励
const conversionSvipStat = statistics.value.find(s => s.type === 'descendant_upgrade_svip')
if (conversionSvipStat) {
conversionSvipStat.amount = stats.descendant_upgrade_svip_amount || 0
conversionSvipStat.count = stats.descendant_upgrade_svip_count || 0
}
}
rewardDetails.value = []
}
total.value = data.value.data.total || 0
// 处理列表数据
if (data.value.data.list) {
const list = data.value.data.list
rewardDetails.value = list
}
else {
rewardDetails.value = []
}
}
}
loading.value = false
}
function onPageChange({ value }) {
page.value = value
fetchRewardDetails()
}
onMounted(() => {
fetchRewardDetails()
})
// 获取收益类型样式
function getRewardTypeClass(type) {
const typeMap = {
descendant_promotion: 'bg-blue-100 text-blue-600',
cost: 'bg-green-100 text-green-600',
pricing: 'bg-purple-100 text-purple-600',
descendant_withdraw: 'bg-yellow-100 text-yellow-600',
descendant_upgrade_vip: 'bg-red-100 text-red-600',
descendant_upgrade_svip: 'bg-orange-100 text-orange-600',
}
return typeMap[type] || 'bg-gray-100 text-gray-600'
}
// 获取收益类型图标
function getRewardTypeIcon(type) {
const iconMap = {
descendant_promotion: 'gift',
cost: 'gold-coin',
pricing: 'balance-pay',
descendant_withdraw: 'cash-back-record',
descendant_upgrade_vip: 'fire',
descendant_upgrade_svip: 'fire',
}
return iconMap[type] || 'balance-o'
}
// 获取收益类型描述
function getRewardTypeDescription(type) {
const descriptionMap = {
descendant_promotion: '推广奖励',
cost: '成本贡献',
pricing: '定价贡献',
descendant_withdraw: '提现收益',
descendant_upgrade_vip: '转化VIP奖励',
descendant_upgrade_svip: '转化SVIP奖励',
}
return descriptionMap[type] || '未知类型'
}
// 格式化时间
function formatTime(timeStr) {
if (!timeStr)
return '-'
const date = new Date(timeStr)
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}
// 格式化金额
function formatNumber(num) {
if (!num)
return '0.00'
return Number(num).toFixed(2)
}
</script>
<template>
<div class="reward-detail">
<!-- 用户信息卡片 -->
<div class="p-4">
<div class="mb-4 rounded-xl bg-white p-5 shadow-sm">
<div class="mb-4 flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="text-xl text-gray-800 font-semibold">
{{ userInfo.mobile }}
</div>
<span class="rounded-full bg-blue-100 px-3 py-1 text-sm text-blue-600 font-medium">
{{ userInfo.level }}代理
</span>
</div>
</div>
<div class="mb-4 text-sm text-gray-500">
成为下级代理时间{{ formatTime(userInfo.createTime) }}
</div>
<div class="grid grid-cols-3 gap-4">
<div class="text-center">
<div class="mb-1 text-sm text-gray-500">
总推广单量
</div>
<div class="text-xl text-blue-600 font-semibold">
{{ summary.totalOrders }}
</div>
</div>
<div class="text-center">
<div class="mb-1 text-sm text-gray-500">
总收益
</div>
<div class="text-xl text-green-600 font-semibold">
¥{{ formatNumber(summary.totalReward) }}
</div>
</div>
<div class="text-center">
<div class="mb-1 text-sm text-gray-500">
总贡献
</div>
<div class="text-xl text-purple-600 font-semibold">
¥{{ formatNumber(summary.totalContribution) }}
</div>
</div>
</div>
</div>
<!-- 贡献统计卡片 -->
<div class="mb-4 rounded-xl bg-white p-4 shadow-sm">
<div class="mb-3 text-base text-gray-800 font-medium">
贡献统计
</div>
<div class="grid grid-cols-2 gap-3">
<div
v-for="item in statistics"
:key="item.type"
class="flex items-center rounded-lg p-2"
:class="getRewardTypeClass(item.type).split(' ')[0]"
>
<wd-icon
:name="getRewardTypeIcon(item.type)"
class="mr-2 text-lg"
:class="getRewardTypeClass(item.type).split(' ')[1]"
/>
<div class="flex-1">
<div class="text-sm font-medium" :class="getRewardTypeClass(item.type).split(' ')[1]">
{{ item.description }}
</div>
<div class="mt-1 flex items-center justify-between">
<div class="text-xs text-gray-500">
{{ item.count }}
</div>
<div class="text-sm font-medium" :class="getRewardTypeClass(item.type).split(' ')[1]">
¥{{ formatNumber(item.amount) }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mb-4 rounded-xl bg-white p-4 shadow-sm">
<!-- 贡献记录列表 -->
<div class="text-base text-gray-800 font-medium">
贡献记录
</div>
<div class="detail-scroll p-4">
<div v-if="rewardDetails.length === 0" class="py-8 text-center text-gray-500">
暂无贡献记录
</div>
<div v-for="item in rewardDetails" v-else :key="item.id" class="reward-item">
<div class="mb-3 border-b border-gray-200 pb-3">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<wd-icon
:name="getRewardTypeIcon(item.type)"
class="text-lg"
:class="getRewardTypeClass(item.type).split(' ')[1]"
/>
<div>
<div class="text-gray-800 font-medium">
{{ getRewardTypeDescription(item.type) }}
</div>
<div class="text-xs text-gray-500">
{{ formatTime(item.create_time) }}
</div>
</div>
</div>
<div class="text-right">
<div class="text-base font-semibold" :class="getRewardTypeClass(item.type).split(' ')[1]">
¥{{ formatNumber(item.amount) }}
</div>
</div>
</div>
</div>
</div>
<div v-if="loading" class="py-3 text-center text-sm text-gray-400">
加载中...
</div>
</div>
<div class="px-4 pb-4">
<wd-pagination
v-model="page"
:total="total"
:page-size="pageSize"
show-icon
show-message
@change="onPageChange"
/>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.reward-detail {
min-height: 100vh;
background-color: #f5f5f5;
}
.reward-item {
transition: transform 0.2s;
}
.reward-item:active {
transform: scale(0.98);
}
.detail-scroll {
min-height: 50vh;
}
</style>