商品列表、分类管理、客户等级
This commit is contained in:
@@ -34,7 +34,7 @@ class ProductCategoryController extends BaseController
|
||||
#[GetRoute('/tree', 'query')]
|
||||
public function tree(): JsonResponse
|
||||
{
|
||||
return $this->success(ProductCategoryModel::getTreeData(onlyEnabled: true));
|
||||
return $this->success(ProductCategoryModel::getTreeData(['id', 'name', 'parent_id'], true));
|
||||
}
|
||||
|
||||
/** 上传商品分类图片文件 */
|
||||
|
||||
@@ -13,6 +13,7 @@ use App\Models\StoreModel;
|
||||
use App\Models\UserModel;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\AnnoRoute\Attribute\DeleteRoute;
|
||||
use Modules\AnnoRoute\Attribute\GetRoute;
|
||||
@@ -20,6 +21,7 @@ use Modules\AnnoRoute\Attribute\PostRoute;
|
||||
use Modules\AnnoRoute\Attribute\PutRoute;
|
||||
use Modules\AnnoRoute\Attribute\RequestAttribute;
|
||||
use Modules\Common\Http\Controllers\BaseController;
|
||||
use Modules\SystemTool\Services\SysFileService;
|
||||
|
||||
/**
|
||||
* 商品档案管理
|
||||
@@ -53,6 +55,21 @@ class ProductController extends BaseController
|
||||
return $this->success($data);
|
||||
}
|
||||
|
||||
/** 上传商品分类图片文件 */
|
||||
#[PostRoute('/upload', 'create')]
|
||||
public function uploadImage(Request $request, SysFileService $service): JsonResponse
|
||||
{
|
||||
$data = $request->validate(['file' => 'required|file']);
|
||||
$result = $service->upload(
|
||||
$data['file'],
|
||||
10,
|
||||
20,
|
||||
Auth::id()
|
||||
);
|
||||
return $this->success($result);
|
||||
}
|
||||
|
||||
|
||||
/** 创建商品(事务内建商品 + 同步等级价格) */
|
||||
#[PostRoute(authorize: 'create')]
|
||||
public function create(ProductFormRequest $request): JsonResponse
|
||||
|
||||
@@ -25,7 +25,7 @@ class CustomerLevelFormRequest extends BaseFormRequest
|
||||
'name' => ['required', 'string', 'max:50', $unique],
|
||||
'sort' => 'nullable|integer',
|
||||
'status' => 'nullable|integer|in:0,1',
|
||||
'icon' => ['nullable', 'integer', new Exists(SysFileModel::class, 'id')],
|
||||
'icon_id' => ['nullable', 'integer', new Exists(SysFileModel::class, 'id')],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class CustomerLevelFormRequest extends BaseFormRequest
|
||||
'name.max' => '等级名称最长 50 个字符',
|
||||
'name.unique' => '等级名称已存在',
|
||||
'status.in' => '状态值不正确',
|
||||
'icon.exists' => '请重新上传图片'
|
||||
'icon_id.exists' => '请重新上传图片'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace App\Http\Requests\Product;
|
||||
|
||||
use Illuminate\Validation\Rules\Exists;
|
||||
use Modules\Common\Http\Requests\BaseFormRequest;
|
||||
use Modules\SystemTool\Models\SysFileModel;
|
||||
|
||||
/**
|
||||
* 商品分类 创建/编辑 验证
|
||||
@@ -22,6 +24,7 @@ class ProductCategoryFormRequest extends BaseFormRequest
|
||||
'name' => 'required|string|max:50',
|
||||
'parent_id' => 'required|integer|min:0',
|
||||
'sort' => 'nullable|integer',
|
||||
'icon_id' => ['nullable', 'integer', new Exists(SysFileModel::class, 'id')],
|
||||
'status' => 'nullable|integer|in:0,1',
|
||||
];
|
||||
}
|
||||
@@ -33,6 +36,7 @@ class ProductCategoryFormRequest extends BaseFormRequest
|
||||
'name.max' => '分类名称最长 50 个字符',
|
||||
'parent_id.min' => '父级分类ID不正确',
|
||||
'status.in' => '状态值不正确',
|
||||
'icon_id.exists' => '请重新上传图片'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
namespace App\Http\Requests\Product;
|
||||
|
||||
use App\Models\ProductCategoryModel;
|
||||
use App\Models\SupplierModel;
|
||||
use Illuminate\Validation\Rules\Exists;
|
||||
use Modules\Common\Http\Requests\BaseFormRequest;
|
||||
use Modules\SystemTool\Models\SysFileModel;
|
||||
|
||||
/**
|
||||
* 商品档案 创建/编辑 验证(含多等级价格 prices 数组)
|
||||
@@ -14,14 +18,17 @@ class ProductFormRequest extends BaseFormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'category_id' => ['required','integer', new Exists(ProductCategoryModel::class,'id')],
|
||||
'supplier_id' => ['nullable','integer', 'exclude_if:supplier_id,0', new Exists(SupplierModel::class,'id')],
|
||||
'name' => 'required|string|max:100',
|
||||
'spec' => 'nullable|string|max:100',
|
||||
'grade' => 'nullable|string|max:50',
|
||||
'unit' => 'nullable|string|max:20',
|
||||
'category_id' => 'required|integer|exists:product_category,id',
|
||||
'supplier_id' => 'nullable|integer|exclude_if:supplier_id,0|exists:supplier,id',
|
||||
'image' => 'nullable|string|max:255',
|
||||
'image_ids' => 'nullable|array|max:255',
|
||||
'image_ids.*' => ['integer', new Exists(SysFileModel::class, 'id')],
|
||||
'content' => 'nullable|string',
|
||||
'sort' => 'nullable|integer',
|
||||
'shelf_life' => 'nullable|integer|min:0',
|
||||
'stock' => 'nullable|integer|min:0',
|
||||
'status' => 'nullable|integer|in:0,1',
|
||||
'remark' => 'nullable|string|max:255',
|
||||
'prices' => 'nullable|array',
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -28,7 +27,7 @@ class CustomerLevelModel extends Model
|
||||
'name',
|
||||
'sort',
|
||||
'status',
|
||||
'icon'
|
||||
'icon_id'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -45,15 +44,16 @@ class CustomerLevelModel extends Model
|
||||
*/
|
||||
public function icon(): HasOne
|
||||
{
|
||||
return $this->hasOne(SysFileModel::class, 'id', 'icon');
|
||||
return $this->hasOne(SysFileModel::class, 'id', 'icon_id');
|
||||
}
|
||||
|
||||
// 图标链接
|
||||
public function icon_url(): Attribute
|
||||
public function getIconUrlAttribute()
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->icon->preview_url,
|
||||
);
|
||||
if($this->icon) {
|
||||
return $this->icon->preview_url;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -27,34 +26,37 @@ class ProductCategoryModel extends Model
|
||||
'name',
|
||||
'sort',
|
||||
'status',
|
||||
'icon'
|
||||
'icon_id'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'parent_id' => 'integer',
|
||||
'sort' => 'integer',
|
||||
'status' => 'integer',
|
||||
'icon' => 'integer',
|
||||
'icon_id' => 'integer',
|
||||
'created_at' => 'datetime:Y-m-d H:i:s',
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
protected $appends = ['icon_url'];
|
||||
|
||||
protected $with = ['icon'];
|
||||
|
||||
/**
|
||||
* 关联图标
|
||||
*/
|
||||
public function icon(): HasOne
|
||||
{
|
||||
return $this->hasOne(SysFileModel::class, 'id', 'icon');
|
||||
return $this->hasOne(SysFileModel::class, 'id', 'icon_id');
|
||||
}
|
||||
|
||||
// 图标链接
|
||||
public function icon_url(): Attribute
|
||||
public function getIconUrlAttribute()
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->icon->preview_url,
|
||||
);
|
||||
if($this->icon) {
|
||||
return $this->icon->preview_url;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,14 +89,14 @@ class ProductCategoryModel extends Model
|
||||
* @param bool $onlyEnabled 是否仅返回启用分类
|
||||
* @return array<int, array{id: int, name: string, parent_id: int, sort: int, status: int, children?: array}>
|
||||
*/
|
||||
public static function getTreeData(bool $onlyEnabled = false): array
|
||||
public static function getTreeData($columns = ['*'], bool $onlyEnabled = false): array
|
||||
{
|
||||
$query = static::query()->orderBy('sort')->orderBy('id');
|
||||
if ($onlyEnabled) {
|
||||
$query->where('status', self::STATUS_NORMAL);
|
||||
}
|
||||
|
||||
return static::buildTree($query->get()->toArray());
|
||||
return static::buildTree($query->get($columns)->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ class ProductModel extends Model
|
||||
'name',
|
||||
'spec',
|
||||
'unit',
|
||||
'images',
|
||||
'image_ids',
|
||||
'content',
|
||||
'sort',
|
||||
'shelf_life',
|
||||
@@ -47,22 +47,32 @@ class ProductModel extends Model
|
||||
'stock' => 'integer',
|
||||
'sort' => 'integer',
|
||||
'status' => 'integer',
|
||||
'created_at' => 'datetime:Y-m-d H:i:s',
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
public function images(): Attribute
|
||||
protected $appends = ['images_arr'];
|
||||
|
||||
/**
|
||||
* 封面图片
|
||||
*/
|
||||
public function imageIds(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function($value){
|
||||
if (empty($value)) {
|
||||
return collect();
|
||||
}
|
||||
$ids = explode(',', $value);
|
||||
return SysFileModel::whereIn('id', $ids)->get();
|
||||
},
|
||||
get: fn ($value) => explode(',', $value),
|
||||
set: fn ($value) => is_array($value) ? implode(',', $value) : $value,
|
||||
);
|
||||
}
|
||||
|
||||
// 获取封面图片关联数据
|
||||
public function getImagesArrAttribute(): array
|
||||
{
|
||||
if( $this->image_ids ) {
|
||||
return SysFileModel::whereIn('id', $this->image_ids )->get()->toArray();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 所属分类
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user