From 8c284937acdeb8a338b1ac2658177e5b1e7a4bbe Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Wed, 9 Apr 2025 09:40:05 +0800 Subject: [PATCH] feat : rank --- app/Cache/Redis/Api/ApiRedisKey.php | 9 ++ app/Cache/Redis/Api/EvaluationCache.php | 57 +++++++++++++ app/Cache/Redis/RedisCache.php | 9 +- app/Service/Api/Chef/IndexService.php | 84 ++++++++++++++++++- .../Api/Evaluation/EvaluationService.php | 9 ++ .../Api/System/GetLeaderboardService.php | 2 +- 6 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 app/Cache/Redis/Api/EvaluationCache.php diff --git a/app/Cache/Redis/Api/ApiRedisKey.php b/app/Cache/Redis/Api/ApiRedisKey.php index 74ded81..7b7a690 100644 --- a/app/Cache/Redis/Api/ApiRedisKey.php +++ b/app/Cache/Redis/Api/ApiRedisKey.php @@ -84,4 +84,13 @@ class ApiRedisKey { return 'chef:leaderboard:city_id:'.$cityId.':type:'.$type.':time_key:'.$timeKey; } + + /** + * @param int $chefId + * @return string + */ + public static function chefEvaluationKey(int $chefId): string + { + return 'evaluation:chef:id:'.$chefId; + } } \ No newline at end of file diff --git a/app/Cache/Redis/Api/EvaluationCache.php b/app/Cache/Redis/Api/EvaluationCache.php new file mode 100644 index 0000000..3f43e6a --- /dev/null +++ b/app/Cache/Redis/Api/EvaluationCache.php @@ -0,0 +1,57 @@ +redis->hIncrBy($key, 'total_score', $score); + $this->redis->hIncrBy($key, 'total_count', 1); + } + + /** + * @param int $chefId + * @return float|int + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function getChefEvaluation(int $chefId): float|int + { + $key = ApiRedisKey::chefEvaluationKey($chefId); + + $totalScore = $this->redis->hGet($key, 'total_score'); + $totalCount = $this->redis->hGet($key, 'total_count'); + + if (empty($totalScore) || empty($totalCount)) return 0; + + $avgScore = $totalScore / $totalCount; + + if ($avgScore < 4) { + $normalized = $avgScore / 4; + $avgScore = 4 + 1 - exp(-2 * $normalized); + } + + return round($avgScore,1); + } +} \ No newline at end of file diff --git a/app/Cache/Redis/RedisCache.php b/app/Cache/Redis/RedisCache.php index 17dc47d..dd0b080 100644 --- a/app/Cache/Redis/RedisCache.php +++ b/app/Cache/Redis/RedisCache.php @@ -409,16 +409,15 @@ class RedisCache /** * 单个字段的 hash 值原子增加 - * @param $key - * @param $hashKey - * @param $hashValue + * @param string $key + * @param string $hashKey + * @param int $hashValue * @param string $poolName * @return false|int|Redis * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface - * @throws RedisException */ - public function HIncrBy($key, $hashKey, $hashValue, string $poolName = RedisCode::DEFAULT_DB) + public function hIncrBy(string $key, string $hashKey, int $hashValue, string $poolName = RedisCode::DEFAULT_DB): false|int|Redis { return $this->getRedis($poolName)->hincrby($key, $hashKey, $hashValue); } diff --git a/app/Service/Api/Chef/IndexService.php b/app/Service/Api/Chef/IndexService.php index 0ea7b14..1a0ff42 100644 --- a/app/Service/Api/Chef/IndexService.php +++ b/app/Service/Api/Chef/IndexService.php @@ -10,12 +10,19 @@ declare(strict_types=1); namespace App\Service\Api\Chef; +use App\Cache\Redis\Api\EvaluationCache; use App\Exception\ErrException; use App\Model\AdminUser; use App\Model\Chef; +use App\Model\Evaluation; +use App\Model\Order; +use App\Model\Sku; +use App\Model\User; use App\Service\Api\BaseService; use App\Service\ServiceTrait\Common\OssTrait; use Hyperf\Di\Annotation\Inject; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; class IndexService extends BaseService { @@ -33,8 +40,15 @@ class IndexService extends BaseService #[Inject] protected Chef $chefModel; + /** + * @var EvaluationCache + */ + protected EvaluationCache $evaluationCache; + /** * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ public function handle(): array { @@ -58,9 +72,77 @@ class IndexService extends BaseService $avatarUrl = $this->getOssObjectById($chef->avatar); $res = $chef->toArray(); $res['avatar_url'] = $avatarUrl; + $res['avg_score'] = $this->evaluationCache->getChefEvaluation($chefId) ?? 0; - // todo 评价补全 + // 评价补全 + $res['evaluation_list'] = $this->getEvaluationList($chefId); return $this->return->success('success', $res); } + + /** + * @var Evaluation + */ + #[Inject] + protected Evaluation $evaluationModel; + + /** + * @var Sku + */ + #[Inject] + protected Sku $skuModel; + + /** + * @var Order + */ + #[Inject] + protected Order $orderModel; + + /** + * @var User + */ + #[Inject] + protected User $userModel; + + private function getEvaluationList(int $chefId): array + { + $limit = $this->request->input('limit') ?? 10; + + $data = $this->evaluationModel + ->where('chef_id', $chefId) + ->orderByDesc('id') + ->paginate($limit,['content','image_ids','id','order_id','user_id','sku_id','score','content']) + ->toArray(); + + if (empty($data['data'])) return []; + + $skuIds = array_column($data['data'], 'sku_id'); + $orderIds = array_column($data['data'], 'order_id'); + $userIds = array_column($data['data'], 'user_id'); + $skuList = $this->skuModel->whereIn('id', $skuIds)->pluck('title','id')->toArray(); + $orderTimes = $this->orderModel->whereIn('id', $orderIds)->pluck('create_time','id')->toArray(); +// $skuList = array_column($skuList, null,'id'); + $userList = $this->userModel->whereIn('id', $userIds)->select(['nickname','id','avatar_id'])->get()->toArray(); + $userList = array_column($userList, null,'id'); + $imageIds = array_column($userList, 'avatar_id'); + $imageIdArr = array_column($data['data'],'image_ids'); + $listImageIds = array_unique(explode(',',implode(',',$imageIdArr))); + $totalImages = array_merge($imageIds,$listImageIds); + unset($listImageIds,$imageIds); + $imageList = $this->getOssObjects($totalImages); + + foreach ($data['data'] as &$item) { + $item['sku_title'] = $skuList[$item['sku_id']]['title'] ?? ''; + $item['order_time'] = $orderTimes[$item['order_id']] ?? ''; + $oneImage = []; + foreach (explode(',',$item['image_ids']) as $imageId) { + $oneImage[] = $imageList[$imageId]['url'] ?? ''; + } + $item['content_image_list'] = $oneImage; + $item['nickname'] = $userList[$item['user_id']]['nickname'] ?? ''; + $item['avatar'] = $imageList[$userList[$item['user_id']]['avatar_id']]['url'] ?? ''; + } + + return $data; + } } \ No newline at end of file diff --git a/app/Service/Api/Evaluation/EvaluationService.php b/app/Service/Api/Evaluation/EvaluationService.php index f492405..48e460b 100644 --- a/app/Service/Api/Evaluation/EvaluationService.php +++ b/app/Service/Api/Evaluation/EvaluationService.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace App\Service\Api\Evaluation; +use App\Cache\Redis\Api\EvaluationCache; use App\Constants\Common\OrderCode; use App\Exception\ErrException; use App\Model\Evaluation; @@ -44,6 +45,12 @@ class EvaluationService extends BaseService #[Inject] protected Sku $skuModel; + /** + * @var EvaluationCache + */ + #[Inject] + protected EvaluationCache $evaluationCache; + /** * @return array */ @@ -89,6 +96,8 @@ class EvaluationService extends BaseService return $insertModel; }); + $this->evaluationCache->addChefEvaluation($skuInfo->chef_id, (int)$this->request->input('score')); + return $this->return->success('success', ['id' => $insertModel->id]); } } \ No newline at end of file diff --git a/app/Service/Api/System/GetLeaderboardService.php b/app/Service/Api/System/GetLeaderboardService.php index c3af89e..6bec794 100644 --- a/app/Service/Api/System/GetLeaderboardService.php +++ b/app/Service/Api/System/GetLeaderboardService.php @@ -82,7 +82,7 @@ class GetLeaderboardService extends BaseService $v = 4 + 1 - exp(-2 * $normalized); } - $v = round($v,2); + $v = round($v,1); } $this->redis->zAdd($redisKey,$v,$k);