diff --git a/README.md b/README.md index 9e36eb0..05f3af5 100755 --- a/README.md +++ b/README.md @@ -4,17 +4,52 @@ Fork From [jqhph/dcat-admin](https://github.com/jqhph/dcat-admin) ## 改动 -### Show +- 文件: `dcat-admin/src/Form/Footer.php`, 将 `reset` 按钮默认设置为 `false` -### 详细页-列表按钮点击跳转方式 +```php +protected $buttons = ['reset' => false, 'submit' => true, 'back' => true]; -- `packages/dcat-admin/src/Show/Tools.php` 254行 - -```html - +public function disableBack(bool $disable = true) +{ + $this->buttons['back'] = !$disable; +} ``` -```html - +- 添加 Form 表单的 `back` 按钮, 文件: `dcat-admin/resources/views/form/footer.blade.php` + +```php +@if(! empty($buttons['back'])) +
+ {{ trans('admin.back') }} +
+@endif ``` +- 文件: `dcat-admin/src/Show/Tools.php`, 添加 `back` 按钮, `list` 默认设置为 `false`, 修改按钮的渲染方式(去掉外层的 `btn-group` 标签, 添加类名 `mr-1`) + +```php +protected $tools = ['back', 'list', 'edit', 'delete']; + +protected $showBack = true; + +public function disableBack(bool $disable = true) +{ + $this->showBack = !$disable; + return $this; +} + +protected function renderBack() +{ + if (! $this->showBack) { + return; + } + + $back = trans('admin.back'); + + return << + {$back} + +HTML; +} +``` diff --git a/packages/goods/resources/lang/zh_CN/goods-brand.php b/packages/goods/resources/lang/zh_CN/goods-brand.php index 59012bc..cd88350 100644 --- a/packages/goods/resources/lang/zh_CN/goods-brand.php +++ b/packages/goods/resources/lang/zh_CN/goods-brand.php @@ -5,6 +5,8 @@ return [ 'GoodsBrand' => '品牌管理', 'goods' => '商品管理', 'brand' => '品牌', + 'create' => '创建', + 'edit' => '修改', ], 'fields' => [ 'name' => '名称', diff --git a/packages/goods/resources/lang/zh_CN/goods.php b/packages/goods/resources/lang/zh_CN/goods.php index f314135..e3a3a27 100644 --- a/packages/goods/resources/lang/zh_CN/goods.php +++ b/packages/goods/resources/lang/zh_CN/goods.php @@ -6,6 +6,8 @@ return [ 'goods' => '商品信息', 'create' => '创建', 'edit' => '修改', + 'attr' => '属性', + 'spec' => '规格', ], 'fields' => [ 'category_id' => '分类', diff --git a/packages/goods/resources/views/form/attr-horizontal.blade.php b/packages/goods/resources/views/form/attr-horizontal.blade.php new file mode 100644 index 0000000..8142809 --- /dev/null +++ b/packages/goods/resources/views/form/attr-horizontal.blade.php @@ -0,0 +1,86 @@ + +
+

{!! $label !!}

+
+
+ +
+ +
+ +
+ + @foreach($forms as $pk => $form) + +
+ + {!! $form->render() !!} + + @if($options['allowDelete']) +
+ +
+
 {{ trans('admin.remove') }}
+
+
+ @endif +
+
+ + @endforeach +
+ + + + + @if($options['allowCreate']) +
+ +
+
 {{ trans('admin.new') }}
+
+
+ @endif + +
+ + diff --git a/packages/goods/resources/views/form/spec.blade.php b/packages/goods/resources/views/form/spec.blade.php new file mode 100644 index 0000000..d58c7b7 --- /dev/null +++ b/packages/goods/resources/views/form/spec.blade.php @@ -0,0 +1,154 @@ +
+ + + + @foreach($headers as $item) + + @endforeach + + + + + @foreach($value as $item) + + + + @foreach($item['values'] as $subItem) + + @foreach($subItem as $value) + + @endforeach + + + @endforeach + + @foreach($headers as $index => $subItem) + @if($index > 0) + + @endif + @endforeach + + + @endforeach + + + + + +
{{ $item }}
{{ $item['name'] }}
{{ $value }} + +
+ + + +
+ + + +
+
+ + diff --git a/packages/goods/src/Actions/RowGoodsSkuList.php b/packages/goods/src/Actions/RowGoodsSkuList.php deleted file mode 100644 index 5e6641a..0000000 --- a/packages/goods/src/Actions/RowGoodsSkuList.php +++ /dev/null @@ -1,16 +0,0 @@ -response()->redirect(admin_route('goods-sku.index', ['goods' => $this->getKey()])); - } -} diff --git a/packages/goods/src/Form/GoodsAttrForm.php b/packages/goods/src/Form/GoodsAttrForm.php new file mode 100644 index 0000000..502fb0a --- /dev/null +++ b/packages/goods/src/Form/GoodsAttrForm.php @@ -0,0 +1,37 @@ +update(['attr' => $input['attr']]); + + return $this->response()->success('保存成功'); + } + + public function form() + { + $this->fill(Arr::only($this->payload, ['type_id', 'goods_id', 'attr'])); + + $this->hidden('type_id'); + $this->hidden('goods_id'); + $this->spec('attr')->header(['分组', '名称', '属性值']); + } + + protected function renderResetButton() + { + return " 返回"; + } +} diff --git a/packages/goods/src/Form/GoodsSpecForm.php b/packages/goods/src/Form/GoodsSpecForm.php new file mode 100644 index 0000000..d8b4080 --- /dev/null +++ b/packages/goods/src/Form/GoodsSpecForm.php @@ -0,0 +1,52 @@ +update(['spec' => $input['spec']]); + + return $this->response()->success('保存成功'); + } + + public function form() + { + $this->spec('spec')->customFormat(function ($v) { + $list = []; + foreach($v as $item) { + $listItem = ['name' => $item['name'], 'values' => []]; + foreach($item['values'] as $subItem) { + array_push($listItem['values'], [ + 'name' => $subItem['value'], + 'value' => $subItem['price'] + ]); + } + array_push($list, $listItem); + } + return $list; + })->header(['名称', '可选值', '价格']); + } + + protected function renderResetButton() + { + return " 返回"; + } + + protected function getSubmitButtonLabel() + { + return '保存'; + } +} diff --git a/packages/goods/src/Form/Spec.php b/packages/goods/src/Form/Spec.php new file mode 100644 index 0000000..09de009 --- /dev/null +++ b/packages/goods/src/Form/Spec.php @@ -0,0 +1,21 @@ + [] + ]; + + public function header(array $headers) + { + $this->addVariables(['headers' => $headers]); + + return $this; + } +} diff --git a/packages/goods/src/GoodsServiceProvider.php b/packages/goods/src/GoodsServiceProvider.php index 6dac8d7..c1e6b29 100644 --- a/packages/goods/src/GoodsServiceProvider.php +++ b/packages/goods/src/GoodsServiceProvider.php @@ -4,6 +4,8 @@ namespace Peidikeji\Goods; use Dcat\Admin\Extend\ServiceProvider; use Dcat\Admin\Admin; +use Dcat\Admin\Form; +use Peidikeji\Goods\Form\Spec; class GoodsServiceProvider extends ServiceProvider { @@ -14,4 +16,10 @@ class GoodsServiceProvider extends ServiceProvider ['title' => '商品类别', 'uri' => 'goods/type', 'icon' => '', 'parent' => '商品管理'], ['title' => '商品信息', 'uri' => 'goods', 'icon' => '', 'parent' => '商品管理'], ]; + + public function init() + { + parent::init(); + Form::extend('spec', Spec::class); + } } diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsController.php b/packages/goods/src/Http/Controllers/Admin/GoodsController.php index 24e41a1..6411674 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsController.php @@ -2,17 +2,16 @@ namespace Peidikeji\Goods\Http\Controllers\Admin; -use Dcat\Admin\Admin; use Dcat\Admin\Form; -use Dcat\Admin\Form\BlockForm; -use Dcat\Admin\Form\NestedForm; -use Dcat\Admin\Form\Row; 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\Layout\Content; use Dcat\Admin\Show; -use Peidikeji\Goods\Actions\RowGoodsSkuList; +use Dcat\Admin\Widgets\Card; +use Peidikeji\Goods\Form\GoodsAttrForm; +use Peidikeji\Goods\Form\GoodsSpecForm; use Peidikeji\Goods\Models\Goods; use Peidikeji\Goods\Models\GoodsBrand; use Peidikeji\Goods\Models\GoodsCategory; @@ -22,6 +21,33 @@ class GoodsController extends AdminController { protected $translation = 'peidikeji.dcat-admin-extension-goods::goods'; + public function attr($goods, Content $content) + { + $goods = Goods::with(['type'])->findOrFail($goods); + $form = GoodsAttrForm::make([ + 'type' => $goods->type + ])->payload(['attr' => $goods->attr, 'type_id' => $goods->type?->id, 'goods_id' => $goods->id])->appendHtmlAttribute('class', 'bg-white'); + return $content + ->translation($this->translation()) + ->title($goods->name) + ->description($goods->type?->name) + ->body($form); + } + + public function spec($goods, Content $content) + { + $goods = Goods::findOrFail($goods); + $form = GoodsSpecForm::make([ + 'type' => $goods->type, + 'spec' => $goods->spec + ])->payload(['type_id' => $goods->type_id, 'goods_id' => $goods->id])->appendHtmlAttribute('class', 'bg-white'); + return $content + ->translation($this->translation()) + ->title($goods->name) + ->description($goods->type?->name) + ->body($form); + } + protected function grid() { return Grid::make(Goods::with(['category', 'brand', 'type']), function (Grid $grid) { @@ -56,7 +82,7 @@ class GoodsController extends AdminController $grid->column('name')->display(function () { return ($this->cover_image ? ' ' : '') . ''.$this->name.''; }); - $grid->column('price'); + $grid->column('price')->editable(); $grid->column('spec')->view('peidikeji.dcat-admin-extension-goods::grid.spec'); $grid->column('on_sale')->switch(); $grid->column('sold_count'); @@ -64,7 +90,10 @@ class GoodsController extends AdminController $grid->disableRowSelector(); $grid->actions(function (Actions $actions) { - $actions->append(new RowGoodsSkuList()); + $row = $actions->row; + $actions->append('货品信息'); + $actions->append('商品属性'); + $actions->append('商品规格'); }); }); } @@ -89,6 +118,7 @@ class GoodsController extends AdminController $show->field('sold_count'); $show->field('created_at')->as(fn($v) => $this->created_at->format('Y-m-d H:i:s')); $show->field('updated_at')->as(fn($v) => $this->updated_at->format('Y-m-d H:i:s')); + return $show; } @@ -97,109 +127,38 @@ class GoodsController extends AdminController return Form::make(new Goods(), function (Form $form) { $model = $form->model(); $isCreating = $form->isCreating(); - $type = null; - if (request('type_id') && $isCreating) { - $typeId = request('type_id'); - $type = GoodsType::find($typeId); - if ($type) { - $attrbutes = [ - 'type_id' => $type->id, - 'attr' => $type->attr, - 'spec' => $type->spec, - 'part' => $type->part, - ]; - $form->model($attrbutes); - } - } - $model = $form->model(); - if (!$type) { - $type = $model && $model->type_id ? GoodsType::find($form->model()->type_id) : null; + if ($isCreating) { + $form->select('type_id')->options(GoodsType::pluck('name', 'id')); + } else { + $type = $model->type_id ? GoodsType::find($form->model()->type_id) : null; + $form->display('type_id')->with(fn() => $type->name); } + $form->select('category_id')->options(GoodsCategory::selectOptions(null, false))->required(); + $form->select('brand_id')->options(GoodsBrand::pluck('name', 'id')); + $form->text('name')->required(); + $form->text('goods_sn'); + $form->image('cover_image') + ->autoUpload() + ->saveFullUrl() + ->move('goods/cover-image') + ->required(); + $form->multipleImage('images') + ->autoUpload() + ->saveFullUrl() + ->move('goods/images'); + $form->multipleImage('content') + ->autoUpload() + ->saveFullUrl() + ->move('goods/content'); - $form->disableHeader(); - $form->tab('基本设置', function (Form $form) use ($isCreating, $type) { - if ($isCreating) { - $form->select('type_id')->options(GoodsType::pluck('name', 'id')); - } else { - $form->display('type_id')->with(fn() => $type->name); - } - $form->select('category_id')->options(GoodsCategory::selectOptions(null, false))->required(); - $form->select('brand_id')->options(GoodsBrand::pluck('name', 'id')); - $form->text('name')->required(); - $form->text('goods_sn'); - $form->image('cover_image') - ->autoUpload() - ->saveFullUrl() - ->move('goods/goods') - ->required(); - $form->multipleImage('images') - ->autoUpload() - ->saveFullUrl() - ->move('goods/goods'); - $form->multipleImage('content') - ->autoUpload() - ->saveFullUrl() - ->move('goods/goods'); - - $form->number('price')->min(0)->attribute('step', 0.01); - $form->switch('on_sale'); - }); - - $form->tab('属性', function (Form $form) use ($type) { - $form->array('attr', null, function (NestedForm $table) use ($type) { - $values = data_get($type, 'attr.' . $table->getKey() . '.values') ?: []; - $table->text('group', '分组'); - $table->text('name', '属性名')->required(); - $table->autocomplete('value', '属性值')->options($values)->configs(['minChars' => 0]); - }); - }); - $form->tab('规格', function (Form $form) use ($type) { - $form->array('spec', null, function (NestedForm $table) use ($type) { - $table->text('name', '名称')->required(); - $values = data_get($type, 'spec.' . $table->getKey() . '.values') ?: []; - $table->array('values', null, function (NestedForm $table) use ($values) { - $index = $table->getKey(); - $table->autocomplete('value', '可选值') - ->default($index === null ? '' : data_get($values, $index, '')) - ->options($values) - ->configs(['minChars' => 0]); - $table->number('price', '加价')->min(0)->default(); - }); - }); - }); - $form->tab('配件', function (Form $form) use ($type) { - $form->array('part', null, function (NestedForm $table) use ($type) { - $table->text('name', '名称')->required(); - $values = data_get($type, 'part.' . $table->getKey() . '.values') ?: []; - $table->array('values', null, function (NestedForm $table) use ($values) { - $index = $table->getKey(); - $table->autocomplete('value', '可选值') - ->default($index === null ? '' : data_get($values, $index, '')) - ->options($values) - ->configs(['minChars' => 0]); - $table->number('price', '加价')->min(0)->default(); - }); - }); - }); + $form->number('price')->min(0)->attribute('step', 0.01); + $form->switch('on_sale'); $form->disableResetButton(); $form->disableCreatingCheck(); $form->disableViewCheck(); $form->disableEditingCheck(); - - $admin_url = request()->url(); - Admin::script( - <<names('goods-sku'); +Route::resource('goods/{goods}/sku', GoodsSkuController::class)->names('goods_sku'); +Route::get('goods/{goods}/attr', [GoodsController::class, 'attr'])->name('goods.attr'); +Route::get('goods/{goods}/spec', [GoodsController::class, 'spec'])->name('goods.spec'); Route::resource('goods', GoodsController::class); diff --git a/packages/goods/updates/CreateGoodsTable.php b/packages/goods/updates/CreateGoodsTable.php index 0e81261..5f3d4da 100644 --- a/packages/goods/updates/CreateGoodsTable.php +++ b/packages/goods/updates/CreateGoodsTable.php @@ -59,9 +59,9 @@ class CreateGoodsTable extends Migration $table->unsignedInteger('stock')->default(0)->comment('库存'); $table->unsignedInteger('sold_count')->default(0)->comment('销量'); $table->decimal('price', 12, 2)->comment('售价'); - $table->json('attr')->nullable()->comment('属性[{name, value}]'); - $table->json('spec')->nullable()->comment('规格[{name, values: [{value, price}]}]'); - $table->json('part')->nullable()->comment('配件[{name, values: [{value, price}]}]'); + $table->json('attr')->nullable()->comment('属性[{name, values: [{name, value}]}]'); + $table->json('spec')->nullable()->comment('规格[{name, values: [{name, value}]}]'); + $table->json('part')->nullable()->comment('配件[{name, values: [{name, value}]}]'); $table->timestamps(); $table->softDeletes(); diff --git a/packages/goods/updates/GoodsTableSeeder.php b/packages/goods/updates/GoodsTableSeeder.php index bf0f38f..f0539da 100644 --- a/packages/goods/updates/GoodsTableSeeder.php +++ b/packages/goods/updates/GoodsTableSeeder.php @@ -36,9 +36,11 @@ class GoodsTableSeeder extends Seeder [ 'name' => '手机', 'attr' => [ - ['group' => '主体', 'name' => '入网型号', 'values' => ['5G', '4G']], - ['group' => '主体', 'name' => '上市年份', 'values' => null], - ['group' => '主体', 'name' => '品牌', 'values' => null] + ['name' => '主体', 'values' => [ + ['name' => '入网型号', 'values' => ['5G', '4G']], + ['name' => '上市年份', 'values' => null], + ['name' => '品牌', 'values' => null] + ]] ], 'spec' => [ ['name' => '颜色', 'values' => ['白色', '红色', '黑色']], @@ -92,9 +94,11 @@ class GoodsTableSeeder extends Seeder 'stock' => 100, 'price' => 6499.00, 'attr' => [ - ['group' => '主体', 'name' => '入网型号', 'value' => '5G'], - ['group' => '主体', 'name' => '品牌', 'value' => '三星Galaxy'], - ['group' => '主体', 'name' => '上市年份', 'value' => '2020'], + ['name' => '主体', 'values' => [ + ['name' => '入网型号', 'value' => '5G'], + ['name' => '品牌', 'value' => '三星Galaxy'], + ['name' => '上市年份', 'value' => '2020'], + ]], ], 'spec' => [ ['name' => '颜色', 'values' => [ @@ -133,8 +137,10 @@ class GoodsTableSeeder extends Seeder 'stock' => 150, 'price' => 17999.00, 'attr' => [ - ['group' => '显示器','name' => '屏幕类型', 'value' => 'LED 背光显示屏'], - ['group' => '显示器','name' => '物理分辨率', 'value' => '3072 x 1920 (226 ppi)'], + ['name' => '显示器', 'values' => [ + ['name' => '屏幕类型', 'value' => 'LED 背光显示屏'], + ['name' => '物理分辨率', 'value' => '3072 x 1920 (226 ppi)'] + ]], ], 'spec' => [ ['name' => '颜色', 'values' => [ diff --git a/resources/views/form/footer.blade.php b/resources/views/form/footer.blade.php index 82113fd..b52f4f8 100755 --- a/resources/views/form/footer.blade.php +++ b/resources/views/form/footer.blade.php @@ -20,5 +20,11 @@ @endif + + @if(! empty($buttons['back'])) +
+ {{ trans('admin.back') }} +
+ @endif - \ No newline at end of file + diff --git a/src/Form/Footer.php b/src/Form/Footer.php index d8e09c7..c163071 100755 --- a/src/Form/Footer.php +++ b/src/Form/Footer.php @@ -33,7 +33,7 @@ class Footer implements Renderable * * @var array */ - protected $buttons = ['reset' => true, 'submit' => true]; + protected $buttons = ['reset' => false, 'submit' => true, 'back' => true]; /** * Available checkboxes. @@ -59,6 +59,11 @@ class Footer implements Renderable $this->builder = $builder; } + public function disableBack(bool $disable = true) + { + $this->buttons['back'] = !$disable; + } + /** * Disable reset button. * diff --git a/src/Show/Tools.php b/src/Show/Tools.php index ebd99c1..7a93590 100755 --- a/src/Show/Tools.php +++ b/src/Show/Tools.php @@ -28,7 +28,7 @@ class Tools implements Renderable * * @var array */ - protected $tools = ['delete', 'edit', 'list']; + protected $tools = ['back', 'list', 'edit', 'delete']; /** * Tools should be appends to default tools. @@ -47,7 +47,7 @@ class Tools implements Renderable /** * @var bool */ - protected $showList = true; + protected $showList = false; /** * @var bool @@ -59,6 +59,8 @@ class Tools implements Renderable */ protected $showEdit = true; + protected $showBack = true; + /** * @var bool */ @@ -173,6 +175,12 @@ class Tools implements Renderable return $this; } + public function disableBack(bool $disable = true) + { + $this->showBack = !$disable; + return $this; + } + /** * @param bool $disable * @return $this @@ -250,11 +258,24 @@ class Tools implements Renderable $list = trans('admin.list'); return << - + {$list} - +HTML; + } + + protected function renderBack() + { + if (! $this->showBack) { + return; + } + + $back = trans('admin.back'); + + return << + {$back} + HTML; } @@ -276,7 +297,7 @@ HTML; if ($this->showEdit) { $btn = << + {$edit} EOF; @@ -293,11 +314,11 @@ EOF; $text = $this->showEdit ? '' : "   $edit"; - $quickBtn = ""; + $quickBtn = ""; } return <<{$btn}{$quickBtn} + {$btn}{$quickBtn} HTML; } @@ -315,11 +336,9 @@ HTML; $delete = trans('admin.delete'); return << - - HTML; }