diff --git a/app/Admin/Controllers/ArticleController.php b/app/Admin/Controllers/ArticleController.php index bd55effc..8b5fa55e 100644 --- a/app/Admin/Controllers/ArticleController.php +++ b/app/Admin/Controllers/ArticleController.php @@ -64,13 +64,14 @@ class ArticleController extends AdminController //新增 if (Admin::user()->can('dcat.admin.articles.create')) { $grid->disableCreateButton(false); - $grid->enableDialogCreate(); + // $grid->enableDialogCreate(); } - //修改 - $grid->showQuickEditButton(Admin::user()->can('dcat.admin.articles.edit')); + //删除以及自定义操作 $grid->actions(function (Grid\Displayers\Actions $actions) { $actions->disableDelete(Admin::user()->cannot('dcat.admin.articles.destroy')); + //修改 + $actions->disableEdit(Admin::user()->cannot('dcat.admin.articles.edit')); }); /** 查询 **/ diff --git a/app/Admin/Controllers/ProductAttrController.php b/app/Admin/Controllers/ProductAttrController.php new file mode 100644 index 00000000..7b883636 --- /dev/null +++ b/app/Admin/Controllers/ProductAttrController.php @@ -0,0 +1,93 @@ +column('id')->sortable(); + $grid->column('group.name'); + $grid->column('name'); + $grid->column('attrs')->label(); + $grid->column('created_at')->sortable(); + + //排序 + $grid->model()->orderBy('created_at', 'desc'); + + /** 操作 **/ + //新增 + if (Admin::user()->can('dcat.admin.product_attrs.create')) { + $grid->disableCreateButton(false); + $grid->enableDialogCreate(); + } + + //修改 + $grid->showQuickEditButton(Admin::user()->can('dcat.admin.product_attrs.edit')); + //删除以及自定义操作 + $grid->actions(function (Grid\Displayers\Actions $actions) { + $actions->disableDelete(Admin::user()->cannot('dcat.admin.product_attrs.destroy')); + }); + + /** 查询 **/ + $grid->filter(function (Grid\Filter $filter) { + $filter->panel(); + $filter->where('group', function ($query) { + $query->whereIn('group_id', ProductAttrGroup::descendantsAndSelf($this->input, ['id'])->pluck('id')); + }, __('product-attr.fields.group.name'))->select(ProductAttrGroup::selectOptions())->width(3); + $filter->like('title')->width(3); + }); + }); + } + + /** + * Make a show builder. + * + * @param mixed $id + * + * @return Show + */ + protected function detail($id) + { + return Show::make($id, new ProductAttr(), function (Show $show) { + $show->field('id'); + $show->field('group_id'); + $show->field('attrs'); + $show->field('created_at'); + $show->field('updated_at'); + }); + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + return Form::make(new ProductAttr(), function (Form $form) { + $form->display('id'); + $form->select('group_id')->options(ProductAttrGroup::selectOptions()); + $form->text('name')->required(); + $form->list('attrs'); + + $form->display('created_at'); + $form->display('updated_at'); + }); + } +} diff --git a/app/Admin/Controllers/ProductAttrGroupController.php b/app/Admin/Controllers/ProductAttrGroupController.php new file mode 100644 index 00000000..7dbbb0bb --- /dev/null +++ b/app/Admin/Controllers/ProductAttrGroupController.php @@ -0,0 +1,98 @@ +column('id')->sortable(); + $grid->column('name')->tree(); + $grid->column('parent_id'); + $grid->column('created_at')->sortable(); + + //排序 + $grid->model()->orderBy('created_at', 'desc'); + + /** 操作 **/ + //新增 + if (Admin::user()->can('dcat.admin.product_attr_groups.create')) { + $grid->disableCreateButton(false); + $grid->enableDialogCreate(); + } + //修改 + $grid->showQuickEditButton(Admin::user()->can('dcat.admin.product_attr_groups.edit')); + //删除以及自定义操作 + $grid->actions(function (Grid\Displayers\Actions $actions) { + $actions->disableDelete(Admin::user()->cannot('dcat.admin.product_attr_groups.destroy')); + }); + + /** 查询 **/ + $grid->filter(function (Grid\Filter $filter) { + $filter->panel(); + $filter->equal('name')->width(3); + }); + }); + } + + /** + * Make a show builder. + * + * @param mixed $id + * + * @return Show + */ + protected function detail($id) + { + return Show::make($id, new ProductAttrGroup(), function (Show $show) { + $show->field('id'); + $show->field('name'); + $show->field('parent_id'); + $show->field('created_at'); + $show->field('updated_at'); + }); + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + return Form::make(new ProductAttrGroup(), function (Form $form) { + $form->display('id'); + $form->select('parent_id')->options(ProductAttrGroupModel::selectOptions()); + $form->text('name'); + + $form->display('created_at'); + $form->display('updated_at'); + }); + } + + public function destroy($id) + { + //如果有子分类或者分类下有文章则不允许删除 + if (ProductAttrGroupModel::descendantsOf($id, ['id'])->count() > 0 + || ProductAttr::where('category_id', $id)->count() > 0) { + throw new BizException(__('product-attr-group.options.deny_message')); + } + return parent::destroy($id); + } +} diff --git a/app/Admin/Controllers/ProductCategoryController.php b/app/Admin/Controllers/ProductCategoryController.php index f3a29ff1..7cd07a5d 100644 --- a/app/Admin/Controllers/ProductCategoryController.php +++ b/app/Admin/Controllers/ProductCategoryController.php @@ -3,7 +3,9 @@ namespace App\Admin\Controllers; use App\Admin\Repositories\ProductCategory; +use App\Exceptions\BizException; use App\Models\ProductCategory as ProductCategoryModel; +use App\Models\ProductSpu; use Carbon\Carbon; use Dcat\Admin\Admin; use Dcat\Admin\Form; @@ -117,4 +119,14 @@ class ProductCategoryController extends AdminController $form->display('updated_at'); }); } + + public function destroy($id) + { + //如果有子分类或者分类下有文章则不允许删除 + if (ProductCategoryModel::descendantsOf($id, ['id'])->count() > 0 + || ProductSpu::where('category_id', $id)->count() > 0) { + throw new BizException(__('product-spu.options.deny_message')); + } + return parent::destroy($id); + } } diff --git a/app/Admin/Controllers/ProductSpuController.php b/app/Admin/Controllers/ProductSpuController.php new file mode 100644 index 00000000..a209a67b --- /dev/null +++ b/app/Admin/Controllers/ProductSpuController.php @@ -0,0 +1,127 @@ +column('id')->sortable(); + $grid->column('name'); + $grid->column('subtitle'); + $grid->column('cover')->image(80, 80); + $grid->column('sell_price'); + $grid->column('market_price'); + $grid->column('cost_price'); + $grid->column('user_price'); + $grid->column('weight'); + $grid->column('is_sell'); + $grid->column('created_at')->sortable(); + + //排序 + $grid->model()->orderBy('created_at', 'desc'); + + /** 操作 **/ + //新增 + if (Admin::user()->can('dcat.admin.product_spus.create')) { + $grid->disableCreateButton(false); + } + //修改 + $grid->showQuickEditButton(Admin::user()->can('dcat.admin.product_spus.edit')); + //删除以及自定义操作 + $grid->actions(function (Grid\Displayers\Actions $actions) { + $actions->disableDelete(Admin::user()->cannot('dcat.admin.product_spus.destroy')); + }); + + /** 查询 **/ + $grid->filter(function (Grid\Filter $filter) { + $filter->panel(); + $filter->equal('name')->width(3); + }); + }); + } + + /** + * Make a show builder. + * + * @param mixed $id + * + * @return Show + */ + protected function detail($id) + { + return Show::make($id, new ProductSpu(), function (Show $show) { + $show->field('id'); + $show->field('name'); + $show->field('subtitle'); + $show->field('cover'); + $show->field('images'); + $show->field('description'); + $show->field('sell_price'); + $show->field('market_price'); + $show->field('cost_price'); + $show->field('user_price'); + $show->field('media'); + $show->field('weight'); + $show->field('attrs'); + $show->field('is_sell'); + $show->field('created_at'); + $show->field('updated_at'); + }); + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + return Form::make(new ProductSpu(), function (Form $form) { + $form->display('id'); + + if ($form->isEditing()) { + return; + } + $form->select('category_id')->options(ProductCategory::selectOptions())->required(); + $form->text('name')->required(); + $form->text('subtitle'); + $form->image('cover') + ->move('product-spus/cover/'.Carbon::now()->toDateString()) + ->saveFullUrl() + ->removable(false) + ->autoUpload(); + $form->multipleImage('images') + ->move('product-spus/'.Carbon::now()->toDateString()) + ->saveFullUrl() + ->removable(false) + ->autoUpload(); + $form->editor('description'); + $form->number('weight'); + + $form->currency('sell_price')->symbol('¥'); + $form->currency('market_price')->symbol('¥'); + $form->currency('cost_price')->symbol('¥'); + $form->currency('user_price')->symbol('¥'); + $form->switch('is_sell'); + + $form->display('created_at'); + $form->display('updated_at'); + }); + } +} diff --git a/app/Admin/Repositories/ProductAttr.php b/app/Admin/Repositories/ProductAttr.php new file mode 100644 index 00000000..3a6db4df --- /dev/null +++ b/app/Admin/Repositories/ProductAttr.php @@ -0,0 +1,16 @@ +resource('product-specs', 'ProductSpecController')->only([ 'index', 'create', 'store', 'edit', 'update', 'destroy', ])->names('product_specs'); + + $router->resource('product-attr-groups', 'ProductAttrGroupController')->only([ + 'index', 'create', 'store', 'edit', 'update', 'destroy', + ])->names('product_attr_groups'); + + $router->resource('product-attrs', 'ProductAttrController')->only([ + 'index', 'create', 'store', 'edit', 'update', 'destroy', + ])->names('product_attrs'); + + $router->resource('product-spus', 'ProductSpuController')->names('product_spus'); }); diff --git a/app/Casts/PriceAttributes.php b/app/Casts/PriceAttributes.php new file mode 100644 index 00000000..a0cfc7fe --- /dev/null +++ b/app/Casts/PriceAttributes.php @@ -0,0 +1,36 @@ + 'array', + ]; + + public function group() + { + return $this->belongsTo(ProductAttrGroup::class, 'group_id'); + } +} diff --git a/app/Models/ProductAttrGroup.php b/app/Models/ProductAttrGroup.php new file mode 100644 index 00000000..3e828378 --- /dev/null +++ b/app/Models/ProductAttrGroup.php @@ -0,0 +1,28 @@ +parent_id; + } +} diff --git a/app/Models/ProductSpu.php b/app/Models/ProductSpu.php new file mode 100644 index 00000000..536ebff0 --- /dev/null +++ b/app/Models/ProductSpu.php @@ -0,0 +1,21 @@ +PriceAttributes::class, + 'market_price'=>PriceAttributes::class, + 'cost_price'=>PriceAttributes::class, + 'user_price'=>PriceAttributes::class, + ]; +} diff --git a/database/migrations/2021_11_22_110044_create_product_spus_table.php b/database/migrations/2021_11_22_110044_create_product_spus_table.php index 2d919ccd..aff6f2f8 100644 --- a/database/migrations/2021_11_22_110044_create_product_spus_table.php +++ b/database/migrations/2021_11_22_110044_create_product_spus_table.php @@ -17,6 +17,7 @@ class CreateProductSpusTable extends Migration $table->id(); $table->string('name')->comment('商品名称'); $table->string('subtitle')->nullable()->comment('商品副标题'); + $table->unsignedBigInteger('category_id')->comment('商品分类'); $table->string('cover')->nullable()->comment('封面图'); $table->json('images')->nullable()->comment('商品图片'); $table->text('description')->nullable()->comment('商品详情'); diff --git a/database/migrations/2021_11_24_120232_create_product_skus_table.php b/database/migrations/2021_11_24_120232_create_product_skus_table.php index 0e49c828..4a65ad8f 100644 --- a/database/migrations/2021_11_24_120232_create_product_skus_table.php +++ b/database/migrations/2021_11_24_120232_create_product_skus_table.php @@ -18,6 +18,7 @@ class CreateProductSkusTable extends Migration $table->unsignedBigInteger('spu_id')->comment('主商品ID'); $table->string('name')->comment('商品名称'); $table->string('subtitle')->nullable()->comment('商品副标题'); + $table->unsignedBigInteger('category_id')->comment('商品分类'); $table->string('cover')->nullable()->comment('封面图'); $table->json('images')->nullable()->comment('商品图片'); $table->text('description')->nullable()->comment('商品详情'); diff --git a/database/migrations/2021_11_25_135708_create_product_attr_groups_table.php b/database/migrations/2021_11_25_135708_create_product_attr_groups_table.php new file mode 100644 index 00000000..a4e28dd2 --- /dev/null +++ b/database/migrations/2021_11_25_135708_create_product_attr_groups_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('name')->comment('名称'); + $table->integer('sort')->default(0)->comment('排序'); + $table->nestedSet(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('product_attr_groups'); + } +} diff --git a/database/migrations/2021_11_25_135716_create_product_attrs_table.php b/database/migrations/2021_11_25_135716_create_product_attrs_table.php new file mode 100644 index 00000000..8c49b241 --- /dev/null +++ b/database/migrations/2021_11_25_135716_create_product_attrs_table.php @@ -0,0 +1,34 @@ +id(); + $table->unsignedBigInteger('group_id')->nullable()->comment('属性分组'); + $table->string('name')->comment('名称'); + $table->json('attrs')->nullable()->comment('属性'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('product_attrs'); + } +} diff --git a/dcat_admin_ide_helper.php b/dcat_admin_ide_helper.php index 96b7a2b3..e765e96e 100644 --- a/dcat_admin_ide_helper.php +++ b/dcat_admin_ide_helper.php @@ -63,6 +63,8 @@ namespace Dcat\Admin { * @property Grid\Column|Collection token * @property Grid\Column|Collection abilities * @property Grid\Column|Collection last_used_at + * @property Grid\Column|Collection group_id + * @property Grid\Column|Collection attrs * @property Grid\Column|Collection spu_id * @property Grid\Column|Collection images * @property Grid\Column|Collection sell_price @@ -71,7 +73,6 @@ namespace Dcat\Admin { * @property Grid\Column|Collection user_price * @property Grid\Column|Collection media * @property Grid\Column|Collection weight - * @property Grid\Column|Collection attrs * @property Grid\Column|Collection is_sell * @property Grid\Column|Collection spec_items * @property Grid\Column|Collection stock @@ -147,6 +148,8 @@ namespace Dcat\Admin { * @method Grid\Column|Collection token(string $label = null) * @method Grid\Column|Collection abilities(string $label = null) * @method Grid\Column|Collection last_used_at(string $label = null) + * @method Grid\Column|Collection group_id(string $label = null) + * @method Grid\Column|Collection attrs(string $label = null) * @method Grid\Column|Collection spu_id(string $label = null) * @method Grid\Column|Collection images(string $label = null) * @method Grid\Column|Collection sell_price(string $label = null) @@ -155,7 +158,6 @@ namespace Dcat\Admin { * @method Grid\Column|Collection user_price(string $label = null) * @method Grid\Column|Collection media(string $label = null) * @method Grid\Column|Collection weight(string $label = null) - * @method Grid\Column|Collection attrs(string $label = null) * @method Grid\Column|Collection is_sell(string $label = null) * @method Grid\Column|Collection spec_items(string $label = null) * @method Grid\Column|Collection stock(string $label = null) @@ -236,6 +238,8 @@ namespace Dcat\Admin { * @property Show\Field|Collection token * @property Show\Field|Collection abilities * @property Show\Field|Collection last_used_at + * @property Show\Field|Collection group_id + * @property Show\Field|Collection attrs * @property Show\Field|Collection spu_id * @property Show\Field|Collection images * @property Show\Field|Collection sell_price @@ -244,7 +248,6 @@ namespace Dcat\Admin { * @property Show\Field|Collection user_price * @property Show\Field|Collection media * @property Show\Field|Collection weight - * @property Show\Field|Collection attrs * @property Show\Field|Collection is_sell * @property Show\Field|Collection spec_items * @property Show\Field|Collection stock @@ -320,6 +323,8 @@ namespace Dcat\Admin { * @method Show\Field|Collection token(string $label = null) * @method Show\Field|Collection abilities(string $label = null) * @method Show\Field|Collection last_used_at(string $label = null) + * @method Show\Field|Collection group_id(string $label = null) + * @method Show\Field|Collection attrs(string $label = null) * @method Show\Field|Collection spu_id(string $label = null) * @method Show\Field|Collection images(string $label = null) * @method Show\Field|Collection sell_price(string $label = null) @@ -328,7 +333,6 @@ namespace Dcat\Admin { * @method Show\Field|Collection user_price(string $label = null) * @method Show\Field|Collection media(string $label = null) * @method Show\Field|Collection weight(string $label = null) - * @method Show\Field|Collection attrs(string $label = null) * @method Show\Field|Collection is_sell(string $label = null) * @method Show\Field|Collection spec_items(string $label = null) * @method Show\Field|Collection stock(string $label = null) diff --git a/public/dist/admin/css/app.css b/public/dist/admin/css/app.css index 704bd10c..66b75657 100644 --- a/public/dist/admin/css/app.css +++ b/public/dist/admin/css/app.css @@ -1 +1 @@ -.tox {z-index:99999999} +/* .tox {z-index:99999999} */ diff --git a/resources/lang/zh_CN/product-attr-group.php b/resources/lang/zh_CN/product-attr-group.php new file mode 100644 index 00000000..537bf88f --- /dev/null +++ b/resources/lang/zh_CN/product-attr-group.php @@ -0,0 +1,16 @@ + [ + 'ProductAttrGroup' => '属性分组', + 'product-attr-groups' => '属性分组', + ], + 'fields' => [ + 'name' => '名称', + 'parent_id' => '上级', + ], + 'options' => [ + 'deny' => '删除失败', + 'deny_message'=>'请先删除该分类下的子分类或者属性', + ], +]; diff --git a/resources/lang/zh_CN/product-attr.php b/resources/lang/zh_CN/product-attr.php new file mode 100644 index 00000000..4f35782b --- /dev/null +++ b/resources/lang/zh_CN/product-attr.php @@ -0,0 +1,17 @@ + [ + 'ProductAttr' => '属性管理', + 'product-attr' => '属性管理', + ], + 'fields' => [ + 'group' => [ + 'name' => '属性分组', + ], + 'group_id' => '属性分组', + 'attrs' => '属性', + ], + 'options' => [ + ], +]; diff --git a/resources/lang/zh_CN/product-category.php b/resources/lang/zh_CN/product-category.php index 35fb50d9..4faf75d2 100644 --- a/resources/lang/zh_CN/product-category.php +++ b/resources/lang/zh_CN/product-category.php @@ -14,5 +14,7 @@ return [ 'parent_id' => '父级', ], 'options' => [ + 'deny' => '删除失败', + 'deny_message'=>'请先删除该分类下的子分类或者主商品', ], ]; diff --git a/resources/lang/zh_CN/product-spu.php b/resources/lang/zh_CN/product-spu.php new file mode 100644 index 00000000..f8530049 --- /dev/null +++ b/resources/lang/zh_CN/product-spu.php @@ -0,0 +1,26 @@ + [ + 'ProductSpu' => '主商品', + 'product-spus' => '主商品', + ], + 'fields' => [ + 'category_id'=>'商品分类', + 'name' => '商品名称', + 'subtitle' => '商品副标题', + 'cover' => '封面图', + 'images' => '商品图片', + 'description' => '商品详情', + 'sell_price' => '销售价格', + 'market_price' => '市场价格', + 'cost_price' => '成本价格', + 'user_price' => '会员价格', + 'media' => '媒体地址', + 'weight' => '重量:g', + 'attrs' => '属性文本', + 'is_sell' => '在售状态', + ], + 'options' => [ + ], +];