From 1adcc15c7f477e4d1e5340d8179a0ec2e13e7ffd Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Wed, 8 Feb 2023 18:15:47 +0800 Subject: [PATCH] store goods excel import --- .env.example | 4 +- README.md | 2 +- app/Admin/Actions/Form/ProductImportForm.php | 10 +- .../Actions/Store/DownloadProductTemplate.php | 19 ++ app/Admin/Actions/Store/ImportProduct.php | 21 ++ .../Controllers/ProductCategoryController.php | 1 + .../Controllers/Store/ProductController.php | 5 + .../Controllers/Store/StoreController.php | 11 +- app/Admin/Imports/Product.php | 68 ++++-- app/Admin/Imports/StoreProduct.php | 219 ++++++++++++++++++ .../Http/Controllers/Auth/LoginController.php | 2 +- .../Api/Http/Controllers/StoreController.php | 2 +- app/Models/Store/Store.php | 2 + app/Models/User.php | 1 + app/Providers/RouteServiceProvider.php | 1 + public/store-goods.xlsx | Bin 0 -> 10925 bytes routes/web.php | 7 +- 17 files changed, 330 insertions(+), 45 deletions(-) create mode 100644 app/Admin/Actions/Store/DownloadProductTemplate.php create mode 100644 app/Admin/Actions/Store/ImportProduct.php create mode 100644 app/Admin/Imports/StoreProduct.php create mode 100644 public/store-goods.xlsx diff --git a/.env.example b/.env.example index e1f3dcad..8a4f3623 100644 --- a/.env.example +++ b/.env.example @@ -7,7 +7,7 @@ APP_URL=http://localhost ENDPOINT_API_DOMAIN=null ENDPOINT_API_PATH=null -LOG_CHANNEL=stack +LOG_CHANNEL=daily LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug @@ -20,7 +20,7 @@ DB_PASSWORD= BROADCAST_DRIVER=log CACHE_DRIVER=file -FILESYSTEM_DRIVER=local +FILESYSTEM_DRIVER=public QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120 diff --git a/README.md b/README.md index 421dca2a..6efacf4a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Require -- php >= 8.0 +- php >= 8.1 ## Step diff --git a/app/Admin/Actions/Form/ProductImportForm.php b/app/Admin/Actions/Form/ProductImportForm.php index 047e6c49..90c378aa 100644 --- a/app/Admin/Actions/Form/ProductImportForm.php +++ b/app/Admin/Actions/Form/ProductImportForm.php @@ -4,7 +4,7 @@ namespace App\Admin\Actions\Form; use Dcat\Admin\Widgets\Form; use Illuminate\Support\Facades\DB; -use App\Admin\Imports\Product; +use App\Admin\Imports\{Product, StoreProduct}; class ProductImportForm extends Form { @@ -13,12 +13,15 @@ class ProductImportForm extends Form try { DB::beginTransaction(); $file = $input['file']; - (new Product())->load($file); + if (data_get($input, 'is_store')) { + (new StoreProduct())->load($file); + } else { + (new Product())->load($file); + } DB::commit(); return $this->response()->success('数据导入成功')->refresh(); } catch (\Exception $e) { DB::rollback(); - dd($e); return $this->response()->error($e->getMessage()); } } @@ -29,5 +32,6 @@ class ProductImportForm extends Form ->attribute('type', 'file') ->attribute('accept', 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') ->rules('required', ['required' => '文件不能为空']); + $this->hidden('is_store'); } } diff --git a/app/Admin/Actions/Store/DownloadProductTemplate.php b/app/Admin/Actions/Store/DownloadProductTemplate.php new file mode 100644 index 00000000..54dfa7b2 --- /dev/null +++ b/app/Admin/Actions/Store/DownloadProductTemplate.php @@ -0,0 +1,19 @@ +下载商品模板 + HTML; + } +} diff --git a/app/Admin/Actions/Store/ImportProduct.php b/app/Admin/Actions/Store/ImportProduct.php new file mode 100644 index 00000000..67bed180 --- /dev/null +++ b/app/Admin/Actions/Store/ImportProduct.php @@ -0,0 +1,21 @@ + 1]); + return Modal::make() + ->lg() + ->title($this->title) + ->body($form) + ->button($this->html()); + } +} \ No newline at end of file diff --git a/app/Admin/Controllers/ProductCategoryController.php b/app/Admin/Controllers/ProductCategoryController.php index 6daf670a..31dc6769 100644 --- a/app/Admin/Controllers/ProductCategoryController.php +++ b/app/Admin/Controllers/ProductCategoryController.php @@ -111,6 +111,7 @@ class ProductCategoryController extends AdminController $form->select('parent_id')->options(ProductCategoryModel::selectOptions()); $form->text('name')->required(); $form->image('icon') + ->uniqueName() ->move('product-categories/'.Carbon::now()->toDateString()) ->saveFullUrl() ->removable(false) diff --git a/app/Admin/Controllers/Store/ProductController.php b/app/Admin/Controllers/Store/ProductController.php index 7aa34a34..101024e6 100644 --- a/app/Admin/Controllers/Store/ProductController.php +++ b/app/Admin/Controllers/Store/ProductController.php @@ -74,6 +74,11 @@ class ProductController extends AdminController $filter->equal('productSku.category_id', '分类')->select(admin_route('api.product_categories', ['level' => 2]))->width(3); $filter->like('productSku.name', '名称')->width(3); }); + $grid->tools(function (Grid\Tools $tools) { + $tools->append(new \App\Admin\Actions\Store\ImportProduct()); + $tools->append(new \App\Admin\Actions\Store\DownloadProductTemplate()); + }); + $grid->footer(function ($collection) use ($grid) { $query = StoreProductSku::join('product_skus', 'product_skus.id', '=', 'store_product_skus.product_sku_id'); $grid->model()->getQueries()->unique()->each(function ($value) use (&$query) { diff --git a/app/Admin/Controllers/Store/StoreController.php b/app/Admin/Controllers/Store/StoreController.php index 1aa40a83..a9cbcb5a 100644 --- a/app/Admin/Controllers/Store/StoreController.php +++ b/app/Admin/Controllers/Store/StoreController.php @@ -81,13 +81,6 @@ class StoreController extends AdminController } - /** - * Make a show builder. - * - * @param mixed $id - * - * @return Show - */ protected function detail($id) { if ($this->canAdmin()) { @@ -107,6 +100,10 @@ class StoreController extends AdminController $show->tools(function (Tools $tools) { $tools->append(new ExportGoodsSpu()); + + $tools->disableList(); + $tools->disableDelete(); + $tools->disableEdit(); }); return $show; } diff --git a/app/Admin/Imports/Product.php b/app/Admin/Imports/Product.php index e13d2d84..b216d4e6 100644 --- a/app/Admin/Imports/Product.php +++ b/app/Admin/Imports/Product.php @@ -21,21 +21,43 @@ class Product continue; } $cells = $row->toArray(); + + $index = 0; + $goodsName = $cells[$index];// 商品名称 + $goodsTitle = $cells[++$index];// 商品副标题 + $categoryName = $cells[++$index];// 分类名称 + $goodsImage = $cells[++$index];// 商品图片 + $salePrice = $cells[++$index];// 销售价 + $marketPrice = $cells[++$index];// 市场价 + $costPrice = $cells[++$index];// 成本价 + $vipPrice = $cells[++$index];// 会员价 + $saleValue = $cells[++$index];// 销售值 + // 属性加价 + // 颜色[远峰蓝:0,石墨色:0,银色:0,金色:0,苍岭绿色:0] + $rowAttrs = $cells[++$index]; + // 规格展示 + // 主体[上市月份:9月,品牌:Apple] + $rowSpecs = $cells[++$index]; + $shipTemplate = $cells[++$index];// 运费模板 + $goodsWeight = $cells[++$index];// 商品重量(克) + // 详细描述 + // https://qiniu.abcdefg.fun/banner/banner4.png,https://qiniu.abcdefg.fun/banner/banner5.png + $goodsContent = $cells[++$index]; $goods = [ - 'name' => $cells[0], - 'subtitle' => $cells[1], + 'name' => $goodsName, + 'subtitle' => $goodsTitle, 'shipping_template_id' => 1, ]; - $category = ProductCategory::where('name', $cells[2])->firstOrFail(); + $category = ProductCategory::where('name', $categoryName)->firstOrFail(); $goods['category_id'] = $category->id; // 图片组 - if ($path = $cells[3]) { - if (Str::startsWith($path, ['http://', 'https://'])) { - $images = explode(',', $path); + if ($goodsImage) { + if (Str::startsWith($goodsImage, ['http://', 'https://'])) { + $images = explode(',', $goodsImage); } else { - $images = $this->getImageUrlFromPath($path); + $images = $this->getImageUrlFromPath($goodsImage); } if (count($images) > 0) { $goods['cover'] = $images[0]; @@ -44,39 +66,37 @@ class Product } // 运费模板 - if ($cell_11 = data_get($cells, 11)) { - $goods['shipping_template_id'] = $cell_11; + if ($shipTemplate) { + $goods['shipping_template_id'] = $shipTemplate; } // 重量 - if ($cell_12 = data_get($cells, 12)) { - $goods['weight'] = $cell_12; + if ($goodsWeight) { + $goods['weight'] = $goodsWeight; } // 详细描述 - if ($cell_13 = data_get($cells, 13)) { + if ($goodsContent) { $description = ''; - foreach(explode(',', $cell_13) as $item) { + foreach(explode(',', $goodsContent) as $item) { $description .= '

'; } $goods['description'] = $description; } $goods = array_merge($goods, [ - 'sell_price' => $cells[4] * 100, - 'market_price' => $cells[5] * 100, - 'cost_price' => $cells[6] * 100, - 'vip_price' => $cells[7] * 100, - 'sales_value' => $cells[8], + 'sell_price' => $salePrice * 100, + 'market_price' => $marketPrice * 100, + 'cost_price' => $costPrice * 100, + 'vip_price' => $vipPrice * 100, + 'sales_value' => $saleValue, ]); $product = ProductSpu::updateOrCreate(['name' => $goods['name']],$goods); // 属性规格 - $coll_9 = data_get($cells, 9); - $cell_10 = data_get($cells, 10); - if ($coll_9) { - $format_specs = $this->formatAttr($coll_9); - $format_attrs = $this->formatAttr($cell_10); - $spec_group = $this->getSpec($cells[0], $coll_9, $cell_10); + if ($rowAttrs) { + $format_specs = $this->formatAttr($rowAttrs); + $format_attrs = $this->formatAttr($rowSpecs); + $spec_group = $this->getSpec($cells[0], $rowAttrs, $rowSpecs); $attrs = []; foreach($spec_group->attrs as $index => $item) { diff --git a/app/Admin/Imports/StoreProduct.php b/app/Admin/Imports/StoreProduct.php new file mode 100644 index 00000000..6d5a1028 --- /dev/null +++ b/app/Admin/Imports/StoreProduct.php @@ -0,0 +1,219 @@ +open($file); + + foreach ($reader->getSheetIterator() as $sheet) { + foreach ($sheet->getRowIterator() as $num => $row) { + if ($num === 1) { + continue; + } + $cells = $row->toArray(); + + $index = 0; + $storeName = $cells[$index];// 店铺名称 + $goodsName = $cells[++$index];// 商品名称 + $goodsTitle = $cells[++$index];// 商品副标题 + $categoryName = $cells[++$index];// 分类名称 + $goodsImage = $cells[++$index];// 商品图片 + $salePrice = $cells[++$index];// 销售价 + $marketPrice = $cells[++$index];// 市场价 + $costPrice = $cells[++$index];// 成本价 + $vipPrice = $cells[++$index];// 会员价 + $saleValue = $cells[++$index];// 销售值 + // 属性加价 + // 颜色[远峰蓝:0,石墨色:0,银色:0,金色:0,苍岭绿色:0] + $rowAttrs = $cells[++$index]; + // 规格展示 + // 主体[上市月份:9月,品牌:Apple] + $rowSpecs = $cells[++$index]; + $shipTemplate = $cells[++$index];// 运费模板 + $goodsWeight = $cells[++$index];// 商品重量(克) + // 详细描述 + // https://qiniu.abcdefg.fun/banner/banner4.png,https://qiniu.abcdefg.fun/banner/banner5.png + $goodsContent = $cells[++$index]; + + $stock = $cells[++$index];// 库存 + + $store = Store::where(['title' => $storeName])->firstOrFail(); + + $goods = [ + 'name' => $goodsName, + 'subtitle' => $goodsTitle, + 'shipping_template_id' => 1, + ]; + $category = ProductCategory::where('name', $categoryName)->firstOrFail(); + $goods['category_id'] = $category->id; + + // 图片组 + if ($goodsImage) { + if (Str::startsWith($goodsImage, ['http://', 'https://'])) { + $images = explode(',', $goodsImage); + } else { + $images = $this->getImageUrlFromPath($goodsImage); + } + if (count($images) > 0) { + $goods['cover'] = $images[0]; + $goods['images'] = $images; + } + } + + // 运费模板 + if ($shipTemplate) { + $goods['shipping_template_id'] = $shipTemplate; + } + // 重量 + if ($goodsWeight) { + $goods['weight'] = $goodsWeight; + } + // 详细描述 + if ($goodsContent) { + $description = ''; + foreach(explode(',', $goodsContent) as $item) { + $description .= '

'; + } + $goods['description'] = $description; + } + + $goods = array_merge($goods, [ + 'sell_price' => $salePrice * 100, + 'market_price' => $marketPrice * 100, + 'cost_price' => $costPrice * 100, + 'vip_price' => $vipPrice * 100, + 'sales_value' => $saleValue, + 'stock' => $stock, + ]); + + $product = ProductSpu::updateOrCreate(['name' => $goods['name']],$goods); + + // 属性规格 + if ($rowAttrs) { + $format_specs = $this->formatAttr($rowAttrs); + $format_attrs = $this->formatAttr($rowSpecs); + $spec_group = $this->getSpec($cells[0], $rowAttrs, $rowSpecs); + + $attrs = []; + foreach($spec_group->attrs as $index => $item) { + $attr = ['name' => $item['title'], 'attrs' => []]; + foreach(explode(PHP_EOL, $item['value']) as $value) { + array_push($attr['attrs'], ['name' => $value, 'value' => data_get($format_attrs, "$index.values.$value")]); + } + array_push($attrs, $attr); + } + $product->update(['attrs' => $attrs]); + + $specs = []; + $product->specs()->delete(); + foreach($spec_group->specs as $index => $item) { + $spec = ['name' => $item['title'], 'items' => []]; + foreach(explode(PHP_EOL, $item['value']) as $value) { + array_push($spec['items'], ['name' => $value, 'value' => data_get($format_specs, "$index.values.$value")]); + } + array_push($specs, $spec); + } + $product->specs()->createMany($specs); + } + + // 清空现有的sku, 重新添加 + StoreProductSku::where('store_id', $store->id)->whereIn('product_sku_id', $product->skus->pluck('id'))->delete(); + $product->skus()->delete(); + ProductSku::createBySpu($product); + + // 将sku 添加到门店 + $skuList = $product->skus()->get(); + $skus = []; + foreach($skuList as $sku) { + array_push($skus, ['amount' => $stock, 'product_sku_id' => $sku->id, 'status' => 1, 'store_id' => $store->id]); + } + StoreProductSku::insert($skus); + } + } + + $reader->close(); + } + + protected function getImageUrlFromPath($dir) + { + $disk = Storage::disk(); + $files = $disk->files($dir); + $images = []; + + foreach($files as $filename) { + array_push($images, $disk->url($filename)); + } + + return $images; + } + + protected function getSpec($name, $specs, $attrs) + { + if (Str::contains($specs, ':')) { + // 创建新的规格 + $spec = ProductGroup::updateOrCreate([ + 'name' => $name + ], [ + 'attrs' => $this->formatGroupAttr($this->formatAttr($attrs)), + 'specs' => $this->formatGroupAttr($this->formatAttr($specs)) + ]); + } else { + $spec = ProductGroup::where('name', $specs)->firstOrFail(); + } + + return $spec; + } + + /** + * 颜色[灰色:0,银色:0] + * 尺寸[13寸:0,14寸:500,16寸:1000] + * 处理器[M1:0,M1 Pro:1000,M1 Max:1500] + * 内存[8G:0,16G:1000,32G:2000] + * 硬盘[256G:0,512G:1000,1TB:2000] + * + * [ + * ['name' => '颜色', 'values' => ['灰色' => 0, '银色' => 0]], + * ['name' => '尺寸', 'values' => ['13寸' => 0, '14寸' => 500, '16寸' => '1000']] + * ... + * ] + */ + protected function formatAttr($attrs) + { + $attr_data = []; + if (!Str::contains($attrs, ':')) { + return $attr_data; + } + foreach(explode("\n", $attrs) as $item) { + $name = explode('[', $item)[0]; + $attr_values = []; + foreach(explode(',', Str::between($item, '[', ']')) as $item1) { + $item1_explode = explode(':', $item1); + $attr_values[$item1_explode[0]] = $item1_explode[1]; + } + array_push($attr_data, ['name' => $name, 'values' => $attr_values]); + } + + return $attr_data; + } + + protected function formatGroupAttr($data) + { + $list = []; + foreach($data as $item) { + array_push($list, ['title' => $item['name'], 'value' => implode(PHP_EOL, array_keys($item['values']))]); + } + return $list; + } +} diff --git a/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php b/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php index 169fab8f..bbcc9570 100644 --- a/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php +++ b/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php @@ -72,7 +72,7 @@ class LoginController extends Controller ]); $user = User::where('phone', $validated['phone'])->first(); - + if (! $user?->verifyPassword($validated['password'])) { throw new BizException(__('Incorrect account or password')); } diff --git a/app/Endpoint/Api/Http/Controllers/StoreController.php b/app/Endpoint/Api/Http/Controllers/StoreController.php index 7cb6aca8..06c3c621 100644 --- a/app/Endpoint/Api/Http/Controllers/StoreController.php +++ b/app/Endpoint/Api/Http/Controllers/StoreController.php @@ -44,7 +44,7 @@ class StoreController extends Controller $skus = $store->productSkus() ->select($fields) ->filter($input) - ->online() + // ->online() ->wherePivot('status', 1) ->simplePaginate(Paginator::resolvePerPage('per_page', 20, 50)); diff --git a/app/Models/Store/Store.php b/app/Models/Store/Store.php index bbc8b916..4ad63770 100644 --- a/app/Models/Store/Store.php +++ b/app/Models/Store/Store.php @@ -10,6 +10,8 @@ class Store extends Model { use HasFactory, HasDateTimeFormatter; + protected $fillable = ['title', 'image']; + protected $attributes = [ 'status' => 1, 'sort' => 1 diff --git a/app/Models/User.php b/app/Models/User.php index 83f8becf..0ce8a557 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -353,6 +353,7 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac */ public function verifyPassword(string $password): bool { + logger('password', ['p1' => $password, 'p2' => $this->password]); // 如果旧密码存在,则校验旧密码 if ($this->old_password) { return $this->old_password === md5($password); diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index f8218ef4..903f76c1 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -38,6 +38,7 @@ class RouteServiceProvider extends ServiceProvider $this->configureRateLimiting(); $this->routes(function () { + Route::middleware('web')->group(base_path('routes/web.php')); Route::domain(config('endpoint.api.domain')) ->group(function () { Route::prefix(config('endpoint.api.path')) diff --git a/public/store-goods.xlsx b/public/store-goods.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d2f90176644ae93ee12518b3b52ce8f20656deac GIT binary patch literal 10925 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 UL+}O#g$8+HLm(SM_uH@k0j~LzZ2$lO literal 0 HcmV?d00001 diff --git a/routes/web.php b/routes/web.php index b8d4384e..fd646792 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,9 +2,4 @@ use Illuminate\Support\Facades\Route; -Route::fallback(function () { - return response()->json([ - 'errcode' => 404, - 'message' => 'Not Found', - ], 404); -}); +Route::redirect('', '/admin');