Merge branch 'master' of https://gitee.com/paddy_technology/dcat-admin
commit
b5a22ce20e
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
return [];
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
return [];
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
return [];
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
return [];
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'labels' => [
|
||||
'GoodsBrand' => '品牌管理',
|
||||
'goods' => '商品管理',
|
||||
'brand' => '品牌',
|
||||
],
|
||||
'fields' => [
|
||||
'name' => '名称',
|
||||
'image' => '图片',
|
||||
]
|
||||
];
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'labels' => [
|
||||
'GoodsSku' => '货品管理',
|
||||
'goods' => '商品管理',
|
||||
'sku' => '商品管理',
|
||||
],
|
||||
'fields' => [
|
||||
'sn' => '货号',
|
||||
'name' => '名称',
|
||||
'price' => '售价',
|
||||
'stock' => '库存',
|
||||
'spec' => '规格',
|
||||
'origin_price' => '原价',
|
||||
]
|
||||
];
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'labels' => [
|
||||
'GoodsType' => '商品类别',
|
||||
'goods' => '商品管理',
|
||||
'type' => '商品类别',
|
||||
],
|
||||
'fields' => [
|
||||
'name' => '名称',
|
||||
'spec' => '规格',
|
||||
'attr' => '属性',
|
||||
'part' => '配件',
|
||||
'values' => '可选值',
|
||||
'group' => '分组',
|
||||
]
|
||||
];
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'labels' => [
|
||||
'Goods' => '商品信息',
|
||||
'goods' => '商品信息',
|
||||
'create' => '创建',
|
||||
'edit' => '修改',
|
||||
],
|
||||
'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' => '更新时间',
|
||||
]
|
||||
];
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- $model 当前行数据 -->
|
||||
<!-- $name 字段名称 -->
|
||||
<!-- $value 为当前列的值 -->
|
||||
@if($value)
|
||||
@foreach($value as $item)
|
||||
<div class="mt-1">
|
||||
<span class="label bg-info">{{ $item['name'] }}</span>
|
||||
<span>{{ $item['value'] }} {{ isset($item['price']) ? '(+'.$item['price'].')' : '' }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!-- $model 当前行数据 -->
|
||||
<!-- $name 字段名称 -->
|
||||
<!-- $value 为当前列的值 -->
|
||||
@if($value)
|
||||
@foreach($value as $item)
|
||||
<div class="mt-1">
|
||||
<span class="label bg-info">{{ $item['name'] }}</span>
|
||||
@if($item['values'])
|
||||
@foreach($item['values'] as $subItem)
|
||||
<span>{{ $subItem }}</span>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!-- $model 当前行数据 -->
|
||||
<!-- $name 字段名称 -->
|
||||
<!-- $value 为当前列的值 -->
|
||||
@if($value)
|
||||
@foreach($value as $item)
|
||||
<div class="mt-1">
|
||||
<span class="label bg-info">{{ $item['name'] }}</span>
|
||||
@if($item['values'])
|
||||
@foreach($item['values'] as $subItem)
|
||||
<span>{{ $subItem['value'] }}({{ $subItem['price'] }})</span>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Peidikeji\Goods\Actions;
|
||||
|
||||
use Dcat\Admin\Grid\RowAction;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class RowGoodsSkuList extends RowAction
|
||||
{
|
||||
protected $title = '货品信息';
|
||||
|
||||
public function handle(Request $request)
|
||||
{
|
||||
return $this->response()->redirect(admin_route('goods-sku.index', ['goods' => $this->getKey()]));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace Peidikeji\Goods;
|
||||
|
||||
use Peidikeji\Goods\Models\{Goods, GoodsSku};
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class GoodsService
|
||||
{
|
||||
public static function make(...$params)
|
||||
{
|
||||
return new static(...$params);
|
||||
}
|
||||
|
||||
public function generateSn()
|
||||
{
|
||||
return (string)Str::uuid();
|
||||
}
|
||||
|
||||
public function clearSku(Goods $goods)
|
||||
{
|
||||
GoodsSku::where('goods_id', $goods->id)->delete();
|
||||
}
|
||||
|
||||
public function generateSku(Goods $goods)
|
||||
{
|
||||
$this->clearSku($goods);
|
||||
if ($goods->spec) {
|
||||
$spec = $goods->spec;
|
||||
$price = $goods->price;
|
||||
$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) {
|
||||
$specPrice = array_sum(array_column($items, 'price'));
|
||||
$goods->skus()->create([
|
||||
'sn' => $this->generateSn(),
|
||||
'name' => $name,
|
||||
'price' => $price + $specPrice,
|
||||
'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;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,5 +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' => '商品管理'],
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Peidikeji\Goods\Http\Controllers\Admin;
|
||||
|
||||
use Dcat\Admin\Form;
|
||||
use Dcat\Admin\Grid;
|
||||
use Dcat\Admin\Http\Controllers\AdminController;
|
||||
use Peidikeji\Goods\Models\Goods;
|
||||
use Peidikeji\Goods\Models\GoodsBrand;
|
||||
|
||||
class GoodsBrandController extends AdminController
|
||||
{
|
||||
protected $translation = 'peidikeji.dcat-admin-extension-goods::goods-brand';
|
||||
|
||||
protected function grid()
|
||||
{
|
||||
return Grid::make(new GoodsBrand(), function (Grid $grid) {
|
||||
$grid->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->oss('file')->config([
|
||||
// 'accessId' => 'LTAI5tFMaynxgZ9aDMNLxpU9',
|
||||
// 'accessKey' => 'pecJA3LX2sQyWxWDMUUb5NhsMe4Czu',
|
||||
// 'host' => 'https://zcs-test.oss-cn-chengdu.aliyuncs.com',
|
||||
// 'dir' => 'mv',
|
||||
// ]);
|
||||
|
||||
$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('请先删除关联的商品');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
|
||||
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\Show;
|
||||
use Peidikeji\Goods\Actions\RowGoodsSkuList;
|
||||
use Peidikeji\Goods\Models\Goods;
|
||||
use Peidikeji\Goods\Models\GoodsBrand;
|
||||
use Peidikeji\Goods\Models\GoodsCategory;
|
||||
use Peidikeji\Goods\Models\GoodsType;
|
||||
|
||||
class GoodsController extends AdminController
|
||||
{
|
||||
protected $translation = 'peidikeji.dcat-admin-extension-goods::goods';
|
||||
|
||||
protected function grid()
|
||||
{
|
||||
return Grid::make(Goods::with(['category', 'brand', 'type']), function (Grid $grid) {
|
||||
$grid->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 ? '<img src="'.$this->cover_image.'" width="60" class="img-thumbnail"/> ' : '') . '<a href="'.admin_url('goods/' . $this->id).'">'.$this->name.'</a>';
|
||||
});
|
||||
$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();
|
||||
|
||||
$grid->actions(function (Actions $actions) {
|
||||
$actions->append(new RowGoodsSkuList());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected function form()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
$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(
|
||||
<<<JS
|
||||
var url = "{$admin_url}"
|
||||
var isCreating = "${isCreating}"
|
||||
$('[name="type_id"]').change(function (e) {
|
||||
if (isCreating) {
|
||||
Dcat.reload(url + '?type_id=' + e.target.value);
|
||||
}
|
||||
})
|
||||
JS
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
|
||||
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;
|
||||
use Dcat\Admin\Layout\Content;
|
||||
use Dcat\Admin\Show;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Peidikeji\Goods\Models\Goods;
|
||||
use Peidikeji\Goods\Models\GoodsSku;
|
||||
|
||||
class GoodsSkuController extends Controller
|
||||
{
|
||||
protected $translation = 'peidikeji.dcat-admin-extension-goods::goods-sku';
|
||||
|
||||
public function index($goods, Content $content)
|
||||
{
|
||||
$goods = Goods::findOrFail($goods);
|
||||
$grid = Grid::make(new GoodsSku(), function (Grid $grid) use ($goods) {
|
||||
$grid->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('origin_price')->display(fn() => $goods->price);
|
||||
$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 '<span class="label bg-info">'.$value.'</span>';
|
||||
});
|
||||
}
|
||||
// $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($goods, $id, Content $content)
|
||||
{
|
||||
$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 '<span class="label bg-info">'.$value.'</span>';
|
||||
// })->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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Peidikeji\Goods\Http\Controllers\Admin;
|
||||
|
||||
use Dcat\Admin\Form;
|
||||
use Dcat\Admin\Form\NestedForm;
|
||||
use Dcat\Admin\Grid;
|
||||
use Dcat\Admin\Http\Controllers\AdminController;
|
||||
use Peidikeji\Goods\Models\Goods;
|
||||
use Peidikeji\Goods\Models\GoodsType;
|
||||
|
||||
class GoodsTypeController extends AdminController
|
||||
{
|
||||
protected $translation = 'peidikeji.dcat-admin-extension-goods::goods-type';
|
||||
|
||||
protected function grid()
|
||||
{
|
||||
return Grid::make(new GoodsType(), function (Grid $grid) {
|
||||
$grid->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->text('group');
|
||||
$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('请先删除关联的商品');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -5,3 +5,9 @@ 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/{goods}/sku', GoodsSkuController::class)->names('goods-sku');
|
||||
|
||||
Route::resource('goods', GoodsController::class);
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Peidikeji\Goods\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class GoodsBrand extends Model
|
||||
{
|
||||
protected $table = 'goods_brand';
|
||||
|
||||
protected $fillable = ['name', 'image'];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public function goods()
|
||||
{
|
||||
return $this->hasMany(Goods::class, 'brand_id');
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Peidikeji\Goods\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
|
||||
class GoodsSku extends Model
|
||||
{
|
||||
protected $table = 'goods_sku';
|
||||
|
||||
protected $fillable = ['sn', 'goods_id', 'name', 'price', 'stock', 'spec'];
|
||||
|
||||
protected $casts = [
|
||||
'spec' => 'array',
|
||||
];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public function goods()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace Peidikeji\Goods\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class GoodsType extends Model
|
||||
{
|
||||
protected $table = 'goods_type';
|
||||
|
||||
protected $fillable = ['name', 'attr', 'spec', 'part'];
|
||||
|
||||
protected $casts = [
|
||||
'attr' => 'array',
|
||||
'spec' => 'array',
|
||||
'part' => 'array',
|
||||
];
|
||||
|
||||
public $timestamps = false;
|
||||
}
|
||||
|
|
@ -25,29 +25,49 @@ 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('销量');
|
||||
$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();
|
||||
|
||||
$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('商品');
|
||||
});
|
||||
|
|
@ -59,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');
|
||||
|
||||
|
|
@ -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');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Peidikeji\Goods\GoodsService;
|
||||
use Peidikeji\Goods\Models\Goods;
|
||||
use Peidikeji\Goods\Models\GoodsBrand;
|
||||
use Peidikeji\Goods\Models\GoodsCategory;
|
||||
use Peidikeji\Goods\Models\GoodsSku;
|
||||
use Peidikeji\Goods\Models\GoodsType;
|
||||
|
||||
class GoodsTableSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::statement('SET FOREIGN_KEY_CHECKS = 0;');
|
||||
GoodsCategory::truncate();
|
||||
$categoryList = [
|
||||
['name' => '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' => [
|
||||
['group' => '主体', 'name' => '入网型号', 'values' => ['5G', '4G']],
|
||||
['group' => '主体', 'name' => '上市年份', 'values' => null],
|
||||
['group' => '主体', 'name' => '品牌', 'values' => null]
|
||||
],
|
||||
'spec' => [
|
||||
['name' => '颜色', 'values' => ['白色', '红色', '黑色']],
|
||||
['name' => '内存', 'values' => ['32G', '64G', '128G']],
|
||||
],
|
||||
'part' => [
|
||||
['name' => '套餐', 'values' => ['套餐1', '套餐2', '套餐3']]
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => '笔记本电脑',
|
||||
'attr' => [
|
||||
['group' => '显示器', 'name' => '屏幕类型', 'values' => ['LED 背光显示屏']],
|
||||
['group' => '显示器','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' => [
|
||||
['group' => '主体', 'name' => '入网型号', 'value' => '5G'],
|
||||
['group' => '主体', 'name' => '品牌', 'value' => '三星Galaxy'],
|
||||
['group' => '主体', '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' => [
|
||||
['group' => '显示器','name' => '屏幕类型', 'value' => 'LED 背光显示屏'],
|
||||
['group' => '显示器','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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,5 +3,6 @@
|
|||
return [
|
||||
'1.0.0' => [
|
||||
'CreateGoodsTable.php',
|
||||
'GoodsTableSeeder.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();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue