diff --git a/app/Admin/Actions/Grid/PointChange.php b/app/Admin/Actions/Grid/PointChange.php new file mode 100644 index 00000000..b5e8d185 --- /dev/null +++ b/app/Admin/Actions/Grid/PointChange.php @@ -0,0 +1,31 @@ + 变更积分'; + } + + protected function authorize($user): bool + { + return $user->can('dcat.admin.users.change_points'); + } + + public function render() + { + $form = PointChangeForm::make()->payload(['id'=>$this->getKey()]); + + return Modal::make() + ->lg() + ->title($this->title()) + ->body($form) + ->button($this->title()); + } +} diff --git a/app/Admin/Controllers/PointLogController.php b/app/Admin/Controllers/PointLogController.php new file mode 100644 index 00000000..8eef2a8a --- /dev/null +++ b/app/Admin/Controllers/PointLogController.php @@ -0,0 +1,76 @@ +model()->orderBy('id', 'desc'); + + $grid->column('id')->sortable(); + $grid->column('user.phone')->copyable(); + $grid->column('action')->display(fn ($action) => $action->label())->label();; + $grid->column('change_points'); + $grid->column('before_points'); + $grid->column('after_points'); + $grid->column('remark'); + $grid->column('created_at'); + + $grid->disableActions(); + + $grid->header(function ($collection) use ($grid) { + return tap(new Row(), function ($row) use ($grid) { + $query = PointLog::query(); + + $grid->model()->getQueries()->unique()->each(function ($value) use (&$query) { + if (in_array($value['method'], ['paginate', 'get', 'orderBy', 'orderByDesc'], true)) { + return; + } + + $query = call_user_func_array([$query, $value['method']], $value['arguments'] ?? []); + }); + + $totalPoints = (clone $query)->sum('change_points'); + + $row->column(2, new InfoBox('积分总数', $totalPoints, 'fa fa-ticket')); + }); + }); + + $grid->filter(function (Grid\Filter $filter) { + $filter->panel(false); + $filter->equal('user.phone')->width(3); + $filter->in('action')->multipleSelect(PointLogAction::options())->width(3); + $filter->between('created_at')->dateTime()->width(3); + }); + + return $grid; + }); + } +} diff --git a/app/Admin/Controllers/PointsLogController.php b/app/Admin/Controllers/PointsLogController.php deleted file mode 100644 index 7802595d..00000000 --- a/app/Admin/Controllers/PointsLogController.php +++ /dev/null @@ -1,81 +0,0 @@ -column('id')->sortable(); - $grid->column('user.phone')->copyable(); - $grid->column('desc'); - // $grid->column('type'); - $grid->column('points'); - $grid->column('old_points'); - - $grid->column('created_at')->sortable(); - $grid->model()->orderBy('created_at', 'desc'); - // $grid->column('updated_at')->sortable(); - - $grid->disableActions(); - $grid->filter(function (Grid\Filter $filter) { - $filter->panel(false); - $filter->equal('user.phone')->width(3); - }); - }); - } - - /** - * Make a show builder. - * - * @param mixed $id - * - * @return Show - */ - protected function detail($id) - { - return Show::make($id, new PointsLog(), function (Show $show) { - $show->field('id'); - $show->field('user_id'); - $show->field('type'); - $show->field('points'); - $show->field('old_points'); - $show->field('desc'); - $show->field('created_at'); - $show->field('updated_at'); - }); - } - - /** - * Make a form builder. - * - * @return Form - */ - protected function form() - { - return Form::make(new PointsLog(), function (Form $form) { - $form->display('id'); - $form->text('user_id'); - $form->text('type'); - $form->text('points'); - $form->text('old_points'); - $form->text('desc'); - - $form->display('created_at'); - $form->display('updated_at'); - }); - } -} diff --git a/app/Admin/Controllers/UserController.php b/app/Admin/Controllers/UserController.php index 4f6f8335..2dbc601b 100644 --- a/app/Admin/Controllers/UserController.php +++ b/app/Admin/Controllers/UserController.php @@ -3,19 +3,12 @@ namespace App\Admin\Controllers; use App\Admin\Actions\Grid\DisableUser; +use App\Admin\Actions\Grid\PointChange; use App\Admin\Actions\Grid\{EnableUser, UserCompany}; -use App\Admin\Actions\Grid\Frozen; -use App\Admin\Actions\Grid\UserResetAccountPassword; -use App\Admin\Actions\Grid\UserResetPassword; -use App\Admin\Actions\Show\{UserEditBank, UserCompany as UserCompanyShow}; -use App\Admin\Actions\Show\UserEditPhone; +use App\Admin\Actions\Show\UserCompany as UserCompanyShow; use App\Admin\Actions\Show\UserEditAgent; -use App\Admin\Renderable\Grid\Filter\PriceBetween; -use App\Admin\Renderable\UserBalanceLogSimpleTable; -use App\Admin\Renderable\UserFansSimpleTable; -use App\Admin\Renderable\UserInviterSimpleTable; +use App\Admin\Actions\Show\UserEditPhone; use App\Admin\Renderable\UserSalesValueLogSimpleTable; -use App\Admin\Renderable\UserWalletLogSimpleTable; use App\Admin\Repositories\User; use App\Exceptions\BizException; use App\Models\Order; @@ -61,6 +54,13 @@ class UserController extends AdminController $grid->column('userInfo.inviterInfo.user.phone')->display(function ($v) { return $v ?: $this->userInfo?->inviter_id; })->copyable(); + $grid->column('userInfo.points')->sortable()->if(function () { + return Admin::user()->can('dcat.admin.point_logs.index'); + })->then(function (Grid\Column $column) { + $column->link(function ($value) { + return route('dcat.admin.point_logs.index', ['user[phone]' => $this->phone]); + }); + }); $grid->column('userInfo.growth_value')->filter( Grid\Column\Filter\Between::make() )->modal(function ($modal) { @@ -89,6 +89,10 @@ class UserController extends AdminController $grid->actions(function (Grid\Displayers\Actions $actions) { $actions->disableView(Admin::user()->cannot('dcat.admin.users.show')); $actions->disableDelete(Admin::user()->cannot('dcat.admin.users.destroy')); + + if (Admin::user()->can('dcat.admin.users.change_points')) { + $actions->append(new PointChange()); + } if ($actions->row->status == 1) { if (Admin::user()->can('dcat.admin.users.disable')) { $actions->append(new DisableUser()); diff --git a/app/Admin/Forms/PointChange.php b/app/Admin/Forms/PointChange.php new file mode 100644 index 00000000..3a231b50 --- /dev/null +++ b/app/Admin/Forms/PointChange.php @@ -0,0 +1,75 @@ +can('dcat.admin.users.change_points'); + } + + public function handle(array $input) + { + $changePoints = (int) $input['change_points']; + + if ($changePoints < 1) { + return $this->response()->error('积分必须大于1'); + } + + $action = PointLogAction::from($input['action']); + + if ($action === PointLogAction::Deduction) { + $changePoints = -$changePoints; + } + + $user = User::findOrFail($this->payload['id']); + + try { + DB::beginTransaction(); + + (new PointService())->change($user, $changePoints, $action, $input['remark'], null, Admin::user()); + + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + + report($th); + + return $this->response()->error('操作失败:'.$th->getMessage()); + } + + return $this->response() + ->success(__('admin.update_succeeded')) + ->refresh(); + } + + /** + * Build a form here. + */ + public function form() + { + $this->radio('action', '操作') + ->options([ + PointLogAction::Recharge->value => '充值', + PointLogAction::Deduction->value => '扣减', + ]) + ->default(PointLogAction::Recharge->value) + ->required(); + $this->number('change_points', '积分')->min(1)->required(); + $this->textarea('remark', '备注')->required(); + $this->confirm('是否确认变更?', '提交后该动作无法逆转'); + } +} diff --git a/app/Admin/Repositories/PointsLog.php b/app/Admin/Repositories/PointLog.php similarity index 51% rename from app/Admin/Repositories/PointsLog.php rename to app/Admin/Repositories/PointLog.php index 679fbe57..81089c3c 100644 --- a/app/Admin/Repositories/PointsLog.php +++ b/app/Admin/Repositories/PointLog.php @@ -2,15 +2,10 @@ namespace App\Admin\Repositories; -use App\Models\PointsLog as Model; +use App\Models\PointLog as Model; use Dcat\Admin\Repositories\EloquentRepository; -class PointsLog extends EloquentRepository +class PointLog extends EloquentRepository { - /** - * Model. - * - * @var string - */ protected $eloquentClass = Model::class; } diff --git a/app/Admin/routes.php b/app/Admin/routes.php index f0579727..3c283a24 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -137,9 +137,9 @@ Route::group([ 'index', ])->names('balance_logs'); - $router->resource('points-logs', 'PointsLogController')->only([ + $router->resource('point-logs', 'PointLogController')->only([ 'index', - ])->names('points_logs'); + ])->names('point_logs'); $router->resource('order-refunds', 'OrderRefundLogController')->only([ 'index', diff --git a/app/Endpoint/Api/Http/Controllers/ArticleController.php b/app/Endpoint/Api/Http/Controllers/ArticleController.php index 902f071e..ebee7fb1 100644 --- a/app/Endpoint/Api/Http/Controllers/ArticleController.php +++ b/app/Endpoint/Api/Http/Controllers/ArticleController.php @@ -10,14 +10,10 @@ use App\Helpers\Paginator as PaginatorHelper; use App\Models\Article; use App\Models\ArticleCategory; use App\Models\ArticleLikesLog; -use App\Models\ArticlePointsLog; -use App\Models\PointsLog; -use App\Services\PointsService; +use Dcat\Admin\Support\Helper; use Illuminate\Http\Request; -use Illuminate\Support\Arr; use Illuminate\Support\Facades\DB; use Throwable; -use Dcat\Admin\Support\Helper; class ArticleController extends Controller { @@ -123,29 +119,10 @@ class ArticleController extends Controller * @param [type] $id * @return void */ - public function read($id, Request $request, PointsService $pointsService) + public function read($id, Request $request) { - $article = Article::where('is_show', 1)->findOrFail($id); - if ($article->points > 0) { - if (ArticlePointsLog::where('user_id', $request->user()->id)->whereDate('created_at', now())->exists()) { - throw new BizException('您今天已拿过积分了,请明天再来'); - } - try { - DB::beginTransaction(); - ArticlePointsLog::create([ - 'user_id' => $request->user()->id, - 'article_id' => $article->id, - ]); - $pointsService->sendPoints(PointsLog::TYPE_READ, $request->user(), $article->points, '阅读文章送积分'); - DB::commit(); - } catch (Throwable $th) { - DB::rollBack(); - report($th); - throw new BizException('系统繁忙,请稍后再试'); - } - } return response()->json([ - 'points'=>$article->points, + 'points' => 0, ]); } } diff --git a/app/Endpoint/Api/Http/Controllers/PointLogController.php b/app/Endpoint/Api/Http/Controllers/PointLogController.php new file mode 100644 index 00000000..ec219566 --- /dev/null +++ b/app/Endpoint/Api/Http/Controllers/PointLogController.php @@ -0,0 +1,26 @@ +user()->id) + ->latest('id') + ->simplePaginate(Paginator::resolvePerPage('per_page', 20, 50)); + + return PointLogResource::collection($pointLogs); + } +} diff --git a/app/Endpoint/Api/Http/Resources/PointLogResource.php b/app/Endpoint/Api/Http/Resources/PointLogResource.php new file mode 100644 index 00000000..2ea25aab --- /dev/null +++ b/app/Endpoint/Api/Http/Resources/PointLogResource.php @@ -0,0 +1,25 @@ + $this->id, + 'action' => $this->action, + 'change_points' => $this->change_points, + 'remark' => (string) $this->remark, + 'created_at' => $this->created_at->toDateTimeString(), + ]; + } +} diff --git a/app/Endpoint/Api/Http/Resources/UserInfoResource.php b/app/Endpoint/Api/Http/Resources/UserInfoResource.php index 2a203f01..af28ef1f 100644 --- a/app/Endpoint/Api/Http/Resources/UserInfoResource.php +++ b/app/Endpoint/Api/Http/Resources/UserInfoResource.php @@ -20,7 +20,8 @@ class UserInfoResource extends JsonResource 'gender' => (string) $this->gender, 'birthday' => (string) $this->birthday?->toDateString(), 'code' => (string) $this->code, - 'is_company' => (boolean) $this->is_company + 'is_company' => (boolean) $this->is_company, + 'points' => $this->points, ]; } } diff --git a/app/Endpoint/Api/routes.php b/app/Endpoint/Api/routes.php index f46b3c99..54f5d185 100644 --- a/app/Endpoint/Api/routes.php +++ b/app/Endpoint/Api/routes.php @@ -13,6 +13,7 @@ use App\Endpoint\Api\Http\Controllers\ArticleController; use App\Endpoint\Api\Http\Controllers\Auth; use App\Endpoint\Api\Http\Controllers\Auth\LoginController; use App\Endpoint\Api\Http\Controllers\Auth\LogoutController; +use App\Endpoint\Api\Http\Controllers\Auth\MiniprogramController; use App\Endpoint\Api\Http\Controllers\Auth\RegisterController; use App\Endpoint\Api\Http\Controllers\Auth\ResetPasswordController; use App\Endpoint\Api\Http\Controllers\CaptchaController; @@ -21,6 +22,7 @@ use App\Endpoint\Api\Http\Controllers\MessageController; use App\Endpoint\Api\Http\Controllers\Order\OrderController; use App\Endpoint\Api\Http\Controllers\Order\OrderVerifyController; use App\Endpoint\Api\Http\Controllers\Order\StatisticsController; +use App\Endpoint\Api\Http\Controllers\PointLogController; use App\Endpoint\Api\Http\Controllers\Product\HotController; use App\Endpoint\Api\Http\Controllers\Product\PartController; use App\Endpoint\Api\Http\Controllers\Product\ProductCategoryController; @@ -33,11 +35,10 @@ use App\Endpoint\Api\Http\Controllers\ShareBgController; use App\Endpoint\Api\Http\Controllers\ShippingAddressController; use App\Endpoint\Api\Http\Controllers\ShoppingCartItemController; use App\Endpoint\Api\Http\Controllers\SmsCodeController; +use App\Endpoint\Api\Http\Controllers\StoreController; use App\Endpoint\Api\Http\Controllers\UserBankController; use App\Endpoint\Api\Http\Controllers\UserCouponController; use App\Endpoint\Api\Http\Controllers\ZoneController; -use App\Endpoint\Api\Http\Controllers\Auth\MiniprogramController; -use App\Endpoint\Api\Http\Controllers\StoreController; use Illuminate\Support\Facades\Route; Route::group([ @@ -127,6 +128,8 @@ Route::group([ Route::post('wallet/wallet-to-balance', [WalletController::class, 'walletToBalance']); Route::post('wallet/balance-transfer', [WalletController::class, 'balanceTransfer']); + Route::get('point-logs', [PointLogController::class, 'index']); + //银行卡 Route::get('user-bank', [UserBankController::class, 'show']); Route::put('user-bank', [UserBankController::class, 'update']); diff --git a/app/Enums/PointLogAction.php b/app/Enums/PointLogAction.php new file mode 100644 index 00000000..702b1b16 --- /dev/null +++ b/app/Enums/PointLogAction.php @@ -0,0 +1,25 @@ +value, 'Unknown'); + } + + public static function options(): array + { + return [ + self::Recharge->value => '充值', + self::Deduction->value => '扣减', + self::Consumption->value => '消费', + ]; + } +} diff --git a/app/Models/PointLog.php b/app/Models/PointLog.php new file mode 100644 index 00000000..67a1916f --- /dev/null +++ b/app/Models/PointLog.php @@ -0,0 +1,40 @@ + PointLogAction::class, + ]; + + public function user() + { + return $this->belongsTo(User::class); + } + + public function administrator() + { + return $this->belongsTo(Administrator::class); + } +} diff --git a/app/Models/PointsLog.php b/app/Models/PointsLog.php deleted file mode 100644 index 96cb9e1e..00000000 --- a/app/Models/PointsLog.php +++ /dev/null @@ -1,25 +0,0 @@ -belongsTo(User::class); - } -} diff --git a/app/Models/UserInfo.php b/app/Models/UserInfo.php index faea7349..20335042 100644 --- a/app/Models/UserInfo.php +++ b/app/Models/UserInfo.php @@ -42,6 +42,7 @@ class UserInfo extends Model 'birthday', 'depth', 'path', + 'points', 'growth_value', 'real_inviter_id', 'is_company', @@ -117,7 +118,7 @@ class UserInfo extends Model { return $this->hasMany(Order::class, 'inviter_id', 'user_id')->where('status', Order::STATUS_COMPLETED); } - + public function inviteUserInfos() { return $this->hasMany(UserInfo::class, 'inviter_id', 'user_id'); diff --git a/app/Services/PointService.php b/app/Services/PointService.php new file mode 100644 index 00000000..55ab6fb1 --- /dev/null +++ b/app/Services/PointService.php @@ -0,0 +1,72 @@ +where('user_id', $user->id)->firstOrFail(); + + switch ($action) { + case PointLogAction::Recharge: + if ($points < 0) { + throw new BizException('积分不能小于 0'); + } + break; + + case PointLogAction::Deduction: + case PointLogAction::Consumption: + if ($points > 0) { + throw new BizException('积分不能大于 0'); + } + break; + } + + $before = $userinfo->points; + $after = $before + $points; + + if ($after < 0) { + throw new BizException('积分不足'); + } + + $userinfo->update([ + 'points' => $after, + ]); + + PointLog::create([ + 'loggable_id' => $loggable?->id, + 'loggable_type' => $loggable?->getMorphClass(), + 'user_id' => $user->id, + 'action' => $action, + 'change_points' => $points, + 'before_points' => $before, + 'after_points' => $after, + 'remark' => $remark, + 'administrator_id' => $administrator?->id, + ]); + } +} diff --git a/app/Services/PointsService.php b/app/Services/PointsService.php deleted file mode 100644 index a4570b29..00000000 --- a/app/Services/PointsService.php +++ /dev/null @@ -1,40 +0,0 @@ - $type, - 'user_id' => $user->id, - 'points' => $points, - 'old_points'=> $user->userInfo->points, - 'desc' => $desc, - ]); - - if ($points > 0) { - $user->userInfo()->increment('points', abs($points)); - } else { - $user->userInfo()->decrement('points', abs($points)); - } - $res = true; - } - return $res; - } -} diff --git a/database/migrations/2021_12_13_173136_create_points_logs_table.php b/database/migrations/2021_12_13_173136_create_points_logs_table.php deleted file mode 100644 index 6d1de4e1..00000000 --- a/database/migrations/2021_12_13_173136_create_points_logs_table.php +++ /dev/null @@ -1,36 +0,0 @@ -id(); - $table->unsignedBigInteger('user_id')->comment('用户ID'); - $table->unsignedTinyInteger('type')->default(0)->comment('类别:1签到,2阅读'); - $table->bigInteger('points')->default(0)->comment('积分:可以为负数'); - $table->unsignedBigInteger('old_points')->default(0)->comment('变动前'); - $table->string('desc')->nullable()->comment('备注'); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('points_logs'); - } -} diff --git a/database/migrations/2023_10_12_103127_create_point_logs_table.php b/database/migrations/2023_10_12_103127_create_point_logs_table.php new file mode 100644 index 00000000..5c6afb21 --- /dev/null +++ b/database/migrations/2023_10_12_103127_create_point_logs_table.php @@ -0,0 +1,42 @@ +id(); + $table->nullableMorphs('loggable'); + $table->unsignedBigInteger('user_id')->comment('用户ID'); + $table->tinyInteger('action')->comment('操作'); + $table->bigInteger('change_points')->comment('变更的积分'); + $table->unsignedBigInteger('before_points')->comment('变更前的积分'); + $table->unsignedBigInteger('after_points')->comment('变更后的积分'); + $table->string('remark')->nullable()->comment('备注'); + $table->unsignedBigInteger('administrator_id')->nullable()->comment('管理员ID'); + $table->timestamps(); + + $table->index('user_id'); + $table->index('action'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('point_logs'); + } +} diff --git a/database/seeders/AdminMenuSeeder.php b/database/seeders/AdminMenuSeeder.php index a2381a2f..1342ff44 100644 --- a/database/seeders/AdminMenuSeeder.php +++ b/database/seeders/AdminMenuSeeder.php @@ -34,7 +34,8 @@ class AdminMenuSeeder extends Seeder 'uri' => 'users', ], ['title' => '代理等级', 'icon' => '', 'uri' => 'agent'], - ['title' => '成长值流水', 'icon' => '', 'uri' => 'sales-value-logs'] + ['title' => '积分流水', 'icon' => '', 'uri' => 'point-logs'], + ['title' => '成长值流水', 'icon' => '', 'uri' => 'sales-value-logs'], ], ], [ diff --git a/database/seeders/AdminPermissionSeeder.php b/database/seeders/AdminPermissionSeeder.php index df39b47e..49a44e21 100644 --- a/database/seeders/AdminPermissionSeeder.php +++ b/database/seeders/AdminPermissionSeeder.php @@ -87,6 +87,7 @@ class AdminPermissionSeeder extends Seeder 'edit_phone'=>['name' =>'修改手机号'], 'edit_bank'=>['name'=>'修改银行卡'], 'agent'=>['name'=>'设置代理'], + 'change_points' => ['name'=>'变更积分'], ], ], 'agent' => [ @@ -298,10 +299,6 @@ class AdminPermissionSeeder extends Seeder 'deduction'=>['name' =>'扣减'], ], ], - 'points_logs'=>[ - 'name' =>'积分账户', - 'curd' => ['index'], - ], 'wallet_to_bank_logs' => [ 'name' => '提现审核', 'curd' => ['index'], @@ -373,7 +370,12 @@ class AdminPermissionSeeder extends Seeder 'sales_value_logs' => [ 'name' => '成长值记录', 'curd' => ['index'] - ] + ], + 'point_logs' => [ + 'name' => '积分流水', + 'curd' => ['index'], + 'children' => [], + ], ]; // try { // DB::begintransaction(); diff --git a/resources/lang/zh_CN/point-log.php b/resources/lang/zh_CN/point-log.php new file mode 100644 index 00000000..c3cbd1b1 --- /dev/null +++ b/resources/lang/zh_CN/point-log.php @@ -0,0 +1,21 @@ + [ + 'PointLog' => '积分流水', + 'point-logs' => '积分流水', + ], + 'fields' => [ + 'user_id' => '用户ID', + 'user'=>[ + 'phone' => '手机号', + ], + 'action' => '操作', + 'change_points' => '变更积分', + 'before_points' => '变更前', + 'after_points' => '变更后', + 'remark' => '备注', + ], + 'options' => [ + ], +]; diff --git a/resources/lang/zh_CN/points-log.php b/resources/lang/zh_CN/points-log.php deleted file mode 100644 index d134c0e5..00000000 --- a/resources/lang/zh_CN/points-log.php +++ /dev/null @@ -1,20 +0,0 @@ - [ - 'PointsLog' => '积分账户', - 'points-logs' => '积分账户', - ], - 'fields' => [ - 'user_id' => '用户ID', - 'user'=>[ - 'phone' => '手机号', - ], - 'type' => '类别', - 'points' => '变动积分', - 'old_points' => '变动前', - 'desc' => '备注', - ], - 'options' => [ - ], -];