TalentLogic.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <?php
  2. namespace App\Module\Promotion\Logics;
  3. use App\Module\Promotion\Enums\TALENT_LEVEL;
  4. use App\Module\Promotion\Models\PromotionTalentConfig;
  5. use App\Module\Promotion\Models\PromotionUserTalent;
  6. use Illuminate\Support\Facades\DB;
  7. use Illuminate\Support\Facades\Log;
  8. use Illuminate\Support\Facades\Redis;
  9. /**
  10. * 达人等级逻辑类
  11. *
  12. * 处理用户达人等级的核心业务逻辑,包括计算达人等级、更新达人等级、
  13. * 获取达人等级配置等功能。该类仅供内部使用,不对外提供服务。
  14. */
  15. class TalentLogic
  16. {
  17. /**
  18. * @var ReferralLogic
  19. */
  20. protected $referralLogic;
  21. /**
  22. * 构造函数
  23. *
  24. * @param ReferralLogic $referralLogic
  25. */
  26. public function __construct(ReferralLogic $referralLogic)
  27. {
  28. $this->referralLogic = $referralLogic;
  29. }
  30. /**
  31. * 获取用户的达人等级信息
  32. *
  33. * @param int $userId 用户ID
  34. * @return PromotionUserTalent|null
  35. */
  36. public function getUserTalent(int $userId): ?PromotionUserTalent
  37. {
  38. // 尝试从缓存获取
  39. $cacheKey = "promotion:user:{$userId}:talent";
  40. $cachedData = Redis::get($cacheKey);
  41. if ($cachedData !== null) {
  42. $talentData = json_decode($cachedData, true);
  43. $talent = new PromotionUserTalent();
  44. $talent->fill($talentData);
  45. return $talent;
  46. }
  47. // 从数据库获取
  48. $talent = PromotionUserTalent::where('user_id', $userId)->first();
  49. // 如果不存在,创建一个默认的达人等级记录
  50. if (!$talent) {
  51. $talent = $this->createDefaultTalent($userId);
  52. }
  53. // 缓存结果
  54. if ($talent) {
  55. Redis::setex($cacheKey, 86400, json_encode($talent->toArray())); // 缓存1天
  56. }
  57. return $talent;
  58. }
  59. /**
  60. * 创建默认的达人等级记录
  61. *
  62. * @param int $userId 用户ID
  63. * @return PromotionUserTalent|null
  64. */
  65. public function createDefaultTalent(int $userId): ?PromotionUserTalent
  66. {
  67. try {
  68. $talent = new PromotionUserTalent();
  69. $talent->user_id = $userId;
  70. $talent->talent_level = TALENT_LEVEL::NONE;
  71. $talent->direct_count = 0;
  72. $talent->promotion_count = 0;
  73. $talent->save();
  74. return $talent;
  75. } catch (\Exception $e) {
  76. Log::error("创建默认达人等级记录失败: " . $e->getMessage());
  77. return null;
  78. }
  79. }
  80. /**
  81. * 更新用户的达人等级
  82. *
  83. * @param int $userId 用户ID
  84. * @param int $talentLevel 达人等级
  85. * @return bool
  86. */
  87. public function updateTalentLevel(int $userId, int $talentLevel): bool
  88. {
  89. try {
  90. $talent = $this->getUserTalent($userId);
  91. if (!$talent) {
  92. return false;
  93. }
  94. // 如果等级没有变化,无需更新
  95. if ($talent->talent_level == $talentLevel) {
  96. return true;
  97. }
  98. $talent->talent_level = $talentLevel;
  99. $result = $talent->save();
  100. if ($result) {
  101. // 清除缓存
  102. Redis::del("promotion:user:{$userId}:talent");
  103. }
  104. return $result;
  105. } catch (\Exception $e) {
  106. Log::error("更新达人等级失败: " . $e->getMessage());
  107. return false;
  108. }
  109. }
  110. /**
  111. * 更新用户的团队统计数据
  112. *
  113. * @param int $userId 用户ID
  114. * @return bool
  115. */
  116. public function updatePromotionCounts(int $userId): bool
  117. {
  118. try {
  119. $talent = $this->getUserTalent($userId);
  120. if (!$talent) {
  121. return false;
  122. }
  123. // 计算直推人数
  124. $directCount = $this->referralLogic->countDirectReferrals($userId);
  125. // 计算团队总人数
  126. $promotionCount = $this->referralLogic->countPromotionMembers($userId);
  127. // 更新数据
  128. $talent->direct_count = $directCount;
  129. $talent->promotion_count = $promotionCount;
  130. $result = $talent->save();
  131. if ($result) {
  132. // 清除缓存
  133. Redis::del("promotion:user:{$userId}:talent");
  134. }
  135. return $result;
  136. } catch (\Exception $e) {
  137. Log::error("更新团队统计数据失败: " . $e->getMessage());
  138. return false;
  139. }
  140. }
  141. /**
  142. * 检查并更新用户的达人等级
  143. *
  144. * @param int $userId 用户ID
  145. * @return bool
  146. */
  147. public function checkAndUpdateTalentLevel(int $userId): bool
  148. {
  149. try {
  150. // 更新团队统计数据
  151. $this->updatePromotionCounts($userId);
  152. // 获取用户的达人信息
  153. $talent = $this->getUserTalent($userId);
  154. if (!$talent) {
  155. return false;
  156. }
  157. // 获取所有达人等级配置
  158. $configs = $this->getAllTalentConfigs();
  159. // 计算应该的达人等级
  160. $newLevel = TALENT_LEVEL::NONE;
  161. foreach ($configs as $config) {
  162. if ($talent->direct_count >= $config->direct_count_required &&
  163. $talent->promotion_count >= $config->promotion_count_required) {
  164. $newLevel = $config->level;
  165. }
  166. }
  167. // 如果等级有变化,更新达人等级
  168. if ($talent->talent_level != $newLevel) {
  169. return $this->updateTalentLevel($userId, $newLevel);
  170. }
  171. return true;
  172. } catch (\Exception $e) {
  173. Log::error("检查并更新达人等级失败: " . $e->getMessage());
  174. return false;
  175. }
  176. }
  177. /**
  178. * 获取达人等级配置
  179. *
  180. * @param int $level 等级
  181. * @return PromotionTalentConfig|null
  182. */
  183. public function getTalentConfig(int $level): ?PromotionTalentConfig
  184. {
  185. // 尝试从缓存获取
  186. $cacheKey = "promotion:talent_config:{$level}";
  187. $cachedData = Redis::get($cacheKey);
  188. if ($cachedData !== null) {
  189. $configData = json_decode($cachedData, true);
  190. $config = new PromotionTalentConfig();
  191. $config->fill($configData);
  192. return $config;
  193. }
  194. // 从数据库获取
  195. $config = PromotionTalentConfig::where('level', $level)->first();
  196. // 缓存结果
  197. if ($config) {
  198. Redis::setex($cacheKey, 86400 * 7, json_encode($config->toArray())); // 缓存7天
  199. }
  200. return $config;
  201. }
  202. /**
  203. * 获取所有达人等级配置
  204. *
  205. * @return array
  206. */
  207. public function getAllTalentConfigs(): array
  208. {
  209. // 尝试从缓存获取
  210. $cacheKey = "promotion:talent_configs";
  211. $cachedData = Redis::get($cacheKey);
  212. if ($cachedData !== null) {
  213. $configsData = json_decode($cachedData, true);
  214. $configs = [];
  215. foreach ($configsData as $configData) {
  216. $config = new PromotionTalentConfig();
  217. $config->fill($configData);
  218. $configs[] = $config;
  219. }
  220. return $configs;
  221. }
  222. // 从数据库获取
  223. $configs = PromotionTalentConfig::orderBy('level')->get()->toArray();
  224. // 缓存结果
  225. Redis::setex($cacheKey, 86400 * 7, json_encode($configs)); // 缓存7天
  226. return $configs;
  227. }
  228. /**
  229. * 获取达人等级分成比例
  230. *
  231. * @param int $level 等级
  232. * @return float
  233. */
  234. public function getTalentProfitRate(int $level): float
  235. {
  236. $config = $this->getTalentConfig($level);
  237. if (!$config) {
  238. return 0.0;
  239. }
  240. return $config->profit_rate;
  241. }
  242. /**
  243. * 获取达人等级权益
  244. *
  245. * @param int $level 等级
  246. * @return array
  247. */
  248. public function getTalentBenefits(int $level): array
  249. {
  250. $config = $this->getTalentConfig($level);
  251. if (!$config || empty($config->benefits)) {
  252. return [];
  253. }
  254. return is_array($config->benefits) ? $config->benefits : json_decode($config->benefits, true);
  255. }
  256. /**
  257. * 批量更新用户的达人等级
  258. *
  259. * @param array $userIds 用户ID数组
  260. * @return int 成功更新的数量
  261. */
  262. public function batchUpdateTalentLevels(array $userIds): int
  263. {
  264. $successCount = 0;
  265. foreach ($userIds as $userId) {
  266. if ($this->checkAndUpdateTalentLevel($userId)) {
  267. $successCount++;
  268. }
  269. }
  270. return $successCount;
  271. }
  272. }