UrsUpdateTalentLevelCommand.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. <?php
  2. namespace App\Module\UrsPromotion\Commands;
  3. use App\Module\UrsPromotion\Services\UrsTalentService;
  4. use App\Module\UrsPromotion\Services\UrsUserMappingService;
  5. use App\Module\UrsPromotion\Models\UrsUserMapping;
  6. use Illuminate\Console\Command;
  7. use Illuminate\Support\Facades\Log;
  8. /**
  9. * URS用户达人等级更新命令
  10. *
  11. * 用于更新指定用户或批量更新用户的达人等级
  12. * 支持单个用户更新和批量更新功能
  13. * php artisan urs:update-talent-level 39296
  14. *
  15. */
  16. class UrsUpdateTalentLevelCommand extends Command
  17. {
  18. /**
  19. * 命令签名
  20. */
  21. protected $signature = 'urs:update-talent-level
  22. {user_id? : 农场用户ID,不指定则更新所有用户}
  23. {--batch-size=100 : 批处理大小}
  24. {--force : 强制重新计算等级}
  25. {--dry-run : 仅模拟运行,不实际执行更新}';
  26. /**
  27. * 命令描述
  28. */
  29. protected $description = 'URS用户达人等级更新命令 - 计算并更新用户的达人等级';
  30. /**
  31. * 执行命令
  32. */
  33. public function handle()
  34. {
  35. $userId = $this->argument('user_id');
  36. $batchSize = (int) $this->option('batch-size');
  37. $force = $this->option('force');
  38. $dryRun = $this->option('dry-run');
  39. $this->info('=== URS用户达人等级更新命令 ===');
  40. if ($dryRun) {
  41. $this->warn('模拟运行模式 - 不会实际执行更新操作');
  42. }
  43. try {
  44. if ($userId) {
  45. // 更新指定用户
  46. return $this->updateSingleUser((int) $userId, $force, $dryRun);
  47. } else {
  48. // 批量更新所有用户
  49. return $this->updateAllUsers($batchSize, $force, $dryRun);
  50. }
  51. } catch (\Exception $e) {
  52. $this->error('命令执行失败: ' . $e->getMessage());
  53. Log::error('URS达人等级更新命令执行失败', [
  54. 'user_id' => $userId,
  55. 'batch_size' => $batchSize,
  56. 'force' => $force,
  57. 'dry_run' => $dryRun,
  58. 'error' => $e->getMessage(),
  59. 'trace' => $e->getTraceAsString()
  60. ]);
  61. return 1;
  62. }
  63. }
  64. /**
  65. * 更新指定用户的达人等级
  66. *
  67. * @param int $userId 农场用户ID
  68. * @param bool $force 是否强制重新计算
  69. * @param bool $dryRun 是否仅模拟运行
  70. * @return int 命令退出码
  71. */
  72. private function updateSingleUser(int $userId, bool $force, bool $dryRun): int
  73. {
  74. $this->info("开始更新用户 {$userId} 的达人等级...");
  75. // 检查用户是否有URS映射关系
  76. $ursUserId = UrsUserMappingService::getMappingUrsUserId($userId);
  77. if ($ursUserId === 0) {
  78. $this->error("用户 {$userId} 没有URS映射关系,无法更新达人等级");
  79. return 1;
  80. }
  81. $this->info("找到URS用户ID: {$ursUserId}");
  82. if ($dryRun) {
  83. $this->info("模拟运行:将调用 UrsTalentService::updateTalentLevel({$userId})");
  84. return 0;
  85. }
  86. try {
  87. // 调用达人等级更新服务
  88. $talentDto = UrsTalentService::updateTalentLevel($userId);
  89. if ($talentDto) {
  90. $this->info("✓ 成功更新用户 {$userId} 的达人等级");
  91. // 基础信息表格
  92. $this->table(['属性', '值'], [
  93. ['URS用户ID', $talentDto->ursUserId],
  94. ['达人等级', $talentDto->talentLevel],
  95. ['等级名称', $talentDto->talentName],
  96. ['最后更新时间', $talentDto->lastLevelUpdateTime ?? '未更新']
  97. ]);
  98. // 团队统计表格
  99. $this->line('');
  100. $this->info('📊 团队统计数据:');
  101. $this->table(['统计项', '总数', '活跃数', '活跃率'], [
  102. [
  103. '直推人数',
  104. $talentDto->directCount,
  105. $talentDto->activeDirectCount,
  106. $talentDto->directCount > 0 ? round($talentDto->activeDirectCount * 100 / $talentDto->directCount, 1) . '%' : '0%'
  107. ],
  108. ['间推人数', $talentDto->indirectCount, '-', '-'],
  109. ['三推人数', $talentDto->thirdCount, '-', '-'],
  110. [
  111. '团队总人数',
  112. $talentDto->promotionCount,
  113. $talentDto->activeTotalCount,
  114. $talentDto->promotionCount > 0 ? round($talentDto->activeTotalCount * 100 / $talentDto->promotionCount, 1) . '%' : '0%'
  115. ]
  116. ]);
  117. // 升级条件检查
  118. if ($talentDto->nextConfig) {
  119. $this->line('');
  120. $this->info('🎯 下一等级升级条件:');
  121. $nextLevel = $talentDto->nextConfig;
  122. $directMet = $talentDto->directCount >= $nextLevel['direct_count_required'];
  123. $teamMet = $talentDto->promotionCount >= $nextLevel['promotion_count_required'];
  124. $activeDirectMet = $talentDto->activeDirectCount >= ($nextLevel['active_direct_required'] ?? 0);
  125. $this->table(['条件', '要求', '当前', '状态'], [
  126. [
  127. '直推人数',
  128. $nextLevel['direct_count_required'],
  129. $talentDto->directCount,
  130. $directMet ? '✅ 已满足' : '❌ 未满足'
  131. ],
  132. [
  133. '团队总人数',
  134. $nextLevel['promotion_count_required'],
  135. $talentDto->promotionCount,
  136. $teamMet ? '✅ 已满足' : '❌ 未满足'
  137. ],
  138. [
  139. '活跃直推',
  140. $nextLevel['active_direct_required'] ?? 0,
  141. $talentDto->activeDirectCount,
  142. $activeDirectMet ? '✅ 已满足' : '❌ 未满足'
  143. ]
  144. ]);
  145. $allMet = $directMet && $teamMet && $activeDirectMet;
  146. if ($allMet) {
  147. $this->info("🎉 恭喜!所有升级条件已满足,可升级到 {$nextLevel['name']}");
  148. } else {
  149. $this->warn("⚠️ 还有条件未满足,无法升级到 {$nextLevel['name']}");
  150. }
  151. }
  152. } else {
  153. $this->error("✗ 用户 {$userId} 达人等级更新失败");
  154. return 1;
  155. }
  156. Log::info('URS达人等级更新成功', [
  157. 'user_id' => $userId,
  158. 'urs_user_id' => $ursUserId,
  159. 'talent_level' => $talentDto->talentLevel,
  160. 'talent_name' => $talentDto->talentName,
  161. 'force' => $force
  162. ]);
  163. return 0;
  164. } catch (\Exception $e) {
  165. $this->error("✗ 用户 {$userId} 达人等级更新失败: " . $e->getMessage());
  166. Log::error('URS达人等级更新失败', [
  167. 'user_id' => $userId,
  168. 'urs_user_id' => $ursUserId,
  169. 'error' => $e->getMessage(),
  170. 'trace' => $e->getTraceAsString()
  171. ]);
  172. return 1;
  173. }
  174. }
  175. /**
  176. * 批量更新所有用户的达人等级
  177. *
  178. * @param int $batchSize 批处理大小
  179. * @param bool $force 是否强制重新计算
  180. * @param bool $dryRun 是否仅模拟运行
  181. * @return int 命令退出码
  182. */
  183. private function updateAllUsers(int $batchSize, bool $force, bool $dryRun): int
  184. {
  185. $this->info("开始批量更新所有用户的达人等级...");
  186. $this->info("批处理大小: {$batchSize}");
  187. // 获取所有有效的用户映射
  188. $totalUsers = UrsUserMapping::where('status', UrsUserMapping::STATUS_VALID)->count();
  189. if ($totalUsers === 0) {
  190. $this->warn('没有找到需要更新的用户');
  191. return 0;
  192. }
  193. $this->info("找到 {$totalUsers} 个用户需要更新");
  194. if ($dryRun) {
  195. $this->info("模拟运行:将分批处理 {$totalUsers} 个用户");
  196. return 0;
  197. }
  198. $progressBar = $this->output->createProgressBar($totalUsers);
  199. $progressBar->start();
  200. $successCount = 0;
  201. $errorCount = 0;
  202. $processedCount = 0;
  203. // 分批处理用户
  204. UrsUserMapping::where('status', UrsUserMapping::STATUS_VALID)
  205. ->chunk($batchSize, function ($mappings) use (
  206. &$successCount, &$errorCount, &$processedCount,
  207. $progressBar, $force
  208. ) {
  209. foreach ($mappings as $mapping) {
  210. try {
  211. $talentDto = UrsTalentService::updateTalentLevel($mapping->user_id);
  212. if ($talentDto) {
  213. $successCount++;
  214. } else {
  215. $errorCount++;
  216. }
  217. } catch (\Exception $e) {
  218. $errorCount++;
  219. Log::error('批量更新用户达人等级失败', [
  220. 'user_id' => $mapping->user_id,
  221. 'urs_user_id' => $mapping->urs_user_id,
  222. 'error' => $e->getMessage()
  223. ]);
  224. }
  225. $processedCount++;
  226. $progressBar->advance();
  227. }
  228. });
  229. $progressBar->finish();
  230. $this->newLine();
  231. // 显示更新结果
  232. $this->info('=== 更新结果统计 ===');
  233. $this->table(['项目', '数量'], [
  234. ['总用户数', $totalUsers],
  235. ['处理用户数', $processedCount],
  236. ['成功更新数', $successCount],
  237. ['失败数量', $errorCount]
  238. ]);
  239. Log::info('URS达人等级批量更新完成', [
  240. 'total_users' => $totalUsers,
  241. 'processed_count' => $processedCount,
  242. 'success_count' => $successCount,
  243. 'error_count' => $errorCount,
  244. 'batch_size' => $batchSize,
  245. 'force' => $force
  246. ]);
  247. if ($errorCount > 0) {
  248. $this->warn("有 {$errorCount} 个用户更新失败,请检查日志");
  249. return 1;
  250. }
  251. $this->info('所有用户达人等级更新完成');
  252. return 0;
  253. }
  254. }