多級分銷、推薦獎勵、層級提成等業務常需根據用戶業績區間、層級關係動態計算獎勵金額。本文展示一種基於鏈表式規則配置 + 遞歸計算的通用方案,將複雜的分級規則數據化、邏輯標準化,便於後台靈活配置與擴展。
/**
* 遞歸計算提成總額
* @param int $range 當前業績值(如訂單量)
* @param array $standard 當前節點規則數組
* @param array $ruleList 所有規則映射 [id => rule]
* @param float $amount 累計金額(引用傳遞)
* @return float 總提成金額
*/
private function bonusRecursion($range, $standard, &$ruleList, &$amount) {
$unitPrice = 1000; // 單筆基準價格(可配置化)
$min = $standard['start_range'];
$max = $standard['end_range'];
$rate = $standard['bonus_rate'] / 100; // 轉為小數
// 業績未達到當前區間最小值,終止遞歸
if ($range < $min) {
return false;
}
$standardAmount = 0;
$plus = 0; // 非首節點區間長度補正
// 首個標準節點:包含基礎額度獎勵
if ($standard['is_standard'] == 1) {
$standardAmount = $unitPrice * $min * $rate + $standard['bonus_reward'];
} else {
$plus = 1; // 區間長度計算時 +1(含邊界)
}
// 計算當前區間實際覆蓋長度
if ($range > $max) {
$covered = ($max - $min) + $plus;
} else {
$covered = ($range - $min) + $plus;
}
// 當前區間提成 = 覆蓋筆數 × 單價 × 費率 + 固定獎勵
$currentAmount = $unitPrice * $covered * $rate + $standard['bonus_reward'];
$amount += $standardAmount + $currentAmount;
// 遞歸處理下一節點
$nextId = $standard['chain_next'];
if (!empty($ruleList[$nextId]) && $range > $max) {
return $this->bonusRecursion($range, $ruleList[$nextId], $ruleList, $amount);
}
return $amount;
}
特性 實現方式
規則動態配置 後台 CRUD 維護規則表,無需改代碼
區間靈活分級 start_range/end_range 任意劃分,支援無上限(9999)
混合獎勵模式 比率提成 + 固定獎勵 並存
多業務隔離 rid 字段區分不同產品/活動規則體系
鏈表順序可變 調整 chain_prev/chain_next 即可重組邏輯
遞歸深度可控 實際層級通常 < 10,無棧溢出風險
🔧 進階優化建議
- 緩存規則鏈:規則變更低頻,啟動時載入 Redis,計算時直接讀取內存陣列。
- 迭代替代遞歸:用
while ($currentNode) 循環避免函數調用開銷,邏輯更清晰。
- 精度處理:金額計算使用
bcmath 或存儲「分」為整數,避免浮點誤差。
- 審計日誌:記錄每次計算的輸入參數、經過節點、各節點金額、最終結果,便於爭議溯源。
- 並發鎖保護:同一用戶並發結算時,用 Redis 分佈式鎖
SET NX EX 防止重複計算。
📊 迭代版本參考實現