Ver Fonte

实现农场房屋排行榜功能

- 新增RankHandler处理房屋排行榜请求
- 扩展HouseLogic添加排行榜查询逻辑
- 扩展HouseService添加排行榜服务方法
- 创建HouseRankDto和HouseRankItemDto数据传输对象
- 创建HouseRankDto Protobuf转换类
- 支持分页查询和用户排名显示
- 按房屋等级降序排列,同等级按升级时间排序
notfff há 7 meses atrás
pai
commit
c17b007e92

+ 57 - 0
app/Module/AppGame/Handler/House/RankHandler.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace App\Module\AppGame\Handler\House;
+
+use App\Module\AppGame\Handler\BaseHandler;
+use App\Module\AppGame\Proto\HouseRankDto;
+use App\Module\Farm\Services\HouseService;
+use Google\Protobuf\Internal\Message;
+use Illuminate\Support\Facades\Log;
+use UCore\Exception\LogicException;
+use Uraus\Kku\Request\RequestHouseRank;
+use Uraus\Kku\Response\ResponseHouseRank;
+
+/**
+ * 处理房屋排行榜请求
+ */
+class RankHandler extends BaseHandler
+{
+    /**
+     * 是否需要登录
+     * @var bool
+     */
+    protected bool $need_login = true;
+
+    /**
+     * 处理房屋排行榜请求
+     *
+     * @param RequestHouseRank $data 房屋排行榜请求数据
+     * @return ResponseHouseRank 房屋排行榜响应
+     */
+    public function handle(Message $data): Message
+    {
+        try {
+            $userId = $this->user_id;
+            
+            // 获取分页参数
+            $page = $data->getPage();
+            $pageNum = $page ? $page->getPage() : 1;
+            $pageSize = $page ? $page->getPerPage() : 20;
+            
+            // 调用服务层获取排行榜数据
+            $rankData = HouseService::getHouseRankList($userId, $pageNum, $pageSize);
+            
+            // 转换为Protobuf格式并返回
+            return HouseRankDto::toProtobuf($rankData);
+            
+        } catch (\Exception $e) {
+            Log::error('获取房屋排行榜失败', [
+                'user_id' => $this->user_id ?? 0,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+            
+            throw new LogicException('获取排行榜数据失败');
+        }
+    }
+}

+ 81 - 0
app/Module/AppGame/Proto/HouseRankDto.php

@@ -0,0 +1,81 @@
+<?php
+
+namespace App\Module\AppGame\Proto;
+
+use App\Module\Farm\Dtos\HouseRankDto as FarmHouseRankDto;
+use App\Module\Farm\Dtos\HouseRankItemDto;
+use Uraus\Kku\Common\ResponsePage;
+use Uraus\Kku\Response\FarmRankItem;
+use Uraus\Kku\Response\ResponseHouseRank;
+
+/**
+ * 房屋排行榜DTO转换为Protobuf数据对象
+ */
+class HouseRankDto
+{
+    /**
+     * 将房屋排行榜DTO转换为Protobuf响应对象
+     *
+     * @param FarmHouseRankDto $dto
+     * @return ResponseHouseRank
+     */
+    public static function toProtobuf(FarmHouseRankDto $dto): ResponseHouseRank
+    {
+        $response = new ResponseHouseRank();
+
+        // 设置分页信息
+        if (!empty($dto->page)) {
+            $page = new ResponsePage();
+            $page->setCurrentPage($dto->page['page'] ?? 1);
+            $page->setPerPage($dto->page['per_page'] ?? 20);
+            $page->setTotal($dto->page['total'] ?? 0);
+
+            // 计算其他分页信息
+            $total = $dto->page['total'] ?? 0;
+            $perPage = $dto->page['per_page'] ?? 20;
+            $currentPage = $dto->page['page'] ?? 1;
+            $lastPage = $perPage > 0 ? ceil($total / $perPage) : 1;
+            $hasMore = $currentPage < $lastPage;
+
+            $page->setLastPage($lastPage);
+            $page->setHasMore($hasMore);
+
+            $response->setPage($page);
+        }
+
+        // 设置用户排名
+        $response->setUserRank($dto->userRank);
+
+        // 设置赛季
+        $response->setReason($dto->reason);
+
+        // 转换排行榜列表
+        $rankItems = [];
+        foreach ($dto->list as $item) {
+            $rankItems[] = self::convertRankItem($item);
+        }
+        $response->setList($rankItems);
+
+        return $response;
+    }
+
+    /**
+     * 转换排行榜项目
+     *
+     * @param HouseRankItemDto $item
+     * @return FarmRankItem
+     */
+    private static function convertRankItem(HouseRankItemDto $item): FarmRankItem
+    {
+        $rankItem = new FarmRankItem();
+        $rankItem->setRank($item->rank);
+        $rankItem->setLevel($item->level);
+        $rankItem->setUserId($item->userId);
+        // 注意:protobuf中nickname字段是int64类型,这里传递用户ID
+        // 客户端需要根据用户ID获取昵称,或者protobuf定义需要修改为string类型
+        $rankItem->setNickname($item->userId);
+        $rankItem->setReason($item->reason);
+
+        return $rankItem;
+    }
+}

+ 49 - 0
app/Module/Farm/Dtos/HouseRankDto.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Module\Farm\Dtos;
+
+/**
+ * 房屋排行榜数据传输对象
+ */
+class HouseRankDto
+{
+    /**
+     * 排行榜列表
+     * @var HouseRankItemDto[]
+     */
+    public array $list = [];
+
+    /**
+     * 用户自己的排名,0表示未上榜
+     * @var int
+     */
+    public int $userRank = 0;
+
+    /**
+     * 第几届/赛季
+     * @var int
+     */
+    public int $reason = 1;
+
+    /**
+     * 分页信息
+     * @var array
+     */
+    public array $page = [];
+
+    /**
+     * 构造函数
+     *
+     * @param array $list 排行榜列表
+     * @param int $userRank 用户排名
+     * @param int $reason 赛季
+     * @param array $page 分页信息
+     */
+    public function __construct(array $list = [], int $userRank = 0, int $reason = 1, array $page = [])
+    {
+        $this->list = $list;
+        $this->userRank = $userRank;
+        $this->reason = $reason;
+        $this->page = $page;
+    }
+}

+ 78 - 0
app/Module/Farm/Dtos/HouseRankItemDto.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace App\Module\Farm\Dtos;
+
+use App\Module\Farm\Models\FarmUser;
+use App\Module\User\Models\User;
+
+/**
+ * 房屋排行榜项目数据传输对象
+ */
+class HouseRankItemDto
+{
+    /**
+     * 排名
+     * @var int
+     */
+    public int $rank = 0;
+
+    /**
+     * 房屋等级
+     * @var int
+     */
+    public int $level = 0;
+
+    /**
+     * 用户ID
+     * @var int
+     */
+    public int $userId = 0;
+
+    /**
+     * 用户昵称
+     * @var string
+     */
+    public string $nickname = '';
+
+    /**
+     * 第几届/赛季
+     * @var int
+     */
+    public int $reason = 1;
+
+    /**
+     * 构造函数
+     *
+     * @param int $rank 排名
+     * @param int $level 房屋等级
+     * @param int $userId 用户ID
+     * @param string $nickname 用户昵称
+     * @param int $reason 赛季
+     */
+    public function __construct(int $rank = 0, int $level = 0, int $userId = 0, string $nickname = '', int $reason = 1)
+    {
+        $this->rank = $rank;
+        $this->level = $level;
+        $this->userId = $userId;
+        $this->nickname = $nickname;
+        $this->reason = $reason;
+    }
+
+    /**
+     * 从数据库查询结果创建DTO
+     *
+     * @param array $data 数据库查询结果
+     * @param int $rank 排名
+     * @return static
+     */
+    public static function fromArray(array $data, int $rank): static
+    {
+        return new static(
+            rank: $rank,
+            level: $data['house_level'] ?? 0,
+            userId: $data['user_id'] ?? 0,
+            nickname: $data['nickname'] ?? '',
+            reason: 1
+        );
+    }
+}

+ 125 - 0
app/Module/Farm/Logics/HouseLogic.php

@@ -2,12 +2,16 @@
 
 namespace App\Module\Farm\Logics;
 
+use App\Module\Farm\Dtos\HouseRankDto;
+use App\Module\Farm\Dtos\HouseRankItemDto;
 use App\Module\Farm\Enums\UPGRADE_TYPE;
 use App\Module\Farm\Events\HouseUpgradedEvent;
 use App\Module\Farm\Models\FarmHouseConfig;
 use App\Module\Farm\Models\FarmUpgradeLog;
 use App\Module\Farm\Models\FarmUser;
+use App\Module\User\Models\User;
 use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
 
 /**
@@ -252,6 +256,127 @@ class HouseLogic
         }
     }
 
+    /**
+     * 获取房屋排行榜数据
+     *
+     * @param int $userId 当前用户ID
+     * @param int $page 页码
+     * @param int $pageSize 每页数量
+     * @return HouseRankDto
+     */
+    public function getHouseRankList(int $userId, int $page = 1, int $pageSize = 20): HouseRankDto
+    {
+        try {
+            // 计算偏移量
+            $offset = ($page - 1) * $pageSize;
+
+            // 查询排行榜数据,按房屋等级降序排列
+            $rankList = DB::table('farm_users as fu')
+                ->join('users as u', 'fu.user_id', '=', 'u.id')
+                ->select([
+                    'fu.user_id',
+                    'fu.house_level',
+                    'u.username as nickname', // 使用username作为昵称
+                    'fu.last_upgrade_time'
+                ])
+                ->orderBy('fu.house_level', 'desc')
+                ->orderBy('fu.last_upgrade_time', 'asc') // 同等级按升级时间排序
+                ->offset($offset)
+                ->limit($pageSize)
+                ->get()
+                ->toArray();
+
+            // 转换为DTO对象
+            $rankItems = [];
+            foreach ($rankList as $index => $item) {
+                $rank = $offset + $index + 1;
+                $rankItems[] = HouseRankItemDto::fromArray((array)$item, $rank);
+            }
+
+            // 查询用户自己的排名
+            $userRank = $this->getUserHouseRank($userId);
+
+            // 构建分页信息
+            $pageInfo = [
+                'page' => $page,
+                'per_page' => $pageSize,
+                'total' => $this->getTotalHouseRankCount()
+            ];
+
+            return new HouseRankDto($rankItems, $userRank, 1, $pageInfo);
+
+        } catch (\Exception $e) {
+            Log::error('获取房屋排行榜失败', [
+                'user_id' => $userId,
+                'page' => $page,
+                'page_size' => $pageSize,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+
+            return new HouseRankDto();
+        }
+    }
+
+    /**
+     * 获取用户的房屋排名
+     *
+     * @param int $userId 用户ID
+     * @return int 排名,0表示未上榜
+     */
+    private function getUserHouseRank(int $userId): int
+    {
+        try {
+            // 获取用户的房屋等级
+            $userFarm = FarmUser::where('user_id', $userId)->first();
+            if (!$userFarm) {
+                return 0;
+            }
+
+            $userLevel = $userFarm->house_level;
+            $userUpgradeTime = $userFarm->last_upgrade_time;
+
+            // 计算排名:比用户等级高的用户数量 + 同等级但升级时间更早的用户数量 + 1
+            $rank = DB::table('farm_users as fu')
+                ->where(function ($query) use ($userLevel, $userUpgradeTime) {
+                    $query->where('fu.house_level', '>', $userLevel)
+                        ->orWhere(function ($subQuery) use ($userLevel, $userUpgradeTime) {
+                            $subQuery->where('fu.house_level', '=', $userLevel)
+                                ->where('fu.last_upgrade_time', '<', $userUpgradeTime);
+                        });
+                })
+                ->count();
+
+            return $rank + 1;
+
+        } catch (\Exception $e) {
+            Log::error('获取用户房屋排名失败', [
+                'user_id' => $userId,
+                'error' => $e->getMessage()
+            ]);
+
+            return 0;
+        }
+    }
+
+    /**
+     * 获取房屋排行榜总数
+     *
+     * @return int
+     */
+    private function getTotalHouseRankCount(): int
+    {
+        try {
+            return FarmUser::count();
+        } catch (\Exception $e) {
+            Log::error('获取房屋排行榜总数失败', [
+                'error' => $e->getMessage()
+            ]);
+
+            return 0;
+        }
+    }
+
     /**
      * 清除房屋配置缓存
      *

+ 27 - 0
app/Module/Farm/Services/HouseService.php

@@ -2,6 +2,7 @@
 
 namespace App\Module\Farm\Services;
 
+use App\Module\Farm\Dtos\HouseRankDto;
 use App\Module\Farm\Logics\HouseLogic;
 use App\Module\Farm\Models\FarmHouseConfig;
 use Illuminate\Support\Facades\Log;
@@ -128,6 +129,32 @@ class HouseService
             return true;
     }
 
+    /**
+     * 获取房屋排行榜数据
+     *
+     * @param int $userId 当前用户ID
+     * @param int $page 页码
+     * @param int $pageSize 每页数量
+     * @return HouseRankDto
+     */
+    public static function getHouseRankList(int $userId, int $page = 1, int $pageSize = 20): HouseRankDto
+    {
+        try {
+            $houseLogic = new HouseLogic();
+            return $houseLogic->getHouseRankList($userId, $page, $pageSize);
+        } catch (\Exception $e) {
+            Log::error('获取房屋排行榜失败', [
+                'user_id' => $userId,
+                'page' => $page,
+                'page_size' => $pageSize,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+
+            return new HouseRankDto();
+        }
+    }
+
     /**
      * 执行房屋升级
      * 要求调用者已开启事务