From 59c7c241ecad7efbba80ed3597a30f3edb7aee2e Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Mon, 16 May 2022 13:19:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=97=A8=E5=BA=97=E7=AE=A1=E7=90=86=E5=90=8E?= =?UTF-8?q?=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdministratorController.php} | 20 ++--- .../ProductController.php} | 33 +++++-- .../Controllers/Store/StockController.php | 69 +++++++++++++++ .../{ => Store}/StoreController.php | 88 ++++++++----------- app/Admin/Controllers/VipController.php | 9 +- app/Admin/routes.php | 7 +- app/Models/Store.php | 37 -------- app/Models/Store/Administrator.php | 25 ++++++ .../ProductSku.php} | 8 +- app/Models/Store/StockLog.php | 41 +++++++++ app/Models/Store/Store.php | 54 ++++++++++++ app/Models/Tag.php | 2 + .../2022_05_06_161251_create_stores_table.php | 22 ++++- .../2022_05_07_174547_add_slug_to_vips.php | 2 +- 14 files changed, 300 insertions(+), 117 deletions(-) rename app/Admin/Controllers/{StoreAdminController.php => Store/AdministratorController.php} (63%) rename app/Admin/Controllers/{StoreProductController.php => Store/ProductController.php} (64%) create mode 100644 app/Admin/Controllers/Store/StockController.php rename app/Admin/Controllers/{ => Store}/StoreController.php (68%) delete mode 100644 app/Models/Store.php create mode 100644 app/Models/Store/Administrator.php rename app/Models/{StoreProductSku.php => Store/ProductSku.php} (68%) create mode 100644 app/Models/Store/StockLog.php create mode 100644 app/Models/Store/Store.php diff --git a/app/Admin/Controllers/StoreAdminController.php b/app/Admin/Controllers/Store/AdministratorController.php similarity index 63% rename from app/Admin/Controllers/StoreAdminController.php rename to app/Admin/Controllers/Store/AdministratorController.php index d9715c27..4d2e45b5 100644 --- a/app/Admin/Controllers/StoreAdminController.php +++ b/app/Admin/Controllers/Store/AdministratorController.php @@ -1,9 +1,9 @@ tree('admin_user', '选择管理员') + $form->tree('administrator_id', '选择管理员') ->nodes(Administrator::all()->toArray()) - ->value($store->adminUsers()->pluck('id')) + ->value($store->administrators()->select(['admin_users.id', 'admin_users.name', 'admin_users.username'])->pluck('id')) ->setTitleColumn('name'); return (new Content())->title('新增')->body($form); } @@ -28,11 +28,11 @@ class StoreAdminController extends Controller public function store($store_id, Request $request) { $store = Store::findOrFail($store_id); - if ($request->input('admin_user')) { - $admin_ids = explode(',', $request->input('admin_user')); - $store->adminUsers()->sync($admin_ids); + if ($request->input('administrator_id')) { + $admin_ids = explode(',', $request->input('administrator_id')); + $store->administrators()->sync($admin_ids); } else { - $store->adminUsers()->detach(); + $store->administrators()->detach(); } return $this->sendResponse($this->response()->success(trans('admin.save_succeeded'))); @@ -42,7 +42,7 @@ class StoreAdminController extends Controller { $store = Store::findOrFail($store_id); $admin_ids = explode(',', $id); - $store->adminUsers()->detach($admin_ids); + $store->administrators()->detach($admin_ids); return $this->sendResponse($this->response()->success(trans('admin.delete_succeeded'))); } } diff --git a/app/Admin/Controllers/StoreProductController.php b/app/Admin/Controllers/Store/ProductController.php similarity index 64% rename from app/Admin/Controllers/StoreProductController.php rename to app/Admin/Controllers/Store/ProductController.php index 024e10ef..a2dc96d3 100644 --- a/app/Admin/Controllers/StoreProductController.php +++ b/app/Admin/Controllers/Store/ProductController.php @@ -1,8 +1,8 @@ productSkus(); + if ($request->filled('key')) { + $query->where('name', 'like', '%'.$request->input('key').'%'); + } + $list = $query->paginate(); + return $list; + } + public function create($store_id) { $store = Store::findOrFail($store_id); @@ -22,8 +33,8 @@ class StoreProductController extends Controller ->from(\App\Admin\Renderable\ProductSkuSimpleTable::make()) ->model(\App\Models\ProductSku::class, 'id', 'name') ->required(); - $form->number('amount', '库存')->min(0); - $form->switch('status', '状态')->default(1); + // $form->number('amount', '库存')->min(0); + $form->switch('status', '上架')->default(1); return (new Content())->title('新增')->body($form); } @@ -34,10 +45,10 @@ class StoreProductController extends Controller if ($product_id) { $product = $store->productSkus()->find($product_id); if ($product) { - $store->productSkus()->updateExistingPivot($product_id, $request->only(['amount', 'status'])); + $store->productSkus()->updateExistingPivot($product_id, $request->only(['status'])); } else { $store->productSkus()->attach([ - $product_id => $request->only(['amount', 'status']) + $product_id => $request->only(['status']) ]); } } @@ -49,14 +60,18 @@ class StoreProductController extends Controller { $store = Store::findOrFail($store_id); $product = $store->productSkus()->wherePivot('id', $id)->firstOrFail(); - $store->productSkus()->updateExistingPivot($product->id, $request->only(['status', 'amount'])); + $store->productSkus()->updateExistingPivot($product->id, $request->only(['status'])); return $this->sendResponse($this->response()->success(trans('admin.update_succeeded'))); } public function destroy($store_id, $id) { $store = Store::findOrFail($store_id); - dd($id); + $product = $store->productSkus()->wherePivot('id', $id)->firstOrFail(); + // 删除库存记录 + $store->stockLogs()->where('product_sku_id', $product->id)->delete(); + // 删除商品关联 + $store->productSkus()->wherePivot('id', $id)->detach(); return $this->sendResponse($this->response()->success(trans('admin.delete_succeeded'))); } } diff --git a/app/Admin/Controllers/Store/StockController.php b/app/Admin/Controllers/Store/StockController.php new file mode 100644 index 00000000..e78c1e96 --- /dev/null +++ b/app/Admin/Controllers/Store/StockController.php @@ -0,0 +1,69 @@ +select('tag', '类目')->options(Tag::where('type', Tag::TYPE_STORE_STOCK)->pluck('name', 'id')); + $form->text('tag_name', '自定义类目'); + $form->select('product', '商品')->options($store->productSkus()->select(['store_product_skus.id', 'product_skus.name'])->pluck('name', 'id'))->required(); + $form->number('amount', '库存')->help('正数为增加, 负数为减少')->default(0)->required(); + $form->text('remarks', '备注'); + return (new Content())->title('新增')->body($form); + } + + public function store($store_id, Request $request) + { + $request->validate([ + 'amount' => ['required', Rule::notIn([0])], + 'product' => 'required', + 'tag' => 'required_without:tag_name' + ], [ + 'amount.not_in' => '库存不能为0', + 'tag.required_without' => '类目必填', + ]); + if ($request->filled('tag')) { + $tag = Tag::findOrFail($request->input('tag')); + } else { + $tag = Tag::firstOrCreate([ + 'type' => Tag::TYPE_STORE_STOCK, + 'name' => $request->input('tag_name') + ]); + } + $store = Store::findOrFail($store_id); + $product = $store->productSkus()->wherePivot('id', $request->input('product'))->firstOrFail(); + $administrator = Admin::user(); + $amount = $request->input('amount'); + if ($product->pivot->amount + $amount < 0) { + return $this->sendResponse($this->response()->error('扣减库存不能超过现有库存')); + } + $store->productSkus()->updateExistingPivot($product->id, [ + 'amount' => $product->pivot->amount + $amount + ]); + $store->stockLogs()->create([ + 'administrator_id' => $administrator->id, + 'amount' => $request->input('amount'), + 'product_sku_id' => $product->id, + 'remarks' => $request->input('remarks'), + 'tag_id' => $tag->id + ]); + return $this->sendResponse($this->response()->success(trans('admin.save_succeeded'))); + } +} diff --git a/app/Admin/Controllers/StoreController.php b/app/Admin/Controllers/Store/StoreController.php similarity index 68% rename from app/Admin/Controllers/StoreController.php rename to app/Admin/Controllers/Store/StoreController.php index 50ca6495..6e210b40 100644 --- a/app/Admin/Controllers/StoreController.php +++ b/app/Admin/Controllers/Store/StoreController.php @@ -1,8 +1,8 @@ canAdmin(); if (!$canAdmin) { - $ids = DB::table('store_admin_users')->where('admin_user_id', $user->id)->pluck('store_id'); + $ids = DB::table('store_admin_users')->where('administrator_id', $user->id)->pluck('store_id'); $query = $query->whereIn('id', $ids); } @@ -43,6 +43,7 @@ class StoreController extends AdminController $grid->column('created_at'); $grid->disableCreateButton(!$canAdmin); + $grid->enableDialogCreate(); $grid->showEditButton(); $grid->showViewButton(); $grid->showDeleteButton($canAdmin); @@ -67,7 +68,7 @@ class StoreController extends AdminController $user = Admin::user(); $canAdmin = $this->canAdmin(); if (!$canAdmin) { - $ids = DB::table('store_admin_users')->where('admin_user_id', $user->id)->pluck('store_id'); + $ids = DB::table('store_admin_users')->where('administrator_id', $user->id)->pluck('store_id'); $query = $query->whereIn('id', $ids); } $row = new Row(); @@ -89,6 +90,7 @@ class StoreController extends AdminController $tab = Tab::make()->theme(); $tab->add('商品', Card::make($this->gridProduct($id))); + $tab->add('库存', Card::make($this->gridStock($id))); if ($canAdmin) { $tab->add('管理员', Card::make($this->gridAdmin($id))); } @@ -104,11 +106,11 @@ class StoreController extends AdminController */ protected function form() { - $query = Store::with(['adminUsers', 'productSkus']); + $query = Store::query(); $user = Admin::user(); $canAdmin = $this->canAdmin(); if (!$canAdmin) { - $ids = DB::table('store_admin_users')->where('admin_user_id', $user->id)->pluck('store_id'); + $ids = DB::table('store_admin_users')->where('administrator_id', $user->id)->pluck('store_id'); $query = $query->whereIn('id', $ids); } return Form::make($query, function (Form $form) use ($canAdmin) { @@ -116,28 +118,6 @@ class StoreController extends AdminController $form->text('title'); $form->switch('status')->default(1); $form->number('sort')->min(1)->default(1); - - // if ($canAdmin) { - // $form->multipleSelectTable('admin_users') - // ->from(\App\Admin\Renderable\AdministratorTable::make()) - // ->model(Administrator::class, 'id', 'name') - // ->customFormat(function ($v) { - // if (! $v) { - // return []; - // } - // return array_column($v, 'id'); - // }); - // } - - $form->multipleSelectTable('product_skus') - ->from(\App\Admin\Renderable\ProductSkuSimpleTable::make()) - ->model(\App\Models\ProductSku::class, 'id', 'name') - ->customFormat(function ($v) { - if (! $v) { - return []; - } - return array_column($v, 'id'); - }); $form->image('image') ->required() ->move('store/'.Carbon::now()->toDateString()) @@ -152,16 +132,6 @@ class StoreController extends AdminController }); } - public function destroy($id) - { - $info = Store::find($id); - // 删除店铺关联的数据 - $info->adminUsers()->detach(); - $info->productSkus()->detach(); - - return parent::destroy($id); - } - protected function canAdmin() { return Admin::user()->isRole('administrator'); @@ -169,16 +139,14 @@ class StoreController extends AdminController protected function gridAdmin($id) { - $grid = Grid::make(new Administrator()); - $grid->model()->join('store_admin_users', function ($join) use ($id) { - $join->on('store_admin_users.admin_user_id', 'id')->where('store_id', '=', $id); - }); + $grid = Grid::make(StoreAdministrator::with(['administrator'])); + $grid->model()->where('store_id', $id); $grid->setResource('store/' . $id . '/admin'); - $grid->column('id'); - $grid->column('username'); - $grid->column('name'); + $grid->column('administrator.id', 'ID'); + $grid->column('administrator.username', '登录名'); + $grid->column('administrator.name', '姓名'); $grid->paginate(10); $grid->showCreateButton(); @@ -192,14 +160,14 @@ class StoreController extends AdminController protected function gridProduct($id) { - $grid = new Grid(StoreProductSku::with(['productSku'])); - $grid->model()->where('store_id', $id); + $grid = new Grid(ProductSku::with(['productSku'])); + $grid->model()->where('store_id', $id)->orderBy('id', 'desc'); $grid->setResource('store/'.$id.'/product'); $grid->column('productSku.id', 'ID'); $grid->column('productSku.name', '名称'); - $grid->column('amount', '库存')->editable(); + $grid->column('amount', '库存'); $grid->column('productSku.specs', '规格')->label(); $grid->column('status', '状态')->switch(); $grid->paginate(10); @@ -207,8 +175,30 @@ class StoreController extends AdminController $grid->showCreateButton(); $grid->enableDialogCreate(); - $grid->disableActions(); + $grid->showDeleteButton(); $grid->showRowSelector(); return $grid; } + + protected function gridStock($id) + { + $grid = new Grid(StockLog::with(['productSku', 'administrator', 'source', 'tag'])); + + $grid->model()->where('store_id', $id)->orderBy('created_at', 'desc'); + + $grid->setResource('store/'.$id.'/stock'); + + $grid->column('productSku.name', '商品'); + $grid->column('amount', '库存'); + $grid->column('tag.name', '类目'); + $grid->column('administrator.name', '操作人'); + $grid->column('remarks', '备注'); + $grid->column('created_at', '操作时间'); + + $grid->disableActions(); + $grid->showCreateButton(); + $grid->enableDialogCreate(); + + return $grid; + } } diff --git a/app/Admin/Controllers/VipController.php b/app/Admin/Controllers/VipController.php index d4a2d634..a11b8963 100644 --- a/app/Admin/Controllers/VipController.php +++ b/app/Admin/Controllers/VipController.php @@ -9,6 +9,7 @@ use Dcat\Admin\Form; use Dcat\Admin\Grid; use Dcat\Admin\Http\Controllers\AdminController; use Dcat\Admin\Show; +use Illuminate\Validation\Rule; class VipController extends AdminController { @@ -81,7 +82,13 @@ class VipController extends AdminController { return Form::make(new Vip(), function (Form $form) { $form->display('id'); - $form->number('sort')->min(1)->required()->help('不可重复'); + $form->number('sort')->min(1)->required()->help('不可重复')->rules(function (Form $form) { + $rule = Rule::unique('vips'); + if ($id = $form->model()->id) { + $rule->ignore($id); + } + return $rule; + }); $form->text('name')->required(); $form->radio('slug')->options(Vip::$typeMap)->default(Vip::TYPE_FAVOITE); $form->number('ratio')->min(0)->max(100)->help('例如: 60%, 填写 60 即可'); diff --git a/app/Admin/routes.php b/app/Admin/routes.php index 729dbb65..905b4ca4 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -176,9 +176,10 @@ Route::group([ /** 调试接口 **/ // $router->get('test', 'HomeController@test'); - $router->resource('store/{store_id}/product', 'StoreProductController'); - $router->resource('store/{store_id}/admin', 'StoreAdminController'); - $router->resource('store', 'StoreController'); + $router->resource('store/{store_id}/product', 'Store\ProductController'); + $router->resource('store/{store_id}/admin', 'Store\AdministratorController'); + $router->resource('store/{store_id}/stock', 'Store\StockController'); + $router->resource('store', 'Store\StoreController'); $router->resource('profit', 'OrderProfitController'); }); diff --git a/app/Models/Store.php b/app/Models/Store.php deleted file mode 100644 index 4f2c1e60..00000000 --- a/app/Models/Store.php +++ /dev/null @@ -1,37 +0,0 @@ - 1, - 'sort' => 1 - ]; - - public function adminUsers() - { - return $this->belongsToMany(\Dcat\Admin\Models\Administrator::class, 'store_admin_users', 'store_id', 'admin_user_id'); - } - - public function productSkus() - { - return $this->belongsToMany(ProductSku::class, 'store_product_skus', 'store_id', 'product_sku_id'); - } - - public function scopeEffective($q) - { - return $q->where('status', 1); - } - - public function scopeSort($q) - { - return $q->orderBy('sort')->orderBy('id', 'desc'); - } -} diff --git a/app/Models/Store/Administrator.php b/app/Models/Store/Administrator.php new file mode 100644 index 00000000..359d81ae --- /dev/null +++ b/app/Models/Store/Administrator.php @@ -0,0 +1,25 @@ +belongsTo(Store::class, 'store_id'); + } + + public function administrator() + { + return $this->belongsTo(\Dcat\Admin\Models\Administrator::class, 'administrator_id'); + } +} diff --git a/app/Models/StoreProductSku.php b/app/Models/Store/ProductSku.php similarity index 68% rename from app/Models/StoreProductSku.php rename to app/Models/Store/ProductSku.php index e7ac6597..8fd992e4 100644 --- a/app/Models/StoreProductSku.php +++ b/app/Models/Store/ProductSku.php @@ -1,16 +1,18 @@ belongsTo(Store::class, 'store_id'); @@ -18,6 +20,6 @@ class StoreProductSku extends Pivot public function productSku() { - return $this->belongsTo(ProductSku::class, 'product_sku_id'); + return $this->belongsTo(\App\Models\ProductSku::class, 'product_sku_id'); } } diff --git a/app/Models/Store/StockLog.php b/app/Models/Store/StockLog.php new file mode 100644 index 00000000..68c71271 --- /dev/null +++ b/app/Models/Store/StockLog.php @@ -0,0 +1,41 @@ +belongsTo(Store::class, 'store_id'); + } + + public function productSku() + { + return $this->belongsTo(\App\Models\ProductSku::class, 'product_sku_id'); + } + + public function administrator() + { + return $this->belongsTo(\Dcat\Admin\Models\Administrator::class, 'administrator_id'); + } + + public function source() + { + return $this->morphTo(); + } + + public function tag() + { + return $this->belongsTo(\App\Models\Tag::class, 'tag_id'); + } +} diff --git a/app/Models/Store/Store.php b/app/Models/Store/Store.php new file mode 100644 index 00000000..4ba14649 --- /dev/null +++ b/app/Models/Store/Store.php @@ -0,0 +1,54 @@ + 1, + 'sort' => 1 + ]; + + protected static function booted() + { + static::deleted(function ($model) { + // 商品记录 + $model->productSkus()->detach(); + // 库存记录 + $model->stockLogs()->delete(); + // 管理员记录 + $model->administrators()->detach(); + }); + } + + public function administrators() + { + return $this->belongsToMany(\Dcat\Admin\Models\Administrator::class, 'store_administrators', 'store_id', 'administrator_id'); + } + + public function productSkus() + { + return $this->belongsToMany(\App\Models\ProductSku::class, 'store_product_skus', 'store_id', 'product_sku_id')->withPivot('amount', 'status'); + } + + public function stockLogs() + { + return $this->hasMany(StockLog::class, 'store_id'); + } + + public function scopeEffective($q) + { + return $q->where('status', 1); + } + + public function scopeSort($q) + { + return $q->orderBy('sort')->orderBy('id', 'desc'); + } +} diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 7a2f74c4..4387b03c 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -14,7 +14,9 @@ class Tag extends Model public const TYPE_ORDER = 1; public const TYPE_PACKAGE = 2; public const TYPE_AFTER_SALE = 3; + public const TYPE_STORE_STOCK = 4; + protected $fillable = ['type', 'name']; // /** // * 标签下的订单 diff --git a/database/migrations/2022_05_06_161251_create_stores_table.php b/database/migrations/2022_05_06_161251_create_stores_table.php index b7aaf460..3bfd98f8 100644 --- a/database/migrations/2022_05_06_161251_create_stores_table.php +++ b/database/migrations/2022_05_06_161251_create_stores_table.php @@ -23,19 +23,32 @@ class CreateStoresTable extends Migration $table->timestamps(); }); - Schema::create('store_admin_users', function (Blueprint $table) { + Schema::create('store_administrators', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('store_id'); - $table->unsignedBigInteger('admin_user_id'); + $table->unsignedBigInteger('administrator_id'); }); Schema::create('store_product_skus', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('store_id'); $table->unsignedBigInteger('product_sku_id'); - $table->unsignedInteger('amount')->comment('库存'); + $table->unsignedInteger('amount')->default(0)->comment('库存'); $table->tinyInteger('status')->default(1)->comment('状态(1: 可用, 0: 不可用)'); }); + + Schema::create('store_stock_logs', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('store_id'); + $table->unsignedBigInteger('product_sku_id'); + $table->integer('amount')->comment('库存变更数量(正/负值)'); + $table->unsignedBigInteger('tag_id')->comment('变更类目(tags.id)'); + $table->unsignedBigInteger('administrator_id')->nullable()->comment('操作管理员'); + $table->string('remarks')->nullable()->comment('备注'); + $table->string('source_type')->nullable()->comment('来源'); + $table->unsignedBigInteger('source_id')->nullable()->comment('来源'); + $table->timestamps(); + }); } /** @@ -46,7 +59,8 @@ class CreateStoresTable extends Migration public function down() { Schema::dropIfExists('stores'); - Schema::dropIfExists('store_admin_users'); + Schema::dropIfExists('store_administrators'); Schema::dropIfExists('store_product_skus'); + Schema::dropIfExists('store_stock_logs'); } } diff --git a/database/migrations/2022_05_07_174547_add_slug_to_vips.php b/database/migrations/2022_05_07_174547_add_slug_to_vips.php index d44af98d..560fc5fb 100644 --- a/database/migrations/2022_05_07_174547_add_slug_to_vips.php +++ b/database/migrations/2022_05_07_174547_add_slug_to_vips.php @@ -15,7 +15,7 @@ class AddSlugToVips extends Migration { Schema::table('vips', function (Blueprint $table) { $table->string('slug')->comment('标识'); - $table->unsignedInteger('sort')->unique()->comment('等级'); + $table->unsignedInteger('sort')->comment('等级'); $table->integer('ratio')->comment('返佣比例, 10 => 10%'); }); }