diff --git a/app/Admin/Actions/Show/UserEditVip.php b/app/Admin/Actions/Show/UserEditVip.php index c51bfccc..6bc6f4b2 100644 --- a/app/Admin/Actions/Show/UserEditVip.php +++ b/app/Admin/Actions/Show/UserEditVip.php @@ -2,7 +2,7 @@ namespace App\Admin\Actions\Show; -use App\Admin\Forms\UserEditPhone as UserEditPhoneForm; +use App\Admin\Forms\UserEditVip as UserEditVipForm; use Dcat\Admin\Show\AbstractTool; use Dcat\Admin\Widgets\Modal; @@ -22,7 +22,7 @@ class UserEditVip extends AbstractTool public function render() { - $form = UserEditPhoneForm::make()->payload(['id'=>$this->getKey()]); + $form = UserEditVipForm::make()->payload(['id'=>$this->getKey()]); return Modal::make() ->lg() ->title($this->title) diff --git a/app/Admin/Controllers/UserController.php b/app/Admin/Controllers/UserController.php index 5c1dbb3a..0ef2068f 100644 --- a/app/Admin/Controllers/UserController.php +++ b/app/Admin/Controllers/UserController.php @@ -42,7 +42,7 @@ class UserController extends AdminController */ protected function grid() { - $builder = User::with(['userInfo', 'wallet', 'balance', 'userInfo.inviterInfo.user']); + $builder = User::with(['userInfo', 'wallet', 'balance', 'userInfo.inviterInfo.user', 'userVip.vip']); return Grid::make($builder, function (Grid $grid) { $grid->model()->whereNotNull('phone'); $grid->column('id')->sortable()->if(function () { @@ -59,9 +59,10 @@ class UserController extends AdminController $grid->column('userInfo.growth_value')->filter( Grid\Column\Filter\Between::make() )->modal(function ($modal) { - $modal->title('消费值'); + $modal->title('成长值'); return UserSalesValueLogSimpleTable::make(['id'=>$this->id]); })->setHeaderAttributes(['style' => 'color:#5b69bc']); + $grid->column('userVip.vip.name'); // $grid->column('wallet.balance')->display(function ($value) { // $value = bcdiv($value, 100, 2); // if ($this->wallet?->is_frozen) { @@ -149,17 +150,24 @@ class UserController extends AdminController { return function (Row $row) use ($id) { $row->column(5, function ($column) use ($id) { - $builder = User::with(['userInfo', 'wallet', 'balance', 'userInfo.inviterInfo.user']); + $builder = User::with(['userInfo', 'wallet', 'balance', 'userInfo.inviterInfo.user', 'userVip.vip']); $column->row(Show::make($id, $builder, function (Show $show) { $show->row(function (Show\Row $show) { - $show->width(12)->field('id')->width(10, 1); + $show->width(6)->field('id'); + $show->width(6)->field('vip', '代理')->as(function () { + return $this->userVip ? $this->userVip->vip->name . '(' .$this->userVip->vip->ratio. '%)' : ''; + })->badge(); $show->width(6)->field('phone'); $show->field('user_info.inviter_info.user.phone'); - $show->field('user_info.nickname'); - $show->field('user_info.gender')->using(UserInfo::$genderTexts)->label(); - $show->field('user_info.birthday'); + // $show->field('user_info.nickname'); + // $show->field('user_info.gender')->using(UserInfo::$genderTexts)->label(); + // $show->field('user_info.birthday'); $show->field('user_info.growth_value'); + $show->field('profit'); + $show->field('userInfo.is_company')->as(function ($v) { + return $v ? '是' : '否'; + }); // $show->field('wallet.balance')->as(function ($value) { // $value = bcdiv($value, 100, 2); @@ -172,9 +180,9 @@ class UserController extends AdminController // $show->field('user_info.points'); }); $show->row(function (Show\Row $show) { - $show->width(6)->field('last_login_ip'); - $show->field('last_login_at'); - $show->field('register_ip'); + // $show->width(6)->field('last_login_ip'); + $show->width(6)->field('last_login_at'); + // $show->field('register_ip'); $show->field('created_at'); }); @@ -187,9 +195,9 @@ class UserController extends AdminController $tools->append(new UserEditPhone()); } // 修改银行卡 - if (Admin::user()->can('dcat.admin.users.edit_bank')) { - $tools->append(new UserEditBank()); - } + // if (Admin::user()->can('dcat.admin.users.edit_bank')) { + // $tools->append(new UserEditBank()); + // } // 设置代理等级 if (Admin::user()->can('dcat.admin.users.edit_vip')) { $tools->append(new UserEditVip()); @@ -203,10 +211,10 @@ class UserController extends AdminController // $tab->add('可提明细', UserWalletLogSimpleTable::make(['id'=>$id])); // 余额明细 // $tab->add('余额明细', UserBalanceLogSimpleTable::make(['id'=>$id])); - // 粉丝列表 - // $tab->add('粉丝列表', UserFansSimpleTable::make(['id'=>$id])); + // 下级列表 + $tab->add('下级列表', UserFansSimpleTable::make(['id'=>$id])); // 上级列表 - $tab->add('上级列表', UserInviterSimpleTable::make(['id'=>$id])); + // $tab->add('上级列表', UserInviterSimpleTable::make(['id'=>$id])); $column->row(Box::make('用户记录', $tab)); }); }; diff --git a/app/Admin/Forms/OrderPackage.php b/app/Admin/Forms/OrderPackage.php index 3699c2a5..71eb9af9 100644 --- a/app/Admin/Forms/OrderPackage.php +++ b/app/Admin/Forms/OrderPackage.php @@ -76,6 +76,7 @@ class OrderPackage extends Form implements LazyRenderable 'EMS'=>'EMS', '顺丰速运'=>'顺丰速运', '德邦快递'=>'德邦快递', + '自提' => '自提', ])->default('韵达快递')->required(); $this->text('shipping_number')->required(); $products = $order->products->filter(function ($items) { @@ -91,8 +92,8 @@ class OrderPackage extends Form implements LazyRenderable }); $this->hasMany('packages', function (Form $form) use ($options) { $form->select('order_product_id')->options($options); - $form->number('quantity')->min(1); - }); + $form->number('quantity')->default(1)->min(1); + })->required(); $this->disableResetButton(); } diff --git a/app/Admin/Forms/UserEditVip.php b/app/Admin/Forms/UserEditVip.php index 65aed84c..d01af520 100644 --- a/app/Admin/Forms/UserEditVip.php +++ b/app/Admin/Forms/UserEditVip.php @@ -2,7 +2,7 @@ namespace App\Admin\Forms; -use App\Models\User; +use App\Models\{User, Vip}; use Dcat\Admin\Contracts\LazyRenderable; use Dcat\Admin\Traits\LazyWidget; use Dcat\Admin\Widgets\Form; @@ -34,9 +34,24 @@ class UserEditVip extends Form implements LazyRenderable { $id = $this->payload['id'] ?? 0; $user = User::findOrFail($id); + $vip_id = $input['vip']; try { DB::beginTransaction(); - $user->update($input); + if ($user->userVip) { + if ($vip_id) { + $user->userVip->update([ + 'vip_id' => $vip_id + ]); + } else { + $user->userVip->delete(); + } + } else { + if ($vip_id) { + $user->userVip()->create([ + 'vip_id' => $vip_id + ]); + } + } DB::commit(); } catch (Throwable $th) { DB::rollBack(); @@ -54,9 +69,10 @@ class UserEditVip extends Form implements LazyRenderable { $id = $this->payload['id'] ?? 0; $user = User::findOrFail($id); + $vips = Vip::orderBy('sort')->get(); - $this->text('old_phone', '旧手机号')->value($user->phone)->disable(); + $this->text('user_vip', '当前代理')->value(data_get($user, 'userVip.vip.name', ''))->disable(); - $this->mobile('phone')->rules('unique:users,phone', ['unique'=>'该手机号已存在'])->required(); + $this->select('vip')->options($vips->pluck('name', 'id')); } } diff --git a/app/Admin/Renderable/UserFansSimpleTable.php b/app/Admin/Renderable/UserFansSimpleTable.php index 7d086b4c..dc1b5bad 100644 --- a/app/Admin/Renderable/UserFansSimpleTable.php +++ b/app/Admin/Renderable/UserFansSimpleTable.php @@ -12,12 +12,13 @@ class UserFansSimpleTable extends LazyRenderable { $userId = $this->payload['id'] ?? 0; $builder = UserInfo::query(); - $builder->with('user')->where('inviter_id', $userId); + $builder->with(['user', 'user.userVip.vip'])->where('inviter_id', $userId); return Grid::make($builder, function (Grid $grid) { $grid->column('user.phone', '手机号')->link(function ($value) { return admin_url('users/'.$this->user_id); }); - $grid->column('growth_value', '消费值'); + $grid->column('user.userVip.vip.name', '代理'); + $grid->column('growth_value', '成长值'); $grid->column('created_at', '注册时间'); // $grid->withBorder(); $grid->model()->orderBy('created_at', 'desc'); diff --git a/app/Admin/Renderable/UserSalesValueLogSimpleTable.php b/app/Admin/Renderable/UserSalesValueLogSimpleTable.php index 6eba24ef..f1ec5ee2 100644 --- a/app/Admin/Renderable/UserSalesValueLogSimpleTable.php +++ b/app/Admin/Renderable/UserSalesValueLogSimpleTable.php @@ -44,9 +44,8 @@ class UserSalesValueLogSimpleTable extends LazyRenderable }); // 查出统计数据 $salesValue1 = (clone $query)->where('type', '1')->sum('change_sales_value'); - $salesValue2 = (clone $query)->where('type', '2')->sum('change_sales_value'); // 自定义组件 - return "
个人消费值:".$salesValue1.'
团队消费值:'.$salesValue2.'
'; + return "
个人消费值:".$salesValue1.'
'; }); $grid->filter(function (Grid\Filter $filter) { $filter->expand(false); diff --git a/app/Admin/Services/OrderPackageService.php b/app/Admin/Services/OrderPackageService.php index 4941f085..48a6e7ac 100644 --- a/app/Admin/Services/OrderPackageService.php +++ b/app/Admin/Services/OrderPackageService.php @@ -71,7 +71,7 @@ class OrderPackageService //保存发货单 $package->save(); - if (app_settings('kuaidi100.is_use')) { + if ($package->shipping_code && app_settings('kuaidi100.is_use')) { $kuaidi100Service = new Kuaidi100Service(); $kuaidi100Service->poll($package->shipping_number, $package->shipping_code, $package->consignee_telephone); } diff --git a/app/Console/Commands/DistributeOrder.php b/app/Console/Commands/DistributeOrder.php new file mode 100644 index 00000000..107ad103 --- /dev/null +++ b/app/Console/Commands/DistributeOrder.php @@ -0,0 +1,54 @@ +argument('order')); + try { + DB::beginTransaction(); + DB::commit(); + $service->storeByOrder($order); + } catch (Throwable $th) { + DB::rollBack(); + } + return 0; + } +} diff --git a/app/Endpoint/Api/Http/Controllers/Order/OrderController.php b/app/Endpoint/Api/Http/Controllers/Order/OrderController.php index ad7e15c3..d77eb54b 100644 --- a/app/Endpoint/Api/Http/Controllers/Order/OrderController.php +++ b/app/Endpoint/Api/Http/Controllers/Order/OrderController.php @@ -51,7 +51,7 @@ class OrderController extends Controller $rules = $isQuick ? [ 'product.sku_id' => ['bail', 'required', 'int'], 'product.quantity' => ['bail', 'required', 'int', 'min:1'], - 'shipping_address_id' => ['bail', 'required', 'int'], + 'shipping_address_id' => ['bail', 'nullable', 'int'], 'coupon_id' => ['bail', 'nullable', 'int'], 'note' => ['bail', 'nullable', 'string', 'max:255'], ] : [ @@ -81,7 +81,7 @@ class OrderController extends Controller $user, $input['product']['sku_id'], $input['product']['quantity'], - $input['shipping_address_id'], + $input['shipping_address_id'] ?? null, $input['coupon_id'] ?? null, $input['note'] ?? null, ); @@ -90,7 +90,7 @@ class OrderController extends Controller return $orderService->createShoppingCartOrder( $user, $input['shopping_cart'], - $input['shipping_address_id'], + $input['shipping_address_id'] ?? null, $input['coupon_id'] ?? null, $input['note'] ?? null, ); diff --git a/app/Models/UserVip.php b/app/Models/UserVip.php index f6078967..70a368dd 100644 --- a/app/Models/UserVip.php +++ b/app/Models/UserVip.php @@ -9,6 +9,12 @@ class UserVip extends Model { use HasFactory; + protected $fillable = ['vip_id', 'growth_value']; + + protected $attributes = [ + 'growth_value' => 0 + ]; + public function vip() { return $this->belongsTo(Vip::class, 'vip_id'); diff --git a/app/Services/DistributeService.php b/app/Services/DistributeService.php index eeb7db61..00500c36 100644 --- a/app/Services/DistributeService.php +++ b/app/Services/DistributeService.php @@ -2,7 +2,7 @@ namespace App\Services; -use App\Models\{User, Order, SalesValueLog}; +use App\Models\{User, Order, SalesValueLog, Vip}; /** * 分销模块 @@ -19,27 +19,42 @@ class DistributeService public function storeByOrder(Order $order) { // 订单已取消 - if ($order->isCancelled) { + if ($order->isCancelled()) { return false; } // 订单成长值 $sales_value = $order->sales_value; $user = $order->user; - $user->salesValueLogs()->create([ - 'order_id' => $order->id, - 'order_user_id' => $user_id, - 'type' => SalesValueLog::TYPE_INDIVIDUAL, - 'change_sales_value' => $sales_value - ]); - $user->userInfo()->increment('growth_value', $sales_value); + // $user->salesValueLogs()->create([ + // 'order_id' => $order->id, + // 'order_user_id' => $order->user_id, + // 'type' => SalesValueLog::TYPE_INDIVIDUAL, + // 'change_sales_value' => $sales_value + // ]); + // $user->userInfo()->increment('growth_value', $sales_value); // 上级返现 $parent_ids = array_reverse($user->userInfo->parent_ids); - $parents = User::with(['userInfo'])->whereIn('id', $parent_ids)->where('role', '!=', '')->get(); - // 没有上级是代理身份 - if ($parents->count() === 0) { - return false; + $parents = User::with(['userInfo', 'userVip.vip'])->whereIn('id', $parent_ids)->get(); + // 过滤掉不是代理身份的用户 + // 当前等级和下一级的等级相同 + $parents->filter(function ($item) { + return $item->userVip ? true : false; + }); + $user_list = collect(); + foreach($parents as $item) { + $user_list->push([ + 'id' => $item->id, + 'vip_name' => $item->userVip->vip->name ?? '', + 'vip_id' => $item->userVip->vip_id ?? '', + ]); } + + // $vip_list = Vip::orderBy('sort', 'desc')->pluk('id'); + // foreach($vip_list as $vip_id) { + + // } + dd($user_list->all()); } } diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index 7c95f129..0a7a192b 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -45,7 +45,7 @@ class OrderService User $user, int $skuId, int $quantity, - int $shippingAddressId, + ?int $shippingAddressId, ?int $couponId = null, ?string $note = null, ?BargainOrder $bargainOrder = null, @@ -105,7 +105,7 @@ class OrderService protected function createOrder( User $user, array $products, - int $shippingAddressId, + ?int $shippingAddressId, ?int $couponId = null, ?string $note = null, ?BargainOrder $bargainOrder = null, @@ -141,12 +141,12 @@ class OrderService $order = $this->storeOrder( $user, - $shippingAddress, $productsTotalAmount, $couponDiscountAmount, $vipDiscountAmount, $shippingFee, $salesValue, + $shippingAddress, $note, $coupon, $bargainOrder,//添加砍价订单逻辑 @@ -182,12 +182,12 @@ class OrderService */ protected function storeOrder( User $user, - ShippingAddress $shippingAddress, int $productsTotalAmount, int $couponDiscountAmount, int $vipDiscountAmount, int $shippingFee, $salesValue, + ?ShippingAddress $shippingAddress, ?string $note = null, ?UserCoupon $coupon = null, ?BargainOrder $bargainOrder = null, @@ -220,10 +220,10 @@ class OrderService 'sales_value' => $salesValue, // 订单总销售值 'note' => $note, // 收货地址 - 'consignee_name' => $shippingAddress->consignee, - 'consignee_telephone' => $shippingAddress->telephone, - 'consignee_zone' => $shippingAddress->zone, - 'consignee_address' => $shippingAddress->address, + 'consignee_name' => $shippingAddress->consignee??'', + 'consignee_telephone' => $shippingAddress->telephone??'', + 'consignee_zone' => $shippingAddress->zone??'', + 'consignee_address' => $shippingAddress->address??'', //砍价订单金额 'bargain_amount'=>$bargainOrder?->bargain_price ?? 0, ]; @@ -644,10 +644,13 @@ class OrderService * @param \App\Models\ShippingAddress $shippingAddress * @return int */ - protected function calculateShippingFee(array $products, ShippingAddress $shippingAddress): int + protected function calculateShippingFee(array $products, ?ShippingAddress $shippingAddress): int { // 运费 $shippingFee = 0; + if (!$shippingAddress) { + return $shippingFee; + } $shippings = []; diff --git a/composer.json b/composer.json index d831fe6c..71ab3513 100644 --- a/composer.json +++ b/composer.json @@ -77,7 +77,10 @@ "config": { "optimize-autoloader": true, "preferred-install": "dist", - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "easywechat-composer/easywechat-composer": true + } }, "minimum-stability": "dev", "prefer-stable": true diff --git a/config/app.php b/config/app.php index f2d90514..96b00f6a 100644 --- a/config/app.php +++ b/config/app.php @@ -93,7 +93,7 @@ return [ | */ - 'fallback_locale' => 'en', + 'fallback_locale' => 'zh_CN', /* |-------------------------------------------------------------------------- diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 00000000..059ea02d --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,27 @@ +faker; + $time = now(); + return [ + 'phone' => $faker->phoneNumber, + 'phone_verified_at' => $time, + 'email' => $faker->email, + 'email_verified_at' => $time, + 'register_ip' => $faker->ipv4, + 'status' => 1 + ]; + } +} diff --git a/database/seeders/AdminMenuSeeder.php b/database/seeders/AdminMenuSeeder.php index f4da7d13..9ebdc7c1 100644 --- a/database/seeders/AdminMenuSeeder.php +++ b/database/seeders/AdminMenuSeeder.php @@ -299,6 +299,7 @@ class AdminMenuSeeder extends Seeder 'icon' => '', 'uri' =>'auth/menus', ], + ['title' => '代理等级', 'icon' => '', 'uri' => 'vips'], [ 'title' =>'配置管理', 'icon' => '', diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php new file mode 100644 index 00000000..bd5b0dc5 --- /dev/null +++ b/database/seeders/UserSeeder.php @@ -0,0 +1,89 @@ +truncate(); + DB::table('user_vips')->truncate(); + DB::table('socialite_users')->truncate(); + DB::table('personal_access_tokens')->truncate(); + DB::table('wallets')->truncate(); + DB::table('balances')->truncate(); + DB::table('users')->truncate(); + $this->faker = $this->withFaker(); + $this->createUsers(1); + } + + protected function createUsers($vip, $parent = null) + { + if ($vip > 7) { + return; + } + $faker = $this->faker; + for ($i = 0; $i < $faker->numberBetween(1, 5); $i++) { + $user = $this->createUser($vip, $parent); + $this->createUsers($vip + 1, $user); + } + } + + protected function createUser($vip = null, $inviter = null) + { + $faker = $this->faker; + $time = now(); + $phone = $this->fakePhone(); + $email = $this->fakeEmail(); + $user = User::create([ + 'phone' => $phone, + 'phone_verified_at' => $time, + 'email' => $email, + 'email_verified_at' => $time, + 'register_ip' => $faker->ipv4, + 'status' => 1 + ], $inviter); + if ($vip && $vip <= 6) { + $user->userVip()->create([ + 'vip_id' => $vip + ]); + } + return $user; + } + + protected function fakePhone() + { + do { + $phone = substr($this->faker->e164PhoneNumber, 1); + } while(User::where('phone', $phone)->exists()); + + return $phone; + } + + protected function fakeEmail() + { + do { + $email = $this->faker->email; + } while(User::where('email', $email)->exists()); + + return $email; + } + + protected function withFaker() + { + return Container::getInstance()->make(Generator::class); + } +} diff --git a/resources/lang/zh_CN/user.php b/resources/lang/zh_CN/user.php index 58f184eb..4270096b 100644 --- a/resources/lang/zh_CN/user.php +++ b/resources/lang/zh_CN/user.php @@ -18,14 +18,14 @@ return [ 'created_at' => '注册时间', 'userVip'=>[ 'vip' => [ - 'name' => '等级', + 'name' => '代理', ], ], 'userInfo'=>[ 'avatar' => '头像', 'nickname' => '昵称', 'code' => '邀请码', - 'growth_value'=>'消费值', + 'growth_value'=>'成长值', 'inviterInfo'=>[ 'user'=>[ 'phone' =>'推荐人手机', @@ -36,7 +36,7 @@ return [ 'user_info'=>[ 'avatar' => '头像', 'nickname' => '昵称', - 'growth_value'=>'消费值', + 'growth_value'=>'成长值', 'points'=>'积分', 'gender'=>'性别', 'birthday'=>'生日', @@ -53,6 +53,7 @@ return [ 'balance'=>'余额', ], 'status_remark'=>'备注', + 'profit' => '累计返利', ], 'options' => [ ], diff --git a/resources/lang/zh_CN/vip.php b/resources/lang/zh_CN/vip.php index 33314ebf..e92e4df2 100644 --- a/resources/lang/zh_CN/vip.php +++ b/resources/lang/zh_CN/vip.php @@ -7,7 +7,7 @@ return [ ], 'fields' => [ 'name' => '等级名称', - 'growth_value' => '等级成长值', + 'growth_value' => '升级', 'sort' => '排序', 'ratio' => '比例' ],