From 6b41a963e793bbd91217db79a3028cb4641c9f92 Mon Sep 17 00:00:00 2001 From: jsasg <735273025@qq.com> Date: Tue, 20 May 2025 14:41:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=80=E6=94=BEAPI=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/openapi/controller/v1/Product.php | 174 ++++++++++++++++++ app/openapi/controller/v1/ProductCategory.php | 51 +++++ app/openapi/model/LanguageModel.php | 19 ++ app/openapi/model/ProductCategoryModel.php | 33 ++++ app/openapi/model/ProductModel.php | 62 +++++++ app/openapi/model/ProductParamsModel.php | 15 ++ .../model/ProductPurchaseLinkModel.php | 19 ++ .../model/ProductPurchasePlatformModel.php | 15 ++ app/openapi/model/ProductRelatedModel.php | 19 ++ app/openapi/model/ProductSkuAttrModel.php | 19 ++ app/openapi/model/ProductSkuModel.php | 19 ++ app/openapi/route/v1.php | 4 +- 12 files changed, 447 insertions(+), 2 deletions(-) create mode 100644 app/openapi/controller/v1/Product.php create mode 100644 app/openapi/controller/v1/ProductCategory.php create mode 100644 app/openapi/model/LanguageModel.php create mode 100644 app/openapi/model/ProductCategoryModel.php create mode 100644 app/openapi/model/ProductModel.php create mode 100644 app/openapi/model/ProductParamsModel.php create mode 100644 app/openapi/model/ProductPurchaseLinkModel.php create mode 100644 app/openapi/model/ProductPurchasePlatformModel.php create mode 100644 app/openapi/model/ProductRelatedModel.php create mode 100644 app/openapi/model/ProductSkuAttrModel.php create mode 100644 app/openapi/model/ProductSkuModel.php diff --git a/app/openapi/controller/v1/Product.php b/app/openapi/controller/v1/Product.php new file mode 100644 index 00000000..1a33bc15 --- /dev/null +++ b/app/openapi/controller/v1/Product.php @@ -0,0 +1,174 @@ +get([ + 'category_id', + 'language' => 'zh-cn', + 'page/d' => 1, + 'size/d' => 50 + ]); + + if ($params['size'] > 200) { + // 每页不超过200条 + $params['size'] = 200; + } + + $list = ProductModel::with([ + 'category' => fn($query) => $query->field(['id', 'name']), + ]) + ->field([ + 'id', + 'category_id', + 'spu', + 'name', + 'short_name', + 'cover_image', + 'desc', + 'deleted_at' + ]) + ->where(function($query) use($params) { + $model = $query->getModel(); + if (!empty($params['category_id'])) { + $model->scopeCategoryId($query, $params['category_id']); + } + }) + ->language($params['language']??'zh-cn') + ->order(['sort' => 'asc', 'id' => 'desc']) + ->hidden(['category_id']) + ->paginate([ + 'list_row' => $params['size'], + 'page' => $params['page'] + ]) + ->each(function($item) { + if (!empty($item['cover_image']) && !str_starts_with($item['cover_image'], 'http')) { + $item['cover_image'] = image_domain_concat($item['cover_image']); + } + + return $item; + }); + + return success('success', $list); + } + + /** + * 产品详情 + */ + public function detail() + { + $id = request()->param('id'); + + $product = ProductModel::with([ + // 关联分类 + 'category' => fn($query) => $query->field(['id', 'name']), + // 关联属性 + 'params' => fn($query) => $query->field(['product_id', 'name', 'value']) + ->hidden(['product_id']), + // 关联sku + 'skus' => fn($query) => $query->withoutField(['created_at', 'updated_at']) + ->with([ + 'sku_attr' => fn($query) => $query->with('attr')->hidden(['sku_id', 'attr_id']) + ]) + ->hidden(['id', 'product_id']), + // 关联购买链接 + 'links' => fn($query) => $query->field(['product_id', 'platform_id', 'link']) + ->with(['platform' => fn($query) => $query->field(['id', 'platform'])]) + ->hidden(['product_id', 'platform_id']), + // 关联相关产品 + 'related' => fn($query) => $query->field(['product_id', 'related_product_id']) + ->with([ + 'product' => fn($query) => $query->field(['id', 'name', 'spu', 'cover_image'])->withBind([ + 'id', + 'name', + 'spu', + 'cover_image' + ]) + ]) + ->hidden(['product_id', 'related_product_id']) + ]) + ->withoutField([ + 'language_id', + 'stock_qty', + 'seo_title', + 'seo_keywords', + 'seo_desc', + 'created_at', + 'updated_at', + 'deleted_at' + ]) + ->bypk($id) + ->hidden(['category_id']) + ->find(); + + // 处理封面图 + if (!empty($product['cover_image']) && !str_starts_with($product['cover_image'], 'http')) { + $product['cover_image'] = image_domain_concat($product['cover_image']); + } + + // 处理视频图片 + if (!empty($product['video_img']) && !str_starts_with($product['video_img'], 'http')) { + $product['video_img'] = image_domain_concat($product['video_img']); + } + + // 处理视频 + if (!empty($product['video_url']) && !str_starts_with($product['video_url'], 'http')) { + $product['video_url'] = video_domain_concat($product['video_url']); + } + + // 处理详情内容中图片 + if (!empty($product['detail'])) { + $product['detail'] = html_image_replace($product['detail']); + } + + // 处理sku中图片 + if (!empty($product['skus'])) { + $skus = $product['skus']->toArray(); + foreach ($skus as $key => $sku) { + // sku二级列表图 + if (!empty($sku['main_image']) && !str_starts_with($sku['main_image'], 'http')) { + $skus[$key]['main_image'] = image_domain_concat($sku['main_image']); + } + // sku相册图 + if (!empty($sku['photo_album'])) { + $photo_album = json_decode($sku['photo_album'], true); + foreach ($photo_album as $idx => $photo) { + if (!empty($photo) && !str_starts_with($photo, 'http')) { + $photo_album[$idx] = image_domain_concat($photo); + } + } + $skus[$key]['photo_album'] = $photo_album; + } + // sku属性图片 + foreach ($sku['sku_attr'] as $idx => $attr) { + if (!empty($attr['attr_value']) && !str_starts_with($attr['attr_value'], 'http')) { + $skus[$key]['sku_attr'][$idx]['attr_value'] = image_domain_concat($attr['attr_value']); + } + } + } + $product['skus'] = $skus; + } + + // 处理相关产品中图片 + if (!empty($product['related'])) { + $related = $product['related']->toArray(); + foreach ($related as $key => $item) { + if (!empty($item['cover_image']) && !str_starts_with($item['cover_image'], 'http')) { + $related[$key]['cover_image'] = image_domain_concat($item['cover_image']); + } + } + $product['related'] = $related; + } + + return success('success', $product); + } +} diff --git a/app/openapi/controller/v1/ProductCategory.php b/app/openapi/controller/v1/ProductCategory.php new file mode 100644 index 00000000..98722c89 --- /dev/null +++ b/app/openapi/controller/v1/ProductCategory.php @@ -0,0 +1,51 @@ +get([ + 'parent_id', + 'language' => 'zh-cn', + 'page' => 1, + 'size' => 50 + ]); + + if ($params['size'] > 200) { + // 每页不超过200条 + $params['size'] = 200; + } + + $categories = ProductCategoryModel::withoutField([ + 'language_id', + 'unique_id', + 'related_tco_category', + 'created_at', + 'updated_at', + 'deleted_at' + ]) + ->language($params['language']??'zh-cn') + ->parent($params['parent_id']??null) + ->paginate([ + 'list_rows' => $params['size'], + 'page' => $params['page'] + ]) + ->each(function($item) { + if (!empty($item['icon']) && !str_starts_with($item['icon'], 'http')) { + $item['icon'] = image_domain_concat($item['icon']); + } + + return $item; + }); + + return success('success', $categories); + } +} diff --git a/app/openapi/model/LanguageModel.php b/app/openapi/model/LanguageModel.php new file mode 100644 index 00000000..d2a008b6 --- /dev/null +++ b/app/openapi/model/LanguageModel.php @@ -0,0 +1,19 @@ +where('code', '=', $code); + } +} diff --git a/app/openapi/model/ProductCategoryModel.php b/app/openapi/model/ProductCategoryModel.php new file mode 100644 index 00000000..3769953a --- /dev/null +++ b/app/openapi/model/ProductCategoryModel.php @@ -0,0 +1,33 @@ +whereExists(function($subquery) use($language) { + $lang_model = new LanguageModel; + $subquery->model($lang_model) + ->name($lang_model->getName()) + ->where('id', '=', Db::Raw($this->getTable() . '.language_id')) + ->where('code', '=', $language); + }); + } + + // 所属上级范围查询 + public function scopeParent($query, $parent_id) + { + if (is_null($parent_id)) return; + $query->where('pid', '=', $parent_id); + } +} diff --git a/app/openapi/model/ProductModel.php b/app/openapi/model/ProductModel.php new file mode 100644 index 00000000..918566c5 --- /dev/null +++ b/app/openapi/model/ProductModel.php @@ -0,0 +1,62 @@ +belongsTo(ProductCategoryModel::class, 'category_id', 'id'); + } + + // 关联产品参数 + public function params() + { + return $this->hasMany(ProductParamsModel::class, 'product_id', 'id'); + } + + // 关联sku + public function skus() + { + return $this->hasMany(ProductSkuModel::class, 'product_id', 'id'); + } + + // 关联购买链接 + public function links() + { + return $this->hasMany(ProductPurchaseLinkModel::class, 'product_id', 'id'); + } + + // 关联相关产品 + public function related() + { + return $this->hasMany(ProductRelatedModel::class, 'product_id', 'id'); + } + + // 根据所属语言范围查询 + public function scopeLanguage($query, $language) + { + $query->whereExists(function($subquery) use($language) { + $lang_model = new LanguageModel; + $subquery->model($lang_model) + ->name($lang_model->getName()) + ->where('id', '=', Db::Raw($this->getTable() . '.language_id')) + ->where('code', '=', $language); + }); + } + + // 根据category_id范围查询 + public function scopeCategoryId($query, $category_id) + { + $query->where('category_id', '=', $category_id); + } +} diff --git a/app/openapi/model/ProductParamsModel.php b/app/openapi/model/ProductParamsModel.php new file mode 100644 index 00000000..0b88a828 --- /dev/null +++ b/app/openapi/model/ProductParamsModel.php @@ -0,0 +1,15 @@ +belongsTo(ProductPurchasePlatformModel::class, 'platform_id', 'id')->bind(['platform']); + } +} diff --git a/app/openapi/model/ProductPurchasePlatformModel.php b/app/openapi/model/ProductPurchasePlatformModel.php new file mode 100644 index 00000000..ab24cc2a --- /dev/null +++ b/app/openapi/model/ProductPurchasePlatformModel.php @@ -0,0 +1,15 @@ +belongsTo(ProductModel::class, 'related_product_id', 'id'); + } +} diff --git a/app/openapi/model/ProductSkuAttrModel.php b/app/openapi/model/ProductSkuAttrModel.php new file mode 100644 index 00000000..b88524c0 --- /dev/null +++ b/app/openapi/model/ProductSkuAttrModel.php @@ -0,0 +1,19 @@ +belongsTo(\app\common\model\ProductAttrBaseModel::class, 'attr_id', 'id')->bind(['attr_name']); + } +} diff --git a/app/openapi/model/ProductSkuModel.php b/app/openapi/model/ProductSkuModel.php new file mode 100644 index 00000000..d75680cb --- /dev/null +++ b/app/openapi/model/ProductSkuModel.php @@ -0,0 +1,19 @@ +hasMany(ProductSkuAttrModel::class, 'sku_id', 'id'); + } +} diff --git a/app/openapi/route/v1.php b/app/openapi/route/v1.php index 765b966d..1c5fc6b7 100644 --- a/app/openapi/route/v1.php +++ b/app/openapi/route/v1.php @@ -12,10 +12,10 @@ Route::group('v1', function() { Route::get('products', 'v1.Product/list'); Route::group('product', function() { // 获取产品信息 - Route::get(':id', 'v1.Product/detail'); + Route::get(':id', 'v1.Product/detail')->when('id', 'number'); // 获取产品分类 - Route::get('categories', 'v1.Product/categories'); + Route::get('categories', 'v1.ProductCategory/list'); }); // 获取新闻动态