|
@@ -0,0 +1,188 @@
|
|
|
|
|
+<?php
|
|
|
|
|
+
|
|
|
|
|
+namespace Webkul\Shop\Http\Controllers\API;
|
|
|
|
|
+
|
|
|
|
|
+use Illuminate\Http\JsonResponse;
|
|
|
|
|
+use Webkul\Category\Repositories\CategoryRepository;
|
|
|
|
|
+use Webkul\Core\Repositories\ChannelRepository;
|
|
|
|
|
+use Webkul\Product\Repositories\ProductRepository;
|
|
|
|
|
+use Webkul\Theme\Repositories\ThemeCustomizationRepository;
|
|
|
|
|
+
|
|
|
|
|
+class HomeController extends APIController
|
|
|
|
|
+{
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Create a new controller instance.
|
|
|
|
|
+ */
|
|
|
|
|
+ public function __construct(
|
|
|
|
|
+ protected ThemeCustomizationRepository $themeCustomizationRepository,
|
|
|
|
|
+ protected CategoryRepository $categoryRepository,
|
|
|
|
|
+ protected ProductRepository $productRepository,
|
|
|
|
|
+ protected ChannelRepository $channelRepository,
|
|
|
|
|
+ ) {}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取首页完整数据
|
|
|
|
|
+ *
|
|
|
|
|
+ * GET /api/home
|
|
|
|
|
+ * Header: X-Channel: default|wap
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return JsonResponse
|
|
|
|
|
+ */
|
|
|
|
|
+ public function index(): JsonResponse
|
|
|
|
|
+ {
|
|
|
|
|
+ $locale = core()->getRequestedLocaleCode();
|
|
|
|
|
+
|
|
|
|
|
+ // 通过 X-Channel header 区分 PC(default) / M(wap) 端
|
|
|
|
|
+ $channelCode = request()->header('X-Channel', 'default');
|
|
|
|
|
+ $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;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 获取分类树(供导航使用)
|
|
|
|
|
+ $categories = $this->categoryRepository->getVisibleCategoryTree(
|
|
|
|
|
+ $channel->root_category_id
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'success' => true,
|
|
|
|
|
+ 'data' => [
|
|
|
|
|
+ 'channel' => $channel->code,
|
|
|
|
|
+ 'sections' => $sections,
|
|
|
|
|
+ 'categories' => $this->formatCategoryTree($categories),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 格式化单个主题区块
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function formatSection($item, string $locale): ?array
|
|
|
|
|
+ {
|
|
|
|
|
+ $base = [
|
|
|
|
|
+ 'id' => $item->id,
|
|
|
|
|
+ 'type' => $item->type,
|
|
|
|
|
+ 'name' => $item->name,
|
|
|
|
|
+ 'sort_order'=> (int) $item->sort_order,
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ $options = $item->translate($locale)?->options ?? [];
|
|
|
|
|
+
|
|
|
|
|
+ switch ($item->type) {
|
|
|
|
|
+ case 'image_carousel':
|
|
|
|
|
+ return array_merge($base, [
|
|
|
|
|
+ 'images' => $options['images'] ?? [],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ case 'static_content':
|
|
|
|
|
+ return array_merge($base, [
|
|
|
|
|
+ 'html' => $options['html'] ?? '',
|
|
|
|
|
+ 'css' => $options['css'] ?? '',
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ case 'category_carousel':
|
|
|
|
|
+ return array_merge($base, [
|
|
|
|
|
+ 'images' => $options['images'] ?? [],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ case 'product_carousel':
|
|
|
|
|
+ $filters = $options['filters'] ?? [];
|
|
|
|
|
+ return array_merge($base, [
|
|
|
|
|
+ 'title' => $options['title'] ?? '',
|
|
|
|
|
+ 'products' => $this->getProductCarouselData($filters),
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ case 'services_content':
|
|
|
|
|
+ return array_merge($base, [
|
|
|
|
|
+ 'services' => $options['services'] ?? [],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取产品轮播数据
|
|
|
|
|
+ */
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $products = $this->productRepository->getAll($params);
|
|
|
|
|
+
|
|
|
|
|
+ return $products->map(function ($product) {
|
|
|
|
|
+ $image = $product->images->first()
|
|
|
|
|
+ ?? $product->base_image;
|
|
|
|
|
+
|
|
|
|
|
+ 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();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 格式化分类树
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function formatCategoryTree($categories): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $result = [];
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($categories as $category) {
|
|
|
|
|
+ $node = [
|
|
|
|
|
+ 'id' => $category->id,
|
|
|
|
|
+ 'name' => $category->name,
|
|
|
|
|
+ 'slug' => $category->slug,
|
|
|
|
|
+ 'description' => $category->description,
|
|
|
|
|
+ 'image_url' => $category->image_url,
|
|
|
|
|
+ 'banner_url' => $category->banner_url,
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ if ($category->children && $category->children->count() > 0) {
|
|
|
|
|
+ $node['children'] = $this->formatCategoryTree($category->children);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $result[] = $node;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $result;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|