diff --git a/app/Console/Commands/ServiceTimer.php b/app/Console/Commands/ServiceTimer.php index 50a4a8ff..4231cd04 100644 --- a/app/Console/Commands/ServiceTimer.php +++ b/app/Console/Commands/ServiceTimer.php @@ -24,8 +24,8 @@ class ServiceTimer extends Command private function expiredPlan(): void { - Order::activePlan()->where('expired_at', '<=', now())->chunk(sysConfig('tasks_chunk'), function ($orders) { - $orders->each->expired(); // 过期订单 + Order::activePlan()->where('expired_at', '<=', now())->chunkById((int) sysConfig('tasks_chunk', 3000), function ($orders) { + $orders->each->expired(); // 过期订单,触发 Observer }); } } diff --git a/app/Console/Commands/TaskAuto.php b/app/Console/Commands/TaskAuto.php index 7fd8a131..78a933d6 100644 --- a/app/Console/Commands/TaskAuto.php +++ b/app/Console/Commands/TaskAuto.php @@ -50,7 +50,7 @@ class TaskAuto extends Command $query->recentUnPay(); // 关闭超时未支付本地订单 })->orWhere(function (Builder $query) { $query->whereStatus(1)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime(sysConfig('tasks_close.confirmation_orders')))); // 关闭未处理的人工支付订单 - })->chunk(sysConfig('tasks_chunk'), function ($orders) { + })->chunkById((int) sysConfig('tasks_chunk', 3000), function ($orders) { $orders->each->close(); }); } @@ -78,7 +78,7 @@ class TaskAuto extends Command $query->whereStatus(1); // 获取有订阅且未被封禁用户 })->whereHas('subscribeLogs', function (Builder $query) { $query->whereDate('request_time', '>=', now()->subDay()); // ->distinct()->count('request_ip'); - }, '>=', sysConfig('subscribe_rate_limit'))->chunk(sysConfig('tasks_chunk'), function ($users) use ($banMsg, $dirtyWorks) { + }, '>=', sysConfig('subscribe_rate_limit'))->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) use ($banMsg, $dirtyWorks) { foreach ($users as $user) { $user->subscribe->update($dirtyWorks); $user->banedLogs()->create($banMsg); // 记录封禁日志 @@ -88,7 +88,7 @@ class TaskAuto extends Command private function unblockSubscribes(): void { - UserSubscribe::whereStatus(0)->where('ban_time', '<=', time())->chunk(sysConfig('tasks_chunk'), function ($subscribes) { + UserSubscribe::whereStatus(0)->where('ban_time', '<=', time())->chunkById((int) sysConfig('tasks_chunk', 3000), function ($subscribes) { $subscribes->each->update(['status' => 1, 'ban_time' => null, 'ban_desc' => null]); }); } @@ -96,7 +96,7 @@ class TaskAuto extends Command private function blockUsers(): void { // 封禁账号 // 禁用流量超限用户 - User::activeUser()->whereRaw('u + d >= transfer_enable')->chunk(sysConfig('tasks_chunk'), function ($users) { + User::activeUser()->whereRaw('u + d >= transfer_enable')->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) { $users->each(function ($user) { $user->update(['enable' => 0]); $user->banedLogs()->create(['description' => __('[Auto Task] Blocked service: Run out of traffic')]); @@ -110,7 +110,7 @@ class TaskAuto extends Command $userService = new UserService; User::activeUser()->whereBanTime(null)->where('t', '>=', strtotime('-5 minutes')) // 只检测最近5分钟有流量使用的用户 - ->chunk(sysConfig('tasks_chunk'), function ($users) use ($userService, $ban_time, $trafficBanTime) { + ->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) use ($userService, $ban_time, $trafficBanTime) { $users->each(function ($user) use ($userService, $ban_time, $trafficBanTime) { $userService->setUser($user); if ($userService->isTrafficWarning()) { @@ -125,7 +125,7 @@ class TaskAuto extends Command private function unblockUsers(): void { // 解封账号 // 解封被临时封禁的账号 - User::bannedUser()->where('ban_time', '<', time())->chunk(sysConfig('tasks_chunk'), function ($users) { + User::bannedUser()->where('ban_time', '<', time())->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) { $users->each(function ($user) { $user->update(['enable' => 1, 'ban_time' => null]); $user->banedLogs()->create(['description' => __('[Auto Task] Unblocked Service: Account ban expired')]); @@ -133,7 +133,7 @@ class TaskAuto extends Command }); // 可用流量大于已用流量也解封(比如:邀请返利加了流量) - User::bannedUser()->whereBanTime(null)->where('expired_at', '>=', date('Y-m-d'))->whereRaw('u + d < transfer_enable')->chunk(sysConfig('tasks_chunk'), function ($users) { + User::bannedUser()->whereBanTime(null)->where('expired_at', '>=', date('Y-m-d'))->whereRaw('u + d < transfer_enable')->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) { $users->each(function ($user) { $user->update(['enable' => 1]); $user->banedLogs()->create(['description' => __('[Auto Task] Unblocked Service: Account has available data traffic')]); diff --git a/app/Console/Commands/TaskDaily.php b/app/Console/Commands/TaskDaily.php index ebde7b9f..2a5c50d7 100644 --- a/app/Console/Commands/TaskDaily.php +++ b/app/Console/Commands/TaskDaily.php @@ -60,7 +60,7 @@ class TaskDaily extends Command } User::activeUser()->where('expired_at', '<', date('Y-m-d')) // 过期 - ->chunk(sysConfig('tasks_chunk'), function ($users) use ($banMsg, $dirtyWorks) { + ->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) use ($banMsg, $dirtyWorks) { $users->each(function ($user) use ($banMsg, $dirtyWorks) { $user->update($dirtyWorks); Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, 0, $banMsg); @@ -74,7 +74,7 @@ class TaskDaily extends Command $closeTicketsHours = (time() - strtotime(sysConfig('tasks_close.tickets'))) / 3600; Ticket::whereStatus(1)->with('reply')->whereHas('reply', function ($query) { $query->where('admin_id', '<>', null); - })->where('updated_at', '<=', date('Y-m-d H:i:s', strtotime(sysConfig('tasks_close.tickets'))))->chunk(sysConfig('tasks_chunk'), function ($tickets) use ($closeTicketsHours) { + })->where('updated_at', '<=', date('Y-m-d H:i:s', strtotime(sysConfig('tasks_close.tickets'))))->chunkById((int) sysConfig('tasks_chunk', 3000), function ($tickets) use ($closeTicketsHours) { $tickets->each(function ($ticket) use ($closeTicketsHours) { if ($ticket->close()) { $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('ticket.edit', $ticket), @@ -91,7 +91,7 @@ class TaskDaily extends Command $query->activePlan(); })->with(['orders' => function ($query) { $query->activePlan(); - }])->chunk(sysConfig('tasks_chunk'), function ($users) { + }])->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) { $users->each(function ($user) { $user->orders()->activePackage()->update(['is_expire' => 1]); // 过期生效中的加油包 $order = $user->orders->first(); // 取出用户正在使用的套餐 @@ -126,7 +126,7 @@ class TaskDaily extends Command 'dataFlowLogs' => function ($query) use ($start, $end) { $query->whereBetween('log_time', [$start, $end]); }, - ])->chunk(sysConfig('tasks_chunk'), function ($users) use ($created_at) { + ])->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) use ($created_at) { foreach ($users as $user) { $dataFlowLogs = $user->dataFlowLogs->groupBy('node_id'); @@ -174,7 +174,7 @@ class TaskDaily extends Command 'userDataFlowLogs as d_sum' => function ($query) use ($start, $end) { $query->select(DB::raw('SUM(d)'))->whereBetween('log_time', [$start, $end]); }, - ])->chunk(sysConfig('tasks_chunk'), function ($nodes) use ($created_at) { + ])->chunkById((int) sysConfig('tasks_chunk', 3000), function ($nodes) use ($created_at) { foreach ($nodes as $node) { $node->dailyDataFlows()->create([ 'u' => $node->u_sum, diff --git a/app/Console/Commands/TaskHourly.php b/app/Console/Commands/TaskHourly.php index 28088733..a892a53e 100644 --- a/app/Console/Commands/TaskHourly.php +++ b/app/Console/Commands/TaskHourly.php @@ -34,14 +34,14 @@ class TaskHourly extends Command $end = strtotime($created_at); $start = $end - 3599; $data_anomaly_notification = sysConfig('data_anomaly_notification'); - $traffic_abuse_threshold = (int) sysConfig('traffic_abuse_limit') * GiB; + $traffic_abuse_threshold = (int) sysConfig('traffic_abuse_limit', 20) * GiB; User::activeUser()->whereHas('dataFlowLogs', function (Builder $query) use ($start, $end) { $query->whereBetween('log_time', [$start, $end]); })->with([ 'dataFlowLogs' => function ($query) use ($start, $end) { $query->whereBetween('log_time', [$start, $end]); }, - ])->chunk(sysConfig('tasks_chunk'), function ($users) use ($traffic_abuse_threshold, $created_at, $data_anomaly_notification) { + ])->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) use ($traffic_abuse_threshold, $created_at, $data_anomaly_notification) { foreach ($users as $user) { $dataFlowLogs = $user->dataFlowLogs->groupBy('node_id'); @@ -97,7 +97,7 @@ class TaskHourly extends Command 'userDataFlowLogs as d_sum' => function ($query) use ($start, $end) { $query->select(DB::raw('SUM(d)'))->whereBetween('log_time', [$start, $end]); }, - ])->chunk(sysConfig('tasks_chunk'), function ($nodes) use ($created_at) { + ])->chunkById((int) sysConfig('tasks_chunk', 3000), function ($nodes) use ($created_at) { foreach ($nodes as $node) { $node->hourlyDataFlows()->create(['u' => $node->u_sum, 'd' => $node->d_sum, 'created_at' => $created_at]); } diff --git a/app/Console/Commands/UserExpireWarning.php b/app/Console/Commands/UserExpireWarning.php index 0002c9d0..2aa66007 100644 --- a/app/Console/Commands/UserExpireWarning.php +++ b/app/Console/Commands/UserExpireWarning.php @@ -30,7 +30,7 @@ class UserExpireWarning extends Command // 只取没被禁用的用户,其他不用管 User::whereEnable(1) ->where('expired_at', '<', date('Y-m-d', strtotime(sysConfig('expire_days').' days'))) - ->chunk(sysConfig('tasks_chunk'), function ($users) { + ->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) { foreach ($users as $user) { if (filter_var($user->username, FILTER_VALIDATE_EMAIL) === false) { // 用户账号不是邮箱的跳过 continue; diff --git a/app/Console/Commands/UserTrafficWarning.php b/app/Console/Commands/UserTrafficWarning.php index c3a77c41..e3c81bb1 100644 --- a/app/Console/Commands/UserTrafficWarning.php +++ b/app/Console/Commands/UserTrafficWarning.php @@ -28,7 +28,7 @@ class UserTrafficWarning extends Command private function userTrafficWarning(): void { // 用户流量超过警告阈值提醒 $trafficWarningPercent = sysConfig('traffic_warning_percent'); - User::activeUser()->where('transfer_enable', '>', 0)->chunk(sysConfig('tasks_chunk'), function ($users) use ($trafficWarningPercent) { + User::activeUser()->where('transfer_enable', '>', 0)->chunkById((int) sysConfig('tasks_chunk', 3000), function ($users) use ($trafficWarningPercent) { foreach ($users as $user) { // 用户账号不是邮箱的跳过 if (filter_var($user->username, FILTER_VALIDATE_EMAIL) === false) { diff --git a/app/Http/Controllers/Admin/LogsController.php b/app/Http/Controllers/Admin/LogsController.php index 89abc2bb..ca662bb6 100644 --- a/app/Http/Controllers/Admin/LogsController.php +++ b/app/Http/Controllers/Admin/LogsController.php @@ -223,7 +223,7 @@ class LogsController extends Controller }); }); - return view('admin.logs.userTraffic', ['userTrafficLogs' => $query->latest()->paginate(15)->appends($request->except('page'))]); + return view('admin.logs.userTraffic', ['userTrafficLogs' => $query->orderByDesc('id')->paginate(15)->appends($request->except('page'))]); } public function userOnlineIPList(Request $request): View diff --git a/app/Http/Controllers/Admin/NodeController.php b/app/Http/Controllers/Admin/NodeController.php index 8bb86d09..0cb94e02 100644 --- a/app/Http/Controllers/Admin/NodeController.php +++ b/app/Http/Controllers/Admin/NodeController.php @@ -146,9 +146,9 @@ class NodeController extends Controller 'method' => $info['method'], 'protocol' => $info['protocol'], 'obfs' => $info['obfs'], - 'obfs_param' => $info['obfs_param'], - 'protocol_param' => $info['protocol_param'], - 'passwd' => $info['passwd'], + 'obfs_param' => $info['obfs_param'] ?? null, + 'protocol_param' => $info['protocol_param'] ?? null, + 'passwd' => $info['passwd'] ?? null, ]; break; } diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 1126be3f..a8386812 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -223,7 +223,7 @@ class UserController extends Controller $data['transfer_enable'] *= GiB; $data['enable'] = $data['status'] < 0 ? 0 : $data['enable']; $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('next year')); - if ($data['remark']) { + if (! empty($data['remark'])) { $data['remark'] = str_replace(['atob', 'eval'], '', $data['remark']); } @@ -253,7 +253,7 @@ class UserController extends Controller $data['password'] = $password; } - if ($user->transfer_enable !== $data['transfer_enable']) { + if ($user->transfer_enable !== (int) $data['transfer_enable']) { Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, $data['transfer_enable'], trans('Manually edit in dashboard.')); } diff --git a/app/Http/Controllers/User/InvoiceController.php b/app/Http/Controllers/User/InvoiceController.php index bfe85f45..aacb50da 100644 --- a/app/Http/Controllers/User/InvoiceController.php +++ b/app/Http/Controllers/User/InvoiceController.php @@ -26,23 +26,12 @@ class InvoiceController extends Controller public function activate(): JsonResponse { // 激活套餐 $activePlan = Order::userActivePlan()->first(); - if ($activePlan) { - if ($activePlan->expired()) { // 关闭先前套餐后,新套餐自动运行 - if (Order::userActivePlan()->exists()) { - return response()->json(['status' => 'success', 'message' => trans('common.active_item', ['attribute' => trans('common.success')])]); - } - - return response()->json(['status' => 'success', 'message' => trans('common.close')]); + if ($activePlan && $activePlan->expired()) { // 关闭先前套餐后,新套餐自动运行 + if (Order::userActivePlan()->exists()) { + return response()->json(['status' => 'success', 'message' => trans('common.active_item', ['attribute' => trans('common.success')])]); } - } else { - $prepaidPlan = Order::userPrepay()->first(); - if ($prepaidPlan) { // 关闭先前套餐后,新套餐自动运行 - if ($prepaidPlan->complete()) { - return response()->json(['status' => 'success', 'message' => trans('common.active_item', ['attribute' => trans('common.success')])]); - } - return response()->json(['status' => 'success', 'message' => trans('common.close')]); - } + return response()->json(['status' => 'success', 'message' => trans('common.close')]); } return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.close')])]); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 6ad74d95..4f00766f 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -34,9 +34,7 @@ class UserController extends Controller 'remainDays' => $userService->getRemainingDays(), 'resetDays' => $userService->getResetDays(), 'unusedPercent' => $userService->getUnusedTrafficPercent(), - 'announcements' => cache()->remember('announcements_'.app()->getLocale(), 300, function () { - return Article::type(2)->lang()->latest()->simplePaginate(1); // 公告缓存 5 分钟 - }), // 公告 + 'announcements' => Article::type(2)->lang()->latest()->simplePaginate(1), // 公告 'isTrafficWarning' => $userService->isTrafficWarning(), // 流量异常判断 'paying_user' => $userService->isActivePaying(), // 付费用户判断 'user' => $user->only(['sub_url', 'unused_traffic', 'expiration_date', 'ban_time']), diff --git a/app/Observers/OrderObserver.php b/app/Observers/OrderObserver.php index 289c9604..fe0f0797 100644 --- a/app/Observers/OrderObserver.php +++ b/app/Observers/OrderObserver.php @@ -16,60 +16,77 @@ class OrderObserver public function updated(Order $order): void { $changes = $order->getChanges(); - // 套餐订单-流量包订单互联 - if (Arr::has($changes, 'is_expire') && $changes['is_expire'] === 1 && $order->goods->type === 2) { - $user = $order->user; - $user->update([ // 清理全部流量,重置重置日期和等级 - 'u' => 0, - 'd' => 0, - 'transfer_enable' => 0, - 'reset_time' => null, - 'level' => 0, - 'enable' => 0, - ]); - Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, 0, trans('[Service Timer] Service Expiration'), $order->id); - Order::userActivePackage($order->user_id)->update(['is_expire' => 1]); // 过期生效中的加油包 - $this->activatePrepaidPlan($order->user_id); // 激活预支付套餐 + // 套餐订单-流量包订单互联:订单过期时直接处理 + if (Arr::has($changes, 'is_expire') && $changes['is_expire'] === 1 && $order->goods && $order->goods->type === 2) { + $user = $order->user; + $oldTransferEnable = $user->transfer_enable; + + // 过期加油包 + Order::userActivePackage($order->user_id)->update(['is_expire' => 1]); + + // 检查是否有预支付订单 + $prepaidOrder = Order::userPrepay($order->user_id)->first(); + + if ($prepaidOrder) { + (new OrderService($prepaidOrder))->activatePlan(); + } else { + // 无预支付订单:仅清理用户 + $user->update([ + 'u' => 0, + 'd' => 0, + 'transfer_enable' => 0, + 'reset_time' => null, + 'level' => 0, + 'enable' => 0, + ]); + + Helpers::addUserTrafficModifyLog($user->id, $oldTransferEnable, 0, trans('[Service Timer] Service Expiration'), $order->id); + } } if (Arr::has($changes, 'status')) { - if ($changes['status'] === -1) { // 本地订单-在线订单 关闭互联 - if ($order->payment) { - $order->payment->close(); // 关闭在线订单 - } + $originalStatus = $order->getOriginal('status'); - if ($order->coupon) { // 退回优惠券 - $this->returnCoupon($order, $order->coupon); - } + switch ($changes['status']) { + case -1: // 订单关闭 + if ($order->payment) { + $order->payment->close(); + } - if ($order->goods && $order->goods->type === 2 && $order->getOriginal('status') === 2 && Order::userPrepay($order->user_id)->exists()) { // 下一个套餐 - $this->activatePrepaidPlan($order->user_id); - } else { - (new OrderService($order))->refreshAccountExpiration(); - } - } elseif ($changes['status'] === 1) { // 待确认支付 通知管理 - Notification::send(User::find(1), new PaymentConfirm($order)); - } elseif ($changes['status'] === 2 && $order->getOriginal('status') !== 3) { // 本地订单-在线订单 支付成功互联 - (new OrderService($order))->receivedPayment(); - } elseif ($changes['status'] === 3) { - if (Order::userActivePlan($order->user_id)->doesntExist()) { - $this->activatePrepaidPlan($order->user_id); - } else { - (new OrderService($order))->refreshAccountExpiration(); - } + if ($order->coupon) { + $this->returnCoupon($order, $order->coupon); + } + + if ($order->goods && $order->goods->type === 2 && $originalStatus === 2 && Order::userPrepay($order->user_id)->exists()) { + $prepaidOrder = Order::userPrepay($order->user_id)->first(); + (new OrderService($prepaidOrder))->activatePlan(); + } else { + (new OrderService($order))->refreshAccountExpiration(); + } + break; + case 1: // 待确认支付 + Notification::send(User::find(1), new PaymentConfirm($order)); + break; + case 2: // 支付成功 + if ($originalStatus !== 3) { + (new OrderService($order))->receivedPayment(); + } + break; + case 3: // 预支付订单 + if (Order::userActivePlan($order->user_id)->doesntExist()) { + $prepaidOrder = Order::userPrepay($order->user_id)->first(); + if ($prepaidOrder) { + (new OrderService($prepaidOrder))->activatePlan(); + } + } else { + (new OrderService($order))->refreshAccountExpiration(); + } + break; } } } - private function activatePrepaidPlan(int $user_id): void - { // 激活[预支付订单] - $prepaidOrder = Order::userPrepay($user_id)->first(); // 检查该订单对应用户是否有预支付套餐 - if ($prepaidOrder) { - (new OrderService($prepaidOrder))->activatePrepaidPlan(); // 激活预支付套餐 - } - } - private function returnCoupon(Order $order, Coupon $coupon): void { // 退回优惠券 if ($coupon->type !== 3 && ! $coupon->isExpired()) { diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php index d529e891..330e456c 100644 --- a/app/Observers/UserObserver.php +++ b/app/Observers/UserObserver.php @@ -24,43 +24,61 @@ class UserObserver public function updated(User $user): void { $changes = $user->getChanges(); - $enableChange = Arr::has($changes, ['enable']); - if (($user->enable === 1 || $enableChange) && Arr::hasAny($changes, ['level', 'user_group_id', 'enable', 'port', 'passwd', 'speed_limit'])) { - $allowNodes = $user->nodes()->whereType(4)->get(); - if (Arr::hasAny($changes, ['level', 'user_group_id'])) { - $oldAllowNodes = $user->nodes($user->getOriginal('level'), $user->getOriginal('user_group_id'))->whereType(4)->get(); - if ($enableChange) { - if ($user->enable === 0 && $oldAllowNodes->isNotEmpty()) { - DelUser::dispatch($user->id, $oldAllowNodes); - } elseif ($user->enable === 1 && $allowNodes->isNotEmpty()) { - AddUser::dispatch($user->id, $allowNodes); + $enableChanged = Arr::has($changes, 'enable'); + $permissionFieldsChanged = Arr::hasAny($changes, ['level', 'user_group_id']); + $configFieldsChanged = Arr::hasAny($changes, ['port', 'passwd', 'speed_limit']); + + // 如果enable状态发生变化,或者用户当前已启用且权限或配置字段发生变化 + if ($enableChanged || ($user->enable === 1 && ($permissionFieldsChanged || $configFieldsChanged))) { + // 获取当前允许的节点 + $currentAllowedNodes = $user->nodes()->whereType(4)->get(); + + if ($permissionFieldsChanged) { + $oldAllowedNodes = $user->nodes($user->getOriginal('level'), $user->getOriginal('user_group_id'))->whereType(4)->get(); + if ($enableChanged) { + if ($user->enable) { + // 用户被启用,添加到所有当前允许的节点 + if ($currentAllowedNodes->isNotEmpty()) { + AddUser::dispatch($user->id, $currentAllowedNodes); + } + } elseif ($oldAllowedNodes->isNotEmpty()) { + DelUser::dispatch($user->id, $oldAllowedNodes); } } else { - $old = $oldAllowNodes->diff($allowNodes); // old 有 allow 没有 - $new = $allowNodes->diff($oldAllowNodes); // allow 有 old 没有 - if ($old->isNotEmpty()) { - DelUser::dispatch($user->id, $old); + // 计算差异 + $nodesToRemove = $oldAllowedNodes->diff($currentAllowedNodes); // 用户失去权限的节点 + $nodesToAdd = $currentAllowedNodes->diff($oldAllowedNodes); // 用户新增权限的节点 + + // 处理节点移除 + if ($nodesToRemove->isNotEmpty()) { + DelUser::dispatch($user->id, $nodesToRemove); } - if ($new->isNotEmpty()) { - AddUser::dispatch($user->id, $new); + + // 处理节点添加 + if ($nodesToAdd->isNotEmpty()) { + AddUser::dispatch($user->id, $nodesToAdd); } - if (Arr::hasAny($changes, ['port', 'passwd', 'speed_limit'])) { - $same = $allowNodes->intersect($oldAllowNodes); // 共有部分 - if ($same->isNotEmpty()) { - EditUser::dispatch($user, $same); + + // 处理节点更新(权限未变但配置变了) + if ($configFieldsChanged && $currentAllowedNodes->isNotEmpty()) { + $nodesToUpdate = $currentAllowedNodes->intersect($oldAllowedNodes); // 权限未变但可能需要更新配置的节点 + if ($nodesToUpdate->isNotEmpty()) { + EditUser::dispatch($user, $nodesToUpdate); } } } - } elseif ($allowNodes->isNotEmpty()) { - if ($enableChange) { - if ($user->enable === 1) { // TODO: 由于vnet未正确使用enable字段,临时解决方案 - AddUser::dispatch($user->id, $allowNodes); - } else { - DelUser::dispatch($user->id, $allowNodes); - } - } elseif (Arr::hasAny($changes, ['port', 'passwd', 'speed_limit'])) { - EditUser::dispatch($user, $allowNodes); + } elseif ($enableChanged && $currentAllowedNodes->isNotEmpty()) { + // 启用状态变化处理 + if ($user->enable) { + // 用户被启用,添加到所有允许的节点 + AddUser::dispatch($user->id, $currentAllowedNodes); + } else { + // 用户被禁用,从所有允许的节点中移除 + DelUser::dispatch($user->id, $currentAllowedNodes); } + } elseif ($configFieldsChanged && $currentAllowedNodes->isNotEmpty()) { + // 仅配置变化,更新所有允许的节点 + EditUser::dispatch($user, $currentAllowedNodes); } } diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index e1e8fd47..06ecbdaa 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -12,27 +12,27 @@ use Log; class OrderService { - public static User $user; + private User $user; - public static ?Goods $goods; + private ?Goods $goods; - public static ?Payment $payment; + private ?Payment $payment; public function __construct(private readonly Order $order) { // 获取需要的信息 - self::$user = $order->user; - self::$goods = $order->goods; - self::$payment = $order->payment; + $this->user = $order->user; + $this->goods = $order->goods; + $this->payment = $order->payment; } public function receivedPayment(): bool { // 支付成功后处理 - $payment = self::$payment; + $payment = $this->payment; if ($payment && $payment->status !== 1) {// 是否为余额购买套餐 $payment->complete(); } - $goods = self::$goods; + $goods = $this->goods; if ($goods === null) { $ret = $this->chargeCredit(); } else { @@ -41,12 +41,12 @@ class OrderService $ret = $this->activatePackage(); break; case 2: // 套餐 - if (Order::userActivePlan(self::$user->id)->where('id', '<>', $this->order->id)->exists()) {// 判断套餐是否直接激活 + if (Order::userActivePlan($this->user->id)->where('id', '<>', $this->order->id)->exists()) {// 判断套餐是否直接激活 $ret = $this->order->prepay(); } else { $ret = $this->activatePlan(); } - $this->setCommissionExpense(self::$user); // 返利 + $this->setCommissionExpense($this->user); // 返利 break; default: Log::emergency('【处理订单】出现错误-未知套餐类型'); @@ -58,11 +58,11 @@ class OrderService private function chargeCredit(): bool { // 余额充值 - $credit = self::$user->credit; - $ret = self::$user->updateCredit($this->order->origin_amount); + $credit = $this->user->credit; + $ret = $this->user->updateCredit($this->order->origin_amount); // 余额变动记录日志 if ($ret) { - Helpers::addUserCreditLog($this->order->user_id, $this->order->id, $credit, self::$user->credit, $this->order->amount, 'The user topped up the balance.'); + Helpers::addUserCreditLog($this->order->user_id, $this->order->id, $credit, $this->user->credit, $this->order->amount, 'The user topped up the balance.'); } return $ret; @@ -70,8 +70,8 @@ class OrderService private function activatePackage(): bool { // 激活流量包 - if (self::$user->incrementData(self::$goods->traffic * MiB)) { - return Helpers::addUserTrafficModifyLog($this->order->user_id, self::$user->transfer_enable - self::$goods->traffic * MiB, self::$user->transfer_enable, trans("[:payment] plus the user's purchased data plan.", ['payment' => $this->order->pay_way])); + if ($this->user->incrementData($this->goods->traffic * MiB)) { + return Helpers::addUserTrafficModifyLog($this->order->user_id, $this->user->transfer_enable - $this->goods->traffic * MiB, $this->user->transfer_enable, trans("[:payment] plus the user's purchased data plan.", ['payment' => $this->order->pay_way])); } return false; @@ -79,23 +79,23 @@ class OrderService public function activatePlan(): bool { // 激活套餐 - $this->order->refresh()->update(['expired_at' => date('Y-m-d H:i:s', strtotime(self::$goods->days.' days'))]); - $oldData = self::$user->transfer_enable; + $this->order->refresh()->updateQuietly(['expired_at' => date('Y-m-d H:i:s', strtotime($this->goods->days.' days')), 'status' => 2]); + $oldData = $this->user->transfer_enable; $updateData = [ - 'invite_num' => self::$user->invite_num + (self::$goods->invite_num ?: 0), - 'level' => self::$goods->level, - 'speed_limit' => self::$goods->speed_limit, + 'invite_num' => $this->user->invite_num + ($this->goods->invite_num ?: 0), + 'level' => $this->goods->level, + 'speed_limit' => $this->goods->speed_limit, 'enable' => 1, ...$this->resetTimeAndData(), ]; // 无端口用户 添加端口 - if (empty(self::$user->port)) { + if (empty($this->user->port)) { $updateData['port'] = Helpers::getPort(); } - if (self::$user->update($updateData)) { - return Helpers::addUserTrafficModifyLog($this->order->user_id, $oldData, self::$user->transfer_enable, trans("[:payment] plus the user's purchased data plan.", ['payment' => $this->order->pay_way]), $this->order->id); + if ($this->user->update($updateData)) { + return Helpers::addUserTrafficModifyLog($this->order->user_id, $oldData, $this->user->transfer_enable, trans("[:payment] plus the user's purchased data plan.", ['payment' => $this->order->pay_way]), $this->order->id); } return false; @@ -108,7 +108,7 @@ class OrderService } // 账号流量重置日期 - $nextResetTime = now()->addDays(self::$goods->period)->toDateString(); + $nextResetTime = now()->addDays($this->goods->period)->toDateString(); if ($nextResetTime >= $expired_at) { $nextResetTime = null; } @@ -116,7 +116,7 @@ class OrderService return [ 'u' => 0, 'd' => 0, - 'transfer_enable' => self::$goods->traffic * MiB, + 'transfer_enable' => $this->goods->traffic * MiB, 'expired_at' => $expired_at, 'reset_time' => $nextResetTime, ]; @@ -124,7 +124,7 @@ class OrderService private function getFinallyExpiredTime(): string { // 推算最新的到期时间 - $orders = self::$user->orders()->whereIn('status', [2, 3])->whereIsExpire(0)->isPlan()->get(); + $orders = $this->user->orders()->whereIn('status', [2, 3])->whereIsExpire(0)->isPlan()->get(); $current = $orders->where('status', '==', 2)->first(); return ($current->expired_at ?? now())->addDays($orders->except($current->id ?? 0)->sum('goods.days'))->toDateString(); @@ -160,7 +160,7 @@ class OrderService { // 刷新账号有效时间 $data = ['expired_at' => $this->getFinallyExpiredTime()]; - if ($data['expired_at'] < now()->toDateString()) { + if ($data['expired_at'] <= now()->toDateString()) { $data += [ 'u' => 0, 'd' => 0, @@ -172,13 +172,6 @@ class OrderService ]; } - return self::$user->update($data); - } - - public function activatePrepaidPlan(): bool - { // 激活预支付套餐 - $this->order->complete(); - - return $this->activatePlan(); + return $this->user->update($data); } } diff --git a/app/Utils/Helpers.php b/app/Utils/Helpers.php index ea8bd01e..668bc552 100644 --- a/app/Utils/Helpers.php +++ b/app/Utils/Helpers.php @@ -34,12 +34,12 @@ class Helpers * @param string $username 用户名 * @param string $password 用户密码 * @param int $transfer_enable 可用流量 - * @param int $date 可使用天数 + * @param int $days 可使用天数 * @param int|null $inviter_id 邀请人 * @param string|null $nickname 昵称 * @param int $status 状态:-1-禁用、0-未激活、1-正常 */ - public static function addUser(string $username, string $password, int $transfer_enable = 0, int $date = 0, ?int $inviter_id = null, ?string $nickname = null, int $status = 0): User + public static function addUser(string $username, string $password, int $transfer_enable = 0, int $days = 7, ?int $inviter_id = null, ?string $nickname = null, int $status = 0): User { return User::create([ 'nickname' => $nickname ?? $username, @@ -52,7 +52,7 @@ class Helpers 'protocol' => self::getDefaultProtocol(), 'obfs' => self::getDefaultObfs(), 'transfer_enable' => $transfer_enable, - 'expired_at' => now()->addDays($date)->toDateString(), + 'expired_at' => now()->addDays($days)->toDateString(), 'user_group_id' => null, 'reg_ip' => IP::getClientIp(), 'inviter_id' => $inviter_id, diff --git a/composer.json b/composer.json index 1ddb384b..82faaeb2 100644 --- a/composer.json +++ b/composer.json @@ -79,7 +79,9 @@ "@php artisan package:discover --ansi" ], "post-update-cmd": [ - "@php artisan vendor:publish --tag=laravel-assets --ansi --force" + "@php artisan vendor:publish --tag=laravel-assets --ansi --force", + "if [ -f vendor/bin/ide-helper ]; then @php artisan ide-helper:generate; fi", + "if [ -f vendor/bin/ide-helper ]; then @php artisan ide-helper:meta; fi" ], "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" diff --git a/resources/views/user/invoices.blade.php b/resources/views/user/invoices.blade.php index f2c26ad7..a25cd368 100644 --- a/resources/views/user/invoices.blade.php +++ b/resources/views/user/invoices.blade.php @@ -79,16 +79,18 @@