AI Assistant před 6 měsíci
rodič
revize
c323b74e35

+ 239 - 0
app/Module/UrsPromotion/Commands/UrsUpdateTalentLevelCommand.php

@@ -0,0 +1,239 @@
+<?php
+
+namespace App\Module\UrsPromotion\Commands;
+
+use App\Module\UrsPromotion\Services\UrsTalentService;
+use App\Module\UrsPromotion\Services\UrsUserMappingService;
+use App\Module\UrsPromotion\Models\UrsUserMapping;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * URS用户达人等级更新命令
+ * 
+ * 用于更新指定用户或批量更新用户的达人等级
+ * 支持单个用户更新和批量更新功能
+ * php artisan urs:update-talent-level 39296
+ * 
+ */
+class UrsUpdateTalentLevelCommand extends Command
+{
+    /**
+     * 命令签名
+     */
+    protected $signature = 'urs:update-talent-level 
+                            {user_id? : 农场用户ID,不指定则更新所有用户}
+                            {--batch-size=100 : 批处理大小}
+                            {--force : 强制重新计算等级}
+                            {--dry-run : 仅模拟运行,不实际执行更新}';
+
+    /**
+     * 命令描述
+     */
+    protected $description = 'URS用户达人等级更新命令 - 计算并更新用户的达人等级';
+
+    /**
+     * 执行命令
+     */
+    public function handle()
+    {
+        $userId = $this->argument('user_id');
+        $batchSize = (int) $this->option('batch-size');
+        $force = $this->option('force');
+        $dryRun = $this->option('dry-run');
+
+        $this->info('=== URS用户达人等级更新命令 ===');
+        
+        if ($dryRun) {
+            $this->warn('模拟运行模式 - 不会实际执行更新操作');
+        }
+
+        try {
+            if ($userId) {
+                // 更新指定用户
+                return $this->updateSingleUser((int) $userId, $force, $dryRun);
+            } else {
+                // 批量更新所有用户
+                return $this->updateAllUsers($batchSize, $force, $dryRun);
+            }
+        } catch (\Exception $e) {
+            $this->error('命令执行失败: ' . $e->getMessage());
+            Log::error('URS达人等级更新命令执行失败', [
+                'user_id' => $userId,
+                'batch_size' => $batchSize,
+                'force' => $force,
+                'dry_run' => $dryRun,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+            return 1;
+        }
+    }
+
+    /**
+     * 更新指定用户的达人等级
+     *
+     * @param int $userId 农场用户ID
+     * @param bool $force 是否强制重新计算
+     * @param bool $dryRun 是否仅模拟运行
+     * @return int 命令退出码
+     */
+    private function updateSingleUser(int $userId, bool $force, bool $dryRun): int
+    {
+        $this->info("开始更新用户 {$userId} 的达人等级...");
+
+        // 检查用户是否有URS映射关系
+        $ursUserId = UrsUserMappingService::getMappingUrsUserId($userId);
+        if ($ursUserId === 0) {
+            $this->error("用户 {$userId} 没有URS映射关系,无法更新达人等级");
+            return 1;
+        }
+
+        $this->info("找到URS用户ID: {$ursUserId}");
+
+        if ($dryRun) {
+            $this->info("模拟运行:将调用 UrsTalentService::updateTalentLevel({$userId})");
+            return 0;
+        }
+
+        try {
+            // 调用达人等级更新服务
+            $talentDto = UrsTalentService::updateTalentLevel($userId);
+            
+            if ($talentDto) {
+                $this->info("✓ 成功更新用户 {$userId} 的达人等级");
+                $this->table(['属性', '值'], [
+                    ['URS用户ID', $talentDto->ursUserId],
+                    ['达人等级', $talentDto->talentLevel],
+                    ['等级名称', $talentDto->talentName],
+                    ['直推人数', $talentDto->directCount],
+                    ['间推人数', $talentDto->indirectCount],
+                    ['三推人数', $talentDto->thirdCount],
+                    ['团队总人数', $talentDto->promotionCount],
+                    ['最后更新时间', $talentDto->lastLevelUpdateTime ?? '未更新']
+                ]);
+            } else {
+                $this->error("✗ 用户 {$userId} 达人等级更新失败");
+                return 1;
+            }
+
+            Log::info('URS达人等级更新成功', [
+                'user_id' => $userId,
+                'urs_user_id' => $ursUserId,
+                'talent_level' => $talentDto->talentLevel,
+                'talent_name' => $talentDto->talentName,
+                'force' => $force
+            ]);
+
+            return 0;
+
+        } catch (\Exception $e) {
+            $this->error("✗ 用户 {$userId} 达人等级更新失败: " . $e->getMessage());
+            
+            Log::error('URS达人等级更新失败', [
+                'user_id' => $userId,
+                'urs_user_id' => $ursUserId,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+
+            return 1;
+        }
+    }
+
+    /**
+     * 批量更新所有用户的达人等级
+     *
+     * @param int $batchSize 批处理大小
+     * @param bool $force 是否强制重新计算
+     * @param bool $dryRun 是否仅模拟运行
+     * @return int 命令退出码
+     */
+    private function updateAllUsers(int $batchSize, bool $force, bool $dryRun): int
+    {
+        $this->info("开始批量更新所有用户的达人等级...");
+        $this->info("批处理大小: {$batchSize}");
+
+        // 获取所有有效的用户映射
+        $totalUsers = UrsUserMapping::where('status', UrsUserMapping::STATUS_VALID)->count();
+        
+        if ($totalUsers === 0) {
+            $this->warn('没有找到需要更新的用户');
+            return 0;
+        }
+
+        $this->info("找到 {$totalUsers} 个用户需要更新");
+
+        if ($dryRun) {
+            $this->info("模拟运行:将分批处理 {$totalUsers} 个用户");
+            return 0;
+        }
+
+        $progressBar = $this->output->createProgressBar($totalUsers);
+        $progressBar->start();
+
+        $successCount = 0;
+        $errorCount = 0;
+        $processedCount = 0;
+
+        // 分批处理用户
+        UrsUserMapping::where('status', UrsUserMapping::STATUS_VALID)
+            ->chunk($batchSize, function ($mappings) use (
+                &$successCount, &$errorCount, &$processedCount, 
+                $progressBar, $force
+            ) {
+                foreach ($mappings as $mapping) {
+                    try {
+                        $talentDto = UrsTalentService::updateTalentLevel($mapping->user_id);
+                        
+                        if ($talentDto) {
+                            $successCount++;
+                        } else {
+                            $errorCount++;
+                        }
+
+                    } catch (\Exception $e) {
+                        $errorCount++;
+                        
+                        Log::error('批量更新用户达人等级失败', [
+                            'user_id' => $mapping->user_id,
+                            'urs_user_id' => $mapping->urs_user_id,
+                            'error' => $e->getMessage()
+                        ]);
+                    }
+
+                    $processedCount++;
+                    $progressBar->advance();
+                }
+            });
+
+        $progressBar->finish();
+        $this->newLine();
+
+        // 显示更新结果
+        $this->info('=== 更新结果统计 ===');
+        $this->table(['项目', '数量'], [
+            ['总用户数', $totalUsers],
+            ['处理用户数', $processedCount],
+            ['成功更新数', $successCount],
+            ['失败数量', $errorCount]
+        ]);
+
+        Log::info('URS达人等级批量更新完成', [
+            'total_users' => $totalUsers,
+            'processed_count' => $processedCount,
+            'success_count' => $successCount,
+            'error_count' => $errorCount,
+            'batch_size' => $batchSize,
+            'force' => $force
+        ]);
+
+        if ($errorCount > 0) {
+            $this->warn("有 {$errorCount} 个用户更新失败,请检查日志");
+            return 1;
+        }
+
+        $this->info('所有用户达人等级更新完成');
+        return 0;
+    }
+}

+ 62 - 0
app/Module/UrsPromotion/Commands/readme.md

@@ -1,5 +1,67 @@
 # Urs推广模块命令行工具
 
+## URS用户达人等级更新命令 (UrsUpdateTalentLevelCommand)
+
+### 功能描述
+用于计算并更新用户的达人等级的命令行工具。支持更新指定用户或批量更新所有用户的达人等级。
+
+### 命令签名
+```bash
+php artisan urs:update-talent-level [user_id] [options]
+```
+
+### 参数说明
+- `user_id` (可选): 农场用户ID,不指定则更新所有用户
+
+### 选项说明
+- `--batch-size=100`: 批处理大小,默认100
+- `--force`: 强制重新计算等级
+- `--dry-run`: 仅模拟运行,不实际执行更新
+
+### 使用示例
+
+#### 1. 更新指定用户
+```bash
+# 更新用户ID为12345的达人等级
+php artisan urs:update-talent-level 12345
+
+# 强制重新计算等级
+php artisan urs:update-talent-level 12345 --force
+
+# 模拟运行,查看将要执行的操作
+php artisan urs:update-talent-level 12345 --dry-run
+```
+
+#### 2. 批量更新所有用户
+```bash
+# 更新所有用户的达人等级
+php artisan urs:update-talent-level
+
+# 指定批处理大小为50
+php artisan urs:update-talent-level --batch-size=50
+
+# 强制重新计算所有用户等级
+php artisan urs:update-talent-level --force
+
+# 模拟运行批量更新
+php artisan urs:update-talent-level --dry-run
+```
+
+### 技术实现
+1. 调用 `UrsTalentService::updateTalentLevel()` 方法
+2. 使用 `UrsUserMappingService` 获取用户映射关系
+3. 通过 `UrsReferralService` 和 `UrsActiveUserService` 获取团队统计
+4. 支持批量处理,避免内存溢出
+5. 提供详细的进度显示和错误处理
+
+### 注意事项
+- 只有有URS映射关系的用户才能更新达人等级
+- 会自动计算团队统计数据并更新等级
+- 批量更新时会显示进度条和统计结果
+- 所有操作都会记录详细日志
+
+---
+
 ## URS推荐关系同步命令 (UrsReferralSyncCommand)
 
 ### 功能描述

+ 1 - 0
app/Module/UrsPromotion/Providers/UrsPromotionServiceProvider.php

@@ -49,6 +49,7 @@ class UrsPromotionServiceProvider extends ServiceProvider
                 \App\Module\UrsPromotion\Commands\UrsRebuildRelationCacheCommand::class,
                 \App\Module\UrsPromotion\Commands\UrsTestRelationCacheCommand::class,
                 \App\Module\UrsPromotion\Commands\UrsReferralSyncCommand::class,
+                \App\Module\UrsPromotion\Commands\UrsUpdateTalentLevelCommand::class,
             ]);
         }
     }

+ 40 - 0
app/Module/UrsPromotion/Services/UrsReferralService.php

@@ -86,6 +86,46 @@ class UrsReferralService
             $maxLevels = UrsPromotionRelationLevel::getTeamStatsDepth();
         }
 
+        // 优先使用关系缓存表进行查询,性能更好
+        return self::getTeamMembersFromCache($ursUserId, $maxLevels);
+    }
+
+    /**
+     * 从关系缓存表获取团队成员(高性能版本)
+     *
+     * @param int $ursUserId URS用户ID
+     * @param int $maxLevels 最大层级数
+     * @return array 团队成员,按层级分组 [level => [urs_user_ids]]
+     */
+    private static function getTeamMembersFromCache(int $ursUserId, int $maxLevels): array
+    {
+        // 使用关系缓存表查询所有下级关系
+        $relations = \App\Module\UrsPromotion\Models\UrsUserRelationCache::where('urs_related_user_id', $ursUserId)
+            ->where('depth', '<=', $maxLevels)
+            ->orderBy('depth')
+            ->get(['urs_user_id', 'depth']);
+
+        $team = [];
+        foreach ($relations as $relation) {
+            $level = $relation->depth;
+            if (!isset($team[$level])) {
+                $team[$level] = [];
+            }
+            $team[$level][] = $relation->urs_user_id;
+        }
+
+        return $team;
+    }
+
+    /**
+     * 获取用户的团队成员(递归查询版本,作为备用方案)
+     *
+     * @param int $ursUserId URS用户ID
+     * @param int $maxLevels 最大层级数
+     * @return array 团队成员,按层级分组 [level => [urs_user_ids]]
+     */
+    private static function getTeamMembersRecursive(int $ursUserId, int $maxLevels): array
+    {
         $team = [];
         $currentLevelUsers = [$ursUserId];
 

+ 3 - 1
app/Module/UrsPromotion/Services/UrsUserMappingService.php

@@ -341,7 +341,9 @@ class UrsUserMappingService
         /**
          * @var UrsUserMapping $mapping
          */
-        $mapping = UrsUserMapping::where('user_id', $userId)->first();
+        $mapping = UrsUserMapping::where('user_id', $userId)
+            ->where('status', UrsUserMapping::STATUS_VALID)
+            ->first();
         if (!$mapping) {
             return 0;
         }