feat(commission): 重构分销商详情运营统计看板紧扣恒联业务与方案B一体化大余额
这个提交包含在:
@@ -69,7 +69,7 @@ class Agent extends Common
|
||||
$detail->next_push3_text = '第 ' . ($seq + 1) . ' 单将返 ' . $detail->next_push3_amount;
|
||||
$detail->last_self_order_text = $last ? date('Y-m-d H:i:s', $last) : '从未下单';
|
||||
|
||||
// 业务核心规范:进阶角色(创客V1~V6、酒道馆、区县代理、合伙股东)需自购考核;基础会员及品酒师免自购考核
|
||||
// 业务核心规范:进阶角色(创客V1~V6、酒道馆、区县代理、合伙人)需自购考核;基础会员及品酒师免自购考核
|
||||
if (!$isAdvanced) {
|
||||
$detail->active_status_text = '免自购考核 (基础会员/品酒师)';
|
||||
} else {
|
||||
@@ -101,18 +101,204 @@ class Agent extends Common
|
||||
$detail->total_income = $alignedIncome;
|
||||
$detail->partner_cash_income = $alignedIncome;
|
||||
$detail->push3_cash_income = number_format((float) $push3Cash, 2, '.', '');
|
||||
$detail->partner_exclusive_cash = number_format((float) $partnerExclusiveCash, 2, '.', '');
|
||||
$detail->user_money = number_format(floatval($detail->user ? $detail->user->money : 0), 2, '.', '');
|
||||
$detail->user_commission = number_format(floatval($detail->user ? $detail->user->commission : 0), 2, '.', '');
|
||||
$userData = $detail->user ? $detail->user->getData() : [];
|
||||
$userMoney = $userData['money'] ?? 0;
|
||||
$userCommission = $userData['commission'] ?? 0;
|
||||
$detail->user_money = number_format(floatval($userMoney), 2, '.', '');
|
||||
$detail->user_commission = number_format(floatval($userCommission), 2, '.', '');
|
||||
$detail->partner_mode = \addons\shopro\service\partner\PartnerConfig::isPartnerMode() ? 1 : 0;
|
||||
$rate = (new \addons\shopro\service\partner\RateService())->currentRate();
|
||||
$detail->madow_value = \addons\shopro\service\partner\IdentityService::formatMoney((float) ($detail->madow ?? 0) * (float) $rate);
|
||||
$detail->custom_role_names = \addons\shopro\service\partner\PartnerConfig::roleNames();
|
||||
$detail->role_names = $detail->custom_role_names;
|
||||
$detail->operational_stats = $this->getOperationalStats($detail, $id);
|
||||
|
||||
$this->success('分销商详情', null, $detail);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建运营官全景统计数据看板
|
||||
*/
|
||||
private function getOperationalStats($detail, $id)
|
||||
{
|
||||
$allUsers = \think\Db::name('user')->column('parent_user_id', 'id');
|
||||
$getDesc = function ($uid) use (&$getDesc, $allUsers) {
|
||||
$res = [];
|
||||
foreach ($allUsers as $cid => $pid) {
|
||||
if ((int)$pid === (int)$uid) {
|
||||
$res[] = $cid;
|
||||
$res = array_merge($res, $getDesc($cid));
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
};
|
||||
$descIds = $getDesc($id);
|
||||
$directIds = [];
|
||||
foreach ($allUsers as $cid => $pid) {
|
||||
if ((int)$pid === (int)$id) {
|
||||
$directIds[] = $cid;
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 团队角色拓扑
|
||||
$directCount = count($directIds);
|
||||
$directPaidCount = empty($directIds) ? 0 : \think\Db::name('user')->whereIn('id', $directIds)->where('total_consume', '>', 0)->count();
|
||||
$directMakerCount = empty($directIds) ? 0 : \think\Db::name('shopro_commission_agent')->whereIn('user_id', $directIds)->where('level', '>=', 2)->count();
|
||||
|
||||
$teamDescCount = count($descIds);
|
||||
$teamPaidCount = empty($descIds) ? 0 : \think\Db::name('user')->whereIn('id', $descIds)->where('total_consume', '>', 0)->count();
|
||||
$teamMakerAgents = empty($descIds) ? [] : \think\Db::name('shopro_commission_agent')->whereIn('user_id', $descIds)->where('level', '>=', 2)->column('level');
|
||||
$teamMakerCount = count($teamMakerAgents);
|
||||
$teamMakerDistribution = array_count_values($teamMakerAgents);
|
||||
ksort($teamMakerDistribution);
|
||||
$makerDistribution = [
|
||||
'v1' => intval($teamMakerDistribution[2] ?? 0),
|
||||
'v2' => intval($teamMakerDistribution[3] ?? 0),
|
||||
'v3' => intval($teamMakerDistribution[4] ?? 0),
|
||||
'v4' => intval($teamMakerDistribution[5] ?? 0),
|
||||
'v5' => intval($teamMakerDistribution[6] ?? 0),
|
||||
'v6' => intval($teamMakerDistribution[7] ?? 0),
|
||||
];
|
||||
$teamVenueCount = empty($descIds) ? 0 : \think\Db::name('shopro_commission_agent')->whereIn('user_id', $descIds)->where('is_venue', 1)->count();
|
||||
$teamCountyCount = empty($descIds) ? 0 : \think\Db::name('shopro_commission_agent')->whereIn('user_id', $descIds)->where('is_county', 1)->count();
|
||||
$conversionRate = $teamDescCount > 0 ? round(($teamPaidCount / $teamDescCount) * 100, 1) : 0.0;
|
||||
|
||||
// 2. 收益分成细项
|
||||
$rewards = \think\Db::name('shopro_partner_reward')
|
||||
->where('user_id', $id)
|
||||
->where('status', 1)
|
||||
->group('reward_type')
|
||||
->column('sum(amount)', 'reward_type');
|
||||
|
||||
$push3Income = (float)($rewards['push3'] ?? 0);
|
||||
$makerDiffIncome = (float)($rewards['maker_diff'] ?? 0);
|
||||
$makerPeerIncome = (float)(($rewards['maker_peer'] ?? 0) + ($rewards['maker_overtaken'] ?? 0));
|
||||
$teamSplitIncome = (float)(($rewards['team_venue'] ?? 0) + ($rewards['team_county'] ?? 0));
|
||||
$sharePoolIncome = (float)(($rewards['venue_share'] ?? 0) + ($rewards['county_share'] ?? 0));
|
||||
|
||||
// 3. 业绩与订单分类
|
||||
$selfOrderMoney = number_format((float)($detail->child_order_money_0 ?? 0), 2, '.', '');
|
||||
$selfOrderCount = intval($detail->child_order_count_0 ?? 0);
|
||||
$directOrderMoney = number_format((float)($detail->child_order_money_1 ?? 0), 2, '.', '');
|
||||
$directOrderCount = intval($detail->child_order_count_1 ?? 0);
|
||||
$teamOrderMoney = number_format((float)($detail->child_order_money_all ?? 0), 2, '.', '');
|
||||
$teamOrderCount = intval($detail->child_order_count_all ?? 0);
|
||||
|
||||
$indirectOrderMoney = number_format(max(0, (float)$teamOrderMoney - (float)$directOrderMoney - (float)$selfOrderMoney), 2, '.', '');
|
||||
$indirectOrderCount = max(0, $teamOrderCount - $directOrderCount - $selfOrderCount);
|
||||
|
||||
// 4. 晋升考核差距雷达
|
||||
$currentLevel = intval($detail->level ?? 1);
|
||||
$currentLevelRow = \think\Db::name('shopro_commission_level')->where('level', $currentLevel)->find();
|
||||
$currentLevelName = $currentLevelRow ? $currentLevelRow['name'] : ($currentLevel >= 2 ? '创客V' . ($currentLevel - 1) : '品酒师');
|
||||
|
||||
$nextLevel = $currentLevel + 1;
|
||||
$nextLevelRow = \think\Db::name('shopro_commission_level')->where('level', $nextLevel)->find();
|
||||
|
||||
if ($nextLevelRow) {
|
||||
$nextRules = json_decode($nextLevelRow['upgrade_rules'] ?? '[]', true) ?: [];
|
||||
$targetDirectUsers = intval($nextRules['child_user_count_1'] ?? 0);
|
||||
$targetTeamOrders = intval($nextRules['child_order_count_all'] ?? 0);
|
||||
|
||||
$currentDirectUsers = intval($detail->child_user_count_1 ?? $directCount);
|
||||
$currentTeamOrders = intval($detail->child_order_count_all ?? 0);
|
||||
$currentSelfMoney = (float)($detail->child_order_money_0 ?? 0);
|
||||
|
||||
$directUserGap = max(0, $targetDirectUsers - $currentDirectUsers);
|
||||
$teamOrderGap = max(0, $targetTeamOrders - $currentTeamOrders);
|
||||
$isSelfPaid = ($selfOrderCount > 0 || $currentSelfMoney >= 1398);
|
||||
|
||||
$directUserPercent = $targetDirectUsers > 0 ? min(100, (int)round(($currentDirectUsers / $targetDirectUsers) * 100)) : 100;
|
||||
$teamOrderPercent = $targetTeamOrders > 0 ? min(100, (int)round(($currentTeamOrders / $targetTeamOrders) * 100)) : 100;
|
||||
|
||||
$upgradeRadar = [
|
||||
'current_level' => $currentLevel,
|
||||
'current_level_name' => $currentLevelName,
|
||||
'next_level' => $nextLevel,
|
||||
'next_level_name' => $nextLevelRow['name'],
|
||||
'target_direct_users' => $targetDirectUsers,
|
||||
'current_direct_users' => $currentDirectUsers,
|
||||
'direct_user_gap' => $directUserGap,
|
||||
'direct_user_reached' => ($directUserGap === 0),
|
||||
'direct_user_percent' => $directUserPercent,
|
||||
'target_team_orders' => $targetTeamOrders,
|
||||
'current_team_orders' => $currentTeamOrders,
|
||||
'team_order_gap' => $teamOrderGap,
|
||||
'team_order_reached' => ($teamOrderGap === 0),
|
||||
'team_order_percent' => $teamOrderPercent,
|
||||
'self_paid_reached' => $isSelfPaid,
|
||||
'all_reached' => ($directUserGap === 0 && $teamOrderGap === 0 && $isSelfPaid),
|
||||
'upgrade_lock' => intval($detail->upgrade_lock ?? 0)
|
||||
];
|
||||
} else {
|
||||
$upgradeRadar = [
|
||||
'current_level' => $currentLevel,
|
||||
'current_level_name' => $currentLevelName,
|
||||
'next_level' => 0,
|
||||
'next_level_name' => '已达最高职级',
|
||||
'target_direct_users' => 0,
|
||||
'current_direct_users' => intval($detail->child_user_count_1 ?? $directCount),
|
||||
'direct_user_gap' => 0,
|
||||
'direct_user_reached' => true,
|
||||
'direct_user_percent' => 100,
|
||||
'target_team_orders' => 0,
|
||||
'current_team_orders' => intval($detail->child_order_count_all ?? 0),
|
||||
'team_order_gap' => 0,
|
||||
'team_order_reached' => true,
|
||||
'team_order_percent' => 100,
|
||||
'self_paid_reached' => true,
|
||||
'all_reached' => true,
|
||||
'upgrade_lock' => intval($detail->upgrade_lock ?? 0)
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'roles' => [
|
||||
'direct_total' => $directCount,
|
||||
'direct_paid' => $directPaidCount,
|
||||
'direct_unpaid' => max(0, $directCount - $directPaidCount),
|
||||
'direct_maker' => $directMakerCount,
|
||||
'team_total' => $teamDescCount,
|
||||
'team_paid' => $teamPaidCount,
|
||||
'team_unpaid' => max(0, $teamDescCount - $teamPaidCount),
|
||||
'team_conversion_rate' => $conversionRate,
|
||||
'team_maker' => $teamMakerCount,
|
||||
'team_maker_distribution' => $makerDistribution,
|
||||
'team_venue' => $teamVenueCount,
|
||||
'team_county' => $teamCountyCount,
|
||||
],
|
||||
'orders' => [
|
||||
'self_money' => $selfOrderMoney,
|
||||
'self_count' => $selfOrderCount,
|
||||
'direct_money' => $directOrderMoney,
|
||||
'direct_count' => $directOrderCount,
|
||||
'indirect_money' => $indirectOrderMoney,
|
||||
'indirect_count' => $indirectOrderCount,
|
||||
'team_money' => $teamOrderMoney,
|
||||
'team_count' => $teamOrderCount,
|
||||
],
|
||||
'rewards' => [
|
||||
'push3' => number_format($push3Income, 2, '.', ''),
|
||||
'maker_diff' => number_format($makerDiffIncome, 2, '.', ''),
|
||||
'maker_peer' => number_format($makerPeerIncome, 2, '.', ''),
|
||||
'maker_total' => number_format($makerDiffIncome + $makerPeerIncome, 2, '.', ''),
|
||||
'team_split' => number_format($teamSplitIncome, 2, '.', ''),
|
||||
'share_pool' => number_format($sharePoolIncome, 2, '.', ''),
|
||||
],
|
||||
'assets' => [
|
||||
'wallet_money' => $detail->user_money,
|
||||
'total_income' => $detail->total_income,
|
||||
'untransfer_commission' => $detail->user_commission,
|
||||
'dmepa_madow' => number_format((float)($detail->madow ?? 0), 4, '.', ''),
|
||||
'dmepa_value' => $detail->madow_value,
|
||||
'voucher_total' => number_format((float)($detail->voucher_total ?? 0), 2, '.', ''),
|
||||
'voucher_released' => number_format((float)($detail->voucher_released ?? 0), 2, '.', ''),
|
||||
'voucher_available' => number_format(max(0, (float)($detail->voucher_released ?? 0) - (float)($detail->voucher_used ?? 0)), 2, '.', ''),
|
||||
],
|
||||
'upgrade_radar' => $upgradeRadar
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 团队
|
||||
|
||||
在新工单中引用
屏蔽一个用户