UrsTalentService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. namespace App\Module\UrsPromotion\Services;
  3. use App\Module\UrsPromotion\Dtos\UrsUserTalentDto;
  4. use App\Module\UrsPromotion\Models\UrsUserTalent;
  5. use App\Module\UrsPromotion\Models\UrsTalentConfig;
  6. use Illuminate\Support\Facades\DB;
  7. use Illuminate\Support\Facades\Log;
  8. /**
  9. * URS达人等级服务
  10. *
  11. * 管理URS用户的达人等级和权益(重构版本,支持分离映射关系)
  12. */
  13. class UrsTalentService
  14. {
  15. /**
  16. * 计算并更新用户的达人等级
  17. *
  18. * @param int $ursUserId URS用户ID
  19. * @return UrsUserTalentDto
  20. */
  21. public static function updateTalentLevel(int $userId): UrsUserTalentDto
  22. {
  23. try {
  24. DB::beginTransaction();
  25. $ursUserId= UrsUserMappingService::getMappingUrsUserId($userId);
  26. // 获取用户的团队统计
  27. $stats = UrsReferralService::getTeamMNumber($ursUserId);
  28. // 获取活跃直推成员统计(优化性能,只获取直推活跃数据)
  29. $activeDirectStats = UrsActiveUserService::getActiveDirectMembers($ursUserId);
  30. // 为了显示完整信息,也获取活跃团队总数
  31. $activeTeamStats = UrsActiveUserService::getActiveTeamMembers($ursUserId);
  32. // 计算应该的达人等级
  33. $newLevel = self::calculateTalentLevel(
  34. $stats[1],
  35. $stats['total'],
  36. $activeDirectStats['active_direct_count'],
  37. 0 // 团队活跃数暂时不需要,传0
  38. );
  39. // 获取或创建达人记录
  40. $talent = UrsUserTalent::firstOrCreate(
  41. ['user_id' => $userId],
  42. [
  43. 'talent_level' => 0,
  44. 'direct_count' => 0,
  45. 'indirect_count' => 0,
  46. 'third_count' => 0,
  47. 'promotion_count' => 0,
  48. ]
  49. );
  50. $oldLevel = $talent->talent_level;
  51. // 更新团队统计数据(使用模型方法确保逻辑一致性)
  52. $talent->updateTeamStats(
  53. $stats[1],
  54. $stats[2],
  55. $stats[3],
  56. $stats['total'] // 20代总人数
  57. );
  58. // 更新达人等级
  59. if ($newLevel > $oldLevel) {
  60. $talent->upgradeTalentLevel($newLevel);
  61. }
  62. $talent->save();
  63. DB::commit();
  64. if ($oldLevel !== $newLevel) {
  65. Log::info('URS达人等级更新', [
  66. 'user_id' => $ursUserId,
  67. 'old_level' => $oldLevel,
  68. 'new_level' => $newLevel,
  69. 'direct_count' => $stats[1],
  70. 'total_team_count' => $stats['total'],
  71. ]);
  72. }
  73. // 获取配置信息用于创建DTO
  74. $config = UrsTalentConfig::where('level', $talent->talent_level)->first();
  75. $nextConfig = UrsTalentConfig::where('level', $talent->talent_level + 1)->first();
  76. $currentConfig = $config ? [
  77. 'name' => $config->name,
  78. 'description' => $config->description,
  79. 'icon' => $config->icon,
  80. ] : null;
  81. $nextConfigArray = $nextConfig ? [
  82. 'level' => $nextConfig->level,
  83. 'name' => $nextConfig->name,
  84. 'direct_count_required' => $nextConfig->direct_count_required,
  85. 'promotion_count_required' => $nextConfig->promotion_count_required,
  86. 'active_direct_required' => $nextConfig->active_direct_required,
  87. 'active_count_required' => $nextConfig->active_count_required,
  88. ] : null;
  89. return UrsUserTalentDto::fromModel(
  90. $talent,
  91. $currentConfig,
  92. $nextConfigArray,
  93. $activeDirectStats['active_direct_count'],
  94. $activeTeamStats['active_total_count']
  95. );
  96. } catch (\Exception $e) {
  97. DB::rollBack();
  98. Log::error('URS达人等级更新失败', [
  99. 'user_id' => $ursUserId,
  100. 'error' => $e->getMessage()
  101. ]);
  102. throw $e;
  103. }
  104. }
  105. /**
  106. * 根据团队数据计算达人等级
  107. *
  108. * @param int $directCount 直推人数
  109. * @param int $totalCount 团队总人数
  110. * @param int $activeDirectCount 活跃直推人数
  111. * @param int $activeTotalCount 活跃团队总人数
  112. * @return int 达人等级
  113. */
  114. private static function calculateTalentLevel(int $directCount, int $totalCount, int $activeDirectCount = 0, int $activeTotalCount = 0): int
  115. {
  116. // 获取等级配置(按等级倒序排列)
  117. $configs = UrsTalentConfig::where('status', 1)
  118. ->orderBy('level', 'desc')
  119. ->get();
  120. foreach ($configs as $config) {
  121. // 检查基础条件
  122. $directCountMet = $directCount >= $config->direct_count_required;
  123. $totalCountMet = $totalCount >= $config->promotion_count_required;
  124. // 检查活跃用户条件
  125. $activeDirectMet = $activeDirectCount >= $config->active_direct_required;
  126. $activeTotalMet = $activeTotalCount >= $config->active_count_required;
  127. if ($directCountMet && $totalCountMet && $activeDirectMet && $activeTotalMet) {
  128. return $config->level;
  129. }
  130. }
  131. return 0; // 默认等级
  132. }
  133. /**
  134. * 获取用户的达人信息
  135. *
  136. * @param int $userId 用户ID
  137. * @return UrsUserTalentDto|null
  138. */
  139. public static function getTalentInfo(int $userId): ?UrsUserTalentDto
  140. {
  141. $talent = UrsUserTalent::where('user_id', $userId)->first();
  142. if (!$talent) {
  143. return null;
  144. }
  145. $config = UrsTalentConfig::where('level', $talent->talent_level)->first();
  146. $nextConfig = UrsTalentConfig::where('level', $talent->talent_level + 1)->first();
  147. $currentConfig = $config ? [
  148. 'name' => $config->name,
  149. 'description' => $config->description,
  150. 'icon' => $config->icon,
  151. ] : null;
  152. $nextConfigArray = $nextConfig ? [
  153. 'level' => $nextConfig->level,
  154. 'name' => $nextConfig->name,
  155. 'direct_count_required' => $nextConfig->direct_count_required,
  156. 'promotion_count_required' => $nextConfig->promotion_count_required,
  157. ] : null;
  158. return UrsUserTalentDto::fromModel($talent, $currentConfig, $nextConfigArray);
  159. }
  160. /**
  161. * 批量更新达人等级
  162. *
  163. * @param array $ursUserIds URS用户ID数组
  164. * @return array 更新结果
  165. */
  166. public static function batchUpdateTalentLevels(array $userIds): array
  167. {
  168. $results = [];
  169. foreach ($userIds as $userId) {
  170. try {
  171. $talent = self::updateTalentLevel($userId);
  172. $results[$userId] = [
  173. 'success' => true,
  174. 'talent_level' => $talent->talentLevel,
  175. 'direct_count' => $talent->directCount,
  176. 'promotion_count' => $talent->promotionCount,
  177. ];
  178. } catch (\Exception $e) {
  179. $results[$userId] = [
  180. 'success' => false,
  181. 'error' => $e->getMessage(),
  182. ];
  183. }
  184. }
  185. return $results;
  186. }
  187. /**
  188. * 获取所有达人等级配置
  189. *
  190. * @return array
  191. */
  192. public static function getAllTalentConfigs(): array
  193. {
  194. return UrsTalentConfig::where('status', 1)
  195. ->orderBy('level')
  196. ->get()
  197. ->map(function ($config) {
  198. return [
  199. 'level' => $config->level,
  200. 'name' => $config->name,
  201. 'description' => $config->description,
  202. 'icon' => $config->icon,
  203. 'direct_count_required' => $config->direct_count_required,
  204. 'promotion_count_required' => $config->promotion_count_required,
  205. 'promotion_reward_rates' => $config->promotion_reward_rates,
  206. 'planting_reward_rates' => $config->planting_reward_rates,
  207. ];
  208. })
  209. ->toArray();
  210. }
  211. /**
  212. * 检查用户是否满足升级条件
  213. *
  214. * @param int $ursUserId URS用户ID
  215. * @return array
  216. */
  217. public static function checkUpgradeEligibility(int $userId): array
  218. {
  219. $talent = UrsUserTalent::where('user_id', $userId)->first();
  220. if (!$talent) {
  221. return ['eligible' => false, 'reason' => '用户达人信息不存在'];
  222. }
  223. $nextLevel = $talent->talent_level + 1;
  224. $nextConfig = UrsTalentConfig::where('level', $nextLevel)->first();
  225. if (!$nextConfig) {
  226. return ['eligible' => false, 'reason' => '已达到最高等级'];
  227. }
  228. $ursUserId = UrsUserMappingService::getUrsUserId($userId);
  229. // 获取活跃团队成员统计
  230. $activeStats = UrsActiveUserService::getActiveTeamMembers($ursUserId);
  231. // 检查各项条件
  232. $directCountMet = $talent->direct_count >= $nextConfig->direct_count_required;
  233. $promotionCountMet = $talent->promotion_count >= $nextConfig->promotion_count_required;
  234. $activeDirectMet = $activeStats['active_direct_count'] >= $nextConfig->active_direct_required;
  235. $activeTotalMet = $activeStats['active_total_count'] >= $nextConfig->active_count_required;
  236. return [
  237. 'eligible' => $directCountMet && $promotionCountMet && $activeDirectMet && $activeTotalMet,
  238. 'next_level' => $nextLevel,
  239. 'next_level_name' => $nextConfig->name,
  240. 'requirements' => [
  241. 'direct_count' => [
  242. 'required' => $nextConfig->direct_count_required,
  243. 'current' => $talent->direct_count,
  244. 'met' => $directCountMet,
  245. 'gap' => max(0, $nextConfig->direct_count_required - $talent->direct_count),
  246. ],
  247. 'promotion_count' => [
  248. 'required' => $nextConfig->promotion_count_required,
  249. 'current' => $talent->promotion_count,
  250. 'met' => $promotionCountMet,
  251. 'gap' => max(0, $nextConfig->promotion_count_required - $talent->promotion_count),
  252. ],
  253. 'active_direct_count' => [
  254. 'required' => $nextConfig->active_direct_required,
  255. 'current' => $activeStats['active_direct_count'],
  256. 'met' => $activeDirectMet,
  257. 'gap' => max(0, $nextConfig->active_direct_required - $activeStats['active_direct_count']),
  258. ],
  259. 'active_total_count' => [
  260. 'required' => $nextConfig->active_count_required,
  261. 'current' => $activeStats['active_total_count'],
  262. 'met' => $activeTotalMet,
  263. 'gap' => max(0, $nextConfig->active_count_required - $activeStats['active_total_count']),
  264. ],
  265. ],
  266. ];
  267. }
  268. }