From bf2cff4de3f9c2056aaee39a7942a91425076306 Mon Sep 17 00:00:00 2001 From: jsasg <735273025@qq.com> Date: Thu, 13 Feb 2025 11:57:54 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E4=BA=A7?= =?UTF-8?q?=E5=93=81=E6=8E=A5=E5=8F=A3=E6=B7=BB=E5=8A=A0sku=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/v1/Product.php | 91 +++++++++--- app/admin/model/v1/ProductSkuAttrModel.php | 15 ++ app/admin/model/v1/ProductSkuModel.php | 24 ++++ app/admin/validate/v1/ProductValidate.php | 131 ++++++++++++------ app/common/model/ProductSkuAttrBaseModel.php | 6 +- ...20241219074458_create_product_sku_attr.php | 2 +- 6 files changed, 205 insertions(+), 64 deletions(-) create mode 100644 app/admin/model/v1/ProductSkuAttrModel.php create mode 100644 app/admin/model/v1/ProductSkuModel.php diff --git a/app/admin/controller/v1/Product.php b/app/admin/controller/v1/Product.php index a02ea5aa..3e169fd9 100644 --- a/app/admin/controller/v1/Product.php +++ b/app/admin/controller/v1/Product.php @@ -6,6 +6,8 @@ namespace app\admin\controller\v1; use app\admin\model\v1\ProductModel; use app\admin\model\v1\ProductParamsModel; use app\admin\model\v1\ProductRelatedModel; +use app\admin\model\v1\ProductSkuAttrModel; +use app\admin\model\v1\ProductSkuModel; use app\admin\validate\v1\ProductValidate; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -123,19 +125,22 @@ class Product 'is_show', 'sort', 'detail', - 'params' => '', + 'params' => '', + 'skus' => '', 'related' => '', - 'status' => 1, + 'status' => 1, 'seo_title', 'seo_keywords', 'seo_desc' ]); + $put = array_merge( + $put, + ['skus' => json_decode($put['skus'], true)], + ['related' => json_decode($put['related'], true)], + ); $validate = new ProductValidate(); - $check_data = array_merge($put, [ - 'id' => $id, - 'language_id' => request()->lang_id - ]); + $check_data = array_merge($put, ['id' => $id, 'language_id' => request()->lang_id]); if (!$validate->scene('update')->check($check_data)) { return error($validate->getError()); } @@ -160,24 +165,72 @@ class Product 'value' => $match_result[2][$i] ]; } - if (!empty($params)) ProductParamsModel::insertAll($params); + if (!empty($params)) { + ProductParamsModel::insertAll($params); + } + } + } + + // 更新SKU + if (!empty($put['skus'])) { + $skus = []; + $attrs_group = []; + foreach ($put['skus'] as $val) { + $skus[] = [ + 'product_id' => $id, + 'sku' => $val['sku'], + 'main_image' => $val['main_image'], + 'photo_album' => $val['photo_album'], + 'sort' => $val['sort'] + ]; + foreach ($val['attrs'] as $v) { + $attrs_group[$val['sku']][] = [ + 'attr_id' => $v['attr_id'], + 'attr_value' => $v['attr_value'] + ]; + } + } + if (!empty($skus)) { + $sku_model = new ProductSkuModel; + // 删除原有SKU + $sku_model->productId($id)->delete(); + // 添加SKU + $save_ret = $sku_model->saveAll($skus); + if (!$save_ret->isEmpty()) { + $sku_map = []; + foreach ($save_ret as $val) { + $sku_map[$val->sku] = $val->id; + } + $attrs = []; + foreach ($attrs_group as $sku => $sku_attrs) { + if (empty($sku_map[$sku])) { + unset($attrs_group[$sku]); + continue; + } + foreach ($sku_attrs as $k => $v) { + $attrs[] = array_merge($v, ['sku_id' => $sku_map[$sku]]); + } + } + (new ProductSkuAttrModel)->saveAll($attrs); + } } } // 更新关联产品 - if ($put['related'] != "") { + if (!empty($put['related'])) { + // 删除原有关联产品 ProductRelatedModel::productId($id)->delete(); - $encode_result = json_decode($put['related'], true); - if (!empty($encode_result)) { - $related = []; - foreach ($encode_result as $val) { - $related[] = [ - 'product_id' => $id, - 'related_product_id' => $val['related_product_id'], - 'sort' => $val['sort'] - ]; - } - if (!empty($related)) ProductRelatedModel::insertAll($related); + // 添加关联产品 + $related = []; + foreach ($put['related'] as $val) { + $related[] = [ + 'product_id' => $id, + 'related_product_id' => $val['related_product_id'], + 'sort' => $val['sort'] + ]; + } + if (!empty($related)) { + ProductRelatedModel::insertAll($related); } } diff --git a/app/admin/model/v1/ProductSkuAttrModel.php b/app/admin/model/v1/ProductSkuAttrModel.php new file mode 100644 index 00000000..289f9006 --- /dev/null +++ b/app/admin/model/v1/ProductSkuAttrModel.php @@ -0,0 +1,15 @@ +where('product_id', '=', $id); + } +} diff --git a/app/admin/validate/v1/ProductValidate.php b/app/admin/validate/v1/ProductValidate.php index 5904f7af..572dcc14 100644 --- a/app/admin/validate/v1/ProductValidate.php +++ b/app/admin/validate/v1/ProductValidate.php @@ -5,6 +5,8 @@ namespace app\admin\validate\v1; use think\Validate; +use function PHPSTORM_META\type; + class ProductValidate extends Validate { /** @@ -14,25 +16,31 @@ class ProductValidate extends Validate * @var array */ protected $rule = [ - 'language_id' => 'require|integer', - 'category_id' => 'integer', - 'spu' => 'require|max:255', - 'name' => 'require|max:125', - 'short_name' => 'max:64', - 'cover_image' => 'max:255', - 'desc' => 'max:255', - 'video_img' => 'max:255', - 'video_url' => 'max:255', - 'is_sale' => 'in:0,1', - 'is_new' => 'in:0,1', - 'is_hot' => 'in:0,1', - 'sort' => 'integer', - 'detail' => 'max:65535', - 'status' => 'in:-1,1', - 'seo_title' => 'max:255', - 'seo_keywords' => 'max:255', - 'seo_desc' => 'max:255', - 'created_at' => 'checkFormatDatetimeRange' + 'language_id' => 'require|integer', + 'category_id' => 'integer', + 'spu' => 'require|max:255', + 'name' => 'require|max:125', + 'short_name' => 'max:64', + 'cover_image' => 'max:255', + 'desc' => 'max:255', + 'video_img' => 'max:255', + 'video_url' => 'max:255', + 'is_sale' => 'in:0,1', + 'is_new' => 'in:0,1', + 'is_hot' => 'in:0,1', + 'sort' => 'integer', + 'detail' => 'max:65535', + 'status' => 'in:-1,1', + 'seo_title' => 'max:255', + 'seo_keywords' => 'max:255', + 'seo_desc' => 'max:255', + 'created_at' => 'checkFormatDatetimeRange', + 'skus.*.sku' => 'max:125', + 'skus.*.main_image' => 'max:255', + 'skus.*.sort' => 'integer', + 'skus.*.attrs' => 'checkSkusAttrsItemType:attr_id,integer|checkSkusAttrsItemMax:attr_value,64', + 'related.*.related_product_id' => 'integer', + 'related.*.sort' => 'integer', ]; /** @@ -42,28 +50,35 @@ class ProductValidate extends Validate * @var array */ protected $message = [ - 'language_id.require' => '语言ID不能为空', - 'language_id.integer' => '语言ID必须为整数', - 'category_id.integer' => '分类ID必须为整数', - 'spu.require' => 'spu不能为空', - 'spu.max' => 'spu不能超过255个字符', - 'name.require' => '名称不能为空', - 'name.max' => '名称不能超过125个字符', - 'short_name.max' => '短标题不能超过64个字符', - 'cover_image.max' => '封面图不能超过255个字符', - 'desc.max' => '描述不能超过255个字符', - 'video_img.max' => '视频封面图不能超过255个字符', - 'video_url.max' => '视频地址不能超过255个字符', - 'is_sale.in' => '上架状态值错误', - 'is_new.in' => '新品状态值错误', - 'is_hot.in' => '热门状态值错误', - 'sort.integer' => '排序值类型错误', - 'detail.max' => '详情不能超过65535个字符', - 'status.in' => '状态值错误', - 'seo_title.max' => 'seo标题不能超过255个字符', - 'seo_keywords.max' => 'seo关键字不能超过255个字符', - 'seo_desc.max' => 'seo描述不能超过255个字符', - 'created_at.checkFormatDatetimeRange' => '添加时间格式错误' + 'language_id.require' => '语言ID不能为空', + 'language_id.integer' => '语言ID必须为整数', + 'category_id.integer' => '分类ID必须为整数', + 'spu.require' => 'spu不能为空', + 'spu.max' => 'spu不能超过255个字符', + 'name.require' => '名称不能为空', + 'name.max' => '名称不能超过125个字符', + 'short_name.max' => '短标题不能超过64个字符', + 'cover_image.max' => '封面图不能超过255个字符', + 'desc.max' => '描述不能超过255个字符', + 'video_img.max' => '视频封面图不能超过255个字符', + 'video_url.max' => '视频地址不能超过255个字符', + 'is_sale.in' => '上架状态值错误', + 'is_new.in' => '新品状态值错误', + 'is_hot.in' => '热门状态值错误', + 'sort.integer' => '排序值类型错误', + 'detail.max' => '详情不能超过65535个字符', + 'status.in' => '状态值错误', + 'seo_title.max' => 'seo标题不能超过255个字符', + 'seo_keywords.max' => 'seo关键字不能超过255个字符', + 'seo_desc.max' => 'seo描述不能超过255个字符', + 'created_at.checkFormatDatetimeRange' => '添加时间格式错误', + 'skus.*.sku.max' => 'sku不能超过125个字符', + 'skus.*.main_image.max' => 'sku主图不能超过255个字符', + 'skus.*.sort.integer' => 'sku排序值类型错误', + 'skus.*.attrs.checkSkusAttrsItemType' => 'sku属性值错误', + 'skus.*.attrs.checkSkusAttrsItemMax' => 'sku属性值错误', + 'related.*.related_product_id.integer' => '关联产品ID格式错误', + 'related.*.sort.integer' => '关联产品排序值类型错误', ]; /** @@ -98,6 +113,12 @@ class ProductValidate extends Validate 'seo_title', 'seo_keywords', 'seo_desc', + 'skus.*.sku', + 'skus.*.main_image', + 'skus.*.sort', + 'skus.*.attrs', + 'related.*.related_product_id', + 'related.*.sort' ]); } @@ -116,4 +137,32 @@ class ProductValidate extends Validate return true; } + + protected function checkSkusAttrsItemType($value, $rule, $data) + { + $rule = explode(',', $rule); + foreach ($value as $v) { + if (!array_key_exists($rule[0], $v)) { + return 'sku属性值错误'; + } + if ($rule[1] == gettype($rule[0])) { + return "sku中{$rule[0]}类型错误"; + } + } + return true; + } + + protected function checkSkusAttrsItemMax($value, $rule, $data) + { + $rule = explode(',', $rule); + foreach ($value as $v) { + if (!array_key_exists($rule[0], $v)) { + return 'sku属性值错误'; + } + if (intval($rule[1]) < mb_strlen($v[$rule[0]], 'utf8')) { + return "sku属性{$rule[0]}不能超过{$rule[1]}个字符"; + } + } + return true; + } } diff --git a/app/common/model/ProductSkuAttrBaseModel.php b/app/common/model/ProductSkuAttrBaseModel.php index 751f9641..31297919 100644 --- a/app/common/model/ProductSkuAttrBaseModel.php +++ b/app/common/model/ProductSkuAttrBaseModel.php @@ -16,8 +16,8 @@ class ProductSkuAttrBaseModel extends Model // 字段信息 protected $schema = [ - 'sku_id' => 'int', - 'attr_id' => 'int', - 'prop_id' => 'int', + 'sku_id' => 'int', + 'attr_id' => 'int', + 'attr_value' => 'string', ]; } diff --git a/database/migrations/20241219074458_create_product_sku_attr.php b/database/migrations/20241219074458_create_product_sku_attr.php index 70d01c4b..f451e5d7 100644 --- a/database/migrations/20241219074458_create_product_sku_attr.php +++ b/database/migrations/20241219074458_create_product_sku_attr.php @@ -30,7 +30,7 @@ class CreateProductSkuAttr extends Migrator $table = $this->table('product_sku_attr', ['id' => false,'engine' => 'InnoDB', 'comment' => '产品SKU属性表']); $table->addColumn('sku_id', 'integer', ['signed' => false, 'null' => false, 'comment' => '产品SKU ID']) ->addColumn('attr_id', 'integer', ['signed' => false, 'null' => false, 'comment' => '属性ID']) - ->addColumn('prop_id', 'integer', ['signed' => false, 'null' => false, 'comment' => '属性特征ID']) + ->addColumn('attr_value', 'string', ['limit' => 64, 'null' => false, 'default' => '', 'comment' => '属性值']) ->addForeignKey('sku_id', 'product_sku', 'id', ['update' => 'CASCADE', 'delete' => 'CASCADE']) ->create(); }