diff --git a/packages/goods/resources/lang/en/goods-sku.php b/packages/goods/resources/lang/en/goods-sku.php new file mode 100644 index 0000000..0b67a5f --- /dev/null +++ b/packages/goods/resources/lang/en/goods-sku.php @@ -0,0 +1,3 @@ + [ + 'GoodsSku' => '货品管理', + 'goods' => '商品管理', + 'sku' => '商品管理', + ], + 'fields' => [ + 'sn' => '货号', + 'name' => '名称', + 'price' => '价格', + 'stock' => '库存', + 'spec' => '规格', + ] +]; diff --git a/packages/goods/src/Actions/RowGoodsSkuList.php b/packages/goods/src/Actions/RowGoodsSkuList.php new file mode 100644 index 0000000..5e6641a --- /dev/null +++ b/packages/goods/src/Actions/RowGoodsSkuList.php @@ -0,0 +1,16 @@ +response()->redirect(admin_route('goods-sku.index', ['goods' => $this->getKey()])); + } +} diff --git a/packages/goods/src/GoodsService.php b/packages/goods/src/GoodsService.php index 9276ccc..6bc81ec 100644 --- a/packages/goods/src/GoodsService.php +++ b/packages/goods/src/GoodsService.php @@ -27,8 +27,8 @@ class GoodsService $this->clearSku($goods); if ($goods->spec) { $spec = $goods->spec; - $goods_price = $goods->price; - $goods_name = $goods->name; + $price = $goods->price; + $name = $goods->name; $specList = []; foreach ($spec as $item) { @@ -44,13 +44,11 @@ class GoodsService } $cartesianList = $this->cartesianProduct($specList); foreach($cartesianList as $items) { - $sub_goods_name = $goods_name; - $sub_price = $goods_price; - + $specPrice = array_sum(array_column($items, 'price')); $goods->skus()->create([ 'sn' => $this->generateSn(), - 'name' => $sub_goods_name, - 'price' => $sub_price, + 'name' => $name, + 'price' => $price + $specPrice, 'stock' => $goods->stock, 'spec' => $items, ]); diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php index 65df6eb..89c4864 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php @@ -28,7 +28,11 @@ class GoodsBrandController extends AdminController { return Form::make(new GoodsBrand(), function (Form $form) { $form->text('name'); - $form->image('image')->autoUpload()->saveFullUrl()->move('goods/brand'); + $form->image('image') + ->autoUpload() + ->saveFullUrl() + ->move('goods/brand'); + // $form->oss('file')->dir('mv'); $form->disableResetButton(); $form->disableCreatingCheck(); diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsController.php b/packages/goods/src/Http/Controllers/Admin/GoodsController.php index 4263b2d..4c9f517 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsController.php @@ -4,9 +4,11 @@ namespace Peidikeji\Goods\Http\Controllers\Admin; use Dcat\Admin\Form; use Dcat\Admin\Grid; +use Dcat\Admin\Grid\Displayers\Actions; use Dcat\Admin\Grid\Tools\Selector; use Dcat\Admin\Http\Controllers\AdminController; use Dcat\Admin\Show; +use Peidikeji\Goods\Actions\RowGoodsSkuList; use Peidikeji\Goods\Models\Goods; use Peidikeji\Goods\Models\GoodsBrand; use Peidikeji\Goods\Models\GoodsCategory; @@ -56,6 +58,10 @@ class GoodsController extends AdminController $grid->column('sold_count'); $grid->disableRowSelector(); + + $grid->actions(function (Actions $actions) { + $actions->append(new RowGoodsSkuList()); + }); }); } diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php b/packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php new file mode 100644 index 0000000..8584747 --- /dev/null +++ b/packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php @@ -0,0 +1,170 @@ +model()->where('goods_id', $goods->id); + + $grid->selector(function (Selector $selector) use ($goods) { + $specs = $goods->spec; + foreach($specs as $key => $item) { + $values = array_column($item['values'], 'value'); + $selector->selectOne('spec_' . $key, $item['name'], array_column($item['values'], 'value'), function ($q, $value) use ($values, $item) { + $selected = array_values(Arr::only($values, $value)); + if (count($selected) > 0) { + $q->jsonArray([['name' => $item['name'], 'value' => $selected[0]]]); + } + }); + } + }); + + $grid->column('id'); + $grid->column('sn'); + $grid->column('name'); + $grid->column('price'); + $grid->column('stock'); + foreach($goods->spec as $key => $item) { + $grid->column('spec_' . $key, $item['name'])->display(function () use ($item) { + $filtered = current(array_filter($this->spec, fn($subItem) => $subItem['name'] === $item['name'])); + $value = data_get($filtered, 'value'); + $price = data_get($filtered, 'price'); + return ''.$value.''; + }); + } + // $grid->column('spec')->view('peidikeji.dcat-admin-extension-goods::grid.attr'); + }); + return $content + ->translation($this->translation) + ->title(admin_trans_label()) + ->description(trans('admin.list')) + ->body($grid); + } + + public function show($id, Content $content) + { + $info = GoodsSku::with(['goods'])->findOrFail($id); + $show = Show::make($info, function (Show $show) { + $show->field('sn'); + $show->field('name'); + $show->field('price'); + $show->field('stock'); + // $show->field('spec')->view('peidikeji.dcat-admin-extension-goods::grid.attr'); + $goods = $show->model()->goods; + foreach($goods->spec as $key => $item) { + $show->field('spec_' . $key, $item['name'])->as(function () use ($item) { + $filtered = current(array_filter($this->spec, fn($subItem) => $subItem['name'] === $item['name'])); + $value = data_get($filtered, 'value'); + $price = data_get($filtered, 'price'); + return ''.$value.''; + })->unescape(); + } + }); + return $content + ->translation($this->translation) + ->title(admin_trans_label()) + ->description(trans('admin.show')) + ->body($show); + } + + protected function form($goods) + { + return Form::make(new GoodsSku(), function (Form $form) use ($goods) { + $unqiue = Rule::unique('goods_sku', 'sn'); + if ($form->isEditing()) { + $unqiue->ignore($form->model()->id); + } + $form->text('sn')->rules([$unqiue])->required(); + $form->text('name')->default($goods->name); + $form->number('price')->min(0)->default($goods->price); + $form->number('stock')->min(0)->default($goods->stock); + $form->hidden('spec')->customFormat(fn($v) => json_encode($v)); + $form->hidden('goods_id')->default($goods->id); + + $spec = $form->model()->spec; + foreach($goods->spec as $key => $item) { + $values = array_column($item['values'], 'value', 'value'); + $value = null; + if ($spec) { + $filtered = current(array_filter($spec, fn($subItem) => $subItem['name'] === $item['name'])); + $value = array_search($filtered['value'], $values); + } + $form->radio($item['name'], $item['name'])->options($values)->value($value); + } + + $form->saving(function (Form $form) use ($goods) { + $info = $form->model(); + $spec = []; + foreach($goods->spec as $item) { + array_push($spec, ['name' => $item['name'], 'value' => $form->input($item['name'])]); + $form->deleteInput($item['name']); + } + $form->input('spec', $spec); + $query = GoodsSku::where('goods_id', $goods->id)->jsonArray($spec); + if ($form->isEditing()) { + $query->where('id', '!=', $info->id); + } + if ($query->exists()) { + return $form->response()->error('该规格已经存在'); + } + }); + + $form->disableCreatingCheck(); + $form->disableEditingCheck(); + $form->disableViewCheck(); + $form->disableResetButton(); + }); + } + + public function edit($goods, $id, Content $content) + { + $goods = Goods::findOrFail($goods); + return $content + ->translation($this->translation) + ->title(admin_trans_label()) + ->description(trans('admin.edit')) + ->body($this->form($goods)->edit($id)); + } + + public function create($goods, Content $content) + { + return $content + ->translation($this->translation) + ->title(admin_trans_label()) + ->description(trans('admin.create')) + ->body($this->form(Goods::findOrFail($goods))); + } + + public function update($goods, $id) + { + return $this->form(Goods::findOrFail($goods))->update($id); + } + + public function store($goods) + { + return $this->form(Goods::findOrFail($goods))->store(); + } + + public function destroy($goods, $id) + { + return $this->form(Goods::findOrFail($goods))->destroy($id); + } +} diff --git a/packages/goods/src/Http/routes.php b/packages/goods/src/Http/routes.php index 8337ee7..40d661d 100644 --- a/packages/goods/src/Http/routes.php +++ b/packages/goods/src/Http/routes.php @@ -8,4 +8,6 @@ Route::resource('goods/category', GoodsCategoryController::class); Route::resource('goods/brand', GoodsBrandController::class); Route::resource('goods/type', GoodsTypeController::class); +Route::resource('goods/{goods}/sku', GoodsSkuController::class)->names('goods-sku'); + Route::resource('goods', GoodsController::class); diff --git a/packages/goods/src/Models/GoodsSku.php b/packages/goods/src/Models/GoodsSku.php index 994e9c9..2468221 100644 --- a/packages/goods/src/Models/GoodsSku.php +++ b/packages/goods/src/Models/GoodsSku.php @@ -3,6 +3,7 @@ namespace Peidikeji\Goods\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Query\Builder; class GoodsSku extends Model { @@ -20,4 +21,22 @@ class GoodsSku extends Model { return $this->belongsTo(Goods::class, 'goods_id'); } + + /** + * Mysql Json 查询 + * 数据库存储格式: [{"name": "颜色", "price": 0, "value": "白色"}, {"name": "内存", "price": 0, "value": "32G"}] + * + * @param Builder $q + * @param array $params [{"name": "颜色", "value": "白色"}, {"name": "内存", "value": "32G"}] + */ + public function scopeJsonArray($q, $params) + { + foreach($params as $item) { + foreach($item as $key => $value) { + $value = is_string($value) ? '"'.$value.'"' : $value; + $q->whereRaw("json_contains(spec->>\"$[*].".$key."\", '".$value."')"); + } + } + return $q; + } }