|
|
@@ -153,52 +153,97 @@
|
|
|
</Column>
|
|
|
</DataTable>
|
|
|
|
|
|
- <div v-else-if="isTeam && teamData" class="flex flex-col items-center justify-center py-4">
|
|
|
- <div class="w-full max-w-xl p-10">
|
|
|
- <div class="text-2xl font-extrabold mb-2 text-center text-blue-700 tracking-wide">我的团队信息</div>
|
|
|
- <div class="border-b border-gray-200 mb-6"></div>
|
|
|
- <div class="grid grid-cols-2 gap-y-6 gap-x-4">
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">团队名称</span>
|
|
|
- <span class="text-lg font-bold text-gray-900">{{ teamData.name }}</span>
|
|
|
+ <div v-else-if="isTeam && teamData" class="py-2">
|
|
|
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
|
+ <!-- 左侧:基本信息卡片(与右侧均分) -->
|
|
|
+ <div>
|
|
|
+ <div class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
|
|
|
+ <div class="text-xl font-extrabold mb-4 text-gray-900">我的团队信息</div>
|
|
|
+ <div class="grid grid-cols-1 sm:grid-cols-2 gap-y-5 gap-x-6">
|
|
|
+ <div class="flex flex-col">
|
|
|
+ <span class="text-gray-500 text-sm mb-1">团队名称</span>
|
|
|
+ <span class="text-base font-bold text-gray-900">{{ teamData.name }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-col">
|
|
|
+ <span class="text-gray-500 text-sm mb-1">佣金比例</span>
|
|
|
+ <span class="text-base font-bold text-purple-700">{{ teamData.commissionRate }}%</span>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-col">
|
|
|
+ <span class="text-gray-500 text-sm mb-1">推广码</span>
|
|
|
+ <span
|
|
|
+ class="text-base font-bold text-orange-600 font-mono copyable-text cursor-pointer"
|
|
|
+ :title="teamData.affCode"
|
|
|
+ @click="copyToClipboard(teamData.affCode)"
|
|
|
+ >
|
|
|
+ {{ teamData.affCode }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-col">
|
|
|
+ <span class="text-gray-500 text-sm mb-1">总用户数</span>
|
|
|
+ <span class="text-lg font-extrabold text-teal-600">{{ teamData.totalUsers || 0 }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">佣金比例</span>
|
|
|
- <span class="text-lg font-bold text-purple-700">{{ teamData.commissionRate }}%</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧:统计快照(与左侧均分) -->
|
|
|
+ <div class="grid grid-cols-2 gap-4">
|
|
|
+ <div class="stat-card stat-yellow">
|
|
|
+ <div class="icon-badge icon-yellow"><i class="pi pi-dollar"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">今日分润收入</div>
|
|
|
+ <div class="stat-value text-yellow-700">¥{{ formatAmount(teamData.todayRevenue) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">总分润收入</span>
|
|
|
- <span class="text-2xl font-extrabold text-blue-600">¥{{ formatAmount(teamData.totalRevenue) }}</span>
|
|
|
+ <div class="stat-card stat-blue">
|
|
|
+ <div class="icon-badge icon-blue"><i class="pi pi-wallet"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">总分润收入</div>
|
|
|
+ <div class="stat-value text-blue-700">¥{{ formatAmount(teamData.totalRevenue) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">总销售额</span>
|
|
|
- <span class="text-2xl font-extrabold text-orange-600">¥{{ formatAmount(teamData.totalSales) }}</span>
|
|
|
+ <div class="stat-card stat-green">
|
|
|
+ <div class="icon-badge icon-green"><i class="pi pi-shopping-cart"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">今日销售额</div>
|
|
|
+ <div class="stat-value text-green-700">¥{{ formatAmount(teamData.todaySales) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">今日分润收入</span>
|
|
|
- <span class="text-2xl font-extrabold text-green-600">¥{{ formatAmount(teamData.todayRevenue) }}</span>
|
|
|
+ <div class="stat-card stat-orange">
|
|
|
+ <div class="icon-badge icon-orange"><i class="pi pi-chart-line"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">总销售额</div>
|
|
|
+ <div class="stat-value text-orange-700">¥{{ formatAmount(teamData.totalSales) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">今日销售额</span>
|
|
|
- <span class="text-2xl font-extrabold text-red-600">¥{{ formatAmount(teamData.todaySales) }}</span>
|
|
|
+ <div class="stat-card stat-indigo">
|
|
|
+ <div class="icon-badge icon-indigo"><i class="pi pi-users"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">今日日活</div>
|
|
|
+ <div class="stat-value text-indigo-700">{{ teamData.todayDAU || 0 }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">今日日活用户</span>
|
|
|
- <span class="text-2xl font-extrabold text-indigo-600">{{ teamData.todayDAU || 0 }}</span>
|
|
|
+ <div class="stat-card stat-slate">
|
|
|
+ <div class="icon-badge icon-slate"><i class="pi pi-database"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">总用户</div>
|
|
|
+ <div class="stat-value text-slate-800">{{ teamData.totalUsers || 0 }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">总用户数</span>
|
|
|
- <span class="text-2xl font-extrabold text-teal-600">{{ teamData.totalUsers || 0 }}</span>
|
|
|
+ <div class="stat-card stat-indigo">
|
|
|
+ <div class="icon-badge icon-indigo"><i class="pi pi-chart-bar"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">今日IP成交率</div>
|
|
|
+ <div class="stat-value text-indigo-700">{{ formatPercent(ipStats?.todayIpConversionRate) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="flex flex-col items-start">
|
|
|
- <span class="text-gray-500 text-base font-medium mb-1">推广码</span>
|
|
|
- <span
|
|
|
- class="text-lg font-bold text-orange-600 font-mono copyable-text cursor-pointer"
|
|
|
- :title="teamData.affCode"
|
|
|
- @click="copyToClipboard(teamData.affCode)"
|
|
|
- >
|
|
|
- {{ teamData.affCode }}
|
|
|
- </span>
|
|
|
+ <div class="stat-card stat-slate">
|
|
|
+ <div class="icon-badge icon-slate"><i class="pi pi-chart-line"></i></div>
|
|
|
+ <div class="stat-body">
|
|
|
+ <div class="stat-title">总IP成交率</div>
|
|
|
+ <div class="stat-value text-slate-800">{{ formatPercent(ipStats?.totalIpConversionRate) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -293,7 +338,7 @@ import InputNumber from 'primevue/inputnumber'
|
|
|
import Password from 'primevue/password'
|
|
|
import { useConfirm } from 'primevue/useconfirm'
|
|
|
import { useToast } from 'primevue/usetoast'
|
|
|
-import { listTeams, createTeam, updateTeam, deleteTeam } from '@/services/api'
|
|
|
+import { listTeams, createTeam, updateTeam, deleteTeam, getTeamIpConversionRate } from '@/services/api'
|
|
|
|
|
|
const toast = useToast()
|
|
|
const confirm = useConfirm()
|
|
|
@@ -338,6 +383,14 @@ const formatAmount = (amount) => {
|
|
|
return Number(amount).toFixed(2)
|
|
|
}
|
|
|
|
|
|
+// 百分比格式化(0-1 -> 0.00%)
|
|
|
+const formatPercent = (rate) => {
|
|
|
+ if (rate === undefined || rate === null) return '0.00%'
|
|
|
+ const num = Number(rate)
|
|
|
+ if (Number.isNaN(num)) return '0.00%'
|
|
|
+ return `${(num * 100).toFixed(2)}%`
|
|
|
+}
|
|
|
+
|
|
|
// 格式化日期时间
|
|
|
const formatDateTime = (dateString) => {
|
|
|
if (!dateString) return '-'
|
|
|
@@ -376,6 +429,24 @@ const fetchData = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 团队IP成交率
|
|
|
+const ipStats = ref(null)
|
|
|
+const loadIpConversionRate = async () => {
|
|
|
+ try {
|
|
|
+ const data = await getTeamIpConversionRate()
|
|
|
+ ipStats.value = data
|
|
|
+ } catch (e) {
|
|
|
+ // 团队角色无权限外的错误提示
|
|
|
+ // 接口做了权限限制,这里仅在请求失败时给出轻提示
|
|
|
+ toast.add({
|
|
|
+ severity: 'warn',
|
|
|
+ summary: '提示',
|
|
|
+ detail: '获取IP成交率失败',
|
|
|
+ life: 2500
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 分页处理
|
|
|
const handlePageChange = (event) => {
|
|
|
tableData.value.metadata.page = event.page
|
|
|
@@ -537,6 +608,9 @@ const saveEdit = async () => {
|
|
|
// 初始化
|
|
|
onMounted(() => {
|
|
|
fetchData()
|
|
|
+ if (isTeam?.value) {
|
|
|
+ loadIpConversionRate()
|
|
|
+ }
|
|
|
})
|
|
|
|
|
|
const teamData = computed(() => tableData.value?.content?.[0] || null)
|
|
|
@@ -697,4 +771,40 @@ const teamData = computed(() => tableData.value?.content?.[0] || null)
|
|
|
min-height: 56px;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/* 统计卡片样式(右侧) */
|
|
|
+.stat-card {
|
|
|
+ border-radius: 0.5rem;
|
|
|
+ border: 1px solid #fde68a; /* amber-300 */
|
|
|
+ padding: 1rem;
|
|
|
+ background: #fffbeb; /* amber-50 统一浅黄色背景 */
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 1rem;
|
|
|
+}
|
|
|
+.stat-title {
|
|
|
+ font-size: 0.875rem; /* text-sm */
|
|
|
+ color: #4b5563; /* gray-600 */
|
|
|
+}
|
|
|
+.stat-value {
|
|
|
+ margin-top: 0.25rem;
|
|
|
+ font-size: 1.5rem; /* text-2xl */
|
|
|
+ font-weight: 800; /* extrabold */
|
|
|
+}
|
|
|
+.icon-badge {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 9999px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 1.125rem; /* text-lg */
|
|
|
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
+}
|
|
|
+.icon-yellow { background: #fef3c7; border: 1px solid #fde68a; color: #ca8a04; }
|
|
|
+.icon-blue { background: #dbeafe; border: 1px solid #bfdbfe; color: #2563eb; }
|
|
|
+.icon-green { background: #dcfce7; border: 1px solid #bbf7d0; color: #16a34a; }
|
|
|
+.icon-orange { background: #ffedd5; border: 1px solid #fed7aa; color: #ea580c; }
|
|
|
+.icon-indigo { background: #e0e7ff; border: 1px solid #c7d2fe; color: #4f46e5; }
|
|
|
+.icon-slate { background: #f1f5f9; border: 1px solid #e2e8f0; color: #475569; }
|
|
|
</style>
|