bianjunhui před 5 dny
rodič
revize
35d45bb4d9

+ 8 - 2
packages/Webkul/BagistoApi/src/Models/ProductReview.php

@@ -27,11 +27,14 @@ use ApiPlatform\OpenApi\Model\Operation;
             openapi: new Operation(
             openapi: new Operation(
                 tags: ['Product'],
                 tags: ['Product'],
                 summary: 'List product reviews',
                 summary: 'List product reviews',
-                description: 'Returns product reviews. Defaults to `approved` reviews only; pass `status` to override. Supports filtering by `product_id`, `status`, and `rating`, with `page` + `per_page` (alias `limit`, max 50) pagination. Mirrors the GraphQL `productReviews` query.',
+                description: 'Returns product reviews. Defaults to `approved` reviews only; pass `status` to override. Supports filtering by `product_id`, `status`, `rating`, `has_images`, and `attachment_type`, with `page` + `per_page` (alias `limit`, max 50) pagination. Mirrors the GraphQL `productReviews` query.',
                 parameters: [
                 parameters: [
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'product_id', in: 'query', description: 'Filter by product ID', required: false, schema: ['type' => 'integer', 'example' => 1]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'product_id', in: 'query', description: 'Filter by product ID', required: false, schema: ['type' => 'integer', 'example' => 1]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'status', in: 'query', description: 'Filter by status. Defaults to `approved` when omitted.', required: false, schema: ['type' => 'string', 'enum' => ['approved', 'pending'], 'example' => 'approved']),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'status', in: 'query', description: 'Filter by status. Defaults to `approved` when omitted.', required: false, schema: ['type' => 'string', 'enum' => ['approved', 'pending'], 'example' => 'approved']),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'rating', in: 'query', description: 'Filter by star rating (1-5)', required: false, schema: ['type' => 'integer', 'minimum' => 1, 'maximum' => 5, 'example' => 5]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'rating', in: 'query', description: 'Filter by star rating (1-5)', required: false, schema: ['type' => 'integer', 'minimum' => 1, 'maximum' => 5, 'example' => 5]),
+                    new \ApiPlatform\OpenApi\Model\Parameter(name: 'has_images', in: 'query', description: 'Only return reviews that have image attachments when set to true (Photos filter). Accepts true/false/1/0.', required: false, schema: ['type' => 'boolean', 'example' => true]),
+                    new \ApiPlatform\OpenApi\Model\Parameter(name: 'attachment_type', in: 'query', description: 'Filter by attachment media type (image or video).', required: false, schema: ['type' => 'string', 'enum' => ['image', 'video'], 'example' => 'image']),
+                    new \ApiPlatform\OpenApi\Model\Parameter(name: 'sort', in: 'query', description: 'Sort reviews. `newest` sorts by created_at descending; default sorts by id ascending.', required: false, schema: ['type' => 'string', 'enum' => ['newest', 'oldest'], 'example' => 'newest']),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'page', in: 'query', description: 'Page number (1-based)', required: false, schema: ['type' => 'integer', 'default' => 1, 'example' => 1]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'page', in: 'query', description: 'Page number (1-based)', required: false, schema: ['type' => 'integer', 'default' => 1, 'example' => 1]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'per_page', in: 'query', description: 'Items per page (alias: `limit`). Default 30, max 50.', required: false, schema: ['type' => 'integer', 'default' => 30, 'maximum' => 50, 'example' => 10]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'per_page', in: 'query', description: 'Items per page (alias: `limit`). Default 30, max 50.', required: false, schema: ['type' => 'integer', 'default' => 30, 'maximum' => 50, 'example' => 10]),
                 ],
                 ],
@@ -263,10 +266,13 @@ use ApiPlatform\OpenApi\Model\Operation;
             openapi: new Operation(
             openapi: new Operation(
                 tags: ['Product'],
                 tags: ['Product'],
                 summary: 'List reviews for a product',
                 summary: 'List reviews for a product',
-                description: 'Returns reviews scoped to the given product ID. Defaults to `approved` reviews only; pass `status` to override. Supports filtering by `status` and `rating`, with `page` + `per_page` (alias `limit`, max 50) pagination.',
+                description: 'Returns reviews scoped to the given product ID. Defaults to `approved` reviews only; pass `status` to override. Supports filtering by `status`, `rating`, `has_images`, and `attachment_type`, with `page` + `per_page` (alias `limit`, max 50) pagination.',
                 parameters: [
                 parameters: [
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'status', in: 'query', description: 'Filter by status. Defaults to `approved` when omitted.', required: false, schema: ['type' => 'string', 'enum' => ['approved', 'pending'], 'example' => 'approved']),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'status', in: 'query', description: 'Filter by status. Defaults to `approved` when omitted.', required: false, schema: ['type' => 'string', 'enum' => ['approved', 'pending'], 'example' => 'approved']),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'rating', in: 'query', description: 'Filter by star rating (1-5)', required: false, schema: ['type' => 'integer', 'minimum' => 1, 'maximum' => 5, 'example' => 5]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'rating', in: 'query', description: 'Filter by star rating (1-5)', required: false, schema: ['type' => 'integer', 'minimum' => 1, 'maximum' => 5, 'example' => 5]),
+                    new \ApiPlatform\OpenApi\Model\Parameter(name: 'has_images', in: 'query', description: 'Only return reviews that have image attachments when set to true (Photos filter). Accepts true/false/1/0.', required: false, schema: ['type' => 'boolean', 'example' => true]),
+                    new \ApiPlatform\OpenApi\Model\Parameter(name: 'attachment_type', in: 'query', description: 'Filter by attachment media type (image or video).', required: false, schema: ['type' => 'string', 'enum' => ['image', 'video'], 'example' => 'image']),
+                    new \ApiPlatform\OpenApi\Model\Parameter(name: 'sort', in: 'query', description: 'Sort reviews. `newest` sorts by created_at descending; default sorts by id ascending.', required: false, schema: ['type' => 'string', 'enum' => ['newest', 'oldest'], 'example' => 'newest']),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'page', in: 'query', description: 'Page number (1-based)', required: false, schema: ['type' => 'integer', 'default' => 1, 'example' => 1]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'page', in: 'query', description: 'Page number (1-based)', required: false, schema: ['type' => 'integer', 'default' => 1, 'example' => 1]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'per_page', in: 'query', description: 'Items per page (alias: `limit`). Default 30, max 50.', required: false, schema: ['type' => 'integer', 'default' => 30, 'maximum' => 50, 'example' => 10]),
                     new \ApiPlatform\OpenApi\Model\Parameter(name: 'per_page', in: 'query', description: 'Items per page (alias: `limit`). Default 30, max 50.', required: false, schema: ['type' => 'integer', 'default' => 30, 'maximum' => 50, 'example' => 10]),
                 ],
                 ],

+ 26 - 1
packages/Webkul/BagistoApi/src/State/ProductReviewProvider.php

@@ -45,6 +45,24 @@ class ProductReviewProvider implements ProviderInterface
             $query->where('rating', (int) $args['rating']);
             $query->where('rating', (int) $args['rating']);
         }
         }
 
 
+        // 仅返回带图片附件的评论(前端 Photos 筛选)
+        if (! empty($args['has_images'])) {
+            $hasImages = filter_var($args['has_images'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+
+            if ($hasImages === true) {
+                $query->has('images');
+            } elseif ($hasImages === false) {
+                $query->doesntHave('images');
+            }
+        }
+        // 按附件类型过滤:image / video
+        if (! empty($args['attachment_type'])) {
+            $type = (string) $args['attachment_type'];
+            $query->whereHas('images', function ($q) use ($type) {
+                $q->where('type', $type);
+            });
+        }
+
         // Eager load relationships
         // Eager load relationships
         $query->with(['product', 'customer']);
         $query->with(['product', 'customer']);
 
 
@@ -81,8 +99,15 @@ class ProductReviewProvider implements ProviderInterface
             }
             }
         }
         }
 
 
-        $query->orderBy('id', 'asc');
+        // 排序:sort=newest(按创建时间倒序)或 sort=oldest(默认,按 id 升序)
+        $sort = $args['sort'] ?? null;
 
 
+        /*if ($sort !== null && strtolower((string) $sort) === 'newest') {
+            $query->orderBy('created_at', 'desc')->orderBy('id', 'desc');
+        } else {
+            $query->orderBy('id', 'asc');
+        }*/
+        $query->orderBy('created_at', 'desc')->orderBy('id', 'desc');
         $total = (clone $query)->count();
         $total = (clone $query)->count();
 
 
         if ($offset > $total) {
         if ($offset > $total) {