|
|
@@ -1,5 +1,6 @@
|
|
|
<template>
|
|
|
<div class="rounded-lg p-4 bg-[var(--p-content-background)]">
|
|
|
+
|
|
|
<DataTable
|
|
|
:value="tableData.content"
|
|
|
:paginator="true"
|
|
|
@@ -45,6 +46,12 @@
|
|
|
<Button icon="pi pi-refresh" @click="handleRefresh" label="刷新" size="small" />
|
|
|
<Button icon="pi pi-plus" @click="openAddDialog" label="新增成员" size="small" severity="success" />
|
|
|
<div class="flex-1"></div>
|
|
|
+ <!-- 团队用户统计信息提示 -->
|
|
|
+ <div v-if="isTeam" class="text-sm text-gray-600">
|
|
|
+ <span class="font-medium">团队统计:</span>
|
|
|
+ <span v-if="teamStats" class="text-green-600 ml-1">已加载</span>
|
|
|
+ <span v-else class="text-orange-600 ml-1">未加载</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -80,42 +87,75 @@
|
|
|
</template>
|
|
|
</Column>
|
|
|
|
|
|
- <!-- <Column field="totalRevenue" header="总收入" style="min-width: 120px">
|
|
|
+ <Column field="commissionRate" header="分成比例" style="min-width: 120px">
|
|
|
<template #body="slotProps">
|
|
|
- <span class="total-revenue-text font-semibold"> {{ formatAmount(slotProps.data.totalRevenue) }} </span>
|
|
|
+ <span class="commission-rate-text font-semibold">
|
|
|
+ {{ slotProps.data.commissionRate || 0 }}%
|
|
|
+ </span>
|
|
|
</template>
|
|
|
</Column>
|
|
|
|
|
|
- <Column field="todayRevenue" header="今日收入" style="min-width: 120px">
|
|
|
+ <!-- 团队用户可见的收入统计列 -->
|
|
|
+ <Column v-if="isTeam" field="totalRevenue" header="总收入" style="min-width: 120px">
|
|
|
<template #body="slotProps">
|
|
|
- <span class="today-revenue-text font-semibold"> {{ formatAmount(slotProps.data.todayRevenue) }} </span>
|
|
|
+ <span class="total-revenue-text font-semibold text-blue-600">
|
|
|
+ ¥{{ formatAmount(getMemberTotalRevenue(slotProps.data.id)) }}
|
|
|
+ </span>
|
|
|
</template>
|
|
|
- </Column> -->
|
|
|
+ </Column>
|
|
|
|
|
|
- <Column field="commissionRate" header="分成比例" style="min-width: 120px">
|
|
|
+ <Column v-if="isTeam" field="todayRevenue" header="今日收入" style="min-width: 120px">
|
|
|
<template #body="slotProps">
|
|
|
- <span class="commission-rate-text font-semibold">
|
|
|
- {{ slotProps.data.commissionRate || 0 }}%
|
|
|
+ <span class="today-revenue-text font-semibold text-green-600">
|
|
|
+ ¥{{ formatAmount(getMemberTodayRevenue(slotProps.data.id)) }}
|
|
|
</span>
|
|
|
</template>
|
|
|
</Column>
|
|
|
|
|
|
- <Column field="totalRevenue" header="总分成" style="min-width: 120px">
|
|
|
+ <!-- 团队用户可见的销售额统计列 -->
|
|
|
+ <Column v-if="isTeam" field="totalSales" header="总销售额" style="min-width: 120px">
|
|
|
<template #body="slotProps">
|
|
|
- <span class="total-revenue-text font-semibold">
|
|
|
- ¥{{ formatAmount(slotProps.data.totalRevenue) }}
|
|
|
+ <span class="total-sales-text font-semibold text-purple-600">
|
|
|
+ ¥{{ formatAmount(getMemberTotalSales(slotProps.data.id)) }}
|
|
|
</span>
|
|
|
</template>
|
|
|
</Column>
|
|
|
|
|
|
- <Column field="todayRevenue" header="今日分成" style="min-width: 120px">
|
|
|
+ <Column v-if="isTeam" field="todaySales" header="今日销售额" style="min-width: 120px">
|
|
|
<template #body="slotProps">
|
|
|
- <span class="today-revenue-text font-semibold">
|
|
|
- ¥{{ formatAmount(slotProps.data.todayRevenue) }}
|
|
|
+ <span class="today-sales-text font-semibold text-orange-600">
|
|
|
+ ¥{{ formatAmount(getMemberTodaySales(slotProps.data.id)) }}
|
|
|
</span>
|
|
|
</template>
|
|
|
</Column>
|
|
|
|
|
|
+ <!-- 实际收入(比例)列 -->
|
|
|
+ <Column v-if="isTeam" field="actualIncome" header="队长收入(比例)" style="min-width: 150px">
|
|
|
+ <template #body="slotProps">
|
|
|
+ <div class="flex flex-col">
|
|
|
+ <span v-if="isTeamLeader(slotProps.data.id)" class="team-leader-income-text font-semibold text-red-600">
|
|
|
+ ¥{{ formatAmount(getTeamLeaderTotalIncome(slotProps.data.id)) }}({{ getMemberActualRate(slotProps.data.id) }}%)
|
|
|
+ </span>
|
|
|
+ <span v-else class="actual-rate-text font-semibold text-blue-600">
|
|
|
+ ¥{{ formatAmount(getMemberTotalRevenue(slotProps.data.id)) }}({{ getMemberActualRate(slotProps.data.id) }}%)
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+
|
|
|
+ <!-- 今日实际收入(比例)列 -->
|
|
|
+ <Column v-if="isTeam" field="todayActualIncome" header="队长今日收入(比例)" style="min-width: 150px">
|
|
|
+ <template #body="slotProps">
|
|
|
+ <div class="flex flex-col">
|
|
|
+ <span v-if="isTeamLeader(slotProps.data.id)" class="team-leader-today-income-text font-semibold text-red-600">
|
|
|
+ ¥{{ formatAmount(getTeamLeaderTodayIncome(slotProps.data.id)) }}({{ getMemberActualRate(slotProps.data.id) }}%)
|
|
|
+ </span>
|
|
|
+ <span v-else class="today-revenue-text font-semibold text-green-600">
|
|
|
+ ¥{{ formatAmount(getMemberTodayRevenue(slotProps.data.id)) }}({{ getMemberActualRate(slotProps.data.id) }}%)
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
|
|
|
<Column field="createdAt" header="创建时间" style="min-width: 150px">
|
|
|
<template #body="slotProps">
|
|
|
@@ -255,7 +295,7 @@ import InputNumber from 'primevue/inputnumber'
|
|
|
import Password from 'primevue/password'
|
|
|
import { useConfirm } from 'primevue/useconfirm'
|
|
|
import { useToast } from 'primevue/usetoast'
|
|
|
-import { listMembers, createMember, updateMember, deleteMember } from '@/services/api'
|
|
|
+import { listMembers, createMember, updateMember, deleteMember, getTeamLeaderStats } from '@/services/api'
|
|
|
import { useTeamStore } from '@/stores/team'
|
|
|
|
|
|
const toast = useToast()
|
|
|
@@ -307,6 +347,10 @@ const tableData = ref({
|
|
|
|
|
|
// 加载状态
|
|
|
const loading = ref(false)
|
|
|
+const statsLoading = ref(false)
|
|
|
+
|
|
|
+// 团队统计数据
|
|
|
+const teamStats = ref(null)
|
|
|
|
|
|
// 编辑相关
|
|
|
const editDialog = ref(false)
|
|
|
@@ -347,6 +391,63 @@ const formatDateTime = (dateString) => {
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+// 获取成员的实际比例
|
|
|
+const getMemberActualRate = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return 0
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.actualRate || 0
|
|
|
+}
|
|
|
+
|
|
|
+// 获取成员的总收入
|
|
|
+const getMemberTotalRevenue = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return 0
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.totalRevenue || 0
|
|
|
+}
|
|
|
+
|
|
|
+// 获取成员的今日收入
|
|
|
+const getMemberTodayRevenue = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return 0
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.todayRevenue || 0
|
|
|
+}
|
|
|
+
|
|
|
+// 获取成员的总销售额
|
|
|
+const getMemberTotalSales = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return 0
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.totalSales || 0
|
|
|
+}
|
|
|
+
|
|
|
+// 获取成员的今日销售额
|
|
|
+const getMemberTodaySales = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return 0
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.todaySales || 0
|
|
|
+}
|
|
|
+
|
|
|
+// 判断是否为队长
|
|
|
+const isTeamLeader = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return false
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.teamLeaderTotalIncome !== undefined || member?.teamLeaderTodayIncome !== undefined
|
|
|
+}
|
|
|
+
|
|
|
+// 获取队长的实际总收入
|
|
|
+const getTeamLeaderTotalIncome = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return 0
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.teamLeaderTotalIncome || 0
|
|
|
+}
|
|
|
+
|
|
|
+// 获取队长的实际今日收入
|
|
|
+const getTeamLeaderTodayIncome = (memberId) => {
|
|
|
+ if (!teamStats.value?.membersStats) return 0
|
|
|
+ const member = teamStats.value.membersStats.find(m => m.memberId === memberId)
|
|
|
+ return member?.teamLeaderTodayIncome || 0
|
|
|
+}
|
|
|
+
|
|
|
// 获取数据
|
|
|
const fetchData = async () => {
|
|
|
loading.value = true
|
|
|
@@ -370,6 +471,36 @@ const fetchData = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 获取团队统计数据
|
|
|
+const fetchTeamStats = async () => {
|
|
|
+ if (!isTeam.value) return
|
|
|
+
|
|
|
+ statsLoading.value = true
|
|
|
+ try {
|
|
|
+ const response = await getTeamLeaderStats()
|
|
|
+ teamStats.value = response
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取团队统计数据失败:', error)
|
|
|
+ if (error.status === 403) {
|
|
|
+ toast.add({
|
|
|
+ severity: 'warn',
|
|
|
+ summary: '权限不足',
|
|
|
+ detail: '只有团队用户才能访问统计数据',
|
|
|
+ life: 3000
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ toast.add({
|
|
|
+ severity: 'error',
|
|
|
+ summary: '错误',
|
|
|
+ detail: '获取团队统计数据失败',
|
|
|
+ life: 3000
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ statsLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 分页处理
|
|
|
const handlePageChange = (event) => {
|
|
|
tableData.value.metadata.page = event.page
|
|
|
@@ -513,6 +644,10 @@ const saveEdit = async () => {
|
|
|
|
|
|
onMounted(() => {
|
|
|
fetchData()
|
|
|
+ // 如果是团队用户,预加载统计数据
|
|
|
+ if (isTeam.value) {
|
|
|
+ fetchTeamStats()
|
|
|
+ }
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
@@ -584,6 +719,31 @@ onMounted(() => {
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
+.actual-rate-text {
|
|
|
+ color: #2563eb;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.total-sales-text {
|
|
|
+ color: #7c3aed;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.today-sales-text {
|
|
|
+ color: #ea580c;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.team-leader-income-text {
|
|
|
+ color: #dc2626;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.team-leader-today-income-text {
|
|
|
+ color: #dc2626;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
.font-medium {
|
|
|
font-weight: 500;
|