Files
tydata-webview-v2/src/views/SubordinateDetail.vue
2025-09-27 17:41:14 +08:00

352 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.

<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import useApiFetch from '@/composables/useApiFetch'
const route = useRoute()
const loading = ref(false)
const refreshing = ref(false)
const finished = ref(false)
const page = ref(1)
const pageSize = 8
// 获取收益列表
const fetchRewardDetails = async () => {
if (loading.value || finished.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奖励',
},
{
type: 'descendant_new_active',
amount: 0,
count: 0,
description: '新增活跃奖励',
},
{
type: 'descendant_stay_active',
amount: 0,
count: 0,
description: '月度活跃奖励',
},
]
// 如果有统计数据,更新对应的值
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
}
// 更新活跃奖励
const activeStat = statistics.value.find(s => s.type === 'descendant_new_active')
if (activeStat) {
activeStat.amount = stats.descendant_new_active_amount || 0
activeStat.count = stats.descendant_new_active_count || 0
}
// 更新月度活跃奖励
const monthlyActiveStat = statistics.value.find(s => s.type === 'descendant_stay_active')
if (monthlyActiveStat) {
monthlyActiveStat.amount = stats.descendant_stay_active_amount || 0
monthlyActiveStat.count = stats.descendant_stay_active_count || 0
}
}
rewardDetails.value = []
}
// 处理列表数据
if (data.value.data.list) {
if (page.value === 1) {
rewardDetails.value = data.value.data.list
} else {
rewardDetails.value.push(...data.value.data.list)
}
finished.value = data.value.data.list.length < pageSize
} else {
finished.value = true
}
}
}
loading.value = false
}
// 下拉刷新
const onRefresh = () => {
finished.value = false
page.value = 1
fetchRewardDetails().finally(() => {
refreshing.value = false
})
}
const rewardDetails = ref([])
const userInfo = ref({})
const summary = ref({})
const statistics = ref([])
onMounted(() => {
fetchRewardDetails()
})
// 获取收益类型样式
const 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',
descendant_new_active: 'bg-indigo-100 text-indigo-600',
descendant_stay_active: 'bg-pink-100 text-pink-600',
}
return typeMap[type] || 'bg-gray-100 text-gray-600'
}
// 获取收益类型图标
const 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',
descendant_new_active: 'medal',
descendant_stay_active: 'medal',
}
return iconMap[type] || 'balance-o'
}
// 获取收益类型描述
const getRewardTypeDescription = type => {
const descriptionMap = {
descendant_promotion: '推广奖励',
cost: '成本贡献',
pricing: '定价贡献',
descendant_withdraw: '提现收益',
descendant_upgrade_vip: '转化VIP奖励',
descendant_upgrade_svip: '转化SVIP奖励',
descendant_new_active: '新增活跃奖励',
descendant_stay_active: '月度活跃奖励',
}
return descriptionMap[type] || '未知类型'
}
// 格式化时间
const 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')}`
}
// 格式化金额
const formatNumber = num => {
if (!num) return '0.00'
return Number(num).toFixed(2)
}
</script>
<template>
<div class="reward-detail">
<!-- 用户信息卡片 -->
<div class="p-4">
<div class="bg-white rounded-xl shadow-sm p-5 mb-4">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center space-x-3">
<div class="text-xl font-semibold text-gray-800">{{ userInfo.mobile }}</div>
<span class="px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-600">
{{ userInfo.level }}代理
</span>
</div>
</div>
<div class="text-sm text-gray-500 mb-4">成为下级代理时间{{ formatTime(userInfo.createTime) }}</div>
<div class="grid grid-cols-3 gap-4">
<div class="text-center">
<div class="text-gray-500 text-sm mb-1">总推广单量</div>
<div class="text-xl font-semibold text-blue-600">{{ summary.totalOrders }}</div>
</div>
<div class="text-center">
<div class="text-gray-500 text-sm mb-1">总收益</div>
<div class="text-xl font-semibold text-green-600">¥{{ formatNumber(summary.totalReward) }}</div>
</div>
<div class="text-center">
<div class="text-gray-500 text-sm mb-1">总贡献</div>
<div class="text-xl font-semibold text-purple-600">¥{{ formatNumber(summary.totalContribution) }}</div>
</div>
</div>
</div>
<!-- 贡献统计卡片 -->
<div class="bg-white rounded-xl shadow-sm p-4 mb-4">
<div class="text-base font-medium text-gray-800 mb-3">贡献统计</div>
<div class="grid grid-cols-2 gap-3">
<div
v-for="item in statistics"
:key="item.type"
class="flex items-center p-2 rounded-lg"
:class="getRewardTypeClass(item.type).split(' ')[0]"
>
<van-icon
:name="getRewardTypeIcon(item.type)"
class="text-lg mr-2"
: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="flex justify-between items-center mt-1">
<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="bg-white rounded-xl shadow-sm p-4 mb-4">
<!-- 贡献记录列表 -->
<div class="text-base font-medium text-gray-800">贡献记录</div>
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="没有更多了"
@load="fetchRewardDetails"
>
<div class="p-4">
<div v-if="rewardDetails.length === 0" class="text-center text-gray-500 py-8">暂无贡献记录</div>
<div v-else v-for="item in rewardDetails" :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">
<van-icon
:name="getRewardTypeIcon(item.type)"
class="text-lg"
:class="getRewardTypeClass(item.type).split(' ')[1]"
/>
<div>
<div class="font-medium text-gray-800">{{ 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>
</van-list>
</van-pull-refresh>
</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);
}
</style>