| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- <?php
- namespace App\Module\Promotion\Logics;
- use App\Module\Promotion\Enums\REFERRAL_LEVEL;
- use App\Module\Promotion\Models\PromotionReferralChange;
- use App\Module\Promotion\Models\PromotionUserReferral;
- use App\Module\Promotion\Models\PromotionUserRelationCache;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Redis;
- /**
- * 推荐关系逻辑类
- *
- * 处理用户推荐关系的核心业务逻辑,包括建立推荐关系、修改推荐关系、
- * 查询推荐关系、检查循环推荐等功能。该类仅供内部使用,不对外提供服务。
- */
- class ReferralLogic
- {
- /**
- * 建立推荐关系
- *
- * @param int $userId 用户ID
- * @param int $referrerId 推荐人ID
- * @return bool
- */
- public function createReferralRelation(int $userId, int $referrerId): bool
- {
- // 验证是否已存在推荐关系
- if ($this->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();
- }
- }
|