feat: 新增产品属性增/删/改/查接口
This commit is contained in:
191
app/admin/controller/v1/ProductAttr.php
Normal file
191
app/admin/controller/v1/ProductAttr.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\controller\v1;
|
||||
|
||||
use app\admin\model\v1\ProductAttrModel;
|
||||
use app\admin\model\v1\ProductAttrPropModel;
|
||||
use app\admin\validate\v1\ProductAttrValidate;
|
||||
|
||||
class ProductAttr
|
||||
{
|
||||
/**
|
||||
* 属性列表
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$params = request()->param([
|
||||
'keywords' => '',
|
||||
'page/d' => 1,
|
||||
'size/d' => 10
|
||||
]);
|
||||
$attrs = ProductAttrModel::withoutField([
|
||||
'language_id',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
])
|
||||
->with(['props' => function ($query) {
|
||||
$query->withoutField(['created_at'])->hidden(['attr_id']);
|
||||
}])
|
||||
->language(request()->lang_id)
|
||||
->withSearch(['attr_name_nullable'], [
|
||||
'attr_name_nullable' => $params['keywords']??null,
|
||||
])
|
||||
->paginate([
|
||||
'list_rows' => $params['size'],
|
||||
'page' => $params['page'],
|
||||
]);
|
||||
|
||||
return success("获取成功", $attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性详情
|
||||
*/
|
||||
public function read()
|
||||
{
|
||||
$id = request()->param('id');
|
||||
|
||||
$attr = ProductAttrModel::withoutField([
|
||||
'language_id',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
])
|
||||
->with(['props' => function ($query) {
|
||||
$query->withoutField(['created_at'])->hidden(['attr_id']);
|
||||
}])
|
||||
->find($id);
|
||||
if (empty($attr)) {
|
||||
return error("获取失败");
|
||||
}
|
||||
|
||||
return success("获取成功", $attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性新增
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$post = request()->post([
|
||||
'attr_name' => '',
|
||||
'is_system' => 0,
|
||||
]);
|
||||
$attr = array_merge($post, ['language_id' => request()->lang_id]);
|
||||
|
||||
// $[*].prop_type
|
||||
// $[*].prop_name
|
||||
// $[*].prop_value
|
||||
$props = json_decode(request()->post('props/s', ''), true);
|
||||
|
||||
// 检验参数
|
||||
$validate = new ProductAttrValidate;
|
||||
$check_data = array_merge($attr, ['props' => $props]);
|
||||
if (!$validate->check($check_data)) {
|
||||
return error($validate->getError());
|
||||
}
|
||||
|
||||
ProductAttrModel::startTrans();
|
||||
try {
|
||||
// 添加属性
|
||||
$attr_ret = ProductAttrModel::create($attr);
|
||||
if ($attr_ret->isEmpty()) {
|
||||
throw new \Exception("操作失败");
|
||||
}
|
||||
|
||||
// 添加属性特征
|
||||
foreach ($props as &$prop) {
|
||||
$prop['attr_id'] = $attr_ret->id;
|
||||
}
|
||||
unset($prop);
|
||||
$props_ret = (new ProductAttrPropModel)->saveAll($props);
|
||||
if ($props_ret->isEmpty()) {
|
||||
throw new \Exception("操作失败");
|
||||
}
|
||||
|
||||
ProductAttrModel::commit();
|
||||
} catch (\Throwable $th) {
|
||||
ProductAttrModel::rollback();
|
||||
return error($th->getMessage());
|
||||
}
|
||||
|
||||
return success("操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性更新
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
$id = request()->param('id');
|
||||
$put = request()->put([
|
||||
'attr_name' => '',
|
||||
'is_system' => 0,
|
||||
]);
|
||||
$attr = array_merge($put, ['language_id' => request()->lang_id]);
|
||||
|
||||
// $[*].prop_type
|
||||
// $[*].prop_name
|
||||
// $[*].prop_value
|
||||
$props = json_decode(request()->post('props/s', ''), true);
|
||||
|
||||
// 检验参数
|
||||
$validate = new ProductAttrValidate;
|
||||
$check_data = array_merge($attr, ['id' => $id], ['props' => $props]);
|
||||
if (!$validate->check($check_data)) {
|
||||
return error($validate->getError());
|
||||
}
|
||||
|
||||
ProductAttrModel::startTrans();
|
||||
try {
|
||||
// 更新属性
|
||||
$attr_ret = ProductAttrModel::bypk($id)->find();
|
||||
if ($attr_ret->isEmpty()) {
|
||||
throw new \Exception("请确认操作对象是否正确");
|
||||
}
|
||||
if (!$attr_ret->save($attr)) {
|
||||
throw new \Exception("操作失败");
|
||||
}
|
||||
|
||||
// 删除旧属性特征
|
||||
ProductAttrPropModel::attrId($attr_ret->id)->delete();
|
||||
// 保存新属性特征
|
||||
foreach ($props as &$prop) {
|
||||
$prop['attr_id'] = $attr_ret->id;
|
||||
}
|
||||
unset($prop);
|
||||
$props_ret = (new ProductAttrPropModel)->saveAll($props);
|
||||
if ($props_ret->isEmpty()) {
|
||||
throw new \Exception("操作失败");
|
||||
}
|
||||
|
||||
ProductAttrModel::commit();
|
||||
} catch (\Throwable $th) {
|
||||
ProductAttrModel::rollback();
|
||||
return error($th->getMessage());
|
||||
}
|
||||
|
||||
return success("操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性删除
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$id = request()->param('id');
|
||||
|
||||
// 删除属性
|
||||
$attr = ProductAttrModel::bypk($id)->find();
|
||||
if (empty($attr)) {
|
||||
return error("请确认操作对象是否正确");
|
||||
}
|
||||
if (!$attr->delete()) {
|
||||
return error("操作失败");
|
||||
}
|
||||
|
||||
return success("操作成功");
|
||||
}
|
||||
}
|
||||
39
app/admin/model/v1/ProductAttrModel.php
Normal file
39
app/admin/model/v1/ProductAttrModel.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use app\common\model\ProductAttrBaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* 产品 - 产品属性模型
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ProductAttrModel extends ProductAttrBaseModel
|
||||
{
|
||||
// 启用软删除
|
||||
use SoftDelete;
|
||||
// 软删除字段
|
||||
protected $deleteTime = 'deleted_at';
|
||||
// 修改自动写入时间格式
|
||||
protected $autoWriteTimestamp = 'datetime';
|
||||
|
||||
// 关联属性特征
|
||||
public function props()
|
||||
{
|
||||
return $this->hasMany(ProductAttrPropModel::class, 'attr_id', 'id');
|
||||
}
|
||||
|
||||
// 所属语言查询
|
||||
public function scopeLanguage($query, $value)
|
||||
{
|
||||
$query->where('language_id', '=', $value);
|
||||
}
|
||||
|
||||
// 属性名称模糊搜索
|
||||
public function searchAttrNameNullableAttr($query, $value, $data)
|
||||
{
|
||||
$query->where('attr_name', 'like', "%{$value}%");
|
||||
}
|
||||
}
|
||||
19
app/admin/model/v1/ProductAttrPropModel.php
Normal file
19
app/admin/model/v1/ProductAttrPropModel.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use app\common\model\ProductAttrPropBaseModel;
|
||||
|
||||
/**
|
||||
* 产品 - 产品属性特征模型
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ProductAttrPropModel extends ProductAttrPropBaseModel
|
||||
{
|
||||
// 所属属性查询
|
||||
public function scopeAttrId($query, $value)
|
||||
{
|
||||
$query->where('attr_id', '=', $value);
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,24 @@ Route::group('v1', function () {
|
||||
Route::delete('delete/:id', 'ProductCategory/delete');
|
||||
});
|
||||
|
||||
// 产品属性
|
||||
Route::group('attr', function () {
|
||||
// 属性列表
|
||||
Route::get('index', 'ProductAttr/index');
|
||||
|
||||
// 属性详情
|
||||
Route::get('read/:id', 'ProductAttr/read');
|
||||
|
||||
// 属性新增
|
||||
Route::post('save', 'ProductAttr/save');
|
||||
|
||||
// 属性更新
|
||||
Route::put('update/:id', 'ProductAttr/update');
|
||||
|
||||
// 属性删除
|
||||
Route::delete('delete/:id', 'ProductAttr/delete');
|
||||
});
|
||||
|
||||
// 产品分页列表
|
||||
Route::get('index', 'Product/index');
|
||||
|
||||
|
||||
43
app/admin/validate/v1/ProductAttrValidate.php
Normal file
43
app/admin/validate/v1/ProductAttrValidate.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\validate\v1;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class ProductAttrValidate extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'language_id' => 'require|number',
|
||||
'attr_name' => 'require|max:64',
|
||||
'is_system' => 'in:0,1',
|
||||
'props.*.prop_type' => 'in:1,2',
|
||||
'props.*.prop_name' => 'require|max:64',
|
||||
'props.*.prop_value' => 'require|max:64',
|
||||
];
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'language_id.require' => '语言ID不能为空',
|
||||
'language_id.number' => '语言ID必须是数字',
|
||||
'attr_name.require' => '属性名称不能为空',
|
||||
'attr_name.max' => '属性名称不能超过64个字符',
|
||||
'is_system.in' => '是否系统属性只能是0或1',
|
||||
'props.*.prop_type.in' => '属性特征类型只能是1或2',
|
||||
'props.*.prop_name.require' => '属性特征名称不能为空',
|
||||
'props.*.prop_name.max' => '属性特征名称不能超过64个字符',
|
||||
'props.*.prop_value.require' => '属性特征值不能为空',
|
||||
'props.*.prop_value.max' => '属性特征值不能超过64个字符',
|
||||
];
|
||||
}
|
||||
@@ -17,7 +17,8 @@ class ProductAttrPropBaseModel extends BaseModel
|
||||
|
||||
// 字段信息
|
||||
protected $schema = [
|
||||
'id' => 'int',
|
||||
'attr_id' => 'int',
|
||||
'prop_type' => 'int',
|
||||
'prop_name' => 'string',
|
||||
'prop_value' => 'string',
|
||||
'created_at' => 'datetime',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
use think\migration\Migrator;
|
||||
|
||||
class CreateProductAttrProp extends Migrator
|
||||
@@ -29,6 +30,7 @@ class CreateProductAttrProp extends Migrator
|
||||
{
|
||||
$table = $this->table('product_attr_prop', ['id' => false, 'engine' => 'InnoDB', 'comment' => '商品属性特征表']);
|
||||
$table->addColumn('attr_id', 'integer', ['signed' => false, 'null' => false, 'comment' => '属性ID'])
|
||||
->addColumn('prop_type', MysqlAdapter::INT_TINY, ['limit' => 3, 'null' => false, 'default' => 2, 'comment' => '类型:1为选项类型,2为文本输入类型'])
|
||||
->addColumn('prop_name', 'string', ['limit' => 64, 'null' => false, 'comment' => '特征名'])
|
||||
->addColumn('prop_value', 'string', ['limit' => 64, 'null' => false, 'comment' => '特征值'])
|
||||
->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP', 'comment' => '新增时间'])
|
||||
|
||||
Reference in New Issue
Block a user