1.优化充值跳转链接的问题

2.优化后台渠道管理页面的显示样式
This commit is contained in:
2026-05-30 14:37:46 +08:00
parent 15b9313c07
commit 1cdd597879
19 changed files with 1096 additions and 180 deletions

View File

@@ -152,11 +152,154 @@ class AdminCommissionDistributionService
}
/**
* 将渠道本期总佣金按管理员树分配,返回各管理员实得金额
*
* @return array<int, array{admin_id:int,commission_amount:string,commission_rate:string,calc_base_amount:string}>
* 代理费前佣金占渠道本期总佣金的比例(%
*/
public static function distributeChannelCommission(int $channelId, string $totalCommission, string $calcBaseAmount): array
public static function calcCommissionSharePercent(string $gross, string $totalCommission): string
{
if (bccomp($totalCommission, '0', 2) <= 0 || bccomp($gross, '0', 2) <= 0) {
return '0.00';
}
return bcdiv(bcmul($gross, '100', 4), $totalCommission, 2);
}
/**
* 按百分比计算手续费金额:手续费 = 费前佣金 × (费率% / 100)
*/
public static function calcHandlingFeeAmount(string $gross, string $ratePercent): string
{
$rate = bcadd($ratePercent, '0', 2);
if (bccomp($gross, '0', 2) <= 0 || bccomp($rate, '0', 2) <= 0) {
return '0.00';
}
if (bccomp($rate, '100', 2) > 0) {
$rate = '100.00';
}
return bcmul($gross, bcdiv($rate, '100', 4), 2);
}
/**
* 将渠道本期总佣金按管理员树分配,返回各管理员实得金额(费前)
*
* @param array<int, string>|null $handlingFeeRateByAdmin admin_id => 手续费比例(%)
* @return array<int, array{admin_id:int,commission_amount:string,commission_rate:string,calc_base_amount:string,handling_fee_rate:string,handling_fee:string,net_commission_amount:string}>
*/
public static function distributeChannelCommission(
int $channelId,
string $totalCommission,
string $calcBaseAmount,
string $defaultHandlingFeeRate = '0.00',
?array $handlingFeeRateByAdmin = null
): array {
$nodes = self::collectHierarchicalNodes($channelId, $totalCommission);
if ($nodes === []) {
return [];
}
$defaultRate = self::normalizeHandlingFeeRatePercent($defaultHandlingFeeRate);
$merged = [];
foreach ($nodes as $node) {
$adminId = intval($node['admin_id'] ?? 0);
if ($adminId <= 0) {
continue;
}
$gross = strval($node['commission_amount'] ?? '0.00');
if (bccomp($gross, '0', 2) <= 0) {
continue;
}
$settlementBase = strval($node['settlement_base_amount'] ?? '0.00');
$feeRate = $defaultRate;
if ($handlingFeeRateByAdmin !== null && isset($handlingFeeRateByAdmin[$adminId])) {
$feeRate = self::normalizeHandlingFeeRatePercent(strval($handlingFeeRateByAdmin[$adminId]));
}
$feeAmount = self::calcHandlingFeeAmount($gross, $feeRate);
$net = bcsub($gross, $feeAmount, 2);
if (bccomp($net, '0', 2) < 0) {
$net = '0.00';
}
$effectiveRate = bccomp($settlementBase, '0', 2) <= 0
? '0.0000'
: bcdiv($gross, $settlementBase, 6);
$merged[$adminId] = [
'admin_id' => $adminId,
'commission_amount' => $gross,
'commission_rate' => $effectiveRate,
'calc_base_amount' => $settlementBase,
'commission_share_percent' => self::calcCommissionSharePercent($gross, $totalCommission),
'handling_fee_rate' => $feeRate,
'handling_fee' => $feeAmount,
'net_commission_amount' => $net,
];
}
return array_values($merged);
}
/**
* 层级分配预览(先序遍历),含结算基数与手续费
*
* @param array<int, string>|null $handlingFeeRateByAdmin admin_id => 手续费比例(%)
* @return array<int, array<string, mixed>>
*/
public static function buildSplitPreview(
int $channelId,
string $commissionTotal,
string $calcBaseAmount,
string $defaultHandlingFeeRate = '0.00',
?array $handlingFeeRateByAdmin = null
): array {
unset($calcBaseAmount);
$nodes = self::collectHierarchicalNodes($channelId, $commissionTotal);
if ($nodes === []) {
return [];
}
$defaultRate = self::normalizeHandlingFeeRatePercent($defaultHandlingFeeRate);
$out = [];
foreach ($nodes as $node) {
$adminId = intval($node['admin_id'] ?? 0);
if ($adminId <= 0) {
continue;
}
$gross = strval($node['commission_amount'] ?? '0.00');
$feeRate = $defaultRate;
if ($handlingFeeRateByAdmin !== null && isset($handlingFeeRateByAdmin[$adminId])) {
$feeRate = self::normalizeHandlingFeeRatePercent(strval($handlingFeeRateByAdmin[$adminId]));
}
$feeAmount = self::calcHandlingFeeAmount($gross, $feeRate);
$net = bcsub($gross, $feeAmount, 2);
if (bccomp($net, '0', 2) < 0) {
$net = '0.00';
}
$out[] = [
'admin_id' => $adminId,
'admin_username' => strval($node['admin_username'] ?? ('#' . $adminId)),
'parent_admin_id' => intval($node['parent_admin_id'] ?? 0),
'level' => intval($node['level'] ?? 0),
'settlement_base_amount' => strval($node['settlement_base_amount'] ?? '0.00'),
'share_rate' => strval($node['share_rate'] ?? '0.00'),
'commission_amount' => $gross,
'commission_share_percent' => self::calcCommissionSharePercent($gross, $commissionTotal),
'handling_fee_rate' => $feeRate,
'handling_fee' => $feeAmount,
'net_commission_amount' => $net,
];
}
return $out;
}
private static function normalizeHandlingFeeRatePercent(string $rateRaw): string
{
$rate = bcadd($rateRaw, '0', 2);
if (bccomp($rate, '0', 2) < 0) {
return '0.00';
}
if (bccomp($rate, '100', 2) > 0) {
return '100.00';
}
return $rate;
}
/**
* @return array<int, array{admin_id:int,admin_username:string,parent_admin_id:int,level:int,settlement_base_amount:string,share_rate:string,commission_amount:string}>
*/
private static function collectHierarchicalNodes(int $channelId, string $totalCommission): array
{
if ($channelId <= 0 || bccomp($totalCommission, '0', 2) <= 0) {
return [];
@@ -166,7 +309,7 @@ class AdminCommissionDistributionService
->where('status', 'enable')
->whereRaw('(parent_admin_id IS NULL OR parent_admin_id = 0)')
->order('id', 'asc')
->field(['id', 'commission_share_rate'])
->field(['id', 'commission_share_rate', 'username'])
->select()
->toArray();
if ($rootRows === []) {
@@ -180,7 +323,7 @@ class AdminCommissionDistributionService
break;
}
}
$merged = [];
$nodes = [];
if ($useRateSplit) {
foreach ($rootRows as $rootRow) {
$rootId = intval($rootRow['id'] ?? 0);
@@ -192,13 +335,7 @@ class AdminCommissionDistributionService
if (bccomp($rootAmount, '0', 2) <= 0) {
continue;
}
$parts = self::distributeFromAdmin($rootId, $rootAmount, $calcBaseAmount);
foreach ($parts as $adminId => $amount) {
if (!isset($merged[$adminId])) {
$merged[$adminId] = '0.00';
}
$merged[$adminId] = bcadd($merged[$adminId], $amount, 2);
}
self::appendNodeTree($rootId, $rootAmount, 0, 0, $rate, $nodes);
}
} else {
$rootCount = count($rootRows);
@@ -214,31 +351,74 @@ class AdminCommissionDistributionService
if (!$isLast) {
$assigned = bcadd($assigned, $rootAmount, 2);
}
$parts = self::distributeFromAdmin($rootId, $rootAmount, $calcBaseAmount);
foreach ($parts as $adminId => $amount) {
if (!isset($merged[$adminId])) {
$merged[$adminId] = '0.00';
}
$merged[$adminId] = bcadd($merged[$adminId], $amount, 2);
if (bccomp($rootAmount, '0', 2) <= 0) {
continue;
}
self::appendNodeTree($rootId, $rootAmount, 0, 0, '100.00', $nodes);
}
}
$out = [];
foreach ($merged as $adminId => $amount) {
if (bccomp($amount, '0', 2) <= 0) {
return $nodes;
}
/**
* @param array<int, array{admin_id:int,admin_username:string,parent_admin_id:int,level:int,settlement_base_amount:string,share_rate:string,commission_amount:string}> $nodes
*/
private static function appendNodeTree(
int $adminId,
string $incomingAmount,
int $level,
int $parentAdminId,
string $shareRateFromParent,
array &$nodes
): void {
if ($adminId <= 0 || bccomp($incomingAmount, '0', 2) <= 0) {
return;
}
$adminRow = Db::name('admin')
->where('id', $adminId)
->field(['id', 'username', 'commission_share_rate'])
->find();
if (!is_array($adminRow)) {
return;
}
$children = Db::name('admin')
->where('parent_admin_id', $adminId)
->where('status', 'enable')
->order('id', 'asc')
->field(['id', 'commission_share_rate'])
->select()
->toArray();
$givenToChildren = '0.00';
$childPlans = [];
foreach ($children as $child) {
$childId = intval($child['id'] ?? 0);
if ($childId <= 0) {
continue;
}
$effectiveRate = bccomp($calcBaseAmount, '0', 2) <= 0
? '0.0000'
: bcdiv($amount, $calcBaseAmount, 6);
$out[] = [
'admin_id' => intval($adminId),
'commission_amount' => $amount,
'commission_rate' => $effectiveRate,
'calc_base_amount' => $calcBaseAmount,
];
$rate = bcadd(strval($child['commission_share_rate'] ?? '0'), '0', 2);
if (bccomp($rate, '0', 2) <= 0) {
continue;
}
$childAmount = bcmul($incomingAmount, bcdiv($rate, '100', 4), 2);
if (bccomp($childAmount, '0', 2) <= 0) {
continue;
}
$givenToChildren = bcadd($givenToChildren, $childAmount, 2);
$childPlans[] = ['id' => $childId, 'amount' => $childAmount, 'rate' => $rate];
}
$selfKeep = bcsub($incomingAmount, $givenToChildren, 2);
$nodes[] = [
'admin_id' => $adminId,
'admin_username' => strval($adminRow['username'] ?? ('#' . $adminId)),
'parent_admin_id' => $parentAdminId,
'level' => $level,
'settlement_base_amount' => $incomingAmount,
'share_rate' => $shareRateFromParent,
'commission_amount' => bccomp($selfKeep, '0', 2) > 0 ? $selfKeep : '0.00',
];
foreach ($childPlans as $plan) {
self::appendNodeTree(intval($plan['id']), strval($plan['amount']), $level + 1, $adminId, strval($plan['rate']), $nodes);
}
return $out;
}
/**
@@ -246,6 +426,7 @@ class AdminCommissionDistributionService
*/
private static function distributeFromAdmin(int $adminId, string $amount, string $calcBaseAmount): array
{
unset($calcBaseAmount);
if ($adminId <= 0 || bccomp($amount, '0', 2) <= 0) {
return [];
}
@@ -272,7 +453,7 @@ class AdminCommissionDistributionService
continue;
}
$givenToChildren = bcadd($givenToChildren, $childAmount, 2);
$childParts = self::distributeFromAdmin($childId, $childAmount, $calcBaseAmount);
$childParts = self::distributeFromAdmin($childId, $childAmount, '0.00');
foreach ($childParts as $aid => $part) {
if (!isset($result[$aid])) {
$result[$aid] = '0.00';
@@ -289,32 +470,4 @@ class AdminCommissionDistributionService
}
return $result;
}
/**
* @return array<int, array{admin_id:int,admin_username:string,share_rate:string,commission_amount:string}>
*/
public static function buildSplitPreview(int $channelId, string $commissionTotal, string $calcBaseAmount): array
{
$rows = self::distributeChannelCommission($channelId, $commissionTotal, $calcBaseAmount);
if ($rows === []) {
return [];
}
$adminIds = array_map(static fn(array $r): int => intval($r['admin_id']), $rows);
$adminNames = Db::name('admin')->where('id', 'in', $adminIds)->column('username', 'id');
$parentMap = Db::name('admin')->where('id', 'in', $adminIds)->column('parent_admin_id', 'id');
$shareRates = Db::name('admin')->where('id', 'in', $adminIds)->column('commission_share_rate', 'id');
$out = [];
foreach ($rows as $row) {
$aid = intval($row['admin_id']);
$parentId = intval($parentMap[$aid] ?? 0);
$shareRate = $parentId > 0 ? bcadd(strval($shareRates[$aid] ?? '0'), '0', 2) : '100.00';
$out[] = [
'admin_id' => $aid,
'admin_username' => strval($adminNames[$aid] ?? ('#' . $aid)),
'share_rate' => $shareRate,
'commission_amount' => strval($row['commission_amount']),
];
}
return $out;
}
}