|
|
@@ -3,6 +3,7 @@
|
|
|
namespace Webkul\Shop\Http\Controllers\API;
|
|
|
|
|
|
use Illuminate\Http\JsonResponse;
|
|
|
+use Illuminate\Support\Facades\Cache;
|
|
|
use Webkul\Category\Repositories\CategoryRepository;
|
|
|
use Webkul\Core\Repositories\ChannelRepository;
|
|
|
use Webkul\Product\Repositories\ProductRepository;
|
|
|
@@ -10,6 +11,11 @@ use Webkul\Theme\Repositories\ThemeCustomizationRepository;
|
|
|
|
|
|
class HomeController extends APIController
|
|
|
{
|
|
|
+ /**
|
|
|
+ * 缓存 TTL(秒)
|
|
|
+ */
|
|
|
+ const CACHE_TTL = 300;
|
|
|
+
|
|
|
/**
|
|
|
* Create a new controller instance.
|
|
|
*/
|
|
|
@@ -37,35 +43,43 @@ class HomeController extends APIController
|
|
|
$channel = $this->channelRepository->findOneByField('code', $channelCode)
|
|
|
?: core()->getCurrentChannel();
|
|
|
|
|
|
- // 1. 获取主题自定义数据(banner、分类轮播、产品轮播等)
|
|
|
- $customizations = $this->themeCustomizationRepository
|
|
|
- ->orderBy('sort_order')
|
|
|
- ->findWhere([
|
|
|
- 'status' => 1,
|
|
|
- 'channel_id' => $channel->id,
|
|
|
- 'theme_code' => $channel->theme,
|
|
|
- ]);
|
|
|
-
|
|
|
- $sections = [];
|
|
|
- foreach ($customizations as $item) {
|
|
|
- $section = $this->formatSection($item, $locale);
|
|
|
- if ($section !== null) {
|
|
|
- $sections[] = $section;
|
|
|
+ $cacheKey = 'home_api:' . $channel->code . ':' . $locale;
|
|
|
+
|
|
|
+ $data = Cache::remember($cacheKey, self::CACHE_TTL, function () use ($channel, $locale) {
|
|
|
+ // 1. 获取主题自定义数据(banner、分类轮播、产品轮播等)
|
|
|
+ $customizations = $this->themeCustomizationRepository
|
|
|
+ ->orderBy('sort_order')
|
|
|
+ ->findWhere([
|
|
|
+ 'status' => 1,
|
|
|
+ 'channel_id' => $channel->id,
|
|
|
+ 'theme_code' => $channel->theme,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $sections = [];
|
|
|
+ foreach ($customizations as $item) {
|
|
|
+ $section = $this->formatSection($item, $locale);
|
|
|
+ if ($section !== null) {
|
|
|
+ $sections[] = $section;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // 2. 获取分类树(供导航使用)
|
|
|
- $categories = $this->categoryRepository->getVisibleCategoryTree(
|
|
|
- $channel->root_category_id
|
|
|
- );
|
|
|
+ // 2. 获取分类树
|
|
|
+ $categories = Cache::remember(
|
|
|
+ 'home_categories:' . $channel->code . ':' . $locale,
|
|
|
+ self::CACHE_TTL,
|
|
|
+ fn () => $this->categoryRepository->getVisibleCategoryTree($channel->root_category_id)
|
|
|
+ );
|
|
|
|
|
|
- return response()->json([
|
|
|
- 'success' => true,
|
|
|
- 'data' => [
|
|
|
+ return [
|
|
|
'channel' => $channel->code,
|
|
|
'sections' => $sections,
|
|
|
'categories' => $this->formatCategoryTree($categories),
|
|
|
- ],
|
|
|
+ ];
|
|
|
+ });
|
|
|
+
|
|
|
+ return response()->json([
|
|
|
+ 'success' => true,
|
|
|
+ 'data' => $data,
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
@@ -122,41 +136,50 @@ class HomeController extends APIController
|
|
|
*/
|
|
|
protected function getProductCarouselData(array $filters): array
|
|
|
{
|
|
|
- $params = [
|
|
|
- 'status' => 1,
|
|
|
- 'visible_individually'=> 1,
|
|
|
- 'limit' => $filters['limit'] ?? 12,
|
|
|
- 'sort' => $filters['sort'] ?? 'name-asc',
|
|
|
- ];
|
|
|
-
|
|
|
- if (! empty($filters['new'])) {
|
|
|
- $params['new'] = 1;
|
|
|
- }
|
|
|
-
|
|
|
- if (! empty($filters['featured'])) {
|
|
|
- $params['featured'] = 1;
|
|
|
- }
|
|
|
+ $cacheKey = 'home_products:' . md5(json_encode($filters));
|
|
|
+
|
|
|
+ return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($filters) {
|
|
|
+ $params = [
|
|
|
+ 'status' => 1,
|
|
|
+ 'visible_individually'=> 1,
|
|
|
+ 'limit' => $filters['limit'] ?? 12,
|
|
|
+ 'sort' => $filters['sort'] ?? 'name-asc',
|
|
|
+ ];
|
|
|
|
|
|
- $products = $this->productRepository->getAll($params);
|
|
|
+ if (! empty($filters['new'])) {
|
|
|
+ $params['new'] = 1;
|
|
|
+ }
|
|
|
|
|
|
- return $products->map(function ($product) {
|
|
|
- $image = $product->images->first()
|
|
|
- ?? $product->base_image;
|
|
|
+ if (! empty($filters['featured'])) {
|
|
|
+ $params['featured'] = 1;
|
|
|
+ }
|
|
|
|
|
|
- return [
|
|
|
- 'id' => $product->id,
|
|
|
- 'sku' => $product->sku,
|
|
|
- 'name' => $product->name,
|
|
|
- 'slug' => $product->slug,
|
|
|
- 'type' => $product->type,
|
|
|
- 'price' => $product->getTypeInstance()->getMinimalPrice(),
|
|
|
- 'special_price' => $product->special_price,
|
|
|
- 'image_url' => $image->url ?? null,
|
|
|
- 'is_new' => (bool) ($product->new ?? false),
|
|
|
- 'is_featured' => (bool) ($product->featured ?? false),
|
|
|
- 'short_description'=> $product->short_description,
|
|
|
- ];
|
|
|
- })->values()->toArray();
|
|
|
+ $products = $this->productRepository->getAll($params);
|
|
|
+
|
|
|
+ return $products->map(function ($product) {
|
|
|
+ $image = $product->images->first()
|
|
|
+ ?? $product->base_image;
|
|
|
+
|
|
|
+ $approvedReviews = $product->reviews->where('status', 'approved');
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'id' => $product->id,
|
|
|
+ 'sku' => $product->sku,
|
|
|
+ 'name' => $product->name,
|
|
|
+ 'slug' => $product->slug,
|
|
|
+ 'type' => $product->type,
|
|
|
+ 'price' => (float) $product->price,
|
|
|
+ 'min_price' => $product->getTypeInstance()->getMinimalPrice(),
|
|
|
+ 'special_price' => $product->special_price,
|
|
|
+ 'image_url' => $image->url ?? null,
|
|
|
+ 'is_new' => (bool) ($product->new ?? false),
|
|
|
+ 'is_featured' => (bool) ($product->featured ?? false),
|
|
|
+ 'short_description'=> $product->short_description,
|
|
|
+ 'rating' => round($approvedReviews->avg('rating') ?? 0, 1),
|
|
|
+ 'review_count' => $approvedReviews->count(),
|
|
|
+ ];
|
|
|
+ })->values()->toArray();
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|