hasReferrer($userId)) { Log::warning("用户 {$userId} 已有推荐人,不能重复设置"); return false; } // 验证是否形成循环推荐 if ($this->checkCircularReferral($userId, $referrerId)) { Log::warning("用户 {$userId} 和推荐人 {$referrerId} 形成循环推荐关系"); return false; } try { // 创建直推关系 $referral = new PromotionUserReferral(); $referral->user_id = $userId; $referral->referrer_id = $referrerId; $result = $referral->save(); if ($result) { // 更新关系缓存 $this->updateRelationCache($userId, null, $referrerId); } return $result; } catch (\Exception $e) { Log::error("创建推荐关系失败: " . $e->getMessage()); return false; } } /** * 更新推荐关系 * * @param int $userId 用户ID * @param int $newReferrerId 新推荐人ID * @param string $reason 修改原因 * @param int $operatorId 操作人ID * @return bool */ public function updateReferralRelation(int $userId, int $newReferrerId, string $reason, int $operatorId): bool { // 获取旧的推荐人 $oldReferrerId = $this->getDirectReferrerId($userId); // 如果新旧推荐人相同,无需更新 if ($oldReferrerId == $newReferrerId) { return true; } // 验证是否形成循环推荐 if ($this->checkCircularReferral($userId, $newReferrerId)) { Log::warning("用户 {$userId} 和新推荐人 {$newReferrerId} 形成循环推荐关系"); return false; } // 检查事务是否已开启 \UCore\Db\Helper::check_tr(); try { // 删除旧的推荐关系 if ($oldReferrerId) { PromotionUserReferral::where('user_id', $userId)->delete(); } // 创建新的推荐关系 $referral = new PromotionUserReferral(); $referral->user_id = $userId; $referral->referrer_id = $newReferrerId; $result = $referral->save(); if ($result) { // 记录修改历史 $change = new PromotionReferralChange(); $change->user_id = $userId; $change->old_referrer_id = $oldReferrerId; $change->new_referrer_id = $newReferrerId; $change->change_time = now(); $change->change_reason = $reason; $change->changed_by = $operatorId; $change->save(); // 更新关系缓存 $this->updateRelationCache($userId, $oldReferrerId, $newReferrerId); } return $result; } catch (\Exception $e) { Log::error("更新推荐关系失败: " . $e->getMessage()); return false; } } /** * 获取用户的直接推荐人ID * * @param int $userId 用户ID * @return int|null */ public function getDirectReferrerId(int $userId): ?int { $referral = PromotionUserReferral::where('user_id', $userId)->first(); return $referral ? $referral->referrer_id : null; } /** * 检查用户是否已有推荐人 * * @param int $userId 用户ID * @return bool */ public function hasReferrer(int $userId): bool { return PromotionUserReferral::where('user_id', $userId)->exists(); } /** * 获取用户的直接下级 * * @param int $userId 用户ID * @return array */ public function getDirectMembers(int $userId): array { return PromotionUserReferral::where('referrer_id', $userId) ->with('user') ->get() ->toArray(); } /** * 获取用户的所有上级(包括直接和间接) * * @param int $userId 用户ID * @param int $maxLevel 最大层级 * @return array */ public function getAllReferrers(int $userId, int $maxLevel = 20): array { // 尝试从缓存获取 $cacheKey = "promotion:user:{$userId}:all_referrers"; $cachedData = Redis::get($cacheKey); if ($cachedData !== null) { return json_decode($cachedData, true); } // 从关系缓存表获取 $relations = PromotionUserRelationCache::where('user_id', $userId) ->where('depth', '<=', $maxLevel) ->orderBy('depth') ->get(); $referrers = []; foreach ($relations as $relation) { $referrers[] = [ 'user_id' => $relation->related_user_id, 'level' => $relation->level, 'depth' => $relation->depth, 'path' => $relation->path, ]; } // 缓存结果 Redis::setex($cacheKey, 86400, json_encode($referrers)); // 缓存1天 return $referrers; } /** * 获取用户的所有团队成员(包括直接和间接) * * @param int $userId 用户ID * @param int $maxLevel 最大层级 * @param int $page 页码 * @param int $pageSize 每页数量 * @return array */ public function getAllPromotionMembers(int $userId, int $maxLevel = 20, int $page = 1, int $pageSize = 20): array { // 从关系缓存表获取 $query = PromotionUserRelationCache::where('related_user_id', $userId) ->where('depth', '<=', $maxLevel); $total = $query->count(); $relations = $query->orderBy('depth') ->offset(($page - 1) * $pageSize) ->limit($pageSize) ->with('user') ->get(); $members = []; foreach ($relations as $relation) { if ($relation->user) { $members[] = [ 'user_id' => $relation->user_id, 'username' => $relation->user->username ?? '', 'level' => $relation->level, 'depth' => $relation->depth, 'path' => $relation->path, 'created_at' => $relation->created_at, ]; } } return [ 'total' => $total, 'page' => $page, 'page_size' => $pageSize, 'total_pages' => ceil($total / $pageSize), 'members' => $members ]; } /** * 检查是否形成循环推荐 * * @param int $userId 用户ID * @param int $referrerId 推荐人ID * @return bool */ public function checkCircularReferral(int $userId, int $referrerId): bool { // 如果用户ID和推荐人ID相同,直接形成循环 if ($userId == $referrerId) { return true; } // 获取推荐人的所有上级 $referrerReferrers = $this->getAllReferrers($referrerId); // 检查用户是否在推荐人的上级中 foreach ($referrerReferrers as $referrer) { if ($referrer['user_id'] == $userId) { return true; } } return false; } /** * 更新关系缓存 * * @param int $userId 用户ID * @param int|null $oldReferrerId 旧推荐人ID * @param int $newReferrerId 新推荐人ID * @return void */ private function updateRelationCache(int $userId, ?int $oldReferrerId, int $newReferrerId): void { // 检查事务是否已开启 \UCore\Db\Helper::check_tr(); try { // 1. 删除用户及其所有下级与旧上级及其所有上级的关系缓存 if ($oldReferrerId) { // 获取用户的所有下级ID $downlineIds = PromotionUserRelationCache::where('related_user_id', $userId) ->pluck('user_id') ->toArray(); $downlineIds[] = $userId; // 包括用户自身 // 获取旧上级的所有上级ID $upperReferrerIds = PromotionUserRelationCache::where('user_id', $oldReferrerId) ->pluck('related_user_id') ->toArray(); $upperReferrerIds[] = $oldReferrerId; // 包括直接上级 // 删除关系缓存 PromotionUserRelationCache::whereIn('user_id', $downlineIds) ->whereIn('related_user_id', $upperReferrerIds) ->delete(); // 清除Redis缓存 foreach ($downlineIds as $downlineId) { Redis::del("promotion:user:{$downlineId}:all_referrers"); } foreach ($upperReferrerIds as $upperReferrerId) { Redis::del("promotion:user:{$upperReferrerId}:all_members"); } } // 2. 为用户创建与新上级的直接关系缓存 $directRelation = new PromotionUserRelationCache(); $directRelation->user_id = $userId; $directRelation->related_user_id = $newReferrerId; $directRelation->level = REFERRAL_LEVEL::DIRECT; $directRelation->path = (string)$newReferrerId; $directRelation->depth = 1; $directRelation->save(); // 3. 获取新上级的所有上级 $upperRelations = PromotionUserRelationCache::where('user_id', $newReferrerId)->get(); // 4. 为用户创建与新上级的所有上级的间接关系缓存 foreach ($upperRelations as $upperRelation) { $indirectRelation = new PromotionUserRelationCache(); $indirectRelation->user_id = $userId; $indirectRelation->related_user_id = $upperRelation->related_user_id; $indirectRelation->level = REFERRAL_LEVEL::INDIRECT; $indirectRelation->path = $newReferrerId . ',' . $upperRelation->path; $indirectRelation->depth = $upperRelation->depth + 1; $indirectRelation->save(); } // 5. 获取用户的所有下级 $downlineRelations = PromotionUserRelationCache::where('related_user_id', $userId)->get(); // 6. 为用户的所有下级创建与新上级及其所有上级的关系缓存 foreach ($downlineRelations as $downlineRelation) { // 创建下级与新上级的关系 $downlineToReferrer = new PromotionUserRelationCache(); $downlineToReferrer->user_id = $downlineRelation->user_id; $downlineToReferrer->related_user_id = $newReferrerId; $downlineToReferrer->level = REFERRAL_LEVEL::INDIRECT; $downlineToReferrer->path = $downlineRelation->path . ',' . $newReferrerId; $downlineToReferrer->depth = $downlineRelation->depth + 1; $downlineToReferrer->save(); // 创建下级与新上级的所有上级的关系 foreach ($upperRelations as $upperRelation) { $downlineToUpper = new PromotionUserRelationCache(); $downlineToUpper->user_id = $downlineRelation->user_id; $downlineToUpper->related_user_id = $upperRelation->related_user_id; $downlineToUpper->level = REFERRAL_LEVEL::INDIRECT; $downlineToUpper->path = $downlineRelation->path . ',' . $newReferrerId . ',' . $upperRelation->path; $downlineToUpper->depth = $downlineRelation->depth + $upperRelation->depth + 1; $downlineToUpper->save(); } // 清除下级的Redis缓存 Redis::del("promotion:user:{$downlineRelation->user_id}:all_referrers"); } // 7. 清除新上级及其所有上级的Redis缓存 Redis::del("promotion:user:{$newReferrerId}:all_members"); foreach ($upperRelations as $upperRelation) { Redis::del("promotion:user:{$upperRelation->related_user_id}:all_members"); } } catch (\Exception $e) { Log::error("更新关系缓存失败: " . $e->getMessage()); } } /** * 统计用户的直推人数 * * @param int $userId 用户ID * @return int */ public function countDirectReferrals(int $userId): int { return PromotionUserReferral::where('referrer_id', $userId)->count(); } /** * 统计用户的团队总人数 * * @param int $userId 用户ID * @return int */ public function countPromotionMembers(int $userId): int { return PromotionUserRelationCache::where('related_user_id', $userId)->count(); } }