From 54bd8cc1a398f272e90701ee037d9cc083a4105e Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Mon, 1 Aug 2022 14:50:37 +0800 Subject: [PATCH 1/8] goods list --- packages/goods/resources/lang/en/goods.php | 3 + packages/goods/resources/lang/zh_CN/goods.php | 36 ++++ .../goods/resources/views/grid/attr.blade.php | 11 ++ .../goods/resources/views/grid/spec.blade.php | 13 ++ packages/goods/src/GoodsService.php | 109 +++++++++++ packages/goods/src/GoodsServiceProvider.php | 1 + .../Controllers/Admin/GoodsController.php | 83 ++++++++ packages/goods/src/Http/routes.php | 2 + packages/goods/src/Models/Goods.php | 35 +++- packages/goods/src/Models/GoodsBrand.php | 14 ++ packages/goods/src/Models/GoodsSku.php | 23 +++ packages/goods/src/Models/GoodsType.php | 20 ++ packages/goods/updates/CreateGoodsTable.php | 26 ++- packages/goods/updates/GoodsTableSeeder.php | 179 ++++++++++++++++++ packages/goods/version.php | 1 + 15 files changed, 553 insertions(+), 3 deletions(-) create mode 100644 packages/goods/resources/lang/en/goods.php create mode 100644 packages/goods/resources/lang/zh_CN/goods.php create mode 100644 packages/goods/resources/views/grid/attr.blade.php create mode 100644 packages/goods/resources/views/grid/spec.blade.php create mode 100644 packages/goods/src/GoodsService.php create mode 100644 packages/goods/src/Http/Controllers/Admin/GoodsController.php create mode 100644 packages/goods/src/Models/GoodsBrand.php create mode 100644 packages/goods/src/Models/GoodsSku.php create mode 100644 packages/goods/src/Models/GoodsType.php create mode 100644 packages/goods/updates/GoodsTableSeeder.php diff --git a/packages/goods/resources/lang/en/goods.php b/packages/goods/resources/lang/en/goods.php new file mode 100644 index 0000000..0b67a5f --- /dev/null +++ b/packages/goods/resources/lang/en/goods.php @@ -0,0 +1,3 @@ + [ + 'Goods' => '商品信息', + 'goods' => '商品信息', + ], + 'fields' => [ + 'category_id' => '分类', + 'category' => [ + 'name' => '分类' + ], + 'brand_id' => '品牌', + 'brand' => [ + 'name' => '品牌' + ], + 'type_id' => '类别', + 'type' => [ + 'name' => '类别' + ], + 'name' => '名称', + 'goods_sn' => '编号', + 'cover_image' => '封面图', + 'price' => '售价', + 'spec' => '规格', + 'attr' => '属性', + 'part' => '配件', + 'on_sale' => '上架', + 'stock' => '库存', + 'sold_count' => '销量', + 'images' => '详细图', + 'content' => '内容', + 'created_at' => '创建时间', + 'updated_at' => '更新时间', + ] +]; diff --git a/packages/goods/resources/views/grid/attr.blade.php b/packages/goods/resources/views/grid/attr.blade.php new file mode 100644 index 0000000..e630876 --- /dev/null +++ b/packages/goods/resources/views/grid/attr.blade.php @@ -0,0 +1,11 @@ + + + +@if($value) +@foreach($value as $item) +
+ {{ $item['name'] }} + {{ $item['value'] }} +
+@endforeach +@endif diff --git a/packages/goods/resources/views/grid/spec.blade.php b/packages/goods/resources/views/grid/spec.blade.php new file mode 100644 index 0000000..697e800 --- /dev/null +++ b/packages/goods/resources/views/grid/spec.blade.php @@ -0,0 +1,13 @@ + + + +@if($value) +@foreach($value as $item) +
+ {{ $item['name'] }} + @foreach($item['values'] as $value) + {{ $value['value'] }}({{ $value['price'] }}) + @endforeach +
+@endforeach +@endif diff --git a/packages/goods/src/GoodsService.php b/packages/goods/src/GoodsService.php new file mode 100644 index 0000000..9276ccc --- /dev/null +++ b/packages/goods/src/GoodsService.php @@ -0,0 +1,109 @@ +id)->delete(); + } + + public function generateSku(Goods $goods) + { + $this->clearSku($goods); + if ($goods->spec) { + $spec = $goods->spec; + $goods_price = $goods->price; + $goods_name = $goods->name; + + $specList = []; + foreach ($spec as $item) { + $items = []; + foreach($item['values'] as $value) { + array_push($items, [ + 'name' => $item['name'], + 'value' => $value['value'], + 'price' => $value['price'], + ]); + } + array_push($specList, $items); + } + $cartesianList = $this->cartesianProduct($specList); + foreach($cartesianList as $items) { + $sub_goods_name = $goods_name; + $sub_price = $goods_price; + + $goods->skus()->create([ + 'sn' => $this->generateSn(), + 'name' => $sub_goods_name, + 'price' => $sub_price, + 'stock' => $goods->stock, + 'spec' => $items, + ]); + } + } + } + + protected function cartesianProduct($sets) + { + // 保存结果 + $result = []; + if (count($sets) === 1) { + // 保存临时数据 + $tmp = array(); + // 结果与下一个集合计算笛卡尔积 + foreach($sets[0] as $set) { + $item = []; + if (isset($set['value'])) { + array_push($item, $set); + } else { + $item = $set; + } + array_push($item, $set); + $tmp[] = $item; + } + // 将笛卡尔积写入结果 + $result = $tmp; + return $result; + } + // 循环遍历集合数据 + for($i = 0; $i < count($sets) -1 ; $i++) { + // 初始化 + if($i==0){ + $result = $sets[$i]; + } + // 保存临时数据 + $tmp = array(); + // 结果与下一个集合计算笛卡尔积 + foreach($result as $res) { + foreach($sets[$i+1] as $set) { + $item = []; + if (isset($res['value'])) { + array_push($item, $res); + } else { + $item = $res; + } + array_push($item, $set); + $tmp[] = $item; + } + } + // 将笛卡尔积写入结果 + $result = $tmp; + } + return $result; + } +} diff --git a/packages/goods/src/GoodsServiceProvider.php b/packages/goods/src/GoodsServiceProvider.php index 8e6b5a1..5d0f646 100644 --- a/packages/goods/src/GoodsServiceProvider.php +++ b/packages/goods/src/GoodsServiceProvider.php @@ -10,5 +10,6 @@ class GoodsServiceProvider extends ServiceProvider protected $menu = [ ['title' => '商品管理', 'uri' => '', 'icon' => ''], ['title' => '商品分类', 'uri' => 'goods/category', 'icon' => '', 'parent' => '商品管理'], + ['title' => '商品信息', 'uri' => 'goods', 'icon' => '', 'parent' => '商品管理'], ]; } diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsController.php b/packages/goods/src/Http/Controllers/Admin/GoodsController.php new file mode 100644 index 0000000..3e18af5 --- /dev/null +++ b/packages/goods/src/Http/Controllers/Admin/GoodsController.php @@ -0,0 +1,83 @@ +model()->sort(); + + $grid->selector(function (Selector $selector) { + $brands = GoodsBrand::get(); + $types = GoodsType::get(); + $categories = GoodsCategory::where('level', 3)->get(); + $prices = ['0-999', '1000-1999', '2000-4999', '5000+']; + $selector->selectOne('category_id', __('peidikeji.dcat-admin-extension-goods::goods.fields.category_id'), $categories->pluck('name', 'id')); + $selector->selectOne('brand_id', __('peidikeji.dcat-admin-extension-goods::goods.fields.brand_id'), $brands->pluck('name', 'id')); + $selector->selectOne('type_id', __('peidikeji.dcat-admin-extension-goods::goods.fields.type_id'), $types->pluck('name', 'id')); + $selector->selectOne('price', __('peidikeji.dcat-admin-extension-goods::goods.fields.price'), $prices, function ($q, $value) use ($prices) { + $parsePrice = data_get($prices, $value); + if ($parsePrice) { + $parts = explode('-', $parsePrice); + $parts = array_map(fn($v) => (int)$v, $parts); + if (count($parts) > 1) { + $q->whereBetween('price', $parts); + } else { + $q->where('price', '>', $parts[0]); + } + } + }); + }); + + $grid->column('goods_sn'); + $grid->column('category.name'); + $grid->column('brand.name'); + $grid->column('type.name')->label(); + $grid->column('name')->display(function () { + return ($this->cover_image ? ' ' : '') . ''.$this->name.''; + }); + $grid->column('price'); + $grid->column('spec')->view('peidikeji.dcat-admin-extension-goods::grid.spec'); + $grid->column('on_sale')->switch(); + $grid->column('sold_count'); + + $grid->disableRowSelector(); + }); + } + + protected function detail($id) + { + $info = Goods::with(['category', 'brand', 'type'])->findOrFail($id); + $show = Show::make($info); + $show->field('goods_sn'); + $show->field('category.name'); + $show->field('brand.name'); + $show->field('type.name'); + $show->field('name'); + $show->field('price'); + $show->field('cover_image')->image('', 100); + $show->field('images')->image('', 100); + $show->field('content')->image(''); + $show->field('spec')->view('peidikeji.dcat-admin-extension-goods::grid.spec'); + $show->field('attr')->view('peidikeji.dcat-admin-extension-goods::grid.attr'); + $show->field('part')->view('peidikeji.dcat-admin-extension-goods::grid.spec'); + $show->field('on_sale')->bool(); + $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; + } +} diff --git a/packages/goods/src/Http/routes.php b/packages/goods/src/Http/routes.php index 6e9220b..4f98c7c 100644 --- a/packages/goods/src/Http/routes.php +++ b/packages/goods/src/Http/routes.php @@ -5,3 +5,5 @@ namespace Peidikeji\Goods\Http\Controllers\Admin; use Illuminate\Support\Facades\Route; Route::resource('goods/category', GoodsCategoryController::class); + +Route::resource('goods', GoodsController::class); diff --git a/packages/goods/src/Models/Goods.php b/packages/goods/src/Models/Goods.php index ed4609f..6ee0993 100644 --- a/packages/goods/src/Models/Goods.php +++ b/packages/goods/src/Models/Goods.php @@ -11,5 +11,38 @@ class Goods extends Model protected $table = 'goods'; - protected $fillable = ['attr', 'category_id', 'content', 'cover_image', 'deleted_at', 'description', 'goods_sn', 'images', 'name', 'on_sale', 'part', 'price', 'sold_count', 'spec', 'stock']; + protected $fillable = ['attr', 'category_id', 'type_id', 'brand_id', 'content', 'cover_image', 'deleted_at', 'description', 'goods_sn', 'images', 'name', 'on_sale', 'part', 'price', 'sold_count', 'spec', 'stock']; + + protected $casts = [ + 'attr' => 'array', + 'spec' => 'array', + 'part' => 'array', + 'content' => 'array', + 'images' => 'array', + ]; + + public function category() + { + return $this->belongsTo(GoodsCategory::class, 'category_id'); + } + + public function type() + { + return $this->belongsTo(GoodsType::class, 'type_id'); + } + + public function brand() + { + return $this->belongsTo(GoodsBrand::class, 'brand_id'); + } + + public function skus() + { + return $this->hasMany(GoodsSku::class, 'goods_id'); + } + + public function scopeSort($q) + { + return $q->orderBy('created_at', 'desc'); + } } diff --git a/packages/goods/src/Models/GoodsBrand.php b/packages/goods/src/Models/GoodsBrand.php new file mode 100644 index 0000000..367562c --- /dev/null +++ b/packages/goods/src/Models/GoodsBrand.php @@ -0,0 +1,14 @@ + 'array', + ]; + + public $timestamps = false; + + public function goods() + { + return $this->belongsTo(Goods::class, 'goods_id'); + } +} diff --git a/packages/goods/src/Models/GoodsType.php b/packages/goods/src/Models/GoodsType.php new file mode 100644 index 0000000..a2d1f22 --- /dev/null +++ b/packages/goods/src/Models/GoodsType.php @@ -0,0 +1,20 @@ + 'array', + 'spec' => 'array', + 'part' => 'array', + ]; + + public $timestamps = false; +} diff --git a/packages/goods/updates/CreateGoodsTable.php b/packages/goods/updates/CreateGoodsTable.php index 020696a..5ab70e6 100644 --- a/packages/goods/updates/CreateGoodsTable.php +++ b/packages/goods/updates/CreateGoodsTable.php @@ -25,18 +25,36 @@ class CreateGoodsTable extends Migration $table->unsignedTinyInteger('is_enable')->default(1)->comment('状态'); $table->string('path')->default('-')->comment('所有的父级ID'); - $table->comment('商品分类'); + $table->comment('商品-分类'); + }); + + Schema::create('goods_type', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->json('attr')->nullable()->comment('属性[{name: "属性名", values: [可选值]}]'); + $table->json('spec')->nullable()->comment('规格[{name: "属性名", values: [可选值]}]'); + $table->json('part')->nullable()->comment('配件[{name: "属性名", values: [可选值]}]'); + $table->comment('商品-类型'); + }); + + Schema::create('goods_brand', function (Blueprint $table) { + $table->id(); + $table->string('name')->comment('名称'); + $table->string('image')->nullable()->comment('图标'); + $table->comment('商品-品牌'); }); Schema::create('goods', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('category_id')->comment('所属分类, 关联 goods_category.id'); + $table->unsignedBigInteger('type_id')->nullable()->comment('所属类别'); + $table->unsignedBigInteger('brand_id')->nullable()->comment('所属品牌'); $table->string('name')->comment('商品名称'); $table->string('goods_sn')->unique()->comment('编号'); $table->string('cover_image')->nullable()->comment('封面图'); $table->json('images')->nullable()->comment('图片集'); $table->string('description')->nullable()->comment('描述'); - $table->text('content')->nullable()->comment('详细'); + $table->json('content')->nullable()->comment('详细'); $table->unsignedInteger('on_sale')->default(0)->comment('是否上架'); $table->unsignedInteger('stock')->default(0)->comment('库存'); $table->unsignedInteger('sold_count')->default(0)->comment('销量'); @@ -48,6 +66,8 @@ class CreateGoodsTable extends Migration $table->softDeletes(); $table->foreign('category_id')->references('id')->on('goods_category'); + $table->foreign('type_id')->references('id')->on('goods_type'); + $table->foreign('brand_id')->references('id')->on('goods_brand'); $table->comment('商品'); }); @@ -77,5 +97,7 @@ class CreateGoodsTable extends Migration Schema::dropIfExists('goods_sku'); Schema::dropIfExists('goods'); Schema::dropIfExists('goods_category'); + Schema::dropIfExists('goods_type'); + Schema::dropIfExists('goods_brand'); } }; diff --git a/packages/goods/updates/GoodsTableSeeder.php b/packages/goods/updates/GoodsTableSeeder.php new file mode 100644 index 0000000..f52eadf --- /dev/null +++ b/packages/goods/updates/GoodsTableSeeder.php @@ -0,0 +1,179 @@ + '1', 'children' => [ + ['name' => '1-1', 'children' => [ + ['name' => '1-1-1'] + ]] + ]], + ['name' => '2', 'children' => [ + ['name' => '2-2', 'children' => [ + ['name' => '2-2-2'] + ]] + ]], + ]; + + $this->createCategory($categoryList); + + GoodsType::truncate(); + $types = [ + [ + 'name' => '手机', + 'attr' => [ + ['name' => '入网型号', 'values' => ['5G', '4G']], + ['name' => '上市年份', 'values' => null], + ['name' => '品牌', 'values' => null] + ], + 'spec' => [ + ['name' => '颜色', 'values' => ['白色', '红色', '黑色']], + ['name' => '内存', 'values' => ['32G', '64G', '128G']], + ], + 'part' => [ + ['name' => '套餐', 'values' => ['套餐1', '套餐2', '套餐3']] + ] + ], + [ + 'name' => '笔记本电脑', + 'attr' => [ + ['name' => '屏幕类型', 'values' => ['LED 背光显示屏']], + ['name' => '物理分辨率', 'values' => ['3072 x 1920 (226 ppi)']], + ], + 'spec' => [ + ['name' => '颜色', 'values' => ['白色', '灰色']], + ['name' => '内存', 'values' => ['16G', '32G', '64G']], + ], + 'part' => [ + ['name' => '套餐', 'values' => ['优惠套装1', '优惠套装2', '优惠套装3']] + ] + ], + ]; + foreach($types as $item) { + GoodsType::create($item); + } + + GoodsBrand::truncate(); + GoodsBrand::insert([ + ['name' => '三星', 'image' => 'https://img20.360buyimg.com/popshop/jfs/t1/1534/38/9873/3556/5bc93df2E73c40121/74dc92d16e483509.jpg'], + ['name' => 'Apple', 'image' => 'https://img20.360buyimg.com/popshop/jfs/t2989/240/151377693/3895/30ad9044/574d36dbN262ef26d.jpg'], + ]); + + Goods::truncate(); + GoodsSku::truncate(); + $goodsList = [ + [ + 'category_id' => 3, + 'type_id' => 1, + 'brand_id' => 1, + 'goods_sn' => '1016', + 'name' => '三星Galaxy Noet10+ 5G(SM-N9760)', + 'cover_image' => 'https://img14.360buyimg.com/n5/s54x54_jfs/t1/85701/3/3164/116271/5ddcffaeEd7924f35/013d69c48b507982.jpg', + 'content' => ['https://img30.360buyimg.com/sku/jfs/t1/91355/34/4028/288919/5de4c653Ed267b5d0/b67ac088ded04947.jpg'], + 'images' => [ + 'https://img14.360buyimg.com/n0/jfs/t1/138249/34/51/266266/5edaed2fE2d4d4050/297b76afaff928bb.jpg', + 'https://img14.360buyimg.com/n0/jfs/t1/85701/3/3164/116271/5ddcffaeEd7924f35/013d69c48b507982.jpg', + 'https://img14.360buyimg.com/n0/jfs/t1/43997/21/12754/274595/5d5f87f1Ec419d2f9/358032d0a7a2ccd7.jpg' + ], + 'stock' => 100, + 'price' => 6499.00, + 'attr' => [ + ['name' => '入网型号', 'value' => '5G'], + ['name' => '品牌', 'value' => '三星Galaxy'], + ['name' => '上市年份', 'value' => '2020'], + ], + 'spec' => [ + ['name' => '颜色', 'values' => [ + ['value' => '白色', 'price' => 0], + ['value' => '红色', 'price' => 800], + ['value' => '黑色', 'price' => 0], + ]], + ['name' => '内存', 'values' => [ + ['value' => '32G', 'price' => 0], + ['value' => '64G', 'price' => 1000], + ['value' => '128G', 'price' => 2000], + ]] + ], + 'part' => [ + ['name' => '套餐', 'values' => [ + ['value' => '套餐1', 'price' => 850], + ['value' => '套餐2', 'price' => 1200], + ['value' => '套餐3', 'price' => 1800], + ]] + ], + ], + [ + 'category_id' => 6, + 'type_id' => 2, + 'brand_id' => 2, + 'goods_sn' => '1017', + 'name' => 'MacBook Pro 16英寸', + 'cover_image' => 'https://img14.360buyimg.com/n0/jfs/t1/64979/31/15492/115459/5dd3d4f2E75b0a9a6/95c273eda00e67c0.jpg', + 'description' => '', + 'content' => ['https://img11.360buyimg.com/cms/jfs/t1/77779/20/15834/638477/5dd3d469Eca9fa4a7/26ff2bd661580a86.jpg'], + 'images' => [ + 'https://img14.360buyimg.com/n0/jfs/t1/64979/31/15492/115459/5dd3d4f2E75b0a9a6/95c273eda00e67c0.jpg', + 'https://img14.360buyimg.com/n0/jfs/t1/50902/13/16242/169086/5dd3d4f2E19e1994f/ff8ecd5a61c1bebb.jpg', + 'https://img14.360buyimg.com/n0/jfs/t1/104429/27/2676/303491/5dd3d4f3E6fd2b80a/b7213eaf5be44b49.jpg' + ], + 'stock' => 150, + 'price' => 17999.00, + 'attr' => [ + ['name' => '屏幕类型', 'value' => 'LED 背光显示屏'], + ['name' => '物理分辨率', 'value' => '3072 x 1920 (226 ppi)'], + ], + 'spec' => [ + ['name' => '颜色', 'values' => [ + ['value' => '白色', 'price' => 0], + ['value' => '灰色', 'price' => 0] + ]], + ['name' => '内存', 'values' => [ + ['value' => '16G', 'price' => 0], + ['value' => '32G', 'price' => 3000], + ['value' => '64G', 'price' => 6000], + ]] + ], + 'part' => [ + ['name' => '套餐', 'values' => [ + ['value' => '优惠套装1', 'price' => 850], + ['value' => '优惠套装2', 'price' => 650], + ['value' => '优惠套装3', 'price' => 1000], + ]] + ], + ] + ]; + + $service = GoodsService::make(); + foreach($goodsList as $item) { + $goods = Goods::create($item); + $service->generateSku($goods); + } + } + + protected function createCategory($list, $pid = 0) + { + foreach($list as $key => $item) { + $attributes = Arr::except($item, ['children']); + $attributes['parent_id'] = $pid; + $attributes['sort'] = $key + 1; + $category = GoodsCategory::create($attributes); + if ($children = data_get($item, 'children')) { + $this->createCategory($children, $category->id); + } + } + } +} diff --git a/packages/goods/version.php b/packages/goods/version.php index bfc02ed..cb0a8b4 100644 --- a/packages/goods/version.php +++ b/packages/goods/version.php @@ -3,5 +3,6 @@ return [ '1.0.0' => [ 'CreateGoodsTable.php', + 'GoodsTableSeeder.php', ], ]; From a08604bf82f867b18fb811846ff956441150b5ae Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Mon, 1 Aug 2022 15:07:32 +0800 Subject: [PATCH 2/8] goods --- .../Controllers/Admin/GoodsController.php | 33 +++++++++++++++++++ packages/goods/src/Models/GoodsCategory.php | 14 ++++++++ 2 files changed, 47 insertions(+) diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsController.php b/packages/goods/src/Http/Controllers/Admin/GoodsController.php index 3e18af5..c5ab3c6 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsController.php @@ -2,6 +2,7 @@ namespace Peidikeji\Goods\Http\Controllers\Admin; +use Dcat\Admin\Form; use Dcat\Admin\Grid; use Dcat\Admin\Grid\Tools\Selector; use Dcat\Admin\Http\Controllers\AdminController; @@ -80,4 +81,36 @@ class GoodsController extends AdminController $show->field('updated_at')->as(fn($v) => $this->updated_at->format('Y-m-d H:i:s')); return $show; } + + protected function form() + { + return Form::make(new Goods(), function (Form $form) { + $form->select('category_id')->options(GoodsCategory::selectOptions(null, false))->required(); + $form->select('brand_id')->options(GoodsBrand::pluck('name', 'id')); + $form->select('type_id')->options(GoodsType::pluck('name', 'id')); + $form->text('name')->required(); + $form->text('goods_sn'); + $form->image('cover_image') + ->autoUpload() + ->saveFullUrl() + ->move('goods') + ->required(); + $form->multipleImage('images') + ->autoUpload() + ->saveFullUrl() + ->move('goods'); + $form->multipleImage('content') + ->autoUpload() + ->saveFullUrl() + ->move('goods'); + + $form->number('price')->min(0)->attribute('step', 0.01); + $form->switch('on_sale'); + + $form->disableResetButton(); + $form->disableCreatingCheck(); + $form->disableViewCheck(); + $form->disableEditingCheck(); + }); + } } diff --git a/packages/goods/src/Models/GoodsCategory.php b/packages/goods/src/Models/GoodsCategory.php index a18c8dd..dda29e3 100644 --- a/packages/goods/src/Models/GoodsCategory.php +++ b/packages/goods/src/Models/GoodsCategory.php @@ -49,6 +49,20 @@ class GoodsCategory extends Model }); } + public static function selectOptions(\Closure $closure = null, $rootText = null) + { + $options = (new static())->withQuery($closure)->buildSelectOptions(); + + $list = collect($options); + + if ($rootText !== false) { + $rootText = $rootText ?: admin_trans_label('root'); + $list->prepend($rootText, 0); + } + + return $list->all(); + } + public function parent() { return $this->belongsTo(self::class, 'parent_id'); From 9fcd37b6464870c58ae57521f51b068cf31e9d9a Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Mon, 1 Aug 2022 15:52:00 +0800 Subject: [PATCH 3/8] goods-brand --- .../goods/resources/lang/en/goods-brand.php | 3 + .../goods/resources/lang/en/goods-type.php | 3 + .../resources/lang/zh_CN/goods-brand.php | 13 ++++ .../goods/resources/lang/zh_CN/goods-type.php | 16 +++++ .../goods/resources/views/grid/part.blade.php | 15 +++++ .../goods/resources/views/grid/spec.blade.php | 6 +- packages/goods/src/GoodsServiceProvider.php | 2 + .../Admin/GoodsBrandController.php | 50 +++++++++++++++ .../Admin/GoodsCategoryController.php | 2 +- .../Controllers/Admin/GoodsController.php | 6 +- .../Controllers/Admin/GoodsTypeController.php | 64 +++++++++++++++++++ packages/goods/src/Http/routes.php | 2 + packages/goods/src/Models/GoodsBrand.php | 5 ++ packages/goods/updates/CreateGoodsTable.php | 8 +-- 14 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 packages/goods/resources/lang/en/goods-brand.php create mode 100644 packages/goods/resources/lang/en/goods-type.php create mode 100644 packages/goods/resources/lang/zh_CN/goods-brand.php create mode 100644 packages/goods/resources/lang/zh_CN/goods-type.php create mode 100644 packages/goods/resources/views/grid/part.blade.php create mode 100644 packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php create mode 100644 packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php diff --git a/packages/goods/resources/lang/en/goods-brand.php b/packages/goods/resources/lang/en/goods-brand.php new file mode 100644 index 0000000..0b67a5f --- /dev/null +++ b/packages/goods/resources/lang/en/goods-brand.php @@ -0,0 +1,3 @@ + [ + 'GoodsBrand' => '品牌管理', + 'goods' => '商品管理', + 'brand' => '品牌', + ], + 'fields' => [ + 'name' => '名称', + 'image' => '图片', + ] +]; diff --git a/packages/goods/resources/lang/zh_CN/goods-type.php b/packages/goods/resources/lang/zh_CN/goods-type.php new file mode 100644 index 0000000..e653e2f --- /dev/null +++ b/packages/goods/resources/lang/zh_CN/goods-type.php @@ -0,0 +1,16 @@ + [ + 'GoodsType' => '商品类别', + 'goods' => '商品管理', + 'brand' => '类别', + ], + 'fields' => [ + 'name' => '名称', + 'spec' => '规格', + 'attr' => '属性', + 'part' => '配件', + 'values' => '可选值', + ] +]; diff --git a/packages/goods/resources/views/grid/part.blade.php b/packages/goods/resources/views/grid/part.blade.php new file mode 100644 index 0000000..69a636a --- /dev/null +++ b/packages/goods/resources/views/grid/part.blade.php @@ -0,0 +1,15 @@ + + + +@if($value) +@foreach($value as $item) +
+ {{ $item['name'] }} + @if($item['values']) + @foreach($item['values'] as $subItem) + {{ $subItem }} + @endforeach + @endif +
+@endforeach +@endif diff --git a/packages/goods/resources/views/grid/spec.blade.php b/packages/goods/resources/views/grid/spec.blade.php index 697e800..e5aa0a5 100644 --- a/packages/goods/resources/views/grid/spec.blade.php +++ b/packages/goods/resources/views/grid/spec.blade.php @@ -5,9 +5,11 @@ @foreach($value as $item)
{{ $item['name'] }} - @foreach($item['values'] as $value) - {{ $value['value'] }}({{ $value['price'] }}) + @if($item['values']) + @foreach($item['values'] as $subItem) + {{ $subItem['value'] }}({{ $subItem['price'] }}) @endforeach + @endif
@endforeach @endif diff --git a/packages/goods/src/GoodsServiceProvider.php b/packages/goods/src/GoodsServiceProvider.php index 5d0f646..6dac8d7 100644 --- a/packages/goods/src/GoodsServiceProvider.php +++ b/packages/goods/src/GoodsServiceProvider.php @@ -10,6 +10,8 @@ class GoodsServiceProvider extends ServiceProvider protected $menu = [ ['title' => '商品管理', 'uri' => '', 'icon' => ''], ['title' => '商品分类', 'uri' => 'goods/category', 'icon' => '', 'parent' => '商品管理'], + ['title' => '品牌管理', 'uri' => 'goods/brand', 'icon' => '', 'parent' => '商品管理'], + ['title' => '商品类别', 'uri' => 'goods/type', 'icon' => '', 'parent' => '商品管理'], ['title' => '商品信息', 'uri' => 'goods', 'icon' => '', 'parent' => '商品管理'], ]; } diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php new file mode 100644 index 0000000..65df6eb --- /dev/null +++ b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php @@ -0,0 +1,50 @@ +disableRowSelector(); + + $grid->disableViewButton(); + + $grid->column('name'); + $grid->column('image')->image('', 120); + }); + } + + protected function form() + { + return Form::make(new GoodsBrand(), function (Form $form) { + $form->text('name'); + $form->image('image')->autoUpload()->saveFullUrl()->move('goods/brand'); + + $form->disableResetButton(); + $form->disableCreatingCheck(); + $form->disableViewCheck(); + $form->disableEditingCheck(); + + $form->deleting(function (Form $form) { + $data = $form->model()->toArray(); + foreach($data as $item) { + $id = data_get($item, 'id'); + // 品牌下面包含商品, 阻止删除 + if (Goods::where('brand_id', $id)->exists()) { + return $form->response()->error('请先删除关联的商品'); + } + } + }); + }); + } +} diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsCategoryController.php b/packages/goods/src/Http/Controllers/Admin/GoodsCategoryController.php index 6223aef..c71c529 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsCategoryController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsCategoryController.php @@ -35,7 +35,7 @@ class GoodsCategoryController extends AdminController $form->text('name')->required(); $form->image('image') ->uniqueName() - ->move('article-category') + ->move('goods/category') ->autoUpload(); $form->number('sort') ->min(0) diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsController.php b/packages/goods/src/Http/Controllers/Admin/GoodsController.php index c5ab3c6..4263b2d 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsController.php @@ -93,16 +93,16 @@ class GoodsController extends AdminController $form->image('cover_image') ->autoUpload() ->saveFullUrl() - ->move('goods') + ->move('goods/goods') ->required(); $form->multipleImage('images') ->autoUpload() ->saveFullUrl() - ->move('goods'); + ->move('goods/goods'); $form->multipleImage('content') ->autoUpload() ->saveFullUrl() - ->move('goods'); + ->move('goods/goods'); $form->number('price')->min(0)->attribute('step', 0.01); $form->switch('on_sale'); diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php b/packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php new file mode 100644 index 0000000..87a9f1f --- /dev/null +++ b/packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php @@ -0,0 +1,64 @@ +disableRowSelector(); + $grid->disableViewButton(); + + $grid->column('name'); + $grid->column('attr')->view('peidikeji.dcat-admin-extension-goods::grid.part'); + $grid->column('spec')->view('peidikeji.dcat-admin-extension-goods::grid.part'); + $grid->column('part')->view('peidikeji.dcat-admin-extension-goods::grid.part'); + }); + } + + protected function form() + { + return Form::make(new GoodsType(), function (Form $form) { + $form->text('name'); + + $form->array('attr', function (NestedForm $table) { + $table->text('name')->required(); + $table->list('values'); + }); + $form->array('spec', function (NestedForm $table) { + $table->text('name')->required(); + $table->list('values'); + }); + $form->array('part', function (NestedForm $table) { + $table->text('name')->required(); + $table->list('values'); + }); + + $form->disableResetButton(); + $form->disableCreatingCheck(); + $form->disableViewCheck(); + $form->disableEditingCheck(); + + $form->deleting(function (Form $form) { + $data = $form->model()->toArray(); + foreach($data as $item) { + $id = data_get($item, 'id'); + // 下面包含商品, 阻止删除 + if (Goods::where('type_id', $id)->exists()) { + return $form->response()->error('请先删除关联的商品'); + } + } + }); + }); + } +} diff --git a/packages/goods/src/Http/routes.php b/packages/goods/src/Http/routes.php index 4f98c7c..8337ee7 100644 --- a/packages/goods/src/Http/routes.php +++ b/packages/goods/src/Http/routes.php @@ -5,5 +5,7 @@ namespace Peidikeji\Goods\Http\Controllers\Admin; use Illuminate\Support\Facades\Route; Route::resource('goods/category', GoodsCategoryController::class); +Route::resource('goods/brand', GoodsBrandController::class); +Route::resource('goods/type', GoodsTypeController::class); Route::resource('goods', GoodsController::class); diff --git a/packages/goods/src/Models/GoodsBrand.php b/packages/goods/src/Models/GoodsBrand.php index 367562c..c0a6b58 100644 --- a/packages/goods/src/Models/GoodsBrand.php +++ b/packages/goods/src/Models/GoodsBrand.php @@ -11,4 +11,9 @@ class GoodsBrand extends Model protected $fillable = ['name', 'image']; public $timestamps = false; + + public function goods() + { + return $this->hasMany(Goods::class, 'brand_id'); + } } diff --git a/packages/goods/updates/CreateGoodsTable.php b/packages/goods/updates/CreateGoodsTable.php index 5ab70e6..0e81261 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('属性'); - $table->json('spec')->nullable()->comment('规格'); - $table->json('part')->nullable()->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->timestamps(); $table->softDeletes(); @@ -79,7 +79,7 @@ class CreateGoodsTable extends Migration $table->string('name')->comment('名称'); $table->decimal('price', 12, 2)->comment('价格'); $table->unsignedInteger('stock')->comment('库存'); - $table->json('spec')->nullable()->comment('规格'); + $table->json('spec')->nullable()->comment('规格[{name, value, price}]'); $table->foreign('goods_id')->references('id')->on('goods'); From c923c50abe567a824b24b2d02b9f51a60d96c52e Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Tue, 2 Aug 2022 15:32:47 +0800 Subject: [PATCH 4/8] goods --- .../goods/resources/lang/en/goods-sku.php | 3 + .../goods/resources/lang/zh_CN/goods-sku.php | 16 ++ .../goods/src/Actions/RowGoodsSkuList.php | 16 ++ packages/goods/src/GoodsService.php | 12 +- .../Admin/GoodsBrandController.php | 6 +- .../Controllers/Admin/GoodsController.php | 6 + .../Controllers/Admin/GoodsSkuController.php | 170 ++++++++++++++++++ packages/goods/src/Http/routes.php | 2 + packages/goods/src/Models/GoodsSku.php | 19 ++ 9 files changed, 242 insertions(+), 8 deletions(-) create mode 100644 packages/goods/resources/lang/en/goods-sku.php create mode 100644 packages/goods/resources/lang/zh_CN/goods-sku.php create mode 100644 packages/goods/src/Actions/RowGoodsSkuList.php create mode 100644 packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php 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; + } } From 41eafd3cdd7649152e8cefbc03ee4f2429f7e21d Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Tue, 2 Aug 2022 15:38:39 +0800 Subject: [PATCH 5/8] sku detaul --- .../goods/resources/views/grid/attr.blade.php | 2 +- .../Controllers/Admin/GoodsSkuController.php | 25 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/goods/resources/views/grid/attr.blade.php b/packages/goods/resources/views/grid/attr.blade.php index e630876..643a91d 100644 --- a/packages/goods/resources/views/grid/attr.blade.php +++ b/packages/goods/resources/views/grid/attr.blade.php @@ -5,7 +5,7 @@ @foreach($value as $item)
{{ $item['name'] }} - {{ $item['value'] }} + {{ $item['value'] }} {{ isset($item['price']) ? '(+'.$item['price'].')' : '' }}
@endforeach @endif diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php b/packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php index 8584747..d61019d 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsSkuController.php @@ -59,24 +59,25 @@ class GoodsSkuController extends Controller ->body($grid); } - public function show($id, Content $content) + public function show($goods, $id, Content $content) { - $info = GoodsSku::with(['goods'])->findOrFail($id); + $goods = Goods::findOrFail($goods); + $info = GoodsSku::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(); - } + $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) From f050bbf5b5f5a629143c64421c47ad483e36ae2d Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Wed, 3 Aug 2022 15:00:58 +0800 Subject: [PATCH 6/8] goods create --- .../goods/resources/lang/zh_CN/goods-sku.php | 3 +- .../goods/resources/lang/zh_CN/goods-type.php | 3 +- packages/goods/resources/lang/zh_CN/goods.php | 2 + .../Admin/GoodsBrandController.php | 7 +- .../Controllers/Admin/GoodsController.php | 125 +++++++++++++++--- .../Controllers/Admin/GoodsSkuController.php | 1 + .../Controllers/Admin/GoodsTypeController.php | 1 + packages/goods/updates/GoodsTableSeeder.php | 20 +-- src/Form.php | 3 +- 9 files changed, 131 insertions(+), 34 deletions(-) diff --git a/packages/goods/resources/lang/zh_CN/goods-sku.php b/packages/goods/resources/lang/zh_CN/goods-sku.php index 3edc557..5c8f5bc 100644 --- a/packages/goods/resources/lang/zh_CN/goods-sku.php +++ b/packages/goods/resources/lang/zh_CN/goods-sku.php @@ -9,8 +9,9 @@ return [ 'fields' => [ 'sn' => '货号', 'name' => '名称', - 'price' => '价格', + 'price' => '售价', 'stock' => '库存', 'spec' => '规格', + 'origin_price' => '原价', ] ]; diff --git a/packages/goods/resources/lang/zh_CN/goods-type.php b/packages/goods/resources/lang/zh_CN/goods-type.php index e653e2f..c2c16dc 100644 --- a/packages/goods/resources/lang/zh_CN/goods-type.php +++ b/packages/goods/resources/lang/zh_CN/goods-type.php @@ -4,7 +4,7 @@ return [ 'labels' => [ 'GoodsType' => '商品类别', 'goods' => '商品管理', - 'brand' => '类别', + 'type' => '商品类别', ], 'fields' => [ 'name' => '名称', @@ -12,5 +12,6 @@ return [ 'attr' => '属性', 'part' => '配件', 'values' => '可选值', + 'group' => '分组', ] ]; diff --git a/packages/goods/resources/lang/zh_CN/goods.php b/packages/goods/resources/lang/zh_CN/goods.php index 23838e5..f314135 100644 --- a/packages/goods/resources/lang/zh_CN/goods.php +++ b/packages/goods/resources/lang/zh_CN/goods.php @@ -4,6 +4,8 @@ return [ 'labels' => [ 'Goods' => '商品信息', 'goods' => '商品信息', + 'create' => '创建', + 'edit' => '修改', ], 'fields' => [ 'category_id' => '分类', diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php index 89c4864..946956e 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php @@ -32,7 +32,12 @@ class GoodsBrandController extends AdminController ->autoUpload() ->saveFullUrl() ->move('goods/brand'); - // $form->oss('file')->dir('mv'); + $form->oss('file')->config([ + 'accessId' => 'LTAI5tFMaynxgZ9aDMNLxpU9', + 'accessKey' => 'pecJA3LX2sQyWxWDMUUb5NhsMe4Czu', + 'host' => 'https://zcs-test.oss-cn-chengdu.aliyuncs.com', + '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 4c9f517..10f80a0 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsController.php @@ -2,7 +2,11 @@ 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; @@ -91,32 +95,113 @@ class GoodsController extends AdminController protected function form() { return Form::make(new Goods(), function (Form $form) { - $form->select('category_id')->options(GoodsCategory::selectOptions(null, false))->required(); - $form->select('brand_id')->options(GoodsBrand::pluck('name', 'id')); - $form->select('type_id')->options(GoodsType::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'); + $model = $form->model(); + $isCreating = $form->isCreating(); + $type = null; - $form->number('price')->min(0)->attribute('step', 0.01); - $form->switch('on_sale'); + 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; + } + + $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->disableResetButton(); $form->disableCreatingCheck(); $form->disableViewCheck(); $form->disableEditingCheck(); + + $admin_url = request()->url(); + Admin::script( + <<column('sn'); $grid->column('name'); + $grid->column('origin_price')->display(fn() => $goods->price); $grid->column('price'); $grid->column('stock'); foreach($goods->spec as $key => $item) { diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php b/packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php index 87a9f1f..950b5c4 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsTypeController.php @@ -33,6 +33,7 @@ class GoodsTypeController extends AdminController $form->array('attr', function (NestedForm $table) { $table->text('name')->required(); + $table->text('group'); $table->list('values'); }); $form->array('spec', function (NestedForm $table) { diff --git a/packages/goods/updates/GoodsTableSeeder.php b/packages/goods/updates/GoodsTableSeeder.php index f52eadf..bf0f38f 100644 --- a/packages/goods/updates/GoodsTableSeeder.php +++ b/packages/goods/updates/GoodsTableSeeder.php @@ -36,9 +36,9 @@ class GoodsTableSeeder extends Seeder [ 'name' => '手机', 'attr' => [ - ['name' => '入网型号', 'values' => ['5G', '4G']], - ['name' => '上市年份', 'values' => null], - ['name' => '品牌', 'values' => null] + ['group' => '主体', 'name' => '入网型号', 'values' => ['5G', '4G']], + ['group' => '主体', 'name' => '上市年份', 'values' => null], + ['group' => '主体', 'name' => '品牌', 'values' => null] ], 'spec' => [ ['name' => '颜色', 'values' => ['白色', '红色', '黑色']], @@ -51,8 +51,8 @@ class GoodsTableSeeder extends Seeder [ 'name' => '笔记本电脑', 'attr' => [ - ['name' => '屏幕类型', 'values' => ['LED 背光显示屏']], - ['name' => '物理分辨率', 'values' => ['3072 x 1920 (226 ppi)']], + ['group' => '显示器', 'name' => '屏幕类型', 'values' => ['LED 背光显示屏']], + ['group' => '显示器','name' => '物理分辨率', 'values' => ['3072 x 1920 (226 ppi)']], ], 'spec' => [ ['name' => '颜色', 'values' => ['白色', '灰色']], @@ -92,9 +92,9 @@ class GoodsTableSeeder extends Seeder 'stock' => 100, 'price' => 6499.00, 'attr' => [ - ['name' => '入网型号', 'value' => '5G'], - ['name' => '品牌', 'value' => '三星Galaxy'], - ['name' => '上市年份', 'value' => '2020'], + ['group' => '主体', 'name' => '入网型号', 'value' => '5G'], + ['group' => '主体', 'name' => '品牌', 'value' => '三星Galaxy'], + ['group' => '主体', 'name' => '上市年份', 'value' => '2020'], ], 'spec' => [ ['name' => '颜色', 'values' => [ @@ -133,8 +133,8 @@ class GoodsTableSeeder extends Seeder 'stock' => 150, 'price' => 17999.00, 'attr' => [ - ['name' => '屏幕类型', 'value' => 'LED 背光显示屏'], - ['name' => '物理分辨率', 'value' => '3072 x 1920 (226 ppi)'], + ['group' => '显示器','name' => '屏幕类型', 'value' => 'LED 背光显示屏'], + ['group' => '显示器','name' => '物理分辨率', 'value' => '3072 x 1920 (226 ppi)'], ], 'spec' => [ ['name' => '颜色', 'values' => [ diff --git a/src/Form.php b/src/Form.php index b6cb6cb..0592589 100755 --- a/src/Form.php +++ b/src/Form.php @@ -1183,13 +1183,14 @@ class Form implements Renderable { $this->build(); + $this->fillFields($this->model()->toArray()); + if ($this->isCreating()) { $this->callCreating(); return; } - $this->fillFields($this->model()->toArray()); $this->callEditing(); } From 4b4a79fde747000b0ba24395d54ce8fafc56ef48 Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Wed, 3 Aug 2022 15:02:13 +0800 Subject: [PATCH 7/8] 1 --- .../Http/Controllers/Admin/GoodsBrandController.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php index 946956e..79618c6 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsBrandController.php @@ -32,12 +32,12 @@ class GoodsBrandController extends AdminController ->autoUpload() ->saveFullUrl() ->move('goods/brand'); - $form->oss('file')->config([ - 'accessId' => 'LTAI5tFMaynxgZ9aDMNLxpU9', - 'accessKey' => 'pecJA3LX2sQyWxWDMUUb5NhsMe4Czu', - 'host' => 'https://zcs-test.oss-cn-chengdu.aliyuncs.com', - 'dir' => 'mv', - ]); + // $form->oss('file')->config([ + // 'accessId' => 'LTAI5tFMaynxgZ9aDMNLxpU9', + // 'accessKey' => 'pecJA3LX2sQyWxWDMUUb5NhsMe4Czu', + // 'host' => 'https://zcs-test.oss-cn-chengdu.aliyuncs.com', + // 'dir' => 'mv', + // ]); $form->disableResetButton(); $form->disableCreatingCheck(); From 5066df4dfe80f2d63d4d2134634f021d8764c6a0 Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Wed, 3 Aug 2022 15:02:32 +0800 Subject: [PATCH 8/8] 1 --- packages/goods/src/Http/Controllers/Admin/GoodsController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/goods/src/Http/Controllers/Admin/GoodsController.php b/packages/goods/src/Http/Controllers/Admin/GoodsController.php index 10f80a0..24e41a1 100644 --- a/packages/goods/src/Http/Controllers/Admin/GoodsController.php +++ b/packages/goods/src/Http/Controllers/Admin/GoodsController.php @@ -193,8 +193,6 @@ class GoodsController extends AdminController <<