refactor: 更新产品接口添加sku处理逻辑
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
15
app/admin/model/v1/ProductSkuAttrModel.php
Normal file
15
app/admin/model/v1/ProductSkuAttrModel.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use app\common\model\ProductSkuAttrBaseModel;
|
||||
|
||||
/**
|
||||
* 产品 - sku属性模型
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ProductSkuAttrModel extends ProductSkuAttrBaseModel
|
||||
{
|
||||
//
|
||||
}
|
||||
24
app/admin/model/v1/ProductSkuModel.php
Normal file
24
app/admin/model/v1/ProductSkuModel.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use app\common\model\ProductSkuBaseModel;
|
||||
|
||||
/**
|
||||
* 产品 - sku模型
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ProductSkuModel extends ProductSkuBaseModel
|
||||
{
|
||||
// 设置json类型字段
|
||||
protected $json = ['photo_album'];
|
||||
// 设置JSON数据返回数组
|
||||
protected $jsonAssoc = true;
|
||||
|
||||
// 所属产品查询
|
||||
public function scopeProductId($query, $id)
|
||||
{
|
||||
$query->where('product_id', '=', $id);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user