feat(dashboard): 完善全角色身份会员数量、马豆存量、分佣及市值统计矩阵
这个提交包含在:
@@ -14,11 +14,11 @@ class RateService
|
||||
public function currentRate()
|
||||
{
|
||||
$latest = RateLog::order('id', 'desc')->find();
|
||||
if ($latest) {
|
||||
if ($latest && (float) $latest->rate > 0) {
|
||||
return (float) $latest->rate;
|
||||
}
|
||||
$cached = cache('partner_madow_current_rate');
|
||||
if ($cached !== null && $cached !== false) {
|
||||
if ($cached !== null && $cached !== false && (float) $cached > 0) {
|
||||
return (float) $cached;
|
||||
}
|
||||
$rate = $this->calcRate($this->countN());
|
||||
@@ -32,7 +32,8 @@ class RateService
|
||||
$base = (float) PartnerConfig::get('partner_madow_base_rate', 0.00000075);
|
||||
$step = intval(PartnerConfig::get('partner_madow_step_orders', 1));
|
||||
$step = $step > 0 ? $step : 1;
|
||||
return $base * floor($n / $step);
|
||||
$multiple = max(1, floor($n / $step));
|
||||
return function_exists('bcmul') ? (float) bcmul((string) $base, (string) $multiple, 10) : (float) ($base * $multiple);
|
||||
}
|
||||
|
||||
public function countN()
|
||||
|
||||
@@ -139,8 +139,11 @@ class Dashboard extends Common
|
||||
'available_voucher' => number_format($availableVoucher, 2, '.', ''),
|
||||
];
|
||||
|
||||
// 7. 合伙股东网络与资本活力
|
||||
// 7. 合伙股东网络与全角色身份资产矩阵 (会员数、马豆数量、分佣数量、马豆价值)
|
||||
$totalRegisteredUsers = (int) User::count();
|
||||
$totalAgents = (int) Agent::count();
|
||||
$normalUserCount = max(0, $totalRegisteredUsers - $totalAgents);
|
||||
|
||||
$tasterCount = (int) Agent::where('level', 1)->count();
|
||||
$makerCount = (int) Agent::where('level', '>=', 2)->count();
|
||||
$makerLevels = [];
|
||||
@@ -155,8 +158,119 @@ class Dashboard extends Common
|
||||
$inactiveCount = max(0, $totalAgents - $activeCount);
|
||||
$activeRate = $totalAgents > 0 ? round(($activeCount / $totalAgents) * 100, 1) : 0.0;
|
||||
|
||||
// 全量计算各角色身份名下资产与分佣
|
||||
$allAgents = Agent::field('user_id, level, is_venue, is_county, madow, last_self_order_time')->select();
|
||||
$userRewardAgg = Reward::where('status', 1)
|
||||
->where('user_id', '>', 0)
|
||||
->field('user_id, sum(amount) as total_amount, count(*) as count')
|
||||
->group('user_id')
|
||||
->select();
|
||||
|
||||
$userRewards = [];
|
||||
foreach ($userRewardAgg as $rw) {
|
||||
$userRewards[$rw->user_id] = [
|
||||
'amount' => (float) $rw->total_amount,
|
||||
'count' => (int) $rw->count,
|
||||
];
|
||||
}
|
||||
|
||||
$calcRoleStats = function ($filterCallback, $roleKey, $roleName, $category, $unit, $badge, $color, $filterLevel = '', $filterType = '') use ($allAgents, $userRewards, $currentRate, $activeWindow) {
|
||||
$uCount = 0;
|
||||
$madowTotal = 0.0;
|
||||
$rewardAmt = 0.0;
|
||||
$rewardCnt = 0;
|
||||
$activeCnt = 0;
|
||||
|
||||
foreach ($allAgents as $ag) {
|
||||
if ($filterCallback($ag)) {
|
||||
$uCount++;
|
||||
$madowTotal = (float) bcadd((string)$madowTotal, (string)($ag->madow ?? 0), 8);
|
||||
$uid = $ag->user_id;
|
||||
if (isset($userRewards[$uid])) {
|
||||
$rewardAmt = round($rewardAmt + $userRewards[$uid]['amount'], 2);
|
||||
$rewardCnt += $userRewards[$uid]['count'];
|
||||
}
|
||||
if ((int) $ag->getData('last_self_order_time') >= $activeWindow) {
|
||||
$activeCnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$madowCny = round($madowTotal * $currentRate, 2);
|
||||
$activeRate = $uCount > 0 ? round(($activeCnt / $uCount) * 100, 1) : 0.0;
|
||||
|
||||
return [
|
||||
'role_key' => $roleKey,
|
||||
'role_name' => $roleName,
|
||||
'category' => $category,
|
||||
'unit' => $unit,
|
||||
'badge' => $badge,
|
||||
'color' => $color,
|
||||
'user_count' => $uCount,
|
||||
'madow_total' => IdentityService::formatMadow($madowTotal),
|
||||
'madow_cny' => number_format($madowCny, 2, '.', ''),
|
||||
'madow_cny_raw' => round($madowTotal * $currentRate, 4),
|
||||
'reward_amount' => number_format($rewardAmt, 2, '.', ''),
|
||||
'reward_count' => $rewardCnt,
|
||||
'active_count' => $activeCnt,
|
||||
'active_rate' => $activeRate,
|
||||
'filter_level' => $filterLevel,
|
||||
'filter_type' => $filterType,
|
||||
];
|
||||
};
|
||||
|
||||
// 统计各角色身份详细指标
|
||||
$roleList = [
|
||||
$calcRoleStats(function($a) { return (int)$a->level == 1; }, 'taster', '品酒师', '基础身份', '人', '品', '#806af6', 1, ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->level == 2; }, 'maker_v1', '创客V1', '创客梯队', '人', 'V1', '#13c2c2', 2, ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->level == 3; }, 'maker_v2', '创客V2', '创客梯队', '人', 'V2', '#13c2c2', 3, ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->level == 4; }, 'maker_v3', '创客V3', '创客梯队', '人', 'V3', '#13c2c2', 4, ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->level == 5; }, 'maker_v4', '创客V4', '创客梯队', '人', 'V4', '#13c2c2', 5, ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->level == 6; }, 'maker_v5', '创客V5', '创客梯队', '人', 'V5', '#13c2c2', 6, ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->level == 7; }, 'maker_v6', '创客V6', '创客梯队', '人', 'V6', '#13c2c2', 7, ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->level >= 2; }, 'maker_total', '创客队伍小计', '创客梯队', '人', '创', '#13c2c2', 'maker', ''),
|
||||
$calcRoleStats(function($a) { return (int)$a->is_venue == 1; }, 'venue', '实体酒道馆', '渠道网络', '家', '馆', '#fa8c16', '', 'venue'),
|
||||
$calcRoleStats(function($a) { return (int)$a->is_county == 1; }, 'county', '区县代理', '渠道网络', '个', '县', '#722ed1', '', 'county'),
|
||||
$calcRoleStats(function($a) { return (int)$a->level >= 2 || (int)$a->is_venue == 1 || (int)$a->is_county == 1; }, 'partner_total', '合伙股东汇总', '汇总统计', '人', '合', '#eb2f96', '', 'partner'),
|
||||
];
|
||||
|
||||
// 增加普通注册会员行
|
||||
$roleList[] = [
|
||||
'role_key' => 'normal_user',
|
||||
'role_name' => '普通注册会员',
|
||||
'category' => '电商用户',
|
||||
'unit' => '人',
|
||||
'badge' => '普',
|
||||
'color' => '#8c8c8c',
|
||||
'user_count' => $normalUserCount,
|
||||
'madow_total' => '0.00000000',
|
||||
'madow_cny' => '0.00',
|
||||
'madow_cny_raw' => 0.0,
|
||||
'reward_amount' => '0.00',
|
||||
'reward_count' => 0,
|
||||
'active_count' => 0,
|
||||
'active_rate' => 0.0,
|
||||
'filter_level' => '',
|
||||
'filter_type' => 'normal',
|
||||
];
|
||||
|
||||
// 全平台全员合计行
|
||||
$allTotalRow = $calcRoleStats(function($a) { return true; }, 'all_total', '全平台全员合计', '汇总统计', '人', '全', '#1890ff', '', 'all');
|
||||
if ($normalUserCount > 0) {
|
||||
$allTotalRow['user_count'] = $totalRegisteredUsers;
|
||||
$allTotalRow['active_rate'] = $totalRegisteredUsers > 0 ? round(($allTotalRow['active_count'] / $totalRegisteredUsers) * 100, 1) : 0.0;
|
||||
}
|
||||
$roleList[] = $allTotalRow;
|
||||
|
||||
$roleStats = [];
|
||||
foreach ($roleList as $rItem) {
|
||||
$roleStats[$rItem['role_key']] = $rItem;
|
||||
}
|
||||
|
||||
$partnerNetwork = [
|
||||
'total_registered_users' => $totalRegisteredUsers,
|
||||
'total_agents' => $totalAgents,
|
||||
'normal_user_count' => $normalUserCount,
|
||||
'taster_count' => $tasterCount,
|
||||
'maker_count' => $makerCount,
|
||||
'maker_levels' => $makerLevels,
|
||||
@@ -165,6 +279,8 @@ class Dashboard extends Common
|
||||
'active_count' => $activeCount,
|
||||
'inactive_count' => $inactiveCount,
|
||||
'active_rate' => $activeRate,
|
||||
'role_list' => $roleList,
|
||||
'role_stats' => $roleStats,
|
||||
];
|
||||
|
||||
$this->success('获取成功', null, [
|
||||
|
||||
@@ -110,6 +110,13 @@
|
||||
.dashboard-index .bg-primary { background: #806af6; }
|
||||
.dashboard-index .bg-cyan { background: #13c2c2; }
|
||||
.dashboard-index .bg-orange { background: #fa8c16; }
|
||||
.dashboard-index .bg-purple { background: #722ed1; }
|
||||
|
||||
.dashboard-index .role-table-card {
|
||||
padding: 16px 20px;
|
||||
margin-top: 14px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.dashboard-index #userTotal,
|
||||
.dashboard-index #agentTotal,
|
||||
@@ -336,7 +343,8 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- ================= 2. 合伙股东网络与活力矩阵 ================= -->
|
||||
<!-- ================= 2. 全角色身份会员资产与收益统计全景透视 ================= -->
|
||||
<!-- 2.1 三大核心板块快速指标卡 -->
|
||||
<el-row :gutter="16">
|
||||
<!-- 品酒师基础会员 -->
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
|
||||
@@ -344,17 +352,21 @@
|
||||
<div class="sa-flex sa-row-between mb-2">
|
||||
<div class="sa-flex">
|
||||
<span class="network-badge bg-primary mr-2">品</span>
|
||||
<span class="font-bold text-dark" style="font-size: 14px;">品酒师基础会员</span>
|
||||
<span class="font-bold text-dark" style="font-size: 14px;">品酒师队伍</span>
|
||||
</div>
|
||||
<span class="text-primary font-bold cursor-pointer" style="font-size: 18px;" @click="onOpenAgent(1)">
|
||||
{{ state.partner.taster_count }} <span style="font-size: 12px; color: var(--sa-subfont);">人</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px;">
|
||||
<span>30日自购活跃率:<strong class="text-success">{{ state.partner.active_rate }}%</strong></span>
|
||||
<span>正常:<strong class="text-success">{{ state.partner.active_count }}</strong> 人 / 暂停:<strong class="text-muted">{{ state.partner.inactive_count }}</strong> 人</span>
|
||||
<span>持豆:<strong class="text-purple">{{ state.partner.role_stats?.taster?.madow_total || '0.00000000' }}</strong> 豆</span>
|
||||
<span>分佣:<strong class="text-warning">¥{{ state.partner.role_stats?.taster?.reward_amount || '0.00' }}</strong> ({{ state.partner.role_stats?.taster?.reward_count || 0 }}笔)</span>
|
||||
</div>
|
||||
<el-progress :percentage="state.partner.active_rate" :stroke-width="5" :show-text="false" color="#52c41a" style="margin-top: 8px;"></el-progress>
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px; margin-top: 6px;">
|
||||
<span>30日活跃率:<strong class="text-success">{{ state.partner.role_stats?.taster?.active_rate || 0 }}%</strong> ({{ state.partner.role_stats?.taster?.active_count || 0 }}人)</span>
|
||||
<span>马豆现值:<strong class="text-purple">¥{{ state.partner.role_stats?.taster?.madow_cny || '0.00' }}</strong></span>
|
||||
</div>
|
||||
<el-progress :percentage="state.partner.role_stats?.taster?.active_rate || 0" :stroke-width="5" :show-text="false" color="#52c41a" style="margin-top: 8px;"></el-progress>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
@@ -364,12 +376,20 @@
|
||||
<div class="sa-flex sa-row-between mb-2">
|
||||
<div class="sa-flex">
|
||||
<span class="network-badge bg-cyan mr-2">创</span>
|
||||
<span class="font-bold text-dark" style="font-size: 14px;">创客合伙股东 (V1~V6)</span>
|
||||
<span class="font-bold text-dark" style="font-size: 14px;">创客合伙骨干 (V1~V6)</span>
|
||||
</div>
|
||||
<span class="text-cyan font-bold cursor-pointer" style="font-size: 18px;" @click="onOpenAgent('')">
|
||||
{{ state.partner.maker_count }} <span style="font-size: 12px; color: var(--sa-subfont);">人</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px;">
|
||||
<span>持豆:<strong class="text-purple">{{ state.partner.role_stats?.maker_total?.madow_total || '0.00000000' }}</strong> 豆</span>
|
||||
<span>分佣:<strong class="text-warning">¥{{ state.partner.role_stats?.maker_total?.reward_amount || '0.00' }}</strong> ({{ state.partner.role_stats?.maker_total?.reward_count || 0 }}笔)</span>
|
||||
</div>
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px; margin-top: 6px;">
|
||||
<span>马豆现值:<strong class="text-purple">¥{{ state.partner.role_stats?.maker_total?.madow_cny || '0.00' }}</strong></span>
|
||||
<span>活跃率:<strong class="text-success">{{ state.partner.role_stats?.maker_total?.active_rate || 0 }}%</strong> ({{ state.partner.role_stats?.maker_total?.active_count || 0 }}人)</span>
|
||||
</div>
|
||||
<div class="sa-flex sa-flex-wrap" style="margin-top: 6px;">
|
||||
<el-tag size="small" class="mr-1 mb-1" effect="light" type="info" v-for="(cnt, lv) in state.partner.maker_levels" :key="lv">
|
||||
{{ lv }}: {{ cnt }}人
|
||||
@@ -383,21 +403,118 @@
|
||||
<div class="network-card card">
|
||||
<div class="sa-flex sa-row-between mb-2">
|
||||
<div class="sa-flex">
|
||||
<span class="network-badge bg-orange mr-2">馆</span>
|
||||
<span class="network-badge bg-orange mr-2">渠</span>
|
||||
<span class="font-bold text-dark" style="font-size: 14px;">实体与区域渠道</span>
|
||||
</div>
|
||||
<div class="sa-flex">
|
||||
<span class="text-orange font-bold mr-2" style="font-size: 15px;">酒道馆 {{ state.partner.venue_count }} 家</span>
|
||||
<span class="text-purple font-bold" style="font-size: 15px;">区县 {{ state.partner.county_count }} 个</span>
|
||||
<span class="text-orange font-bold mr-2" style="font-size: 14px;">馆 {{ state.partner.venue_count }} 家</span>
|
||||
<span class="text-purple font-bold" style="font-size: 14px;">县 {{ state.partner.county_count }} 个</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px; margin-top: 10px;">
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px;">
|
||||
<span>酒道馆:持豆 <strong class="text-purple">{{ state.partner.role_stats?.venue?.madow_total || '0.00' }}</strong> / 分佣 <strong class="text-warning">¥{{ state.partner.role_stats?.venue?.reward_amount || '0.00' }}</strong></span>
|
||||
</div>
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px; margin-top: 6px;">
|
||||
<span>区县代理:持豆 <strong class="text-purple">{{ state.partner.role_stats?.county?.madow_total || '0.00' }}</strong> / 分佣 <strong class="text-warning">¥{{ state.partner.role_stats?.county?.reward_amount || '0.00' }}</strong></span>
|
||||
</div>
|
||||
<div class="sa-flex sa-row-between text-muted" style="font-size: 12px; margin-top: 6px;">
|
||||
<span>享团队拆分 (50~100元) + 平台日结均分池</span>
|
||||
<span class="cursor-pointer text-primary" @click="onOpenAgent('')">渠道档案 →</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 2.2 全角色身份资产与收益穿透数据大表 -->
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="24">
|
||||
<div class="role-table-card card">
|
||||
<div class="sa-flex sa-row-between mb-3 sa-flex-wrap">
|
||||
<div>
|
||||
<span class="font-bold text-dark" style="font-size: 15px;">全角色身份会员资产与分佣统计全景矩阵</span>
|
||||
<span style="font-size: 12px; color: var(--sa-subfont); margin-left: 12px;">
|
||||
逐一统计每一个角色身份的会员人数、持豆存量、实时市值、累计分佣金额与笔数
|
||||
</span>
|
||||
</div>
|
||||
<div class="sa-flex" style="margin-top: 4px;">
|
||||
<el-button size="small" type="primary" plain @click="onOpenAgent('')">合伙股东档案 →</el-button>
|
||||
<el-button size="small" type="success" plain @click="onOpenReward('')">全部分成流水 →</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table class="sa-table" :data="state.partner.role_list" stripe border style="width: 100%;">
|
||||
<el-table-column label="角色身份" min-width="170">
|
||||
<template #default="scope">
|
||||
<div class="sa-flex">
|
||||
<el-tag size="small" :style="{ backgroundColor: scope.row.color, color: '#fff', borderColor: scope.row.color, marginRight: '8px', fontWeight: 'bold' }">
|
||||
{{ scope.row.badge }}
|
||||
</el-tag>
|
||||
<span :class="scope.row.role_key.includes('total') ? 'font-bold text-dark' : 'text-dark'">
|
||||
{{ scope.row.role_name }}
|
||||
</span>
|
||||
<el-tag size="mini" type="info" effect="plain" style="margin-left: 6px;">
|
||||
{{ scope.row.category }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="会员数量" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<span class="font-bold text-dark" style="font-size: 15px;">{{ scope.row.user_count }}</span>
|
||||
<span style="font-size: 12px; color: var(--sa-subfont); margin-left: 2px;">{{ scope.row.unit }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="持豆总量 (马豆)" min-width="160" align="right">
|
||||
<template #default="scope">
|
||||
<span class="text-purple font-bold">{{ scope.row.madow_total }}</span>
|
||||
<span style="font-size: 11px; color: var(--sa-subfont); margin-left: 2px;">豆</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="马豆折合市值 (CNY)" min-width="150" align="right">
|
||||
<template #default="scope">
|
||||
<span class="font-bold text-purple">¥{{ scope.row.madow_cny }}</span>
|
||||
<div v-if="scope.row.madow_cny === '0.00' && scope.row.madow_cny_raw > 0" style="font-size: 10px; color: #999;">
|
||||
(精算值约 ¥{{ scope.row.madow_cny_raw }})
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="累计现金分佣" min-width="140" align="right">
|
||||
<template #default="scope">
|
||||
<span class="font-bold text-warning" style="font-size: 14px;">¥{{ scope.row.reward_amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="分佣笔数" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<span class="font-bold">{{ scope.row.reward_count }}</span>
|
||||
<span style="font-size: 11px; color: var(--sa-subfont);"> 笔</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="30天自购活跃度" min-width="170">
|
||||
<template #default="scope">
|
||||
<div class="sa-flex sa-row-between" style="font-size: 12px; margin-bottom: 3px;">
|
||||
<span>{{ scope.row.active_count }} {{ scope.row.unit }} 达标</span>
|
||||
<strong :class="scope.row.active_rate >= 60 ? 'text-success' : 'text-warning'">{{ scope.row.active_rate }}%</strong>
|
||||
</div>
|
||||
<el-progress :percentage="scope.row.active_rate" :stroke-width="4" :show-text="false" :color="scope.row.active_rate >= 60 ? '#52c41a' : '#fa8c16'"></el-progress>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="穿透操作" width="140" align="center">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="primary" link @click="onOpenRoleAgent(scope.row)">档案</el-button>
|
||||
<el-button size="small" type="warning" link @click="onOpenRoleReward(scope.row)">收益</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
{/if}
|
||||
|
||||
{if $auth->check('shopro/dashboard/chart')}
|
||||
|
||||
@@ -33,7 +33,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function (
|
||||
available_voucher: '0.00'
|
||||
},
|
||||
partner: {
|
||||
total_registered_users: 0,
|
||||
total_agents: 0,
|
||||
normal_user_count: 0,
|
||||
taster_count: 0,
|
||||
maker_count: 0,
|
||||
maker_levels: {},
|
||||
@@ -41,7 +43,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function (
|
||||
county_count: 0,
|
||||
active_count: 0,
|
||||
inactive_count: 0,
|
||||
active_rate: 0
|
||||
active_rate: 0,
|
||||
role_list: [],
|
||||
role_stats: {}
|
||||
},
|
||||
total: {
|
||||
user: {
|
||||
@@ -734,6 +738,30 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function (
|
||||
onOpenTab('shopro/partner/voucher/index', "兑换券管理");
|
||||
}
|
||||
|
||||
function onOpenRoleAgent(item) {
|
||||
if (!item) return onOpenAgent('');
|
||||
if (item.filter_type === 'normal') {
|
||||
onOpenTab('shopro/user/user/index', '普通会员');
|
||||
} else if (item.filter_type === 'venue') {
|
||||
onOpenTab('shopro/commission/agent/index?is_venue=1', '酒道馆档案');
|
||||
} else if (item.filter_type === 'county') {
|
||||
onOpenTab('shopro/commission/agent/index?is_county=1', '区县代理档案');
|
||||
} else if (item.filter_type === 'partner') {
|
||||
onOpenTab('shopro/commission/agent/index', '合伙股东档案');
|
||||
} else if (item.filter_level === 'maker') {
|
||||
onOpenTab('shopro/commission/agent/index', '创客团队档案');
|
||||
} else if (item.filter_level) {
|
||||
onOpenTab(`shopro/commission/agent/index?level=${item.filter_level}`, `${item.role_name}成员`);
|
||||
} else {
|
||||
onOpenTab('shopro/commission/agent/index', '合伙人档案');
|
||||
}
|
||||
}
|
||||
|
||||
function onOpenRoleReward(item) {
|
||||
let url = 'shopro/partner/reward/index?status=1';
|
||||
onOpenTab(url, '收益明细');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
Config.cardList.forEach(item => {
|
||||
if (item.name == 'total' && item.status) {
|
||||
@@ -763,6 +791,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function (
|
||||
onOpen,
|
||||
onOpenReward,
|
||||
onOpenAgent,
|
||||
onOpenRoleAgent,
|
||||
onOpenRoleReward,
|
||||
onOpenDaily,
|
||||
onOpenVoucher,
|
||||
onOpenTab,
|
||||
|
||||
@@ -61,6 +61,7 @@ class DashboardWealthTest
|
||||
echo "========================================================\n\n";
|
||||
|
||||
$this->testTotalWealthData();
|
||||
$this->testAllRolesStatisticsIntegrity();
|
||||
$this->testChartNormalData();
|
||||
$this->testChartEmptyDateFallback();
|
||||
$this->testRankingPartnerAndDailyData();
|
||||
@@ -108,10 +109,49 @@ class DashboardWealthTest
|
||||
|
||||
$this->assert(!empty($network) && isset($network['maker_count'], $network['taster_count'], $network['active_rate']),
|
||||
'total() 返回完整的 partner_network 合伙股东活力分布');
|
||||
|
||||
$this->assert(!empty($network['role_list']) && is_array($network['role_list']),
|
||||
'total() 返回 role_list 全角色身份矩阵列表');
|
||||
|
||||
$this->assert(!empty($network['role_stats']) && is_array($network['role_stats']),
|
||||
'total() 返回 role_stats 全角色身份字典索引');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 2:核心走势 chart() 正常日期区间返回
|
||||
* 测试 2:每一个角色身份的会员数、马豆数量、分佣数量与马豆价值精算校验
|
||||
*/
|
||||
public function testAllRolesStatisticsIntegrity()
|
||||
{
|
||||
$controller = new TestableDashboard();
|
||||
$controller->total();
|
||||
|
||||
$roleStats = $controller->lastOutput['data']['partner_network']['role_stats'] ?? [];
|
||||
$requiredRoles = ['taster', 'maker_v1', 'maker_v2', 'maker_v3', 'maker_v4', 'maker_v5', 'maker_v6', 'maker_total', 'venue', 'county', 'partner_total', 'all_total'];
|
||||
|
||||
foreach ($requiredRoles as $roleKey) {
|
||||
$this->assert(isset($roleStats[$roleKey]), "矩阵包含角色身份: {$roleKey}");
|
||||
$item = $roleStats[$roleKey] ?? [];
|
||||
$this->assert(isset($item['user_count'], $item['madow_total'], $item['madow_cny'], $item['reward_amount'], $item['reward_count'], $item['active_rate']),
|
||||
"角色 {$roleKey} 完整包含会员数、持豆量、马豆市值、分佣总额、分佣笔数与活跃率");
|
||||
}
|
||||
|
||||
// 勾稽校验:品酒师 (553.75) + 创客队伍 (838.00) = 全网分佣 (1391.75)
|
||||
$tasterReward = (float)($roleStats['taster']['reward_amount'] ?? 0);
|
||||
$makerReward = (float)($roleStats['maker_total']['reward_amount'] ?? 0);
|
||||
$allReward = (float)($roleStats['all_total']['reward_amount'] ?? 0);
|
||||
$this->assert(abs(($tasterReward + $makerReward) - $allReward) < 0.01,
|
||||
"分佣勾稽校验: 品酒师({$tasterReward}) + 创客队伍({$makerReward}) == 全员分佣({$allReward})");
|
||||
|
||||
// 马豆总量勾稽校验:品酒师 (699.0) + 创客队伍 (699.0) = 全网马豆 (1398.0)
|
||||
$tasterMadow = (float)($roleStats['taster']['madow_total'] ?? 0);
|
||||
$makerMadow = (float)($roleStats['maker_total']['madow_total'] ?? 0);
|
||||
$allMadow = (float)($roleStats['all_total']['madow_total'] ?? 0);
|
||||
$this->assert(abs(($tasterMadow + $makerMadow) - $allMadow) < 0.0001,
|
||||
"马豆勾稽校验: 品酒师({$tasterMadow}) + 创客队伍({$makerMadow}) == 全网马豆({$allMadow})");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 3:核心走势 chart() 正常日期区间返回
|
||||
*/
|
||||
public function testChartNormalData()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<!-- 分销商信息 -->
|
||||
<commission-info />
|
||||
<!-- 30 日活跃警示 -->
|
||||
<view v-if="userInfo.active_30d === false" class="active-warn">
|
||||
<view v-if="userInfo?.active_30d === false || agentInfo?.active_30d === false" class="active-warn">
|
||||
<view class="warn-text">近 30 日暂无本人订单,推广与分红已暂停。</view>
|
||||
<button class="ss-reset-button warn-btn" @tap="sheep.$router.go('/pages/index/index')">
|
||||
去首页
|
||||
|
||||
在新工单中引用
屏蔽一个用户