UrsProfitLogic.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. <?php
  2. namespace App\Module\UrsPromotion\Logics;
  3. use App\Module\Game\Enums\REWARD_SOURCE_TYPE;
  4. use App\Module\UrsPromotion\Models\UrsUserReferral;
  5. use App\Module\UrsPromotion\Models\UrsUserTalent;
  6. use App\Module\UrsPromotion\Models\UrsProfit;
  7. use App\Module\UrsPromotion\Models\UrsTalentConfig;
  8. use App\Module\UrsPromotion\Models\UrsUserMapping;
  9. use App\Module\UrsPromotion\Models\UrsUserRelationCache;
  10. use App\Module\UrsPromotion\Enums\UrsProfitType;
  11. use App\Module\UrsPromotion\Enums\UrsPromotionRelationLevel;
  12. use App\Module\Game\Services\RewardService;
  13. use App\Module\GameItems\Services\ItemService;
  14. use Illuminate\Support\Facades\DB;
  15. use Illuminate\Support\Facades\Log;
  16. /**
  17. * URS收益分成逻辑类
  18. *
  19. * 处理URS推广系统的收益分成逻辑,支持三代推广关系
  20. */
  21. class UrsProfitLogic
  22. {
  23. /**
  24. * 计算并分发URS推广收益(按人头奖励)
  25. *
  26. * @param int $userId 新注册用户ID
  27. * @param string $sourceType 收益来源类型
  28. * @param int $sourceId 收益来源ID
  29. * @return array 分成记录
  30. */
  31. public function distributePromotionReward(
  32. int $userId,
  33. string $sourceType,
  34. int $sourceId
  35. ): array {
  36. $profits = [];
  37. try {
  38. // 获取用户的推荐关系链(三代)
  39. $referralChain = $this->getUserReferralChain($userId);
  40. if (empty($referralChain)) {
  41. Log::info("用户 {$userId} 无推荐关系,无需分成");
  42. return $profits;
  43. }
  44. // 获取达人等级配置
  45. $talentConfigs = $this->getTalentConfigs();
  46. // 为每一级推荐人发放奖励
  47. foreach ($referralChain as $level => $referrerId) {
  48. $profit = $this->calculatePromotionReward(
  49. $referrerId,
  50. $userId,
  51. $sourceType,
  52. $sourceId,
  53. $level,
  54. $talentConfigs
  55. );
  56. if ($profit) {
  57. $profits[] = $profit;
  58. }
  59. }
  60. Log::info("用户 {$userId} 推广收益分发完成", [
  61. 'source_type' => $sourceType,
  62. 'source_id' => $sourceId,
  63. 'profits_count' => count($profits)
  64. ]);
  65. } catch (\Exception $e) {
  66. Log::error("URS推广收益分发失败", [
  67. 'user_id' => $userId,
  68. 'source_type' => $sourceType,
  69. 'source_id' => $sourceId,
  70. 'error' => $e->getMessage()
  71. ]);
  72. }
  73. return $profits;
  74. }
  75. /**
  76. * 计算并分发URS种植收益(按比例分成)
  77. *
  78. * @param int $userId 产生收益的用户ID
  79. * @param string $sourceType 收益来源类型
  80. * @param int $sourceId 收益来源ID
  81. * @param int $originalAmount 原始收益数量(整数)
  82. * @param int $itemId 收获的物品ID
  83. * @return array 分成记录
  84. */
  85. public function distributePlantingReward(
  86. int $userId,
  87. string $sourceType,
  88. int $sourceId,
  89. int $originalAmount,
  90. int $itemId
  91. ): array {
  92. $profits = [];
  93. try {
  94. // 获取用户的推荐关系链(三代)
  95. $referralChain = $this->getUserReferralChain($userId);
  96. if (empty($referralChain)) {
  97. Log::info("用户 {$userId} 无推荐关系,无需分成");
  98. return $profits;
  99. }
  100. // 获取达人等级配置
  101. $talentConfigs = $this->getTalentConfigs();
  102. // 为每一级推荐人计算分成
  103. foreach ($referralChain as $level => $referrerId) {
  104. $profit = $this->calculatePlantingReward(
  105. $referrerId,
  106. $userId,
  107. $sourceType,
  108. $sourceId,
  109. $level,
  110. $originalAmount, // 传递原始整数数量
  111. $talentConfigs,
  112. $itemId // 传递物品ID
  113. );
  114. if ($profit) {
  115. $profits[] = $profit;
  116. }
  117. }
  118. Log::info("用户 {$userId} 种植收益分成完成", [
  119. 'source_type' => $sourceType,
  120. 'source_id' => $sourceId,
  121. 'original_amount' => $originalAmount,
  122. 'profits_count' => count($profits)
  123. ]);
  124. } catch (\Exception $e) {
  125. Log::error("URS种植收益分成失败", [
  126. 'user_id' => $userId,
  127. 'source_type' => $sourceType,
  128. 'source_id' => $sourceId,
  129. 'error' => $e->getMessage()
  130. ]);
  131. throw $e;
  132. }
  133. return $profits;
  134. }
  135. /**
  136. * 获取用户的推荐关系链(三代)
  137. *
  138. * @param int $userId 用户ID
  139. * @return array [level => user_id] 1:直推 2:间推 3:三推
  140. */
  141. private function getUserReferralChain(int $userId): array
  142. {
  143. // 优先从缓存表查询
  144. $cacheChain = $this->getUserReferralChainFromCache($userId);
  145. if (!empty($cacheChain)) {
  146. return $cacheChain;
  147. }
  148. // 缓存不存在时,使用原有的递归查询方式
  149. return $this->getUserReferralChainFromReferrals($userId);
  150. }
  151. /**
  152. * 从缓存表获取用户的推荐关系链
  153. *
  154. * @param int $userId 用户ID
  155. * @return array [level => user_id]
  156. */
  157. private function getUserReferralChainFromCache(int $userId): array
  158. {
  159. $chain = [];
  160. try {
  161. // 从缓存表查询用户的所有上级关系(最多20代)
  162. $relations = UrsUserRelationCache::where('user_id', $userId)
  163. ->where('depth', '<=', UrsPromotionRelationLevel::getMaxLevel())
  164. ->orderBy('depth')
  165. ->get();
  166. foreach ($relations as $relation) {
  167. $chain[$relation->depth] = $relation->related_user_id;
  168. }
  169. Log::info("从缓存表获取推荐关系链成功", [
  170. 'user_id' => $userId,
  171. 'chain_levels' => count($chain),
  172. 'max_depth' => $relations->max('depth') ?? 0
  173. ]);
  174. return $chain;
  175. } catch (\Exception $e) {
  176. Log::warning("从缓存表获取推荐关系链失败", [
  177. 'user_id' => $userId,
  178. 'error' => $e->getMessage()
  179. ]);
  180. return [];
  181. }
  182. }
  183. /**
  184. * 从推荐关系表递归获取用户的推荐关系链(原有方式)
  185. *
  186. * @param int $userId 用户ID
  187. * @return array [level => user_id]
  188. */
  189. private function getUserReferralChainFromReferrals(int $userId): array
  190. {
  191. $chain = [];
  192. $currentUserId = $userId;
  193. // 最多查找三代
  194. for ($level = 1; $level <= UrsPromotionRelationLevel::getMaxLevel(); $level++) {
  195. $referral = UrsUserReferral::where('user_id', $currentUserId)
  196. ->where('status', UrsUserReferral::STATUS_VALID)
  197. ->first();
  198. if (!$referral) {
  199. break;
  200. }
  201. // 过滤掉农场用户ID为0的推荐人(还没有进入农场)
  202. if ($referral->referrer_id <= 0) {
  203. break;
  204. }
  205. $chain[$level] = $referral->referrer_id;
  206. $currentUserId = $referral->referrer_id;
  207. }
  208. return $chain;
  209. }
  210. /**
  211. * 获取达人等级配置
  212. *
  213. * @return array [level => config]
  214. */
  215. private function getTalentConfigs(): array
  216. {
  217. static $configs = null;
  218. if ($configs === null) {
  219. $configs = UrsTalentConfig::where('status', UrsTalentConfig::STATUS_ENABLED)
  220. ->get()
  221. ->keyBy('level')
  222. ->toArray();
  223. }
  224. return $configs;
  225. }
  226. /**
  227. * 计算推广收益奖励(按人头)
  228. *
  229. * @param int $referrerId 推荐人ID
  230. * @param int $memberId 新注册用户ID
  231. * @param string $sourceType 收益来源类型
  232. * @param int $sourceId 收益来源ID
  233. * @param int $relationLevel 推荐层级
  234. * @param array $talentConfigs 达人等级配置
  235. * @return UrsProfit|null
  236. */
  237. private function calculatePromotionReward(
  238. int $referrerId,
  239. int $memberId,
  240. string $sourceType,
  241. int $sourceId,
  242. int $relationLevel,
  243. array $talentConfigs
  244. ): ?UrsProfit {
  245. // 获取推荐人的达人等级
  246. $talent = UrsUserTalent::where('user_id', $referrerId)->first();
  247. $talentLevel = $talent ? $talent->talent_level : 0;
  248. // 获取对应等级的配置
  249. $config = $talentConfigs[$talentLevel] ?? null;
  250. if (!$config) {
  251. Log::warning("推荐人 {$referrerId} 达人等级 {$talentLevel} 配置不存在");
  252. return null;
  253. }
  254. // 获取奖励组ID
  255. $rewardGroupId = $this->getPromotionRewardGroupId($config, $relationLevel);
  256. if (!$rewardGroupId) {
  257. Log::debug("推荐人 {$referrerId} 等级 {$talentLevel} 层级 {$relationLevel} 无奖励组配置");
  258. return null;
  259. }
  260. // 开启事务(奖励组系统要求在事务中执行)
  261. DB::beginTransaction();
  262. try {
  263. // 使用奖励组系统发放奖励
  264. $rewardResult = RewardService::grantReward(
  265. $referrerId,
  266. $rewardGroupId,
  267. REWARD_SOURCE_TYPE::from($sourceType),
  268. $sourceId
  269. );
  270. if (!$rewardResult->success) {
  271. DB::rollBack();
  272. Log::error("推广奖励发放失败", [
  273. 'referrer_id' => $referrerId,
  274. 'reward_group_id' => $rewardGroupId,
  275. 'error' => $rewardResult->errorMessage
  276. ]);
  277. return null;
  278. }
  279. // 计算奖励总金额(用于记录)
  280. $totalRewardAmount = $this->calculateTotalRewardAmount($rewardResult->items);
  281. // 获取产生收益的URS用户ID
  282. $memberMapping = UrsUserMapping::where('user_id', $memberId)->first();
  283. $memberUrsUserId = $memberMapping ? $memberMapping->urs_user_id : null;
  284. // 获取获得收益的URS用户ID
  285. $referrerMapping = UrsUserMapping::where('user_id', $referrerId)->first();
  286. $referrerUrsUserId = $referrerMapping ? $referrerMapping->urs_user_id : null;
  287. // 创建收益记录
  288. $profit = UrsProfit::create([
  289. 'urs_user_id' => $referrerUrsUserId,
  290. 'urs_promotion_member_id' => $memberUrsUserId,
  291. 'promotion_member_farm_user_id' => $memberId,
  292. 'farm_user_id' => $referrerId,
  293. 'source_id' => $sourceId,
  294. 'source_type' => $sourceType,
  295. 'profit_type' => UrsProfitType::PROMOTION_REWARD->value,
  296. 'relation_level' => $relationLevel,
  297. 'original_amount' => '0', // 推广收益无原始金额概念
  298. 'profit_amount' => $totalRewardAmount,
  299. 'profit_rate' => 0, // 推广收益无比例概念
  300. 'reward_group_id' => $rewardResult->groupId,
  301. 'talent_level' => $talentLevel,
  302. 'status' => UrsProfit::STATUS_NORMAL,
  303. ]);
  304. DB::commit();
  305. } catch (\Exception $e) {
  306. DB::rollBack();
  307. Log::error("推广奖励发放事务失败", [
  308. 'referrer_id' => $referrerId,
  309. 'reward_group_id' => $rewardGroupId,
  310. 'error' => $e->getMessage()
  311. ]);
  312. return null;
  313. }
  314. Log::info("URS推广收益记录创建", [
  315. 'profit_id' => $profit->id,
  316. 'referrer_id' => $referrerId,
  317. 'member_id' => $memberId,
  318. 'relation_level' => $relationLevel,
  319. 'talent_level' => $talentLevel,
  320. 'reward_group_id' => $rewardGroupId,
  321. 'reward_amount' => $totalRewardAmount
  322. ]);
  323. return $profit;
  324. }
  325. /**
  326. * 计算种植收益分成(按比例发放物品)
  327. *
  328. * @param int $referrerId 推荐人ID
  329. * @param int $memberId 团队成员ID
  330. * @param string $sourceType 收益来源类型
  331. * @param int $sourceId 收益来源ID
  332. * @param int $relationLevel 推荐层级
  333. * @param int $originalAmount 原始收益数量(整数)
  334. * @param array $talentConfigs 达人等级配置
  335. * @param int $itemId 收获的物品ID
  336. * @return UrsProfit|null
  337. */
  338. private function calculatePlantingReward(
  339. int $referrerId,
  340. int $memberId,
  341. string $sourceType,
  342. int $sourceId,
  343. int $relationLevel,
  344. int $originalAmount,
  345. array $talentConfigs,
  346. int $itemId
  347. ): ?UrsProfit {
  348. // 获取推荐人的达人等级
  349. $talent = UrsUserTalent::where('user_id', $referrerId)->first();
  350. $talentLevel = $talent ? $talent->talent_level : 0;
  351. // 获取对应等级的配置
  352. $config = $talentConfigs[$talentLevel] ?? null;
  353. if (!$config) {
  354. Log::warning("推荐人 {$referrerId} 达人等级 {$talentLevel} 配置不存在");
  355. return null;
  356. }
  357. // 获取分成比例
  358. $profitRate = $this->getPlantingRewardRate($config, $relationLevel);
  359. if ($profitRate <= 0) {
  360. Log::debug("推荐人 {$referrerId} 等级 {$talentLevel} 层级 {$relationLevel} 分成比例为0");
  361. return null;
  362. }
  363. // 计算应该奖励的物品数量(向下取整)
  364. $rewardQuantity = (int)floor($originalAmount * $profitRate);
  365. if ($rewardQuantity <= 0) {
  366. Log::debug("推荐人 {$referrerId} 计算出的奖励数量为0", [
  367. 'original_amount' => $originalAmount,
  368. 'profit_rate' => $profitRate,
  369. 'calculated_quantity' => $originalAmount * $profitRate
  370. ]);
  371. // 创建收益记录
  372. $profit = UrsProfit::create([
  373. 'urs_user_id' => 0,
  374. 'urs_promotion_member_id' => 0,
  375. 'promotion_member_farm_user_id' => $referrerId,
  376. 'farm_user_id' => $memberId,
  377. 'source_id' => $sourceId,
  378. 'source_type' => $sourceType,
  379. 'profit_type' => UrsProfitType::PLANTING_REWARD->value,
  380. 'relation_level' => $relationLevel,
  381. 'original_amount' => (string)$originalAmount,
  382. 'profit_amount' => (string)$rewardQuantity, // 记录实际发放的物品数量
  383. 'profit_rate' => $profitRate,
  384. 'reward_group_id' => null, // 种植收益不使用奖励组
  385. 'talent_level' => $talentLevel,
  386. 'status' => UrsProfit::STATUS_NORMAL,
  387. ]);
  388. return null;
  389. }
  390. // 开启事务发放物品奖励
  391. try {
  392. // 使用物品模块服务发放物品
  393. $addResult = ItemService::addItem($referrerId, $itemId, $rewardQuantity, [
  394. 'source_type' => $sourceType,
  395. 'source_id' => $sourceId,
  396. 'source' => 'urs_planting_reward',
  397. 'details' => [
  398. 'member_id' => $memberId,
  399. 'relation_level' => $relationLevel,
  400. 'talent_level' => $talentLevel,
  401. 'profit_rate' => $profitRate,
  402. 'original_amount' => $originalAmount
  403. ]
  404. ]);
  405. if (!$addResult['success']) {
  406. Log::error("种植收益物品发放失败", [
  407. 'referrer_id' => $referrerId,
  408. 'item_id' => $itemId,
  409. 'quantity' => $rewardQuantity,
  410. 'error' => $addResult['message'] ?? '未知错误'
  411. ]);
  412. return null;
  413. }
  414. // 获取产生收益的农场用户ID
  415. $memberMapping = UrsUserMapping::where('user_id', $memberId)->first();
  416. $memberurs_user_id = $memberMapping ? $memberMapping->urs_user_id : 0;
  417. // 获取获得收益的农场用户ID
  418. $referrerMapping = UrsUserMapping::where('user_id', $referrerId)->first();
  419. $referrerurs_user_id = $referrerMapping ? $referrerMapping->urs_user_id : 0;
  420. // 创建收益记录
  421. $profit = UrsProfit::create([
  422. 'urs_user_id' => $referrerurs_user_id,
  423. 'urs_promotion_member_id' => $memberurs_user_id,
  424. 'promotion_member_farm_user_id' => $referrerId,
  425. 'farm_user_id' => $memberId,
  426. 'source_id' => $sourceId,
  427. 'source_type' => $sourceType,
  428. 'profit_type' => UrsProfitType::PLANTING_REWARD->value,
  429. 'relation_level' => $relationLevel,
  430. 'original_amount' => (string)$originalAmount,
  431. 'profit_amount' => (string)$rewardQuantity, // 记录实际发放的物品数量
  432. 'profit_rate' => $profitRate,
  433. 'reward_group_id' => null, // 种植收益不使用奖励组
  434. 'talent_level' => $talentLevel,
  435. 'status' => UrsProfit::STATUS_NORMAL,
  436. ]);
  437. } catch (\Exception $e) {
  438. Log::error("种植收益发放事务失败", [
  439. 'referrer_id' => $referrerId,
  440. 'item_id' => $itemId,
  441. 'quantity' => $rewardQuantity,
  442. 'error' => $e->getMessage()
  443. ]);
  444. throw $e;
  445. }
  446. Log::info("URS种植收益记录创建", [
  447. 'profit_id' => $profit->id,
  448. 'referrer_id' => $referrerId,
  449. 'member_id' => $memberId,
  450. 'relation_level' => $relationLevel,
  451. 'talent_level' => $talentLevel,
  452. 'profit_rate' => $profitRate,
  453. 'item_id' => $itemId,
  454. 'reward_quantity' => $rewardQuantity,
  455. 'original_amount' => $originalAmount
  456. ]);
  457. return $profit;
  458. }
  459. /**
  460. * 计算奖励总金额(用于记录)
  461. *
  462. * @param array $rewardItems 奖励项列表
  463. * @return string
  464. */
  465. private function calculateTotalRewardAmount(array $rewardItems): string
  466. {
  467. $totalAmount = '0';
  468. foreach ($rewardItems as $item) {
  469. // 计算货币类型的奖励金额
  470. if (in_array($item->rewardType, ['fund', 'currency', 'fund_config'])) {
  471. $totalAmount = bcadd($totalAmount, (string)$item->quantity, 10);
  472. }
  473. // 计算物品类型的奖励价值(按物品售价计算,如果没有售价则按数量计算)
  474. elseif ($item->rewardType === 'item') {
  475. // 获取物品售价作为价值参考
  476. $itemValue = $this->getItemValue($item->targetId);
  477. $itemTotalValue = bcmul((string)$itemValue, (string)$item->quantity, 10);
  478. $totalAmount = bcadd($totalAmount, $itemTotalValue, 10);
  479. }
  480. // 其他类型奖励按数量计算基础价值
  481. else {
  482. $totalAmount = bcadd($totalAmount, (string)$item->quantity, 10);
  483. }
  484. }
  485. return $totalAmount;
  486. }
  487. /**
  488. * 获取物品价值(用于奖励金额计算)
  489. *
  490. * @param int $itemId 物品ID
  491. * @return string
  492. */
  493. private function getItemValue(int $itemId): string
  494. {
  495. try {
  496. // 查询物品售价
  497. $item = \App\Module\GameItems\Models\Item::find($itemId);
  498. if ($item && $item->sell_price > 0) {
  499. return (string)$item->sell_price;
  500. }
  501. // 如果没有售价,返回默认价值(可以根据物品类型调整)
  502. return '1.0000000000';
  503. } catch (\Exception $e) {
  504. Log::warning("获取物品价值失败", [
  505. 'item_id' => $itemId,
  506. 'error' => $e->getMessage()
  507. ]);
  508. return '1.0000000000';
  509. }
  510. }
  511. /**
  512. * 获取推广收益奖励组ID
  513. *
  514. * @param array $config 达人等级配置
  515. * @param int $relationLevel 推荐层级
  516. * @return int|null
  517. */
  518. private function getPromotionRewardGroupId(array $config, int $relationLevel): ?int
  519. {
  520. // 使用新的独立字段结构
  521. switch ($relationLevel) {
  522. case 1: // 直推
  523. return $config['promotion_direct_group'] ?? null;
  524. case 2: // 间推
  525. return $config['promotion_indirect_group'] ?? null;
  526. case 3: // 三推
  527. return $config['promotion_third_group'] ?? null;
  528. default:
  529. return null;
  530. }
  531. }
  532. /**
  533. * 获取种植收益分成比例
  534. *
  535. * @param array $config 达人等级配置
  536. * @param int $relationLevel 推荐层级
  537. * @return float
  538. */
  539. private function getPlantingRewardRate(array $config, int $relationLevel): float
  540. {
  541. // 使用新的独立字段结构
  542. switch ($relationLevel) {
  543. case 1: // 直推
  544. return (float)($config['planting_direct_rate'] ?? 0);
  545. case 2: // 间推
  546. return (float)($config['planting_indirect_rate'] ?? 0);
  547. case 3: // 三推
  548. return (float)($config['planting_third_rate'] ?? 0);
  549. default:
  550. return 0;
  551. }
  552. }
  553. /**
  554. * 获取用户的收益统计
  555. *
  556. * @param int $userId 用户ID
  557. * @param UrsProfitType|null $profitType 收益类型
  558. * @param string|null $startDate 开始日期
  559. * @param string|null $endDate 结束日期
  560. * @return array
  561. */
  562. public function getUserProfitStats(
  563. int $userId,
  564. ?UrsProfitType $profitType = null,
  565. ?string $startDate = null,
  566. ?string $endDate = null
  567. ): array {
  568. $query = UrsProfit::where('urs_user_id', $userId)
  569. ->where('status', UrsProfit::STATUS_NORMAL);
  570. if ($profitType) {
  571. $query->where('profit_type', $profitType->value);
  572. }
  573. if ($startDate) {
  574. $query->where('created_at', '>=', $startDate);
  575. }
  576. if ($endDate) {
  577. $query->where('created_at', '<=', $endDate);
  578. }
  579. $profits = $query->get();
  580. $stats = [
  581. 'total_amount' => '0',
  582. 'total_count' => 0,
  583. 'by_type' => [],
  584. 'by_level' => [],
  585. ];
  586. foreach ($profits as $profit) {
  587. $stats['total_amount'] = bcadd($stats['total_amount'], $profit->profit_amount, 10);
  588. $stats['total_count']++;
  589. // 按收益类型统计
  590. $type = $profit->profit_type;
  591. if (!isset($stats['by_type'][$type])) {
  592. $stats['by_type'][$type] = ['amount' => '0', 'count' => 0];
  593. }
  594. $stats['by_type'][$type]['amount'] = bcadd($stats['by_type'][$type]['amount'], $profit->profit_amount, 10);
  595. $stats['by_type'][$type]['count']++;
  596. // 按推荐层级统计
  597. $level = $profit->relation_level;
  598. if (!isset($stats['by_level'][$level])) {
  599. $stats['by_level'][$level] = ['amount' => '0', 'count' => 0];
  600. }
  601. $stats['by_level'][$level]['amount'] = bcadd($stats['by_level'][$level]['amount'], $profit->profit_amount, 10);
  602. $stats['by_level'][$level]['count']++;
  603. }
  604. return $stats;
  605. }
  606. }