Эх сурвалжийг харах

2.4.0 phase 1: 大量代码优化与改写

1. models 关系规范化;
2. 本地-在线 订单处理改写;
3. 优化用户界面节点的查表操作;
4. 半修复 VNet SSR版需要面板主动提交用户信息变动的问题;(节点等级,用户分组,Node信息修改 主动通知节点尚未添加);
5. 简化并提取出了 返利佣金相关处理逻辑;
兔姬桑 4 жил өмнө
parent
commit
66c3c53038
100 өөрчлөгдсөн 1076 нэмэгдсэн , 2226 устгасан
  1. 32 28
      app/Components/Helpers.php
  2. 1 2
      app/Components/Namesilo.php
  3. 15 19
      app/Console/Commands/AutoClearLog.php
  4. 62 154
      app/Console/Commands/AutoJob.php
  5. 1 1
      app/Console/Commands/AutoPingNode.php
  6. 2 4
      app/Console/Commands/AutoReportNode.php
  7. 2 4
      app/Console/Commands/AutoStatisticsNodeDailyTraffic.php
  8. 2 4
      app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php
  9. 3 5
      app/Console/Commands/AutoStatisticsUserDailyTraffic.php
  10. 3 5
      app/Console/Commands/AutoStatisticsUserHourlyTraffic.php
  11. 29 54
      app/Console/Commands/DailyJob.php
  12. 3 3
      app/Console/Commands/NodeBlockedDetection.php
  13. 16 60
      app/Console/Commands/ServiceTimer.php
  14. 2 2
      app/Console/Commands/UserExpireAutoWarning.php
  15. 2 6
      app/Console/Commands/UserTrafficAbnormalAutoWarning.php
  16. 1 1
      app/Console/Commands/UserTrafficAutoWarning.php
  17. 8 10
      app/Console/Commands/fixDailyTrafficLogError.php
  18. 37 0
      app/Console/Commands/updateCoupon.php
  19. 3 3
      app/Console/Commands/updateTicket.php
  20. 7 12
      app/Console/Commands/updateUserLevel.php
  21. 2 2
      app/Console/Commands/updateUserName.php
  22. 2 2
      app/Console/Commands/upgradeUserResetTime.php
  23. 20 26
      app/Http/Controllers/Admin/AffiliateController.php
  24. 36 44
      app/Http/Controllers/Admin/CouponController.php
  25. 2 2
      app/Http/Controllers/Admin/EmailFilterController.php
  26. 3 3
      app/Http/Controllers/Admin/MarketingController.php
  27. 2 2
      app/Http/Controllers/Admin/RuleController.php
  28. 5 5
      app/Http/Controllers/Admin/RuleGroupController.php
  29. 6 6
      app/Http/Controllers/Admin/ShopController.php
  30. 3 3
      app/Http/Controllers/Admin/SubscribeController.php
  31. 7 7
      app/Http/Controllers/Admin/TicketController.php
  32. 1 2
      app/Http/Controllers/Admin/ToolsController.php
  33. 6 6
      app/Http/Controllers/Admin/UserGroupController.php
  34. 123 176
      app/Http/Controllers/AdminController.php
  35. 0 136
      app/Http/Controllers/Api/LoginController.php
  36. 0 77
      app/Http/Controllers/Api/PingController.php
  37. 4 5
      app/Http/Controllers/Api/WebApi/BaseController.php
  38. 2 5
      app/Http/Controllers/Api/WebApi/TrojanController.php
  39. 5 8
      app/Http/Controllers/Api/WebApi/V2RayController.php
  40. 2 4
      app/Http/Controllers/Api/WebApi/VNetController.php
  41. 41 61
      app/Http/Controllers/AuthController.php
  42. 10 11
      app/Http/Controllers/Controller.php
  43. 1 142
      app/Http/Controllers/Gateway/AbstractPayment.php
  44. 9 4
      app/Http/Controllers/Gateway/BitpayX.php
  45. 9 4
      app/Http/Controllers/Gateway/CodePay.php
  46. 9 4
      app/Http/Controllers/Gateway/EPay.php
  47. 10 6
      app/Http/Controllers/Gateway/F2Fpay.php
  48. 7 10
      app/Http/Controllers/Gateway/Local.php
  49. 10 5
      app/Http/Controllers/Gateway/PayJs.php
  50. 11 9
      app/Http/Controllers/Gateway/PayPal.php
  51. 39 50
      app/Http/Controllers/NodeController.php
  52. 20 36
      app/Http/Controllers/PaymentController.php
  53. 0 61
      app/Http/Controllers/ServiceController.php
  54. 16 14
      app/Http/Controllers/User/AffiliateController.php
  55. 6 11
      app/Http/Controllers/User/SubscribeController.php
  56. 74 122
      app/Http/Controllers/UserController.php
  57. 2 2
      app/Http/Middleware/WebApi.php
  58. 58 0
      app/Jobs/VNet/addUser.php
  59. 45 0
      app/Jobs/VNet/delUser.php
  60. 48 0
      app/Jobs/VNet/editUser.php
  61. 53 0
      app/Jobs/VNet/reloadNode.php
  62. 1 1
      app/Mail/activeUser.php
  63. 1 1
      app/Mail/closeTicket.php
  64. 1 1
      app/Mail/newTicket.php
  65. 1 1
      app/Mail/nodeCrashWarning.php
  66. 1 1
      app/Mail/replyTicket.php
  67. 1 1
      app/Mail/resetPassword.php
  68. 1 1
      app/Mail/sendUserInfo.php
  69. 1 1
      app/Mail/sendVerifyCode.php
  70. 1 1
      app/Mail/userExpireWarning.php
  71. 1 1
      app/Mail/userExpireWarningToday.php
  72. 1 1
      app/Mail/userTrafficWarning.php
  73. 1 32
      app/Models/Article.php
  74. 4 12
      app/Models/Config.php
  75. 4 12
      app/Models/Country.php
  76. 1 64
      app/Models/Coupon.php
  77. 1 19
      app/Models/CouponLog.php
  78. 0 12
      app/Models/EmailFilter.php
  79. 0 53
      app/Models/Goods.php
  80. 7 37
      app/Models/Invite.php
  81. 5 12
      app/Models/Label.php
  82. 0 12
      app/Models/Level.php
  83. 0 25
      app/Models/Marketing.php
  84. 18 108
      app/Models/Node.php
  85. 3 22
      app/Models/NodeAuth.php
  86. 0 18
      app/Models/NodeCertificate.php
  87. 4 25
      app/Models/NodeDailyDataFlow.php
  88. 17 0
      app/Models/NodeHeartBeat.php
  89. 4 25
      app/Models/NodeHourlyDataFlow.php
  90. 0 29
      app/Models/NodeInfo.php
  91. 7 16
      app/Models/NodeLabel.php
  92. 0 14
      app/Models/NodeOnlineLog.php
  93. 2 24
      app/Models/NodeOnlineUserIp.php
  94. 4 25
      app/Models/NodePing.php
  95. 0 18
      app/Models/NodeRule.php
  96. 0 24
      app/Models/NotificationLog.php
  97. 40 54
      app/Models/Order.php
  98. 3 32
      app/Models/Payment.php
  99. 0 21
      app/Models/PaymentCallback.php
  100. 0 20
      app/Models/ProductsPool.php

+ 32 - 28
app/Components/Helpers.php

@@ -10,6 +10,7 @@ use App\Models\User;
 use App\Models\UserCreditLog;
 use App\Models\UserDataModifyLog;
 use App\Models\UserSubscribe;
+use DateTime;
 use Str;
 
 class Helpers {
@@ -57,7 +58,7 @@ class Helpers {
 	// 生成用户的订阅码
 	public static function makeSubscribeCode(): string {
 		$code = makeRandStr(5);
-		if(UserSubscribe::query()->whereCode($code)->exists()){
+		if(UserSubscribe::whereCode($code)->exists()){
 			$code = self::makeSubscribeCode();
 		}
 
@@ -67,15 +68,15 @@ class Helpers {
 	/**
 	 * 添加用户
 	 *
-	 * @param  string  $email            用户邮箱
-	 * @param  string  $password         用户密码
-	 * @param  string  $transfer_enable  可用流量
-	 * @param  int     $data             可使用天数
-	 * @param  int     $referral_uid     邀请人
+	 * @param  string    $email            用户邮箱
+	 * @param  string    $password         用户密码
+	 * @param  string    $transfer_enable  可用流量
+	 * @param  int       $data             可使用天数
+	 * @param  int|null  $inviter_id       邀请人
 	 *
 	 * @return int
 	 */
-	public static function addUser($email, $password, $transfer_enable, $data, $referral_uid = 0): int {
+	public static function addUser($email, $password, $transfer_enable, $data, $inviter_id = null): int {
 		$user = new User();
 		$user->username = $email;
 		$user->email = $email;
@@ -89,10 +90,9 @@ class Helpers {
 		$user->protocol = self::getDefaultProtocol();
 		$user->obfs = self::getDefaultObfs();
 		$user->transfer_enable = $transfer_enable;
-		$user->enable_time = date('Y-m-d');
-		$user->expire_time = date('Y-m-d', strtotime("+".$data." days"));
+		$user->expired_at = date('Y-m-d', strtotime("+".$data." days"));
 		$user->reg_ip = getClientIp();
-		$user->referral_uid = $referral_uid;
+		$user->inviter_id = $inviter_id;
 		$user->reset_time = null;
 		$user->status = 0;
 		$user->save();
@@ -109,10 +109,10 @@ class Helpers {
 	}
 
 	// 获取一个随机端口
-	public static function getRandPort() {
+	public static function getRandPort(): int {
 		$port = random_int(self::sysConfig()['min_port'], self::sysConfig()['max_port']);
 
-		$exists_port = User::query()->pluck('port')->toArray();
+		$exists_port = User::pluck('port')->toArray();
 		if(in_array($port, $exists_port, true) || in_array($port, self::$denyPorts, true)){
 			$port = self::getRandPort();
 		}
@@ -121,10 +121,10 @@ class Helpers {
 	}
 
 	// 获取一个随机端口
-	public static function getOnlyPort() {
+	public static function getOnlyPort(): int {
 		$port = (int) self::sysConfig()['min_port'];
 
-		$exists_port = User::query()->where('port', '>=', $port)->pluck('port')->toArray();
+		$exists_port = User::where('port', '>=', $port)->pluck('port')->toArray();
 		while(in_array($port, $exists_port, true) || in_array($port, self::$denyPorts, true)){
 			++$port;
 		}
@@ -133,26 +133,30 @@ class Helpers {
 	}
 
 	// 获取默认加密方式
-	public static function getDefaultMethod() {
+	public static function getDefaultMethod(): string {
 		$config = SsConfig::default()->type(1)->first();
 
 		return $config? $config->name : 'aes-256-cfb';
 	}
 
 	// 获取默认协议
-	public static function getDefaultProtocol() {
+	public static function getDefaultProtocol(): string {
 		$config = SsConfig::default()->type(2)->first();
 
 		return $config? $config->name : 'origin';
 	}
 
 	// 获取默认混淆
-	public static function getDefaultObfs() {
+	public static function getDefaultObfs(): string {
 		$config = SsConfig::default()->type(3)->first();
 
 		return $config? $config->name : 'plain';
 	}
 
+	public static function daysToNow($date): int {
+		return (new DateTime())->diff(new DateTime($date))->days;
+	}
+
 	/**
 	 * 添加通知推送日志
 	 *
@@ -182,14 +186,14 @@ class Helpers {
 	/**
 	 * 添加优惠券操作日志
 	 *
+	 * @param  string  $description  备注
 	 * @param  int     $couponId     优惠券ID
 	 * @param  int     $goodsId      商品ID
 	 * @param  int     $orderId      订单ID
-	 * @param  string  $description  备注
 	 *
-	 * @return int
+	 * @return boolean
 	 */
-	public static function addCouponLog($couponId, $goodsId, $orderId, $description = ''): int {
+	public static function addCouponLog($description, $couponId, $goodsId = 0, $orderId = 0): bool {
 		$log = new CouponLog();
 		$log->coupon_id = $couponId;
 		$log->goods_id = $goodsId;
@@ -203,18 +207,18 @@ class Helpers {
 	 * 记录余额操作日志
 	 *
 	 * @param  int     $userId       用户ID
-	 * @param  string  $oid          订单ID
+	 * @param  int     $orderId      订单ID
 	 * @param  int     $before       记录前余额
 	 * @param  int     $after        记录后余额
 	 * @param  int     $amount       发生金额
 	 * @param  string  $description  描述
 	 *
-	 * @return int
+	 * @return boolean
 	 */
-	public static function addUserCreditLog($userId, $oid, $before, $after, $amount, $description = ''): int {
+	public static function addUserCreditLog($userId, $orderId, $before, $after, $amount, $description = ''): bool {
 		$log = new UserCreditLog();
 		$log->user_id = $userId;
-		$log->order_id = $oid;
+		$log->order_id = $orderId;
 		$log->before = $before;
 		$log->after = $after;
 		$log->amount = $amount;
@@ -228,17 +232,17 @@ class Helpers {
 	 * 记录流量变动日志
 	 *
 	 * @param  int     $userId       用户ID
-	 * @param  string  $oid          订单ID
+	 * @param  int     $orderId      订单ID
 	 * @param  int     $before       记录前的值
 	 * @param  int     $after        记录后的值
 	 * @param  string  $description  描述
 	 *
-	 * @return int
+	 * @return bool
 	 */
-	public static function addUserTrafficModifyLog($userId, $oid, $before, $after, $description = ''): int {
+	public static function addUserTrafficModifyLog($userId, $orderId, $before, $after, $description = ''): bool {
 		$log = new UserDataModifyLog();
 		$log->user_id = $userId;
-		$log->order_id = $oid;
+		$log->order_id = $orderId;
 		$log->before = $before;
 		$log->after = $after;
 		$log->description = $description;

+ 1 - 2
app/Components/Namesilo.php

@@ -9,8 +9,7 @@ use LSS\XML2Array;
 class Namesilo {
 	private static $host = 'https://www.namesilo.com/api/';
 
-	// Todo Debug测试
-	// 列出账号下所有域名
+	// 列出账号下所有域名 Todo Debug测试
 	public function listDomains() {
 		return $this->send('listDomains');
 	}

+ 15 - 19
app/Console/Commands/AutoClearLog.php

@@ -2,12 +2,11 @@
 
 namespace App\Console\Commands;
 
-use App\Components\Helpers;
-use App\Models\NodeInfo;
-use App\Models\NodeOnlineLog;
-use App\Models\NodeOnlineUserIp;
 use App\Models\NodeDailyDataFlow;
+use App\Models\NodeHeartBeat;
 use App\Models\NodeHourlyDataFlow;
+use App\Models\NodeOnlineLog;
+use App\Models\NodeOnlineUserIp;
 use App\Models\UserBanedLog;
 use App\Models\UserDailyDataFlow;
 use App\Models\UserDataFlowLog;
@@ -40,45 +39,42 @@ class AutoClearLog extends Command {
 	private function clearLog(): void {
 		try{
 			// 清除节点负载信息日志
-			NodeInfo::query()->where('log_time', '<=', strtotime("-30 minutes"))->delete();
+			NodeHeartBeat::where('log_time', '<=', strtotime("-30 minutes"))->delete();
 
 			// 清除节点在线用户数日志
-			NodeOnlineLog::query()->where('log_time', '<=', strtotime("-1 hour"))->delete();
+			NodeOnlineLog::where('log_time', '<=', strtotime("-1 hour"))->delete();
 
 			// 清除用户流量日志
-			UserDataFlowLog::query()->where('log_time', '<=', strtotime("-3 days"))->delete();
+			UserDataFlowLog::where('log_time', '<=', strtotime("-3 days"))->delete();
 
 			// 清除用户每时各流量数据日志
-			UserHourlyDataFlow::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
+			UserHourlyDataFlow::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
 
 			// 清除用户各节点的每天流量数据日志
-			UserDailyDataFlow::query()
-			                 ->where('node_id', '<>', 0)
+			UserDailyDataFlow::where('node_id', '<>', 0)
 			                 ->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-1 month')))
 			                 ->delete();
 
 			// 清除用户每天流量数据日志
-			UserDailyDataFlow::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))->delete();
+			UserDailyDataFlow::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))->delete();
 
 			// 清除节点每小时流量数据日志
-			NodeHourlyDataFlow::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
+			NodeHourlyDataFlow::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
 
 			// 清除节点每天流量数据日志
-			NodeDailyDataFlow::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-2 month')))->delete();
+			NodeDailyDataFlow::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-2 month')))->delete();
 
 			// 清除用户封禁日志
-			UserBanedLog::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
+			UserBanedLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
 
 			// 清除用户连接IP
-			NodeOnlineUserIp::query()->where('created_at', '<=', strtotime("-1 month"))->delete();
+			NodeOnlineUserIp::where('created_at', '<=', strtotime("-1 month"))->delete();
 
 			// 清除用户登陆日志
-			UserLoginLog::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
+			UserLoginLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
 
 			// 清除用户订阅记录
-			UserSubscribeLog::query()
-			                ->where('request_time', '<=', date('Y-m-d H:i:s', strtotime("-1 month")))
-			                ->delete();
+			UserSubscribeLog::where('request_time', '<=', date('Y-m-d H:i:s', strtotime("-1 month")))->delete();
 		}catch(Exception $e){
 			Log::error('【清理日志】错误: '.$e->getMessage());
 		}

+ 62 - 154
app/Console/Commands/AutoJob.php

@@ -8,18 +8,14 @@ use App\Models\Config;
 use App\Models\Coupon;
 use App\Models\Invite;
 use App\Models\Node;
-use App\Models\NodeInfo;
+use App\Models\NodeHeartBeat;
 use App\Models\Order;
-use App\Models\Payment;
 use App\Models\User;
 use App\Models\UserBanedLog;
 use App\Models\UserHourlyDataFlow;
-use App\Models\UserSubscribe;
 use App\Models\UserSubscribeLog;
 use App\Models\VerifyCode;
 use Cache;
-use DB;
-use Exception;
 use Illuminate\Console\Command;
 use Log;
 
@@ -33,10 +29,7 @@ class AutoJob extends Command {
 	public function handle(): void {
 		$jobStartTime = microtime(true);
 
-		// 关闭超时未支付在线订单
-		$this->closePayments();
-
-		// 关闭超时未支付订单
+		// 关闭超时未支付本地订单
 		$this->closeOrders();
 
 		//过期验证码、优惠券、邀请码无效化
@@ -52,15 +45,16 @@ class AutoJob extends Command {
 		$this->unblockUsers();
 
 		// 端口回收与分配
-		$this->dispatchPort();
+		if(sysConfig('auto_release_port')){
+			$this->dispatchPort();
+		}
 
 		// 检测节点是否离线
 		$this->checkNodeStatus();
 
-		// 检查 维护模式
-		if(sysConfig('maintenance_mode') && strtotime(sysConfig('maintenance_time')) < time()){
-			Config::query()->whereName('maintenance_mode')->update(['value' => 0]);
-			Config::query()->whereName('maintenance_time')->update(['value' => '']);
+		// 检查维护模式
+		if(sysConfig('maintenance_mode')){
+			Config::whereIn('name', ['maintenance_mode', 'maintenance_time'])->update(['value' => null]);
 		}
 
 		$jobEndTime = microtime(true);
@@ -69,127 +63,51 @@ class AutoJob extends Command {
 		Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
 	}
 
-	// 关闭超时未在线支付订单
-	private function closePayments(): void {
-		// 关闭超时未支付的在线订单(15分钟关闭订单)
-		$paymentList = Payment::query()
-		                      ->whereStatus(0)
-		                      ->where('created_at', '<=', date("Y-m-d H:i:s", strtotime("-15 minutes")))
-		                      ->get();
-		if($paymentList->isNotEmpty()){
-			try{
-				DB::beginTransaction();
-
-				foreach($paymentList as $payment){
-					// 关闭支付单
-					Payment::query()->whereId($payment->id)->update(['status' => -1]);
-					// 关闭回调PaymentCallback::query()->whereTradeNo($payment->trade_no)->update(['status' => 0]);
-
-					// 关闭订单
-					Order::query()->whereOid($payment->oid)->update(['status' => -1]);
-
-					// 退回优惠券
-					if($payment->order->coupon_id){
-						$result = $this->returnCoupon($payment->order->coupon_id);
-						if($result){
-							Helpers::addCouponLog($payment->order->coupon_id, $payment->order->goods_id, $payment->oid,
-								'在线订单超时未支付,自动退回');
-						}
-					}
-				}
-
-				DB::commit();
-			}catch(Exception $e){
-				Log::info('【异常】自动关闭超时未支付在线订单:'.$e);
-
-				DB::rollBack();
-			}
-		}
-	}
-
-	//返回优惠券
-	private function returnCoupon($coupon_id): bool {
-		$coupon = Coupon::find($coupon_id);
-		if($coupon && $coupon->type !== 3){
-			Coupon::query()->whereId($coupon_id)->increment('usage_count', 1, ['status' => 0]);
-			return true;
-		}
-		return false;
-	}
-
-	// 关闭超时未支付订单
+	// 关闭超时未支付本地订单
 	private function closeOrders(): void {
-		// 关闭超时未支付的支付订单(15分钟关闭订单)
-		$orderList = Order::query()
-		                  ->whereStatus(0)
-		                  ->where('created_at', '<=', date("Y-m-d H:i:s", strtotime("-15 minutes")))
-		                  ->get();
-		if($orderList->isNotEmpty()){
-			try{
-				DB::beginTransaction();
-
-				foreach($orderList as $order){
-					// 关闭订单
-					Order::query()->whereOid($order->oid)->update(['status' => -1]);
-
-					// 退回优惠券
-					if($order->coupon_id){
-						$result = $this->returnCoupon($order->coupon_id);
-						if($result){
-							Helpers::addCouponLog($order->coupon_id, $order->goods_id, $order->oid, '订单超时未支付,自动退回');
-						}
-					}
-				}
-
-				DB::commit();
-			}catch(Exception $e){
-				Log::info('【异常】自动关闭超时未支付订单:'.$e);
-
-				DB::rollBack();
-			}
+		// 关闭超时未支付的本地支付订单
+		foreach(Order::recentUnPay()->get() as $order){
+			// 关闭订单
+			$order->update(['status' => -1]);
 		}
 	}
 
 	// 注册验证码自动置无效 & 优惠券无效化
 	private function expireCode(): void {
 		// 注册验证码自动置无效
-		VerifyCode::query()
-		          ->whereStatus(0)
-		          ->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-10 minutes")))
-		          ->update(['status' => 2]);
+		VerifyCode::recentUnused()->update(['status' => 2]);
 
 		// 优惠券到期自动置无效
-		Coupon::query()->whereStatus(0)->where('available_end', '<=', time())->update(['status' => 2]);
+		Coupon::whereStatus(0)->where('end_time', '<=', time())->update(['status' => 2]);
 
 		// 用尽的优惠劵
-		Coupon::query()->whereStatus(0)->whereIn('type', [1, 2])->whereUsageCount(0)->update(['status' => 2]);
+		Coupon::whereStatus(0)->whereIn('type', [1, 2])->whereUsableTimes(0)->update(['status' => 2]);
 
 		// 邀请码到期自动置无效
-		Invite::query()->whereStatus(0)->where('dateline', '<=', date('Y-m-d H:i:s'))->update(['status' => 2]);
+		Invite::whereStatus(0)->where('dateline', '<=', date('Y-m-d H:i:s'))->update(['status' => 2]);
 	}
 
 	// 封禁访问异常的订阅链接
 	private function blockSubscribe(): void {
 		if(sysConfig('is_subscribe_ban')){
-			foreach(User::query()->activeUser()->get() as $user){
-				$subscribe = UserSubscribe::query()->whereUserId($user->id)->first();
-				if($subscribe){
-					// 24小时内不同IP的请求次数
-					$request_times = UserSubscribeLog::query()
-					                                 ->whereSid($subscribe->id)
-					                                 ->where('request_time', '>=',
-						                                 date("Y-m-d H:i:s", strtotime("-1 days")))
-					                                 ->distinct()
-					                                 ->count('request_ip');
-					if($request_times >= sysConfig('subscribe_ban_times')){
-						UserSubscribe::query()->whereId($subscribe->id)->update([
-							'status'   => 0,
-							'ban_time' => time(),
-							'ban_desc' => '存在异常,自动封禁'
-						]);
-
-						// 记录封禁日志
+			$pastSubLogs = UserSubscribeLog::where('request_time', '>=', date("Y-m-d H:i:s", strtotime("-1 days")))
+			                               ->groupBy('subscribe_id')
+			                               ->selectRaw('count(*) as total, subscribe_id')
+			                               ->get();
+			foreach($pastSubLogs as $log){
+				if($log->total >= sysConfig('subscribe_ban_times')){
+					$subscribe = $log->subscribe;
+					$ret = $subscribe->update([
+						'status'   => 0,
+						'ban_time' => time(),
+						'ban_desc' => '存在异常,自动封禁'
+					]);
+
+					// 记录封禁日志
+					if($ret){
 						$this->addUserBanLog($subscribe->user_id, 0, '【完全封禁订阅】-订阅24小时内请求异常');
+					}else{
+						Log::error('【自动化任务】封禁订阅失败,尝试封禁订阅ID:'.$subscribe->id);
 					}
 				}
 			}
@@ -200,13 +118,13 @@ class AutoJob extends Command {
 	 * 添加用户封禁日志
 	 *
 	 * @param  int     $userId       用户ID
-	 * @param  int     $minutes      封禁时长,单位分钟
+	 * @param  int     $time         封禁时长,单位分钟
 	 * @param  string  $description  封禁理由
 	 */
-	private function addUserBanLog($userId, $minutes, $description): void {
+	private function addUserBanLog($userId, $time, $description): void {
 		$log = new UserBanedLog();
 		$log->user_id = $userId;
-		$log->minutes = $minutes;
+		$log->time = $time;
 		$log->description = $description;
 		$log->save();
 	}
@@ -215,7 +133,7 @@ class AutoJob extends Command {
 	private function blockUsers(): void {
 		// 封禁1小时内流量异常账号
 		if(sysConfig('is_traffic_ban')){
-			$userList = User::query()->activeUser()->whereBanTime(0)->get();
+			$userList = User::activeUser()->whereBanTime(0)->get();
 			foreach($userList as $user){
 				// 对管理员豁免
 				if($user->is_admin){
@@ -223,12 +141,9 @@ class AutoJob extends Command {
 				}
 
 				// 多往前取5分钟,防止数据统计任务执行时间过长导致没有数据
-				$totalTraffic = UserHourlyDataFlow::query()
-				                                  ->userHourly($user->id)
-				                                  ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
-				                                  ->sum('total');
+				$totalTraffic = UserHourlyDataFlow::userRecentUsed($user->id)->sum('total');
 				if($totalTraffic >= sysConfig('traffic_ban_value') * GB){
-					User::query()->whereId($user->id)->update([
+					$user->update([
 						'enable'   => 0,
 						'ban_time' => strtotime("+".sysConfig('traffic_ban_time')." minutes")
 					]);
@@ -240,9 +155,9 @@ class AutoJob extends Command {
 		}
 
 		// 禁用流量超限用户
-		$userList = User::query()->activeUser()->whereBanTime(0)->whereRaw("u + d >= transfer_enable")->get();
+		$userList = User::activeUser()->whereBanTime(0)->whereRaw("u + d >= transfer_enable")->get();
 		foreach($userList as $user){
-			User::query()->whereId($user->id)->update(['enable' => 0]);
+			$user->update(['enable' => 0]);
 
 			// 写入日志
 			$this->addUserBanLog($user->id, 0, '【封禁代理】-流量已用完');
@@ -252,10 +167,10 @@ class AutoJob extends Command {
 	// 解封被临时封禁的账号
 	private function unblockUsers(): void {
 		// 解封被临时封禁的账号
-		$userList = User::query()->whereEnable(0)->where('status', '>=', 0)->where('ban_time', '>', 0)->get();
+		$userList = User::whereEnable(0)->where('status', '>=', 0)->where('ban_time', '>', 0)->get();
 		foreach($userList as $user){
 			if($user->ban_time < time()){
-				User::query()->whereId($user->id)->update(['enable' => 1, 'ban_time' => 0]);
+				$user->update(['enable' => 1, 'ban_time' => 0]);
 
 				// 写入操作日志
 				$this->addUserBanLog($user->id, 0, '【自动解封】-临时封禁到期');
@@ -263,15 +178,14 @@ class AutoJob extends Command {
 		}
 
 		// 可用流量大于已用流量也解封(比如:邀请返利自动加了流量)
-		$userList = User::query()
-		                ->whereEnable(0)
+		$userList = User::whereEnable(0)
 		                ->where('status', '>=', 0)
 		                ->whereBanTime(0)
-		                ->where('expire_time', '>=', date('Y-m-d'))
+		                ->where('expired_at', '>=', date('Y-m-d'))
 		                ->whereRaw("u + d < transfer_enable")
 		                ->get();
 		foreach($userList as $user){
-			User::query()->whereId($user->id)->update(['enable' => 1]);
+			$user->update(['enable' => 1]);
 
 			// 写入操作日志
 			$this->addUserBanLog($user->id, 0, '【自动解封】-有流量解封');
@@ -280,36 +194,30 @@ class AutoJob extends Command {
 
 	// 端口回收与分配
 	private function dispatchPort(): void {
-		if(sysConfig('auto_release_port')){
-			## 自动分配端口
-			foreach(User::query()->activeUser()->wherePort(0)->get() as $user){
-				$port = sysConfig('is_rand_port')? Helpers::getRandPort() : Helpers::getOnlyPort();
+		## 自动分配端口
+		foreach(User::activeUser()->wherePort(0)->get() as $user){
+			$port = sysConfig('is_rand_port')? Helpers::getRandPort() : Helpers::getOnlyPort();
 
-				User::query()->whereId($user->id)->update(['port' => $port]);
-			}
+			$user->update(['port' => $port]);
+		}
 
-			## 被封禁的账号自动释放端口
-			User::query()->whereEnable(0)->whereStatus(-1)->where('port', '!=', 0)->update(['port' => 0]);
+		## 被封禁的账号自动释放端口
+		User::whereEnable(0)->whereStatus(-1)->where('port', '!=', 0)->update(['port' => 0]);
 
-			## 过期一个月的账户自动释放端口
-			User::query()
-			    ->whereEnable(0)
-			    ->where('port', '!=', 0)
-			    ->where('expire_time', '<=', date("Y-m-d", strtotime("-30 days")))
-			    ->update(['port' => 0]);
-		}
+		## 过期一个月的账户自动释放端口
+		User::whereEnable(0)
+		    ->where('port', '!=', 0)
+		    ->where('expired_at', '<=', date("Y-m-d", strtotime("-1 months")))
+		    ->update(['port' => 0]);
 	}
 
 	// 检测节点是否离线
 	private function checkNodeStatus(): void {
 		if(sysConfig('is_node_offline')){
-			foreach(Node::query()->whereIsRelay(0)->whereStatus(1)->get() as $node){
+			$onlineNode = NodeHeartBeat::recently()->distinct()->pluck('node_id')->toArray();
+			foreach(Node::whereIsRelay(0)->whereStatus(1)->get() as $node){
 				// 10分钟内无节点负载信息则认为是后端炸了
-				$nodeTTL = NodeInfo::query()
-				                   ->whereNodeId($node->id)
-				                   ->where('log_time', '>=', strtotime("-10 minutes"))
-				                   ->latest('log_time')
-				                   ->doesntExist();
+				$nodeTTL = !in_array($node->id, $onlineNode);
 				if($nodeTTL && sysConfig('offline_check_times')){
 					// 已通知次数
 					$cacheKey = 'offline_check_times'.$node->id;

+ 1 - 1
app/Console/Commands/AutoPingNode.php

@@ -15,7 +15,7 @@ class AutoPingNode extends Command {
 	public function handle(): void {
 		$jobStartTime = microtime(true);
 
-		foreach(Node::query()->whereIsRelay(0)->whereStatus(1)->get() as $node){
+		foreach(Node::whereIsRelay(0)->whereStatus(1)->get() as $node){
 			$this->pingNode($node->id, $node->is_ddns? $node->server : $node->ip);
 		}
 

+ 2 - 4
app/Console/Commands/AutoReportNode.php

@@ -2,7 +2,6 @@
 
 namespace App\Console\Commands;
 
-use App\Components\Helpers;
 use App\Components\PushNotification;
 use App\Models\Node;
 use App\Models\NodeDailyDataFlow;
@@ -17,12 +16,11 @@ class AutoReportNode extends Command {
 		$jobStartTime = microtime(true);
 
 		if(sysConfig('node_daily_report')){
-			$nodeList = Node::query()->whereStatus(1)->get();
+			$nodeList = Node::whereStatus(1)->get();
 			if($nodeList->isNotEmpty()){
 				$msg = "|节点|上行流量|下行流量|合计|\r\n| :------ | :------ | :------ |\r\n";
 				foreach($nodeList as $node){
-					$log = NodeDailyDataFlow::query()
-					                        ->whereNodeId($node->id)
+					$log = NodeDailyDataFlow::whereNodeId($node->id)
 					                        ->whereDate('created_at', date("Y-m-d", strtotime('-1 days')))
 					                        ->first();
 

+ 2 - 4
app/Console/Commands/AutoStatisticsNodeDailyTraffic.php

@@ -15,7 +15,7 @@ class AutoStatisticsNodeDailyTraffic extends Command {
 	public function handle(): void {
 		$jobStartTime = microtime(true);
 
-		foreach(Node::query()->whereStatus(1)->orderBy('id')->get() as $node){
+		foreach(Node::whereStatus(1)->orderBy('id')->get() as $node){
 			$this->statisticsByNode($node->id);
 		}
 
@@ -26,9 +26,7 @@ class AutoStatisticsNodeDailyTraffic extends Command {
 	}
 
 	private function statisticsByNode($node_id): void {
-		$query = UserDataFlowLog::query()
-		                        ->whereNodeId($node_id)
-		                        ->whereBetween('log_time', [strtotime(date('Y-m-d')), time()]);
+		$query = UserDataFlowLog::whereNodeId($node_id)->whereBetween('log_time', [strtotime(date('Y-m-d')), time()]);
 
 		$u = $query->sum('u');
 		$d = $query->sum('d');

+ 2 - 4
app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php

@@ -15,7 +15,7 @@ class AutoStatisticsNodeHourlyTraffic extends Command {
 	public function handle(): void {
 		$jobStartTime = microtime(true);
 
-		foreach(Node::query()->whereStatus(1)->orderBy('id')->get() as $node){
+		foreach(Node::whereStatus(1)->orderBy('id')->get() as $node){
 			$this->statisticsByNode($node->id);
 		}
 
@@ -26,9 +26,7 @@ class AutoStatisticsNodeHourlyTraffic extends Command {
 	}
 
 	private function statisticsByNode($node_id): void {
-		$query = UserDataFlowLog::query()
-		                        ->whereNodeId($node_id)
-		                        ->whereBetween('log_time', [strtotime("-1 hour"), time()]);
+		$query = UserDataFlowLog::whereNodeId($node_id)->whereBetween('log_time', [strtotime("-1 hour"), time()]);
 
 		$u = $query->sum('u');
 		$d = $query->sum('d');

+ 3 - 5
app/Console/Commands/AutoStatisticsUserDailyTraffic.php

@@ -16,12 +16,12 @@ class AutoStatisticsUserDailyTraffic extends Command {
 	public function handle(): void {
 		$jobStartTime = microtime(true);
 
-		foreach(User::query()->activeUser()->get() as $user){
+		foreach(User::activeUser()->get() as $user){
 			// 统计一次所有节点的总和
 			$this->statisticsByUser($user->id);
 
 			// 统计每个节点产生的流量
-			foreach(Node::query()->whereStatus(1)->orderBy('id')->get() as $node){
+			foreach(Node::whereStatus(1)->orderBy('id')->get() as $node){
 				$this->statisticsByUser($user->id, $node->id);
 			}
 		}
@@ -33,9 +33,7 @@ class AutoStatisticsUserDailyTraffic extends Command {
 	}
 
 	private function statisticsByUser($user_id, $node_id = 0): void {
-		$query = UserDataFlowLog::query()
-		                        ->whereUserId($user_id)
-		                        ->whereBetween('log_time', [strtotime(date('Y-m-d')), time()]);
+		$query = UserDataFlowLog::whereUserId($user_id)->whereBetween('log_time', [strtotime(date('Y-m-d')), time()]);
 
 		if($node_id){
 			$query->whereNodeId($node_id);

+ 3 - 5
app/Console/Commands/AutoStatisticsUserHourlyTraffic.php

@@ -16,12 +16,12 @@ class AutoStatisticsUserHourlyTraffic extends Command {
 	public function handle(): void {
 		$jobStartTime = microtime(true);
 
-		foreach(User::query()->activeUser()->get() as $user){
+		foreach(User::activeUser()->get() as $user){
 			// 统计一次所有节点的总和
 			$this->statisticsByNode($user->id);
 
 			// 统计每个节点产生的流量
-			foreach(Node::query()->whereStatus(1)->orderBy('id')->get() as $node){
+			foreach(Node::whereStatus(1)->orderBy('id')->get() as $node){
 				$this->statisticsByNode($user->id, $node->id);
 			}
 		}
@@ -33,9 +33,7 @@ class AutoStatisticsUserHourlyTraffic extends Command {
 	}
 
 	private function statisticsByNode($user_id, $node_id = 0): void {
-		$query = UserDataFlowLog::query()
-		                        ->whereUserId($user_id)
-		                        ->whereBetween('log_time', [strtotime("-1 hour"), time()]);
+		$query = UserDataFlowLog::whereUserId($user_id)->whereBetween('log_time', [strtotime("-1 hour"), time()]);
 
 		if($node_id){
 			$query->whereNodeId($node_id);

+ 29 - 54
app/Console/Commands/DailyJob.php

@@ -9,6 +9,7 @@ use App\Models\Order;
 use App\Models\Ticket;
 use App\Models\User;
 use App\Models\UserBanedLog;
+use App\Services\OrderService;
 use Illuminate\Console\Command;
 use Log;
 
@@ -38,10 +39,10 @@ class DailyJob extends Command {
 
 	private function expireUser(): void {
 		// 过期用户处理
-		$userList = User::query()->activeUser()->where('expire_time', '<', date('Y-m-d'))->get();
+		$userList = User::activeUser()->where('expired_at', '<', date('Y-m-d'))->get();
 		foreach($userList as $user){
 			if(sysConfig('is_ban_status')){
-				User::query()->whereId($user->id)->update([
+				$user->update([
 					'u'               => 0,
 					'd'               => 0,
 					'transfer_enable' => 0,
@@ -54,12 +55,12 @@ class DailyJob extends Command {
 				$this->addUserBanLog($user->id, 0, '【禁止登录,清空账户】-账号已过期');
 
 				// 废除其名下邀请码
-				Invite::query()->whereUid($user->id)->whereStatus(0)->update(['status' => 2]);
+				Invite::whereInviterId($user->id)->whereStatus(0)->update(['status' => 2]);
 
 				// 写入用户流量变动记录
 				Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, 0, '[定时任务]账号已过期(禁止登录,清空账户)');
 			}else{
-				User::query()->whereId($user->id)->update([
+				$user->update([
 					'u'               => 0,
 					'd'               => 0,
 					'transfer_enable' => 0,
@@ -80,25 +81,23 @@ class DailyJob extends Command {
 	 * 添加用户封禁日志
 	 *
 	 * @param  int     $userId       用户ID
-	 * @param  int     $minutes      封禁时长,单位分钟
+	 * @param  int     $time         封禁时长,单位分钟
 	 * @param  string  $description  封禁理由
+	 * @return bool
 	 */
-	private function addUserBanLog($userId, $minutes, $description): void {
+	private function addUserBanLog($userId, $time, $description): bool {
 		$log = new UserBanedLog();
 		$log->user_id = $userId;
-		$log->minutes = $minutes;
+		$log->time = $time;
 		$log->description = $description;
-		$log->save();
+		return $log->save();
 	}
 
 	// 关闭超过72小时未处理的工单
 	private function closeTickets(): void {
-		$ticketList = Ticket::query()
-		                    ->where('updated_at', '<=', date('Y-m-d', strtotime("-3 days")))
-		                    ->whereStatus(1)
-		                    ->get();
+		$ticketList = Ticket::where('updated_at', '<=', date('Y-m-d', strtotime("-3 days")))->whereStatus(1)->get();
 		foreach($ticketList as $ticket){
-			$ret = Ticket::query()->whereId($ticket->id)->update(['status' => 2]);
+			$ret = Ticket::whereId($ticket->id)->update(['status' => 2]);
 			if($ret){
 				PushNotification::send('工单关闭提醒', '工单:ID'.$ticket->id.'超过72小时未处理,系统已自动关闭');
 			}
@@ -107,9 +106,8 @@ class DailyJob extends Command {
 
 	// 重置用户流量
 	private function resetUserTraffic(): void {
-		$userList = User::query()
-		                ->where('status', '<>', -1)
-		                ->where('expire_time', '>', date('Y-m-d'))
+		$userList = User::where('status', '<>', -1)
+		                ->where('expired_at', '>', date('Y-m-d'))
 		                ->where('reset_time', '<=', date('Y-m-d'))
 		                ->get();
 		foreach($userList as $user){
@@ -119,50 +117,27 @@ class DailyJob extends Command {
 			}
 
 			// 取出用户正在使用的套餐
-			$order = Order::query()
-			              ->with(['goods'])
-			              ->whereUserId($user->id)
-			              ->whereStatus(2)
-			              ->whereIsExpire(0)
-			              ->whereHas('goods', static function($q) {
-				              $q->whereType(2);
-			              })
-			              ->first();
-
-			// 无订单的免费/特殊用户跳过
+			$order = Order::userActivePlan($user->id)->first();
+
+			// 无订单用户跳过
 			if(!$order){
 				continue;
 			}
 
 			// 过期生效中的加油包
-			Order::query()
-			     ->with(['goods'])
-			     ->whereUserId($user->id)
-			     ->whereStatus(2)
-			     ->whereIsExpire(0)
-			     ->whereHas('goods', static function($q) {
-				     $q->whereType(1);
-			     })
-			     ->update(['is_expire' => 1]);
-
-			//账号下一个重置时间
-			$nextResetTime = date('Y-m-d', strtotime("+".$order->goods->period." days"));
-			if($nextResetTime >= $user->expire_time){
-				$nextResetTime = null;
-			}
-			// 可用流量 变动日志
-			if($user->transfer_enable != $order->goods->traffic * MB){
-				Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable,
-					$order->goods->traffic * MB, '【流量重置】重置可用流量');
+			Order::userActivePackage($user->id)->update(['is_expire' => 1]);
+
+			$oldData = $user->transfer_enable;
+			// 重置流量与重置日期 TODO 可用流量变动日志加入至UserObserver
+			$ret = $user->update((new OrderService($order))->resetTimeAndData($user->expired_at));
+			if($ret){
+				// 可用流量变动日志
+				Helpers::addUserTrafficModifyLog($order->user_id, $order->id, $oldData, $user->transfer_enable,
+					'【流量重置】重置可用流量');
+				Log::info('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置为 '.flowAutoShow($user->transfer_enable).'. 重置日期为 '.($user->reset_time?: '【无】'));
+			}else{
+				Log::error('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置失败');
 			}
-			// 重置流量
-			User::query()->whereId($user->id)->update([
-				'u'               => 0,
-				'd'               => 0,
-				'transfer_enable' => $order->goods->traffic * MB,
-				'reset_time'      => $nextResetTime
-			]);
-			Log::info('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置为 '.($order->goods->traffic * MB).'. 重置日期为 '.($nextResetTime?: '【无】'));
 		}
 	}
 }

+ 3 - 3
app/Console/Commands/NodeBlockedDetection.php

@@ -36,7 +36,7 @@ class NodeBlockedDetection extends Command {
 
 	// 监测节点状态
 	private function checkNodes(): void {
-		$nodeList = Node::query()->whereIsRelay(0)->whereStatus(1)->where('detection_type', '>', 0)->get();
+		$nodeList = Node::whereIsRelay(0)->whereStatus(1)->where('detection_type', '>', 0)->get();
 		$sendText = false;
 		$message = "| 线路 | 协议 | 状态 |\r\n| ------ | ------ | ------ |\r\n";
 		$additionalMessage = '';
@@ -84,11 +84,11 @@ class NodeBlockedDetection extends Command {
 					$times = 1;
 				}
 
-				if($times < self::sysConfig('detection_check_times')){
+				if($times < sysConfig('detection_check_times')){
 					Cache::increment($cacheKey);
 				}else{
 					Cache::forget($cacheKey);
-					Node::query()->whereId($node->id)->update(['status' => 0]);
+					Node::find($node->id)->update(['status' => 0]);
 					$additionalMessage .= "\r\n节点【{$node->name}】自动进入维护状态\r\n";
 				}
 			}

+ 16 - 60
app/Console/Commands/ServiceTimer.php

@@ -3,11 +3,7 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use App\Http\Controllers\ServiceController;
 use App\Models\Order;
-use App\Models\User;
-use DB;
-use Exception;
 use Illuminate\Console\Command;
 use Log;
 
@@ -30,62 +26,22 @@ class ServiceTimer extends Command {
 	// 扣减用户到期商品的流量
 	private function decGoodsTraffic(): void {
 		//获取失效的套餐
-		$orderList = Order::query()
-		                  ->with(['goods'])
-		                  ->whereStatus(2)
-		                  ->whereIsExpire(0)
-		                  ->whereHas('goods', static function($q) {
-			                  $q->whereType(2);
-		                  })
-		                  ->where('expired_at', '<=', date('Y-m-d H:i:s'))
-		                  ->get();
-		if($orderList->isNotEmpty()){
-			try{
-				DB::beginTransaction();
-				foreach($orderList as $order){
-					// 过期本订单
-					Order::query()->whereOid($order->oid)->update(['is_expire' => 1]);
-
-					// 过期生效中的加油包
-					Order::query()
-					     ->with(['goods'])
-					     ->whereUserId($order->user_id)
-					     ->whereStatus(2)
-					     ->whereIsExpire(0)
-					     ->whereHas('goods', static function($q) {
-						     $q->whereType(1);
-					     })
-					     ->update(['is_expire' => 1]);
-
-					if(empty($order->user) || empty($order->goods)){
-						continue;
-					}
-
-					// 清理全部流量,重置重置日期和等级
-					User::query()->whereId($order->user_id)->update([
-						'u'               => 0,
-						'd'               => 0,
-						'transfer_enable' => 0,
-						'reset_time'      => null,
-						'level'           => 0
-					]);
-					Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $order->user->transfer_enable, 0,
-						'[定时任务]用户所购商品到期,扣减商品对应的流量');
-
-					// 检查该订单对应用户是否有预支付套餐
-					$prepaidOrder = Order::query()->whereUserId($order->user_id)->whereStatus(3)->oldest()->first();
-
-					if($prepaidOrder){
-						(new ServiceController)->activePrepaidOrder($prepaidOrder->oid);
-					}
-				}
-
-				DB::commit();
-			}catch(Exception $e){
-				Log::error($this->description.':'.$e);
-
-				DB::rollBack();
-			}
+		$orders = Order::activePlan()->where('expired_at', '<=', date('Y-m-d H:i:s'))->get();
+		foreach($orders as $order){
+			// 清理全部流量,重置重置日期和等级 TODO 可用流量变动日志加入至UserObserver
+			$user = $order->user;
+			$user->update([
+				'u'               => 0,
+				'd'               => 0,
+				'transfer_enable' => 0,
+				'reset_time'      => null,
+				'level'           => 0
+			]);
+			Helpers::addUserTrafficModifyLog($user->id, $order->id, $user->transfer_enable, 0,
+				'[定时任务]用户所购商品到期,扣减商品对应的流量');
+
+			// 过期本订单
+			$order->update(['is_expire' => 1]);
 		}
 	}
 }

+ 2 - 2
app/Console/Commands/UserExpireAutoWarning.php

@@ -30,14 +30,14 @@ class UserExpireAutoWarning extends Command {
 
 	private function userExpireWarning(): void {
 		// 只取SSR没被禁用的用户,其他不用管
-		foreach(User::query()->whereEnable(1)->get() as $user){
+		foreach(User::whereEnable(1)->get() as $user){
 			// 用户名不是邮箱的跳过
 			if(false === filter_var($user->email, FILTER_VALIDATE_EMAIL)){
 				continue;
 			}
 
 			// 计算剩余可用时间
-			$lastCanUseDays = ceil(round(strtotime($user->expire_time) - time()) / Day);
+			$lastCanUseDays = Helpers::daysToNow($user->expired_at);
 			if($lastCanUseDays == 0){
 				$title = '账号过期提醒';
 				$content = '您的账号将于今天晚上【24:00】过期。';

+ 2 - 6
app/Console/Commands/UserTrafficAbnormalAutoWarning.php

@@ -2,7 +2,6 @@
 
 namespace App\Console\Commands;
 
-use App\Components\Helpers;
 use App\Components\PushNotification;
 use App\Models\User;
 use App\Models\UserHourlyDataFlow;
@@ -28,8 +27,7 @@ class UserTrafficAbnormalAutoWarning extends Command {
 	// 用户流量异常警告
 	private function userTrafficAbnormalWarning(): void {
 		// 1小时内流量异常用户(多往前取5分钟,防止数据统计任务执行时间过长导致没有数据)
-		$userTotalTrafficList = UserHourlyDataFlow::query()
-		                                          ->whereNodeId(0)
+		$userTotalTrafficList = UserHourlyDataFlow::whereNodeId(0)
 		                                          ->where('total', '>', MB * 50)
 		                                          ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
 		                                          ->groupBy('user_id')
@@ -43,9 +41,7 @@ class UserTrafficAbnormalAutoWarning extends Command {
 
 				// 推送通知管理员
 				if($vo->totalTraffic > sysConfig('traffic_ban_value') * GB){
-					$traffic = UserHourlyDataFlow::query()
-					                             ->userHourly($vo->user_id)
-					                             ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
+					$traffic = UserHourlyDataFlow::userRecentUsed($user->id)
 					                             ->selectRaw("user_id, sum(`u`) as totalU, sum(`d`) as totalD, sum(total) as totalTraffic")
 					                             ->firstOrFail();
 

+ 1 - 1
app/Console/Commands/UserTrafficAutoWarning.php

@@ -29,7 +29,7 @@ class UserTrafficAutoWarning extends Command {
 
 	// 用户流量超过警告阈值自动发邮件提醒
 	private function userTrafficWarning(): void {
-		foreach(User::query()->activeUser()->where('transfer_enable', '>', 0)->get() as $user){
+		foreach(User::activeUser()->where('transfer_enable', '>', 0)->get() as $user){
 			// 用户名不是邮箱的跳过
 			if(false === filter_var($user->email, FILTER_VALIDATE_EMAIL)){
 				continue;

+ 8 - 10
app/Console/Commands/fixDailyTrafficLogError.php

@@ -17,20 +17,19 @@ class fixDailyTrafficLogError extends Command {
 	public function handle(): void {
 		// set value
 		$this->end = date('Y-m-d 23:59:59', strtotime("-1 days"));
-		$nodeArray = UserDataFlowLog::query()->distinct()->pluck('node_id')->toArray();
+		$nodeArray = UserDataFlowLog::distinct()->pluck('node_id')->toArray();
 
 		Log::info('----------------------------【修复原版本的每日流量计算错误】开始----------------------------');
 		Log::info('----------------------------【节点流量日志修正】开始----------------------------');
 		foreach(NodeDailyDataFlow::all() as $log){
-			NodeDailyDataFlow::query()->whereId($log->id)->update([
-				'created_at' => date('Y-m-d H:i:s', strtotime("-1 days", strtotime($log->created_at)))
+			NodeDailyDataFlow::whereId($log->id)->update([
+				'created_at' => date('Y-m-d H:i:s', strtotime("$log->created_at -1 days"))
 			]);
 		}
 
 		Log::info('----------------------------【添加节点流量日志】开始----------------------------');
 		foreach($nodeArray as $nodeId){
-			$query = UserDataFlowLog::query()
-			                        ->whereNodeId($nodeId)
+			$query = UserDataFlowLog::whereNodeId($nodeId)
 			                        ->whereBetween('log_time',
 				                        [strtotime(date('Y-m-d', strtotime("-1 days"))), strtotime($this->end)]);
 
@@ -53,12 +52,12 @@ class fixDailyTrafficLogError extends Command {
 		Log::info('----------------------------【节点流量日志修正】结束----------------------------');
 		Log::info('----------------------------【用户流量日志修正】开始----------------------------');
 		foreach(UserDailyDataFlow::all() as $log){
-			UserDailyDataFlow::query()->whereId($log->id)->update([
-				'created_at' => date('Y-m-d H:i:s', strtotime("-1 days", strtotime($log->created_at)))
+			UserDailyDataFlow::whereId($log->id)->update([
+				'created_at' => date('Y-m-d H:i:s', strtotime("$log->created_at -1 days"))
 			]);
 		}
 		Log::info('----------------------------【用户个人流量日志修正】开始----------------------------');
-		foreach(UserDataFlowLog::query()->distinct()->pluck('user_id')->toArray() as $userId){
+		foreach(UserDataFlowLog::distinct()->pluck('user_id')->toArray() as $userId){
 			// 统计一次所有节点的总和
 			$this->statisticsByUser($userId);
 			// 统计每个节点产生的流量
@@ -72,8 +71,7 @@ class fixDailyTrafficLogError extends Command {
 	}
 
 	private function statisticsByUser($user_id, $node_id = 0): void {
-		$query = UserDataFlowLog::query()
-		                        ->whereUserId($user_id)
+		$query = UserDataFlowLog::whereUserId($user_id)
 		                        ->whereBetween('log_time',
 			                        [strtotime(date('Y-m-d', strtotime("-1 days"))), strtotime($this->end)]);
 

+ 37 - 0
app/Console/Commands/updateCoupon.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Coupon;
+use Illuminate\Console\Command;
+use Log;
+
+class updateCoupon extends Command {
+	protected $signature = 'updateCoupon';
+	protected $description = '修改原版Coupon至新版';
+
+
+	public function __construct() {
+		parent::__construct();
+	}
+
+	public function handle() {
+		Log::info('----------------------------【优惠券转换】开始----------------------------');
+		$coupons = Coupon::withTrashed()->get();
+		foreach($coupons as $coupon){
+			if($coupon->amount){
+				$coupon->value = $coupon->amount / 100;
+			}elseif($coupon->discount){
+				$coupon->value = $coupon->discount * 100;
+			}
+
+			if($coupon->rule === 0){
+				$coupon->rule = null;
+			}else{
+				$coupon->rule /= 100;
+			}
+			$coupon->save();
+		}
+		Log::info('----------------------------【优惠券转换】结束----------------------------');
+	}
+}

+ 3 - 3
app/Console/Commands/updateTicket.php

@@ -14,11 +14,11 @@ class updateTicket extends Command {
 	public function handle(): void {
 		Log::info('----------------------------【更新工单】开始----------------------------');
 		// 获取管理员
-		foreach(User::query()->whereIsAdmin(1)->get() as $admin){
+		foreach(User::whereIsAdmin(1)->get() as $admin){
 			Log::info('----------------------------【更新管理员'.$admin->id.'回复工单】开始----------------------------');
 			// 获取该管理回复过的工单, 更新工单
-			foreach(TicketReply::query()->whereUserId($admin->id)->get() as $reply){
-				$ret = TicketReply::query()->whereId($reply->id)->update(['user_id' => 0, 'admin_id' => $admin->id]);
+			foreach(TicketReply::whereUserId($admin->id)->get() as $reply){
+				$ret = TicketReply::whereId($reply->id)->update(['user_id' => 0, 'admin_id' => $admin->id]);
 				if($ret){
 					Log::info('--- 管理员:'.$admin->email.'回复子单ID:'.$reply->id.' ---');
 				}else{

+ 7 - 12
app/Console/Commands/updateUserLevel.php

@@ -15,24 +15,19 @@ class updateUserLevel extends Command {
 	public function handle(): void {
 		Log::info('----------------------------【用户等级升级】开始----------------------------');
 		// 预设level 0
-		foreach(User::query()->where('level', '<>', 0)->get() as $user){
-			User::query()->whereId($user->id)->update(['level' => 0]);
-		}
+		User::where('level', '<>', 0)->update(['level' => 0]);
+
 		// 获取商品列表,取新等级
-		$goodList = Goods::query()->where('level', '<>', 0)->whereType(2)->get();
+		$goodsLevel = Goods::type(2)->where('level', '<>', 0)->pluck('id')->toArray();
 		// 取生效的套餐
-		$orderList = Order::query()
-		                  ->whereIn('goods_id', $goodList->pluck('id')->toArray())
-		                  ->whereStatus(2)
-		                  ->whereIsExpire(0)
-		                  ->get();
+		$orderList = Order::with('goods')->whereIn('goods_id', $goodsLevel)->active()->get();
 		foreach($orderList as $order){
-			$ret = User::query()->whereId($order->user_id)->update(['level' => $order->goods->level]);
+			$ret = $order->user->update(['level' => $order->goods->level]);
 
 			if($ret){
-				Log::info('用户: '.$order->user->id.', 按照订单'.$order->id.' 等级为'.$order->goods->level);
+				Log::info('用户: '.$order->user_id.', 按照订单'.$order->id.' 等级为'.$order->goods->level);
 			}else{
-				Log::error('用户: '.$order->user->id.' 等级更新失败!');
+				Log::error('用户: '.$order->user_id.' 等级更新失败!');
 			}
 		}
 		Log::info('----------------------------【用户等级升级】结束----------------------------');

+ 2 - 2
app/Console/Commands/updateUserName.php

@@ -17,7 +17,7 @@ class updateUserName extends Command {
 		$userList = User::all();
 		foreach($userList as $user){
 			$name = process($user->id);
-			User::query()->whereId($user->id)->update(['username' => $name]);
+			$user->update(['username' => $name]);
 
 			Log::info('---用户[ID:'.$user->id.' - '.$user->email.'] :'.$user->username.'---');
 		}
@@ -26,7 +26,7 @@ class updateUserName extends Command {
 			if($user->email == $user->username){
 				$name = process($user->id);
 
-				User::query()->whereId($user->id)->update(['username' => $name]);
+				$user->update(['username' => $name]);
 
 				Log::info('---用户[ID:'.$user->id.' - '.$user->email.'] :'.$user->username.'---');
 			}

+ 2 - 2
app/Console/Commands/upgradeUserResetTime.php

@@ -42,10 +42,10 @@ class upgradeUserResetTime extends Command {
 					}
 				}
 				// 用户账号有效期大于重置日期
-				if($reset_time > $user->expire_time){
+				if($reset_time > $user->expired_at){
 					$reset_time = null;
 				}
-				User::query()->whereId($user->id)->update(['reset_time' => $reset_time]);
+				$user->update(['reset_time' => $reset_time]);
 			}
 
 			Log::info('---用户[ID:'.$user->id.' - '.$user->username.' ('.$user->email.')]的新重置日期为'.($reset_time != null? '【'.$reset_time.'】' : '【无】').'---');

+ 20 - 26
app/Http/Controllers/Admin/AffiliateController.php

@@ -23,7 +23,7 @@ class AffiliateController extends Controller {
 		$email = $request->input('email');
 		$status = $request->input('status');
 
-		$query = ReferralApply::with('user');
+		$query = ReferralApply::with('user:id,email');
 		if(isset($email)){
 			$query->whereHas('user', static function($q) use ($email) {
 				$q->where('email', 'like', '%'.$email.'%');
@@ -41,21 +41,15 @@ class AffiliateController extends Controller {
 
 	// 提现申请详情
 	public function affiliateDetail(Request $request): \Illuminate\Http\Response {
-		$id = $request->input('id');
-
-		$list = null;
-		$apply = ReferralApply::query()->with(['user'])->whereId($id)->first();
-		if($apply && $apply->link_logs){
-			$list = ReferralLog::query()
-			                   ->with(['user', 'order.goods'])
-			                   ->whereIn('id', $apply->link_logs)
-			                   ->paginate(15)
-			                   ->appends($request->except('page'));
+		$view['basic'] = ReferralApply::with('user:id,email')->find($request->input('id'));
+		$view['commissions'] = [];
+		if($view['basic'] && $view['basic']->link_logs){
+			$view['commissions'] = ReferralLog::with(['invitee:id,email', 'order.goods:id,name'])
+			                                  ->whereIn('id', $view['basic']->link_logs)
+			                                  ->paginate(15)
+			                                  ->appends($request->except('page'));
 		}
 
-		$view['info'] = $apply;
-		$view['list'] = $list;
-
 		return Response::view('admin.affiliate.affiliateDetail', $view);
 	}
 
@@ -64,14 +58,14 @@ class AffiliateController extends Controller {
 		$id = $request->input('id');
 		$status = $request->input('status');
 
-		$ret = ReferralApply::query()->whereId($id)->update(['status' => $status]);
+		$ret = ReferralApply::whereId($id)->update(['status' => $status]);
 		if($ret){
 			// 审核申请的时候将关联的
 			$referralApply = ReferralApply::findOrFail($id);
 			if($referralApply && $status == 1){
-				ReferralLog::query()->whereIn('id', $referralApply->link_logs)->update(['status' => 1]);
+				ReferralLog::whereIn('id', $referralApply->link_logs)->update(['status' => 1]);
 			}elseif($referralApply && $status == 2){
-				ReferralLog::query()->whereIn('id', $referralApply->link_logs)->update(['status' => 2]);
+				ReferralLog::whereIn('id', $referralApply->link_logs)->update(['status' => 2]);
 			}
 		}
 
@@ -80,21 +74,21 @@ class AffiliateController extends Controller {
 
 	// 用户返利流水记录
 	public function userRebateList(Request $request): \Illuminate\Http\Response {
-		$email = $request->input('email');
-		$ref_email = $request->input('ref_email');
+		$invitee_email = $request->input('invitee_email');
+		$inviter_email = $request->input('inviter_email');
 		$status = $request->input('status');
 
-		$query = ReferralLog::query()->with(['user', 'order'])->orderBy('status')->latest();
+		$query = ReferralLog::with(['invitee:id,email', 'inviter:id,email'])->orderBy('status')->latest();
 
-		if(isset($email)){
-			$query->whereHas('user', static function($q) use ($email) {
-				$q->where('email', 'like', '%'.$email.'%');
+		if(isset($invitee_email)){
+			$query->whereHas('invitee', static function($q) use ($invitee_email) {
+				$q->where('email', 'like', '%'.$invitee_email.'%');
 			});
 		}
 
-		if(isset($ref_email)){
-			$query->whereHas('ref_user', static function($q) use ($ref_email) {
-				$q->where('email', 'like', '%'.$ref_email.'%');
+		if(isset($inviter_email)){
+			$query->whereHas('inviter', static function($q) use ($inviter_email) {
+				$q->where('email', 'like', '%'.$inviter_email.'%');
 			});
 		}
 

+ 36 - 44
app/Http/Controllers/Admin/CouponController.php

@@ -48,42 +48,35 @@ class CouponController extends Controller {
 		return Response::view('admin.coupon.couponList', $view);
 	}
 
-	// 添加商品
+	// 添加优惠券
 	public function addCoupon(Request $request) {
 		if($request->isMethod('POST')){
 			Validator::make($request->all(), [
-				'name'            => 'required',
-				'sn'              => 'unique:coupon',
-				'type'            => 'required|integer|between:1,3',
-				'usage_count'     => 'required|integer',
-				'num'             => 'required|integer|min:1',
-				'amount'          => 'required_unless:type,2|numeric|min:0.01|nullable',
-				'discount'        => 'required_if:type,2|numeric|between:1,9.9|nullable',
-				'available_start' => 'required|date|before_or_equal:available_end',
-				'available_end'   => 'required|date|after_or_equal:available_start',
+				'name'         => 'required',
+				'sn'           => 'unique:coupon',
+				'type'         => 'required|integer|between:1,3',
+				'usable_times' => 'integer|nullable',
+				'num'          => 'required|integer|min:1',
+				'value'        => 'required|numeric|min:0',
+				'start_time'   => 'required|date|before_or_equal:end_time',
+				'end_time'     => 'required|date|after_or_equal:start_time',
 			], [
-				'name.required'                   => '请填入卡券名称',
-				'type.required'                   => '请选择卡券类型',
-				'type.integer'                    => '卡券类型不合法,请重选',
-				'type.between'                    => '卡券类型不合法,请重选',
-				'usage_count.required'            => '请选择卡券用途',
-				'usage_count.integer'             => '卡券用途不合法,请重选',
-				'usage_count.between'             => '卡券用途不合法,请重选',
-				'num.required'                    => '请填写卡券数量',
-				'num.integer'                     => '卡券数量不合法',
-				'num.min'                         => '卡券数量不合法,最小1',
-				'amount.required_unless'          => '请填入卡券面值',
-				'amount.numeric'                  => '卡券金额不合法',
-				'amount.min'                      => '卡券金额不合法,最小0.01',
-				'discount.required_if'            => '请填入卡券折扣',
-				'discount.numeric'                => '卡券折扣不合法',
-				'discount.between'                => '卡券折扣不合法,有效范围:1 ~ 9.9',
-				'available_start.required'        => '请填入有效期',
-				'available_start.date'            => '有效期不合法',
-				'available_start.before_or_equal' => '有效期不合法',
-				'available_end.required'          => '请填入有效期',
-				'available_end.date'              => '有效期不合法',
-				'available_end.after_or_equal'    => '有效期不合法'
+				'name.required'              => '请填入卡券名称',
+				'type.required'              => '请选择卡券类型',
+				'type.integer'               => '卡券类型不合法,请重选',
+				'type.between'               => '卡券类型不合法,请重选',
+				'num.required'               => '请填写卡券数量',
+				'num.integer'                => '卡券数量不合法',
+				'num.min'                    => '卡券数量不合法,最小1',
+				'value.required_unless'      => '请填入优惠值',
+				'value.numeric'              => '优惠值金额不合法',
+				'value.min'                  => '优惠值不合法,最小0',
+				'start_time.required'        => '请填入有效期',
+				'start_time.date'            => '有效期不合法',
+				'start_time.before_or_equal' => '有效期不合法',
+				'end_time.required'          => '请填入有效期',
+				'end_time.date'              => '有效期不合法',
+				'end_time.after_or_equal'    => '有效期不合法'
 			]);
 
 			$type = $request->input('type');
@@ -107,12 +100,11 @@ class CouponController extends Controller {
 					$obj->logo = $logo;
 					$obj->sn = $num == 1 && $request->input('sn')? $request->input('sn') : makeRandStr(8);
 					$obj->type = $type;
-					$obj->usage_count = $request->input('usage_count');
-					$obj->amount = $type == 2? 0 : $request->input('amount');
-					$obj->discount = $type != 2? 0 : $request->input('discount');
+					$obj->usable_times = $request->input('usable_times');
+					$obj->value = $request->input('value');
 					$obj->rule = $request->input('rule');
-					$obj->available_start = strtotime($request->input('available_start'));
-					$obj->available_end = strtotime($request->input('available_end'));
+					$obj->start_time = strtotime($request->input('start_time'));
+					$obj->end_time = strtotime($request->input('end_time'));
 					$obj->status = 0;
 					$obj->save();
 				}
@@ -134,7 +126,7 @@ class CouponController extends Controller {
 
 	// 删除优惠券
 	public function delCoupon(Request $request): JsonResponse {
-		Coupon::query()->whereId($request->input('id'))->delete();
+		Coupon::find($request->input('id'))->delete();
 
 		return Response::json(['status' => 'success', 'message' => '删除成功']);
 	}
@@ -162,8 +154,8 @@ class CouponController extends Controller {
 		$sheet->setTitle('抵用券');
 		$sheet->fromArray(['名称', '使用次数', '有效期', '券码', '金额(元)', '使用限制(元)'], null);
 		foreach($voucherList as $k => $vo){
-			$dateRange = date('Y-m-d', $vo->available_start).' ~ '.date('Y-m-d', $vo->available_end);
-			$sheet->fromArray([$vo->name, $vo->usage_count, $dateRange, $vo->sn, $vo->amount, $vo->rule], null,
+			$dateRange = date('Y-m-d', $vo->start_time).' ~ '.date('Y-m-d', $vo->end_time);
+			$sheet->fromArray([$vo->name, $vo->usable_times, $dateRange, $vo->sn, $vo->value, $vo->rule], null,
 				'A'.($k + 2));
 		}
 
@@ -174,8 +166,8 @@ class CouponController extends Controller {
 		$sheet->setTitle('折扣券');
 		$sheet->fromArray(['名称', '使用次数', '有效期', '券码', '折扣(折)', '使用限制(元)'], null);
 		foreach($discountCouponList as $k => $vo){
-			$dateRange = date('Y-m-d', $vo->available_start).' ~ '.date('Y-m-d', $vo->available_end);
-			$sheet->fromArray([$vo->name, $vo->usage_count, $dateRange, $vo->sn, $vo->discount, $vo->rule], null,
+			$dateRange = date('Y-m-d', $vo->start_time).' ~ '.date('Y-m-d', $vo->end_time);
+			$sheet->fromArray([$vo->name, $vo->usable_times, $dateRange, $vo->sn, $vo->value, $vo->rule], null,
 				'A'.($k + 2));
 		}
 
@@ -186,8 +178,8 @@ class CouponController extends Controller {
 		$sheet->setTitle('充值券');
 		$sheet->fromArray(['名称', '有效期', '券码', '金额(元)'], null);
 		foreach($refillList as $k => $vo){
-			$dateRange = date('Y-m-d', $vo->available_start).' ~ '.date('Y-m-d', $vo->available_end);
-			$sheet->fromArray([$vo->name, $dateRange, $vo->sn, $vo->amount], null, 'A'.($k + 2));
+			$dateRange = date('Y-m-d', $vo->start_time).' ~ '.date('Y-m-d', $vo->end_time);
+			$sheet->fromArray([$vo->name, $dateRange, $vo->sn, $vo->value], null, 'A'.($k + 2));
 		}
 
 		// 指针切换回第一个sheet

+ 2 - 2
app/Http/Controllers/Admin/EmailFilterController.php

@@ -19,7 +19,7 @@ use Validator;
 class EmailFilterController extends Controller {
 	// 邮箱过滤列表
 	public function filterList(): \Illuminate\Http\Response {
-		$view['list'] = EmailFilter::query()->orderByDesc('id')->paginate(15);
+		$view['list'] = EmailFilter::orderByDesc('id')->paginate(15);
 
 		return Response::view('admin.config.emailFilter', $view);
 	}
@@ -50,7 +50,7 @@ class EmailFilterController extends Controller {
 
 	// 删除邮箱后缀
 	public function delSuffix(Request $request): ?JsonResponse {
-		$result = EmailFilter::query()->whereId($request->input('id'))->delete();
+		$result = EmailFilter::whereId($request->input('id'))->delete();
 		if($result){
 			return Response::json(['status' => 'success', 'message' => '删除成功']);
 		}

+ 3 - 3
app/Http/Controllers/Admin/MarketingController.php

@@ -25,7 +25,7 @@ class MarketingController extends Controller {
 	public function emailList(Request $request): \Illuminate\Http\Response {
 		$status = $request->input('status');
 
-		$query = Marketing::query()->whereType(1);
+		$query = Marketing::whereType(1);
 
 		if(isset($status)){
 			$query->whereStatus($status);
@@ -40,13 +40,13 @@ class MarketingController extends Controller {
 	public function pushList(Request $request): \Illuminate\Http\Response {
 		$status = $request->input('status');
 
-		$query = Marketing::query()->whereType(2);
+		$query = Marketing::whereType(2);
 
 		if(isset($status)){
 			$query->whereStatus($status);
 		}
 
-		$view['list'] = $query->paginate(15);
+		$view['list'] = $query->paginate(15)->appends($request->except('page'));
 
 		return Response::view('admin.marketing.pushList', $view);
 	}

+ 2 - 2
app/Http/Controllers/Admin/RuleController.php

@@ -53,7 +53,7 @@ class RuleController extends Controller {
 
 	// 编辑审计规则
 	public function update(Request $request, $id): JsonResponse {
-		$ret = Rule::query()->whereId($id)->update([
+		$ret = Rule::whereId($id)->update([
 			'name'    => $request->input('rule_name'),
 			'pattern' => $request->input('rule_pattern')
 		]);
@@ -117,7 +117,7 @@ class RuleController extends Controller {
 		}catch(Exception $e){
 			return Response::json(['status' => 'fail', 'message' => '清理失败, '.$e->getMessage()]);
 		}
-		$result = RuleLog::query()->doesntExist();
+		$result = RuleLog::doesntExist();
 		if($ret || $result){
 			return Response::json(['status' => 'success', 'message' => '清理成功']);
 		}

+ 5 - 5
app/Http/Controllers/Admin/RuleGroupController.php

@@ -17,8 +17,8 @@ use Validator;
 
 class RuleGroupController extends Controller {
 	// 审计规则分组列表
-	public function index(): \Illuminate\Http\Response {
-		$view['ruleGroupList'] = RuleGroup::query()->paginate(15);
+	public function index(Request $request): \Illuminate\Http\Response {
+		$view['ruleGroupList'] = RuleGroup::paginate(15)->appends($request->except('page'));
 
 		return Response::view('admin.rule.group.index', $view);
 	}
@@ -90,7 +90,7 @@ class RuleGroupController extends Controller {
 	public function destroy($id): JsonResponse {
 		try{
 			RuleGroup::whereId($id)->delete();
-			RuleGroupNode::query()->whereRuleGroupId($id)->delete();
+			RuleGroupNode::whereRuleGroupId($id)->delete();
 
 		}catch(Exception $e){
 			return Response::json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
@@ -115,7 +115,7 @@ class RuleGroupController extends Controller {
 			if($ruleGroup->nodes === $nodes){
 				return Redirect::back()->with('successMsg', '检测为未修改,无变动!');
 			}
-			RuleGroupNode::query()->whereRuleGroupId($id)->delete();
+			RuleGroupNode::whereRuleGroupId($id)->delete();
 			if($nodes){
 				$ruleGroup->nodes = $nodes;
 				if(!$ruleGroup->save()){
@@ -129,7 +129,7 @@ class RuleGroupController extends Controller {
 					$obj->save();
 				}
 			}else{
-				RuleGroup::query()->whereId($id)->update(['nodes' => null]);
+				RuleGroup::whereId($id)->update(['nodes' => null]);
 			}
 
 		}catch(Exception $e){

+ 6 - 6
app/Http/Controllers/Admin/ShopController.php

@@ -47,7 +47,7 @@ class ShopController extends Controller {
 	// 添加商品页面
 	public function create(): \Illuminate\Http\Response {
 		$view['goods'] = null;
-		$view['levelList'] = Level::query()->orderBy('level')->get();
+		$view['levelList'] = Level::orderBy('level')->get();
 
 		return Response::view('admin.shop.info', $view);
 	}
@@ -108,7 +108,7 @@ class ShopController extends Controller {
 			return Redirect::back()->with('successMsg', '添加成功');
 		}catch(Exception $e){
 			DB::rollBack();
-			Log::info($e);
+			Log::info('添加商品信息异常:'.$e->getMessage());
 
 			return Redirect::back()->withInput()->withErrors('添加失败');
 		}
@@ -117,7 +117,7 @@ class ShopController extends Controller {
 	// 编辑商品页面
 	public function edit($id): \Illuminate\Http\Response {
 		$view['goods'] = Goods::find($id);
-		$view['levelList'] = Level::query()->orderBy('level')->get();
+		$view['levelList'] = Level::orderBy('level')->get();
 
 		return Response::view('admin.shop.info', $view);
 	}
@@ -140,7 +140,7 @@ class ShopController extends Controller {
 
 				return Redirect::back()->withInput();
 			}
-			Goods::query()->whereId($id)->update(['logo' => $logo]);
+			Goods::whereId($id)->update(['logo' => $logo]);
 		}
 
 		try{
@@ -162,7 +162,7 @@ class ShopController extends Controller {
 				'status'      => $request->input('status', 0)
 			];
 
-			Goods::query()->whereId($id)->update($data);
+			Goods::whereId($id)->update($data);
 
 			Session::flash('successMsg', '编辑成功');
 
@@ -179,7 +179,7 @@ class ShopController extends Controller {
 	// 删除商品
 	public function destroy($id): JsonResponse {
 		try{
-			$goods = Goods::query()->findOrFail($id)->delete();
+			$goods = Goods::findOrFail($id)->delete();
 
 		}catch(Exception $e){
 			Session::flash('errorMsg', '编辑失败'.$e);

+ 3 - 3
app/Http/Controllers/Admin/SubscribeController.php

@@ -50,7 +50,7 @@ class SubscribeController extends Controller {
 		$query = UserSubscribeLog::with('user:email');
 
 		if(isset($id)){
-			$query->whereSid($id);
+			$query->whereSubscribeId($id);
 		}
 
 		$view['subscribeLog'] = $query->latest()->paginate(20)->appends($request->except('page'));
@@ -68,9 +68,9 @@ class SubscribeController extends Controller {
 		}
 
 		if($status){
-			UserSubscribe::query()->whereId($id)->update(['status' => 1, 'ban_time' => 0, 'ban_desc' => '']);
+			UserSubscribe::find($id)->update(['status' => 1, 'ban_time' => 0, 'ban_desc' => '']);
 		}else{
-			UserSubscribe::query()->whereId($id)->update(['status' => 0, 'ban_time' => time(), 'ban_desc' => '后台手动封禁']);
+			UserSubscribe::find($id)->update(['status' => 0, 'ban_time' => time(), 'ban_desc' => '后台手动封禁']);
 		}
 
 		return Response::json(['status' => 'success', 'message' => '操作成功']);

+ 7 - 7
app/Http/Controllers/Admin/TicketController.php

@@ -28,7 +28,7 @@ class TicketController extends Controller {
 	public function ticketList(Request $request): \Illuminate\Http\Response {
 		$email = $request->input('email');
 
-		$query = Ticket::query()->whereIn('admin_id', [0, Auth::id()]);
+		$query = Ticket::whereIn('admin_id', [0, Auth::id()]);
 
 		if(isset($email)){
 			$query->whereHas('user', static function($q) use ($email) {
@@ -48,7 +48,7 @@ class TicketController extends Controller {
 		$title = $request->input('title');
 		$content = $request->input('content');
 
-		$user = User::find($id)?: User::query()->whereEmail($email)->first();
+		$user = User::find($id)?: User::whereEmail($email)->first();
 
 		if(!$user){
 			return Response::json(['status' => 'fail', 'message' => '用户不存在']);
@@ -94,8 +94,8 @@ class TicketController extends Controller {
 
 			if($obj->id){
 				// 将工单置为已回复
-				$ticket = Ticket::query()->with(['user'])->whereId($id)->firstOrFail();
-				Ticket::query()->whereId($id)->update(['status' => 1]);
+				$ticket = Ticket::with('user')->whereId($id)->firstOrFail();
+				Ticket::whereId($id)->update(['status' => 1]);
 
 				$title = "工单回复提醒";
 				$content = "标题:".$ticket->title."<br>管理员回复:".$content;
@@ -120,7 +120,7 @@ class TicketController extends Controller {
 		}
 
 		$view['ticket'] = Ticket::find($id);
-		$view['replyList'] = TicketReply::query()->whereTicketId($id)->oldest()->get();
+		$view['replyList'] = TicketReply::whereTicketId($id)->oldest()->get();
 
 		return Response::view('admin.ticket.replyTicket', $view);
 	}
@@ -129,12 +129,12 @@ class TicketController extends Controller {
 	public function closeTicket(Request $request): JsonResponse {
 		$id = $request->input('id');
 
-		$ticket = Ticket::query()->with(['user'])->whereId($id)->first();
+		$ticket = Ticket::with('user')->whereId($id)->first();
 		if(!$ticket){
 			return Response::json(['status' => 'fail', 'message' => '关闭失败']);
 		}
 
-		$ret = Ticket::query()->whereId($id)->update(['status' => 2]);
+		$ret = Ticket::whereId($id)->update(['status' => 2]);
 		if(!$ret){
 			return Response::json(['status' => 'fail', 'message' => '关闭失败']);
 		}

+ 1 - 2
app/Http/Controllers/Admin/ToolsController.php

@@ -174,8 +174,7 @@ class ToolsController extends Controller {
 					$obj->method = $user->method;
 					$obj->protocol = $user->protocol;
 					$obj->obfs = $user->obfs;
-					$obj->enable_time = date('Y-m-d');
-					$obj->expire_time = '2099-01-01';
+					$obj->expired_at = '2099-01-01';
 					$obj->reg_ip = getClientIp();
 					$obj->created_at = date('Y-m-d H:i:s');
 					$obj->updated_at = date('Y-m-d H:i:s');

+ 6 - 6
app/Http/Controllers/Admin/UserGroupController.php

@@ -15,14 +15,14 @@ use Response;
 use Validator;
 
 class UserGroupController extends Controller {
-	public function index(): \Illuminate\Http\Response {
-		$view['list'] = UserGroup::query()->paginate(15);
+	public function index(Request $request): \Illuminate\Http\Response {
+		$view['list'] = UserGroup::paginate(15)->appends($request->except('page'));
 		return Response::view('admin.user.group.index', $view);
 	}
 
 	// 添加用户分组页面
 	public function create(): \Illuminate\Http\Response {
-		$view['nodeList'] = Node::query()->whereStatus(1)->get();
+		$view['nodeList'] = Node::whereStatus(1)->get();
 		return Response::view('admin.user.group.info', $view);
 	}
 
@@ -51,7 +51,7 @@ class UserGroupController extends Controller {
 	// 编辑用户分组页面
 	public function edit($id): \Illuminate\Http\Response {
 		$view['userGroup'] = UserGroup::findOrFail($id);
-		$view['nodeList'] = Node::query()->whereStatus(1)->get();
+		$view['nodeList'] = Node::whereStatus(1)->get();
 
 		return Response::view('admin.user.group.info', $view);
 	}
@@ -71,12 +71,12 @@ class UserGroupController extends Controller {
 	// 删除用户分组
 	public function destroy($id): JsonResponse {
 		// 校验该分组下是否存在关联账号
-		if(User::query()->whereGroupId($id)->count()){
+		if(User::whereGroupId($id)->count()){
 			return Response::json(['status' => 'fail', 'message' => '该分组下存在关联账号,请先取消关联!']);
 		}
 
 		try{
-			UserGroup::query()->whereId($id)->delete();
+			UserGroup::whereId($id)->delete();
 		}catch(Exception $e){
 			return Response::json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
 		}

+ 123 - 176
app/Http/Controllers/AdminController.php

@@ -28,8 +28,8 @@ use App\Models\UserDataFlowLog;
 use App\Models\UserDataModifyLog;
 use App\Models\UserGroup;
 use App\Models\UserHourlyDataFlow;
-use App\Models\UserLoginLog;
 use App\Models\UserSubscribe;
+use App\Services\UserService;
 use Auth;
 use DB;
 use Exception;
@@ -64,37 +64,34 @@ class AdminController extends Controller {
 		$past = strtotime("-".self::$sysConfig['expire_days']." days");
 
 		$view['expireDays'] = self::$sysConfig['expire_days'];
-		$view['totalUserCount'] = User::query()->count(); // 总用户数
-		$view['enableUserCount'] = User::query()->whereEnable(1)->count(); // 有效用户数
-		$view['activeUserCount'] = User::query()->where('t', '>=', $past)->count(); // 活跃用户数
-		$view['unActiveUserCount'] = User::query()->whereBetween('t', [1, $past])->whereEnable(1)->count(); // 不活跃用户数
-		$view['onlineUserCount'] = User::query()->where('t', '>=', strtotime("-10 minutes"))->count(); // 10分钟内在线用户数
-		$view['expireWarningUserCount'] = User::query()->whereBetween('expire_time', [
+		$view['totalUserCount'] = User::count(); // 总用户数
+		$view['enableUserCount'] = User::whereEnable(1)->count(); // 有效用户数
+		$view['activeUserCount'] = User::where('t', '>=', $past)->count(); // 活跃用户数
+		$view['unActiveUserCount'] = User::whereBetween('t', [1, $past])->whereEnable(1)->count(); // 不活跃用户数
+		$view['onlineUserCount'] = User::where('t', '>=', strtotime("-10 minutes"))->count(); // 10分钟内在线用户数
+		$view['expireWarningUserCount'] = User::whereBetween('expired_at', [
 			date('Y-m-d'),
 			strtotime("+".self::$sysConfig['expire_days']." days")
 		])->count(); // 临近过期用户数
-		$view['largeTrafficUserCount'] = User::query()
-		                                     ->whereRaw('(u + d) >= 107374182400')
+		$view['largeTrafficUserCount'] = User::whereRaw('(u + d) >= 107374182400')
 		                                     ->where('status', '<>', -1)
 		                                     ->count(); // 流量超过100G的用户
 
 		$view['flowAbnormalUserCount'] = count($this->trafficAbnormal());// 1小时内流量异常用户
-		$view['nodeCount'] = Node::query()->count();
-		$view['unnormalNodeCount'] = Node::query()->whereStatus(0)->count();
-		$view['flowCount'] = flowAutoShow(NodeDailyDataFlow::query()
-		                                                   ->where('created_at', '>=',
-			                                                   date('Y-m-d', strtotime("-30 days")))
-		                                                   ->sum('total'));
-		$view['totalFlowCount'] = flowAutoShow(NodeDailyDataFlow::query()->sum('total'));
-		$view['totalCredit'] = User::query()->where('credit', '<>', 0)->sum('credit') / 100;
-		$view['totalWaitRefAmount'] = ReferralLog::query()->whereIn('status', [0, 1])->sum('ref_amount') / 100;
-		$view['totalRefAmount'] = ReferralApply::query()->whereStatus(2)->sum('amount') / 100;
-		$view['totalOrder'] = Order::query()->count();
-		$view['totalOnlinePayOrder'] = Order::query()->wherePayWay(2)->count();
-		$view['totalSuccessOrder'] = Order::query()->whereStatus(2)->count();
-		$view['todaySuccessOrder'] = Order::query()->whereStatus(2)->whereDate('created_at', date('Y-m-d'))->count();
+		$view['nodeCount'] = Node::count();
+		$view['unnormalNodeCount'] = Node::whereStatus(0)->count();
+		$view['flowCount'] = flowAutoShow(NodeDailyDataFlow::where('created_at', '>=',
+			date('Y-m-d', strtotime("-30 days")))->sum('total'));
+		$view['totalFlowCount'] = flowAutoShow(NodeDailyDataFlow::sum('total'));
+		$view['totalCredit'] = User::where('credit', '<>', 0)->sum('credit') / 100;
+		$view['totalWaitRefAmount'] = ReferralLog::whereIn('status', [0, 1])->sum('commission') / 100;
+		$view['totalRefAmount'] = ReferralApply::whereStatus(2)->sum('amount') / 100;
+		$view['totalOrder'] = Order::count();
+		$view['totalOnlinePayOrder'] = Order::where('pay_type', '<>', 0)->count();
+		$view['totalSuccessOrder'] = Order::whereStatus(2)->count();
+		$view['todaySuccessOrder'] = Order::whereStatus(2)->whereDate('created_at', date('Y-m-d'))->count();
 		// 今日
-		$view['todayRegister'] = User::query()->whereDate('created_at', date('Y-m-d'))->count();
+		$view['todayRegister'] = User::whereDate('created_at', date('Y-m-d'))->count();
 
 		return Response::view('admin.index', $view);
 	}
@@ -102,8 +99,7 @@ class AdminController extends Controller {
 	// 1小时内流量异常用户
 	private function trafficAbnormal(): array {
 		$result = [];
-		$userTotalTrafficList = UserHourlyDataFlow::query()
-		                                          ->whereNodeId(0)
+		$userTotalTrafficList = UserHourlyDataFlow::whereNodeId(0)
 		                                          ->where('total', '>', MB * 50)
 		                                          ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
 		                                          ->groupBy('user_id')
@@ -131,7 +127,7 @@ class AdminController extends Controller {
 		$expireWarning = $request->input('expireWarning');
 		$largeTraffic = $request->input('largeTraffic');
 
-		$query = User::query()->with(['subscribe']);
+		$query = User::with('subscribe');
 		if(isset($id)){
 			$query->whereId($id);
 		}
@@ -167,7 +163,7 @@ class AdminController extends Controller {
 
 		// 临近过期提醒
 		if($expireWarning){
-			$query->whereBetween('expire_time',
+			$query->whereBetween('expired_at',
 				[date('Y-m-d'), date('Y-m-d', strtotime("+".self::$sysConfig['expire_days']." days"))]);
 		}
 
@@ -190,22 +186,18 @@ class AdminController extends Controller {
 		foreach($userList as $user){
 			$user->transfer_enable = flowAutoShow($user->transfer_enable);
 			$user->used_flow = flowAutoShow($user->u + $user->d);
-			if($user->expire_time < date('Y-m-d')){
+			if($user->expired_at < date('Y-m-d')){
 				$user->expireWarning = -1; // 已过期
-			}elseif($user->expire_time == date('Y-m-d')){
+			}elseif($user->expired_at == date('Y-m-d')){
 				$user->expireWarning = 0; // 今天过期
-			}elseif($user->expire_time > date('Y-m-d') && $user->expire_time <= date('Y-m-d', strtotime("+30 days"))){
+			}elseif($user->expired_at > date('Y-m-d') && $user->expired_at <= date('Y-m-d', strtotime("+30 days"))){
 				$user->expireWarning = 1; // 最近一个月过期
 			}else{
 				$user->expireWarning = 2; // 大于一个月过期
 			}
 
 			// 流量异常警告
-			$time = date('Y-m-d H:i:s', time() - 3900);
-			$totalTraffic = UserHourlyDataFlow::query()
-			                                  ->userHourly($user->id)
-			                                  ->where('created_at', '>=', $time)
-			                                  ->sum('total');
+			$totalTraffic = UserHourlyDataFlow::userRecentUsed($user->id)->sum('total');
 			$user->trafficWarning = $totalTraffic > (self::$sysConfig['traffic_ban_value'] * GB)? 1 : 0;
 
 			// 订阅地址
@@ -221,7 +213,7 @@ class AdminController extends Controller {
 	public function addUser(Request $request) {
 		if($request->isMethod('POST')){
 			// 校验email是否已存在
-			$exists = User::query()->whereEmail($request->input('email'))->first();
+			$exists = User::whereEmail($request->input('email'))->first();
 			if($exists){
 				return Response::json(['status' => 'fail', 'message' => '用户名已存在,请重新输入']);
 			}
@@ -241,8 +233,7 @@ class AdminController extends Controller {
 			$user->speed_limit = $request->input('speed_limit') * Mbps;
 			$user->wechat = $request->input('wechat');
 			$user->qq = $request->input('qq');
-			$user->enable_time = $request->input('enable_time')?: date('Y-m-d');
-			$user->expire_time = $request->input('expire_time')?: date('Y-m-d', strtotime("+365 days"));
+			$user->expired_at = $request->input('expired_at')?: date('Y-m-d', strtotime("+365 days"));
 			$user->remark = str_replace(["atob", "eval"], "", $request->input('remark'));
 			$user->level = $request->input('level')?: 0;
 			$user->group_id = $request->input('group_id')?: 0;
@@ -274,14 +265,14 @@ class AdminController extends Controller {
 		$view['methodList'] = Helpers::methodList();
 		$view['protocolList'] = Helpers::protocolList();
 		$view['obfsList'] = Helpers::obfsList();
-		$view['levelList'] = Level::query()->orderBy('level')->get();
-		$view['groupList'] = UserGroup::query()->orderBy('id')->get();
+		$view['levelList'] = Level::orderBy('level')->get();
+		$view['groupList'] = UserGroup::orderBy('id')->get();
 
 		return Response::view('admin.user.userInfo', $view);
 	}
 
 	// 生成端口
-	public function makePort() {
+	public function makePort(): int {
 		return self::$sysConfig['is_rand_port']? Helpers::getRandPort() : Helpers::getOnlyPort();
 	}
 
@@ -320,6 +311,7 @@ class AdminController extends Controller {
 
 	// 编辑账号
 	public function editUser(Request $request, $id) {
+		$user = User::find($id);
 		if($request->isMethod('POST')){
 			$email = $request->input('email');
 			$password = $request->input('password');
@@ -329,14 +321,12 @@ class AdminController extends Controller {
 			$status = $request->input('status');
 
 			// 校验email是否已存在
-			$exists = User::query()->where('id', '<>', $id)->whereEmail($email)->first();
-			if($exists){
+			if(User::where('id', '<>', $id)->whereEmail($email)->exists()){
 				return Response::json(['status' => 'fail', 'message' => '用户名已存在,请重新输入']);
 			}
 
 			// 校验端口是否已存在
-			$exists = User::query()->where('id', '<>', $id)->where('port', '>', 0)->wherePort($port)->first();
-			if($exists){
+			if(User::where('id', '<>', $id)->where('port', '>', 0)->wherePort($port)->exists()){
 				return Response::json(['status' => 'fail', 'message' => '端口已存在,请重新输入']);
 			}
 
@@ -345,12 +335,8 @@ class AdminController extends Controller {
 				return Response::json(['status' => 'fail', 'message' => '系统默认管理员不可取消']);
 			}
 
-			// 用户编辑前的信息
-			$user = User::find($id);
-
 			try{
 				DB::beginTransaction();
-
 				$data = [
 					'username'        => $request->input('username'),
 					'email'           => $email,
@@ -365,12 +351,12 @@ class AdminController extends Controller {
 					'speed_limit'     => $request->input('speed_limit') * Mbps,
 					'wechat'          => $request->input('wechat'),
 					'qq'              => $request->input('qq'),
-					'enable_time'     => $request->input('enable_time')?: date('Y-m-d'),
-					'expire_time'     => $request->input('expire_time')?: date('Y-m-d', strtotime("+365 days")),
+					'expired_at'      => $request->input('expired_at')?: date('Y-m-d', strtotime("+365 days")),
 					'remark'          => str_replace("eval", "", str_replace("atob", "", $request->input('remark'))),
 					'level'           => $request->input('level'),
 					'group_id'        => $request->input('group_id'),
 					'reset_time'      => $request->input('reset_time'),
+					'invite_num'      => $request->input('invite_num'),
 					'status'          => $status
 				];
 
@@ -384,7 +370,7 @@ class AdminController extends Controller {
 					$data['password'] = Hash::make($password);
 				}
 
-				User::query()->whereId($id)->update($data);
+				$user->update($data);
 
 				// 写入用户流量变动记录
 				if($user->transfer_enable != toGB($transfer_enable)){
@@ -402,19 +388,18 @@ class AdminController extends Controller {
 				return Response::json(['status' => 'fail', 'message' => '编辑失败']);
 			}
 		}else{
-			$user = User::query()->with(['referral'])->whereId($id)->first();
 			if($user){
 				$user->transfer_enable = flowToGB($user->transfer_enable);
 			}
 
-			$view['user'] = $user;
+			$view['user'] = $user->load('inviter:id,email');
 			$view['methodList'] = Helpers::methodList();
 			$view['protocolList'] = Helpers::protocolList();
 			$view['obfsList'] = Helpers::obfsList();
-			$view['levelList'] = Level::query()->orderBy('level')->get();
-			$view['groupList'] = UserGroup::query()->orderBy('id')->get();
+			$view['levelList'] = Level::orderBy('level')->get();
+			$view['groupList'] = UserGroup::orderBy('id')->get();
 
-			return view('admin.user.userInfo', $view)->with(compact('user'));
+			return view('admin.user.userInfo', $view);
 		}
 	}
 
@@ -429,18 +414,13 @@ class AdminController extends Controller {
 		try{
 			DB::beginTransaction();
 
-			User::query()->whereId($id)->delete();
-			UserSubscribe::query()->whereUserId($id)->delete();
-			UserBanedLog::query()->whereUserId($id)->delete();
-			UserCreditLog::query()->whereUserId($id)->delete();
-			UserDataModifyLog::query()->whereUserId($id)->delete();
-			UserLoginLog::query()->whereUserId($id)->delete();
+			User::find($id)->delete();
 
 			DB::commit();
 
 			return Response::json(['status' => 'success', 'message' => '删除成功']);
 		}catch(Exception $e){
-			Log::error($e);
+			Log::error('删除用户信息异常:'.$e->getMessage());
 			DB::rollBack();
 
 			return Response::json(['status' => 'fail', 'message' => '删除失败']);
@@ -449,7 +429,7 @@ class AdminController extends Controller {
 
 	// 文章列表
 	public function articleList(Request $request): \Illuminate\Http\Response {
-		$view['list'] = Article::query()->orderByDesc('sort')->paginate(15)->appends($request->except('page'));
+		$view['list'] = Article::orderByDesc('sort')->paginate(15)->appends($request->except('page'));
 
 		return Response::view('admin.article.articleList', $view);
 	}
@@ -460,7 +440,6 @@ class AdminController extends Controller {
 			$article = new Article();
 			$article->title = $request->input('title');
 			$article->type = $request->input('type', 1);
-			$article->author = '管理员';
 			$article->summary = $request->input('summary');
 			// LOGO
 			if($article->type == 4){
@@ -480,7 +459,6 @@ class AdminController extends Controller {
 				$article = new Article();
 				$article->title = $request->input('title');
 				$article->type = $request->input('type', 1);
-				$article->author = '管理员';
 				$article->summary = $request->input('summary');
 				$article->logo = $logo;
 			}
@@ -533,7 +511,7 @@ class AdminController extends Controller {
 				$data['logo'] = $logo;
 			}
 
-			$ret = Article::query()->whereId($id)->update($data);
+			$ret = Article::whereId($id)->update($data);
 			if($ret){
 				Session::flash('successMsg', '编辑成功');
 			}else{
@@ -552,7 +530,7 @@ class AdminController extends Controller {
 	public function delArticle(Request $request): ?JsonResponse {
 		$id = $request->input('id');
 
-		$ret = Article::query()->whereId($id)->delete();
+		$ret = Article::whereId($id)->delete();
 		if($ret){
 			return Response::json(['status' => 'success', 'message' => '删除成功']);
 		}
@@ -569,7 +547,7 @@ class AdminController extends Controller {
 		$startTime = $request->input('startTime');
 		$endTime = $request->input('endTime');
 
-		$query = UserDataFlowLog::query()->with(['user', 'node']);
+		$query = UserDataFlowLog::with(['user', 'node']);
 
 		if(isset($port)){
 			$query->whereHas('user', static function($q) use ($port) {
@@ -610,7 +588,7 @@ class AdminController extends Controller {
 		}
 
 		$view['list'] = $list;
-		$view['nodeList'] = Node::query()->whereStatus(1)->orderByDesc('sort')->latest()->get();
+		$view['nodeList'] = Node::whereStatus(1)->orderByDesc('sort')->latest()->get();
 
 		return Response::view('admin.logs.trafficLog', $view);
 	}
@@ -646,8 +624,7 @@ class AdminController extends Controller {
 
 		}
 
-		$view['nodeList'] = Node::query()
-		                        ->whereStatus(1)
+		$view['nodeList'] = Node::whereStatus(1)
 		                        ->orderByDesc('sort')
 		                        ->orderBy('id')
 		                        ->paginate(15)
@@ -659,7 +636,7 @@ class AdminController extends Controller {
 
 	// 导出原版SS用户配置信息
 	public function exportSSJson() {
-		$userList = User::query()->where('port', '>', 0)->get();
+		$userList = User::where('port', '>', 0)->get();
 
 		$json = '';
 		if(!$userList->isEmpty()){
@@ -704,7 +681,7 @@ class AdminController extends Controller {
 				return Redirect::back()->withErrors('新密码不可与旧密码一样,请重新输入');
 			}
 
-			$ret = User::uid()->update(['password' => Hash::make($new_password)]);
+			$ret = Auth::getUser()->update(['password' => Hash::make($new_password)]);
 			if(!$ret){
 				return Redirect::back()->withErrors('修改失败');
 			}
@@ -761,17 +738,12 @@ class AdminController extends Controller {
 			return Response::json(['status' => 'success', 'message' => '添加成功']);
 		}
 
-		$labelList = Label::all();
-		foreach($labelList as $label){
-			$label->nodeCount = NodeLabel::query()->whereLabelId($label->id)->groupBy('label_id')->count();
-		}
-
 		$view['methodList'] = SsConfig::type(1)->get();
 		$view['protocolList'] = SsConfig::type(2)->get();
 		$view['obfsList'] = SsConfig::type(3)->get();
 		$view['countryList'] = Country::all();
 		$view['levelList'] = Level::all();
-		$view['labelList'] = $labelList;
+		$view['labelList'] = Label::with('nodes')->get();
 
 		return Response::view('admin.config.config', $view);
 	}
@@ -780,7 +752,7 @@ class AdminController extends Controller {
 	public function delConfig(Request $request): ?JsonResponse {
 		$id = $request->input('id');
 
-		$ret = SsConfig::query()->whereId($id)->delete();
+		$ret = SsConfig::whereId($id)->delete();
 		if($ret){
 			return Response::json(['status' => 'success', 'message' => '删除成功']);
 		}
@@ -805,7 +777,7 @@ class AdminController extends Controller {
 		SsConfig::default()->type($config->type)->update(['is_default' => 0]);
 
 		// 将该ID对应记录值置为默认值
-		SsConfig::query()->whereId($id)->update(['is_default' => 1]);
+		SsConfig::whereId($id)->update(['is_default' => 1]);
 
 		return Response::json(['status' => 'success', 'message' => '操作成功']);
 	}
@@ -825,7 +797,7 @@ class AdminController extends Controller {
 					Session::flash('errorMsg', 'LOGO不合法');
 					return Redirect::back();
 				}
-				Config::query()->whereName('website_home_logo')->update(['value' => $ret]);
+				Config::find('website_home_logo')->update(['value' => $ret]);
 			}
 
 			// 站内LOGO
@@ -835,11 +807,11 @@ class AdminController extends Controller {
 					Session::flash('errorMsg', 'LOGO不合法');
 					return Redirect::back();
 				}
-				Config::query()->whereName('website_logo')->update(['value' => $ret]);
+				Config::find('website_logo')->update(['value' => $ret]);
 			}
 
-			Config::query()->whereName('website_analytics')->update(['value' => $websiteAnalytics]);
-			Config::query()->whereName('website_customer_service')->update(['value' => $websiteCustomerService]);
+			Config::find('website_analytics')->update(['value' => $websiteAnalytics]);
+			Config::find('website_customer_service')->update(['value' => $websiteCustomerService]);
 
 			Session::flash('successMsg', '更新成功');
 
@@ -893,18 +865,18 @@ class AdminController extends Controller {
 			return Response::json(['status' => 'fail', 'message' => $validator->errors()->all()]);
 		}
 		// 校验该等级下是否存在关联账号
-		$levelCheck = Level::query()->where('id', '<>', $id)->whereLevel($level)->exists();
+		$levelCheck = Level::where('id', '<>', $id)->whereLevel($level)->exists();
 		if($levelCheck){
 			return Response::json(['status' => 'fail', 'message' => '该等级已存在!']);
 		}
 
 		// 校验该等级下是否存在关联账号
-		$userCount = User::query()->whereLevel($level)->count();
+		$userCount = User::whereLevel($level)->count();
 		if($userCount){
 			return Response::json(['status' => 'fail', 'message' => '该等级下存在关联账号,请先取消关联!']);
 		}
 
-		Level::query()->whereId($id)->update(['level' => $level, 'name' => $request->input('level_name')]);
+		Level::whereId($id)->update(['level' => $level, 'name' => $request->input('level_name')]);
 
 		return Response::json(['status' => 'success', 'message' => '操作成功']);
 	}
@@ -924,15 +896,15 @@ class AdminController extends Controller {
 		$level = Level::find($id);
 
 		// 校验该等级下是否存在关联账号
-		$userCount = User::query()->whereLevel($level->level)->count();
+		$userCount = User::whereLevel($level->level)->count();
 		if($userCount){
 			return Response::json(['status' => 'fail', 'message' => '该等级下存在关联账号,请先取消关联']);
 		}
 		$ret = false;
 		try{
-			$ret = Level::query()->whereId($id)->delete();
+			$ret = Level::whereId($id)->delete();
 		}catch(Exception $e){
-			Log::error('删除等级时报错:'.$e);
+			Log::error('删除等级时报错:'.$e->getMessage());
 		}
 		if($ret){
 			return Response::json(['status' => 'success', 'message' => '操作成功']);
@@ -942,29 +914,28 @@ class AdminController extends Controller {
 	}
 
 	// 添加国家/地区
-	public function addCountry(Request $request): ?JsonResponse {
-		$name = $request->input('country_name');
-		$code = $request->input('country_code');
-
-		if(empty($name)){
-			return Response::json(['status' => 'fail', 'message' => '国家/地区名称不能为空']);
-		}
+	public function addCountry(Request $request): JsonResponse {
+		$code = $request->input('code');
+		$name = $request->input('name');
 
 		if(empty($code)){
 			return Response::json(['status' => 'fail', 'message' => '国家/地区代码不能为空']);
 		}
 
-		$exists = Country::query()->whereName($name)->first();
+		if(empty($name)){
+			return Response::json(['status' => 'fail', 'message' => '国家/地区名称不能为空']);
+		}
+
+		$exists = Country::find($code);
 		if($exists){
 			return Response::json(['status' => 'fail', 'message' => '该国家/地区名称已存在,请勿重复添加']);
 		}
 
 		$obj = new Country();
-		$obj->name = $name;
 		$obj->code = $code;
-		$obj->save();
+		$obj->name = $name;
 
-		if($obj->id){
+		if($obj->save()){
 			return Response::json(['status' => 'success', 'message' => '提交成功']);
 		}
 
@@ -972,14 +943,9 @@ class AdminController extends Controller {
 	}
 
 	// 编辑国家/地区
-	public function updateCountry(Request $request): ?JsonResponse {
-		$id = $request->input('id');
-		$name = $request->input('country_name');
-		$code = $request->input('country_code');
-
-		if(empty($id)){
-			return Response::json(['status' => 'fail', 'message' => 'ID不能为空']);
-		}
+	public function updateCountry(Request $request): JsonResponse {
+		$code = $request->input('code');
+		$name = $request->input('name');
 
 		if(empty($name)){
 			return Response::json(['status' => 'fail', 'message' => '国家/地区名称不能为空']);
@@ -989,18 +955,17 @@ class AdminController extends Controller {
 			return Response::json(['status' => 'fail', 'message' => '国家/地区代码不能为空']);
 		}
 
-		$country = Country::find($id);
-		if($country){
+		$country = Country::find($code);
+		if(!$country){
 			return Response::json(['status' => 'fail', 'message' => '国家/地区不存在']);
 		}
 
 		// 校验该国家/地区下是否存在关联节点
-		$existNode = Node::query()->whereCountryCode($country->code)->get();
-		if(!$existNode){
+		if(Node::whereCountryCode($country->code)->exists()){
 			return Response::json(['status' => 'fail', 'message' => '该国家/地区下存在关联节点,请先取消关联']);
 		}
 
-		$ret = Country::query()->whereId($id)->update(['name' => $name, 'code' => $code]);
+		$ret = $country->update(['name' => $name, 'code' => $code]);
 		if($ret){
 			return Response::json(['status' => 'success', 'message' => '操作成功']);
 		}
@@ -1010,29 +975,23 @@ class AdminController extends Controller {
 
 	// 删除国家/地区
 	public function delCountry(Request $request): ?JsonResponse {
-		$id = $request->input('id');
+		$code = $request->input('code');
 
 		if(empty($id)){
 			return Response::json(['status' => 'fail', 'message' => 'ID不能为空']);
 		}
 
-		$country = Country::find($id);
+		$country = Country::find($code);
 		if(!$country){
 			return Response::json(['status' => 'fail', 'message' => '国家/地区不存在']);
 		}
 
 		// 校验该国家/地区下是否存在关联节点
-		$existNode = Node::query()->whereCountryCode($country->code)->get();
-		if(!$existNode){
+		if(Node::whereCountryCode($country->code)->exists()){
 			return Response::json(['status' => 'fail', 'message' => '该国家/地区下存在关联节点,请先取消关联']);
 		}
-		$ret = false;
-		try{
-			$ret = Country::query()->whereId($id)->delete();
-		}catch(Exception $e){
-			Log::error('删除国家/地区时报错:'.$e);
-		}
-		if($ret){
+
+		if($country->delete()){
 			return Response::json(['status' => 'success', 'message' => '操作成功']);
 		}
 
@@ -1042,7 +1001,7 @@ class AdminController extends Controller {
 	// 系统设置
 	public function system(): \Illuminate\Http\Response {
 		$view = self::$sysConfig;
-		$view['labelList'] = Label::query()->orderByDesc('sort')->orderBy('id')->get();
+		$view['labelList'] = Label::orderByDesc('sort')->orderBy('id')->get();
 
 		return Response::view('admin.config.system', $view);
 	}
@@ -1064,19 +1023,19 @@ class AdminController extends Controller {
 		// 如果开启用户邮件重置密码,则先设置网站名称和网址
 		if($value !== '0'
 		   && in_array($name, ['is_reset_password', 'is_activate_account', 'expire_warning', 'traffic_warning'], true)){
-			$config = Config::query()->whereName('website_name')->firstOrFail();
+			$config = Config::find('website_name');
 			if(!$config->value){
 				return Response::json(['status' => 'fail', 'message' => '设置失败:启用该配置需要先设置【网站名称】']);
 			}
 
-			$config = Config::query()->whereName('website_url')->firstOrFail();
+			$config = Config::find('website_url');
 			if(!$config->value){
 				return Response::json(['status' => 'fail', 'message' => '设置失败:启用该配置需要先设置【网站地址】']);
 			}
 		}
 
 		// 支付设置判断
-		if($value !== '' && in_array($name, ['is_AliPay', 'is_QQPay', 'is_WeChatPay', 'is_otherPay'], true)){
+		if($value !== null && in_array($name, ['is_AliPay', 'is_QQPay', 'is_WeChatPay', 'is_otherPay'], true)){
 			switch($value){
 				case 'f2fpay':
 					if(!self::$sysConfig['f2fpay_app_id'] || !self::$sysConfig['f2fpay_private_key']
@@ -1139,7 +1098,7 @@ class AdminController extends Controller {
 		}
 
 		// 更新配置
-		Config::query()->whereName($name)->update(['value' => $value]);
+		Config::find($name)->update(['value' => $value]);
 
 		return Response::json(['status' => 'success', 'message' => '操作成功']);
 	}
@@ -1173,8 +1132,7 @@ class AdminController extends Controller {
 
 	// 邀请码列表
 	public function inviteList(Request $request): \Illuminate\Http\Response {
-		$view['inviteList'] = Invite::query()
-		                            ->with(['generator', 'user'])
+		$view['inviteList'] = Invite::with(['invitee:id,email', 'inviter:id,email'])
 		                            ->orderBy('status')
 		                            ->latest()
 		                            ->paginate(15)
@@ -1187,8 +1145,8 @@ class AdminController extends Controller {
 	public function makeInvite(): JsonResponse {
 		for($i = 0; $i < 10; $i++){
 			$obj = new Invite();
-			$obj->uid = 0;
-			$obj->fuid = 0;
+			$obj->inviter_id = 0;
+			$obj->invitee_id = 0;
 			$obj->code = strtoupper(substr(md5(microtime().makeRandStr()), 8, 12));
 			$obj->status = 0;
 			$obj->dateline = date('Y-m-d H:i:s', strtotime("+".self::$sysConfig['admin_invite_days']." days"));
@@ -1200,7 +1158,7 @@ class AdminController extends Controller {
 
 	// 导出邀请码
 	public function exportInvite(): void {
-		$inviteList = Invite::query()->whereStatus(0)->orderBy('id')->get();
+		$inviteList = Invite::whereStatus(0)->orderBy('id')->get();
 
 		$filename = '邀请码'.date('Ymd').'.xlsx';
 
@@ -1231,7 +1189,7 @@ class AdminController extends Controller {
 			$writer = new Xlsx($spreadsheet);
 			$writer->save('php://output');
 		}catch(\PhpOffice\PhpSpreadsheet\Exception $e){
-			Log::error('导出优惠券时报错'.$e);
+			Log::error('导出优惠券时报错'.$e->getMessage());
 		}
 	}
 
@@ -1245,9 +1203,9 @@ class AdminController extends Controller {
 		$status = $request->input('status');
 		$range_time = $request->input('range_time');
 		$sort = $request->input('sort'); // 0-按创建时间降序、1-按创建时间升序
-		$order_id = $request->input('oid');
+		$order_id = $request->input('id');
 
-		$query = Order::query()->with(['user', 'goods', 'coupon']);
+		$query = Order::with(['user:id,email', 'goods:id,name', 'coupon:id,name,sn']);
 
 		if(isset($email)){
 			$query->whereHas('user', static function($q) use ($email) {
@@ -1284,13 +1242,13 @@ class AdminController extends Controller {
 		}
 
 		if(isset($order_id)){
-			$query->whereOid($order_id);
+			$query->whereId($order_id);
 		}
 
 		if($sort){
-			$query->orderBy('oid');
+			$query->orderBy('id');
 		}else{
-			$query->orderByDesc('oid');
+			$query->orderByDesc('id');
 		}
 
 		$view['orderList'] = $query->paginate(15)->appends($request->except('page'));
@@ -1302,7 +1260,7 @@ class AdminController extends Controller {
 	public function resetUserTraffic(Request $request): JsonResponse {
 		$id = $request->input('id');
 
-		User::query()->whereId($id)->update(['u' => 0, 'd' => 0]);
+		User::find($id)->update(['u' => 0, 'd' => 0]);
 
 		return Response::json(['status' => 'success', 'message' => '操作成功']);
 	}
@@ -1322,13 +1280,7 @@ class AdminController extends Controller {
 			Helpers::addUserCreditLog($userId, 0, $user->credit, $user->credit + $amount, $amount, '后台手动充值');
 
 			// 加减余额
-			if($amount < 0){
-				$ret = User::whereId($user->id)->decrement('credit', abs($amount) * 100);
-			}else{
-				$ret = User::whereId($user->id)->increment('credit', $amount * 100);
-			}
-
-			if($ret){
+			if((new UserService($user))->updateCredit($amount)){
 				return Response::json(['status' => 'success', 'message' => '充值成功']);
 			}
 
@@ -1342,7 +1294,7 @@ class AdminController extends Controller {
 	public function userCreditLogList(Request $request): \Illuminate\Http\Response {
 		$email = $request->input('email');
 
-		$query = UserCreditLog::query()->with(['user'])->latest();
+		$query = UserCreditLog::with('user:id,email')->latest();
 
 		if(isset($email)){
 			$query->whereHas('user', static function($q) use ($email) {
@@ -1359,7 +1311,7 @@ class AdminController extends Controller {
 	public function userBanLogList(Request $request): \Illuminate\Http\Response {
 		$email = $request->input('email');
 
-		$query = UserBanedLog::query()->with(['user'])->latest();
+		$query = UserBanedLog::with('user:id,email,t')->latest();
 
 		if(isset($email)){
 			$query->whereHas('user', static function($q) use ($email) {
@@ -1376,7 +1328,7 @@ class AdminController extends Controller {
 	public function userTrafficLogList(Request $request): \Illuminate\Http\Response {
 		$email = $request->input('email');
 
-		$query = UserDataModifyLog::query()->with(['user', 'order', 'order.goods']);
+		$query = UserDataModifyLog::with(['user:id,email', 'order.goods:id,name']);
 
 		if(isset($email)){
 			$query->whereHas('user', static function($q) use ($email) {
@@ -1396,7 +1348,7 @@ class AdminController extends Controller {
 		$wechat = $request->input('wechat');
 		$qq = $request->input('qq');
 
-		$query = User::query()->activeUser();
+		$query = User::activeUser();
 
 		if(isset($email)){
 			$query->where('email', 'like', '%'.$email.'%');
@@ -1415,18 +1367,15 @@ class AdminController extends Controller {
 		}
 
 		$userList = $query->paginate(15)->appends($request->except('page'));
-		if(!$userList->isEmpty()){
-			foreach($userList as $user){
-				// 最近5条在线IP记录,如果后端设置为60秒上报一次,则为10分钟内的在线IP
-				$user->onlineIPList = NodeOnlineUserIp::query()
-				                                      ->with(['node'])
-				                                      ->whereType('tcp')
-				                                      ->wherePort($user->port)
-				                                      ->where('created_at', '>=', strtotime("-10 minutes"))
-				                                      ->latest()
-				                                      ->limit(5)
-				                                      ->get();
-			}
+
+		$nodeOnlineIPs = NodeOnlineUserIp::with('node:id,name')
+		                                 ->where('created_at', '>=', strtotime("-10 minutes"))
+		                                 ->latest()
+		                                 ->distinct();
+		// Todo 优化查询
+		foreach($userList as $user){
+			// 最近5条在线IP记录,如果后端设置为60秒上报一次,则为10分钟内的在线IP
+			$user->onlineIPList = $nodeOnlineIPs->wherePort($user->port)->limit(5)->get();
 		}
 
 		$view['userList'] = $userList;
@@ -1474,7 +1423,7 @@ class AdminController extends Controller {
 			$name = $request->input('name');
 			$sort = $request->input('sort');
 
-			Label::query()->whereId($id)->update(['name' => $name, 'sort' => $sort]);
+			Label::whereId($id)->update(['name' => $name, 'sort' => $sort]);
 
 			return Response::json(['status' => 'success', 'message' => '添加成功']);
 		}
@@ -1492,8 +1441,8 @@ class AdminController extends Controller {
 		try{
 			DB::beginTransaction();
 
-			Label::query()->whereId($id)->delete();
-			NodeLabel::query()->whereLabelId($id)->delete(); // 删除节点关联
+			Label::whereId($id)->delete();
+			NodeLabel::whereLabelId($id)->delete(); // 删除节点关联
 
 			DB::commit();
 
@@ -1533,9 +1482,7 @@ class AdminController extends Controller {
 		$nodeId = $request->input('nodeId');
 		$userId = $request->input('id');
 
-		$query = NodeOnlineUserIp::query()
-		                         ->with(['node', 'user'])
-		                         ->where('created_at', '>=', strtotime("-120 seconds"));
+		$query = NodeOnlineUserIp::with(['node:id,name', 'user:id,name'])->where('created_at', '>=', strtotime("-2 minutes"));
 
 		if(isset($ip)){
 			$query->whereIp($ip);
@@ -1586,7 +1533,7 @@ class AdminController extends Controller {
 		}
 
 		$view['list'] = $list->paginate(20)->appends($request->except('page'));
-		$view['nodeList'] = Node::query()->whereStatus(1)->orderByDesc('sort')->latest()->get();
+		$view['nodeList'] = Node::whereStatus(1)->orderByDesc('sort')->latest()->get();
 
 		return Response::view('admin.logs.onlineIPMonitor', $view);
 	}

+ 0 - 136
app/Http/Controllers/Api/LoginController.php

@@ -1,136 +0,0 @@
-<?php
-
-namespace App\Http\Controllers\Api;
-
-use App\Http\Controllers\Controller;
-use App\Models\Node;
-use App\Models\User;
-use App\Models\UserSubscribe;
-use App\Models\UserSubscribeLog;
-use Cache;
-use DB;
-use Exception;
-use Hash;
-use Illuminate\Http\JsonResponse;
-use Illuminate\Http\Request;
-use Response;
-
-/**
- * 登录接口
- *
- * Class LoginController
- *
- * @package App\Http\Controllers
- */
-class LoginController extends Controller {
-	// 登录返回订阅信息
-	public function login(Request $request): ?JsonResponse {
-		$email = $request->input('email');
-		$password = $request->input('password');
-		$cacheKey = 'request_times_'.md5(getClientIp());
-
-		if(!$email || !$password){
-			Cache::increment($cacheKey);
-
-			return Response::json(['status' => 'fail', 'message' => '请输入用户名和密码']);
-		}
-
-		// 连续请求失败15次,则封IP一小时
-		if(Cache::has($cacheKey)){
-			if(Cache::get($cacheKey) >= 15){
-				return Response::json(['status' => 'fail', 'message' => '请求失败超限,禁止访问1小时']);
-			}
-		}else{
-			Cache::put($cacheKey, 1, Hour);
-		}
-
-		$user = User::query()->whereEmail($email)->where('status', '>=', 0)->first();
-		if(!$user){
-			Cache::increment($cacheKey);
-
-			return Response::json(['status' => 'fail', 'message' => '账号不存在或已被禁用']);
-		}
-
-		if(!Hash::check($password, $user->password)){
-			return Response::json(['status' => 'fail', 'message' => '用户名或密码错误']);
-		}
-
-		try{
-			DB::beginTransaction();
-			// 如果未生成过订阅链接则生成一个
-			$subscribe = UserSubscribe::query()->whereUserId($user->id)->firstOrFail();
-
-			// 更新订阅链接访问次数
-			$subscribe->increment('times', 1);
-
-			// 记录每次请求
-			$this->subscribeLog($subscribe->id, getClientIp(), 'API访问');
-
-			// 订阅链接
-			$url = sysConfig('subscribe_domain')?: sysConfig('website_url');
-
-			// 节点列表
-			$nodeList = Node::query()
-			                ->whereStatus(1)
-			                ->GroupNodePermit($user->group_id)
-			                ->where('level', '<=', $user->level)
-			                ->orderByDesc('sort')
-			                ->orderBy('id')
-			                ->get();
-
-			$c_nodes = collect();
-			foreach($nodeList as $node){
-				$temp_node = [
-					'name'          => $node->name,
-					'server'        => $node->server,
-					'server_port'   => $user->port,
-					'method'        => $user->method,
-					'obfs'          => $user->obfs,
-					'flags'         => $url.'/assets/images/country/'.$node->country_code.'.png',
-					'obfsparam'     => '',
-					'password'      => $user->passwd,
-					'group'         => '',
-					'protocol'      => $user->protocol,
-					'protoparam'    => '',
-					'protocolparam' => ''
-				];
-				$c_nodes = $c_nodes->push($temp_node);
-			}
-
-			$data = [
-				'status'       => 1,
-				'class'        => 0,
-				'level'        => 2,
-				'expire_in'    => $user->expire_time,
-				'text'         => '',
-				'buy_link'     => '',
-				'money'        => '0.00',
-				'sspannelName' => 'proxypanel',
-				'usedTraffic'  => flowAutoShow($user->u + $user->d),
-				'Traffic'      => flowAutoShow($user->transfer_enable),
-				'all'          => 1,
-				'residue'      => '',
-				'nodes'        => $c_nodes,
-				'link'         => $url.'/s/'.$subscribe->code
-			];
-
-			DB::commit();
-
-			return Response::json(['status' => 'success', 'data' => $data, 'message' => '登录成功']);
-		}catch(Exception $e){
-			DB::rollBack();
-
-			return Response::json(['status' => 'success', 'message' => '登录失败']);
-		}
-	}
-
-	// 写入订阅访问日志
-	private function subscribeLog($subscribeId, $ip, $headers): void {
-		$log = new UserSubscribeLog();
-		$log->sid = $subscribeId;
-		$log->request_ip = $ip;
-		$log->request_time = date('Y-m-d H:i:s');
-		$log->request_header = $headers;
-		$log->save();
-	}
-}

+ 0 - 77
app/Http/Controllers/Api/PingController.php

@@ -1,77 +0,0 @@
-<?php
-
-namespace App\Http\Controllers\Api;
-
-use App\Http\Controllers\Controller;
-use Exception;
-use Illuminate\Http\Request;
-use Log;
-
-/**
- * PING检测工具
- *
- * Class PingController
- *
- * @package App\Http\Controllers\Api
- */
-class PingController extends Controller {
-	public function ping(Request $request) {
-		$token = $request->input('token');
-		$host = $request->input('host');
-		$port = $request->input('port', 22);
-		$transport = $request->input('transport', 'tcp');
-		$timeout = $request->input('timeout', 0.5);
-
-		if(empty($host)){
-			echo "<pre>";
-			echo "使用方法:";
-			echo "<br>";
-			echo "GET /api/ping?token=toke_value&host=www.baidu.com&port=80&transport=tcp&timeout=0.5";
-			echo "<br>";
-			echo "token:.env下加入API_TOKEN,其值就是token的值";
-			echo "<br>";
-			echo "host:检测地址,必传,可以是域名、IPv4、IPv6";
-			echo "<br>";
-			echo "port:检测端口,可不传,默认22";
-			echo "<br>";
-			echo "transport:检测协议,可不传,默认tcp,可以是tcp、udp";
-			echo "<br>";
-			echo "timeout:检测超时,单位秒,可不传,默认0.5秒,建议不超过3秒";
-			echo "<br>";
-			echo "成功返回:1,失败返回:0";
-			echo "</pre>";
-			exit();
-		}
-
-		// 验证TOKEN,防止滥用
-		if(env('API_TOKEN') != $token){
-			return response()->json(['status' => 0, 'message' => 'token invalid']);
-		}
-
-		if((false === filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))// 如果不是IPv4
-		   && filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){// 如果是IPv6
-			$host = '['.$host.']';
-		}
-
-		try{
-			$host = gethostbyname($host); // 这里如果挂了,说明服务器的DNS解析不给力,必须换
-			$fp = stream_socket_client($transport.'://'.$host.':'.$port, $errno, $errstr, $timeout);
-			if(!$fp){
-				Log::info("$errstr ($errno)");
-				$ret = 0;
-				$message = 'port close';
-			}else{
-				$ret = 1;
-				$message = 'port open';
-			}
-
-			fclose($fp);
-
-			return response()->json(['status' => $ret, 'message' => $message]);
-		}catch(Exception $e){
-			Log::info($e);
-
-			return response()->json(['status' => 0, 'message' => 'port close']);
-		}
-	}
-}

+ 4 - 5
app/Http/Controllers/Api/WebApi/BaseController.php

@@ -3,7 +3,7 @@
 namespace App\Http\Controllers\Api\WebApi;
 
 use App\Models\Node;
-use App\Models\NodeInfo;
+use App\Models\NodeHeartBeat;
 use App\Models\NodeOnlineLog;
 use App\Models\NodeOnlineUserIp;
 use App\Models\Rule;
@@ -27,7 +27,7 @@ class BaseController {
 			return $this->returnData('上报节点心跳信息失败,请检查字段');
 		}
 
-		$obj = new NodeInfo();
+		$obj = new NodeHeartBeat();
 		$obj->node_id = $id;
 		$obj->uptime = (int) $request->input('uptime');
 		//$obj->load = $request->input('load');
@@ -129,7 +129,7 @@ class BaseController {
 
 	// 获取节点的审计规则
 	public function getNodeRule($id): JsonResponse {
-		$nodeRule = RuleGroupNode::query()->whereNodeId($id)->first();
+		$nodeRule = RuleGroupNode::whereNodeId($id)->first();
 		$data = [];
 		//节点未设置任何审计规则
 		if($nodeRule){
@@ -138,12 +138,11 @@ class BaseController {
 				foreach($ruleGroup->rules as $ruleId){
 					$rule = Rule::find($ruleId);
 					if($rule){
-						$new = [
+						$data[] = [
 							'id'      => $rule->id,
 							'type'    => $rule->type_api_label,
 							'pattern' => $rule->pattern
 						];
-						$data[] = $new;
 					}
 				}
 

+ 2 - 5
app/Http/Controllers/Api/WebApi/TrojanController.php

@@ -3,7 +3,6 @@
 namespace App\Http\Controllers\Api\WebApi;
 
 use App\Models\Node;
-use App\Models\User;
 use Illuminate\Http\JsonResponse;
 
 class TrojanController extends BaseController {
@@ -26,17 +25,15 @@ class TrojanController extends BaseController {
 
 	// 获取节点可用的用户列表
 	public function getUserList($id): JsonResponse {
-		$node = Node::find($id);
-		$users = User::query()->activeUser()->groupUserPermit($node->id)->where('level', '>=', $node->level)->get();
+		$users = Node::find($id)->node_access_users;
 		$data = [];
 
 		foreach($users as $user){
-			$new = [
+			$data[] = [
 				'uid'         => $user->id,
 				'password'    => $user->passwd,
 				'speed_limit' => $user->speed_limit
 			];
-			$data[] = $new;
 		}
 
 		return $this->returnData('获取用户列表成功', 'success', 200, $data, ['updateTime' => time()]);

+ 5 - 8
app/Http/Controllers/Api/WebApi/V2RayController.php

@@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api\WebApi;
 
 use App\Models\Node;
 use App\Models\NodeCertificate;
-use App\Models\User;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 
@@ -12,7 +11,7 @@ class V2RayController extends BaseController {
 	// 获取节点信息
 	public function getNodeInfo($id): JsonResponse {
 		$node = Node::find($id);
-		$nodeDv = NodeCertificate::query()->whereDomain($node->v2_host)->first();
+		$nodeDv = NodeCertificate::whereDomain($node->v2_host)->first();
 
 		return $this->returnData('获取节点信息成功', 'success', 200, [
 			'id'              => $node->id,
@@ -39,17 +38,15 @@ class V2RayController extends BaseController {
 
 	// 获取节点可用的用户列表
 	public function getUserList($id): JsonResponse {
-		$node = Node::find($id);
-		$users = User::query()->activeUser()->groupUserPermit($node->id)->where('level', '>=', $node->level)->get();
+		$users = Node::find($id)->node_access_users;
 		$data = [];
 
 		foreach($users as $user){
-			$new = [
+			$data[] = [
 				'uid'         => $user->id,
 				'vmess_uid'   => $user->vmess_id,
 				'speed_limit' => $user->speed_limit
 			];
-			$data[] = $new;
 		}
 
 		return $this->returnData('获取用户列表成功', 'success', 200, $data, ['updateTime' => time()]);
@@ -62,9 +59,9 @@ class V2RayController extends BaseController {
 
 		if($request->has(['key', 'pem'])){
 			$node = Node::find($id);
-			$Dv = NodeCertificate::query()->whereDomain($node->v2_host)->first();
+			$Dv = NodeCertificate::whereDomain($node->v2_host)->first();
 			if($Dv){
-				$ret = NodeCertificate::query()->whereId($Dv->id)->update(['key' => $key, 'pem' => $pem]);
+				$ret = NodeCertificate::whereId($Dv->id)->update(['key' => $key, 'pem' => $pem]);
 			}else{
 				$ret = new NodeCertificate();
 				$ret->domain = $node->server;

+ 2 - 4
app/Http/Controllers/Api/WebApi/VNetController.php

@@ -3,7 +3,6 @@
 namespace App\Http\Controllers\Api\WebApi;
 
 use App\Models\Node;
-use App\Models\User;
 use Illuminate\Http\JsonResponse;
 
 class VNetController extends BaseController {
@@ -32,11 +31,11 @@ class VNetController extends BaseController {
 	// 获取节点可用的用户列表
 	public function getUserList($id): JsonResponse {
 		$node = Node::find($id);
-		$users = User::query()->activeUser()->groupUserPermit($node->id)->where('level', '>=', $node->level)->get();
+		$users = $node->node_access_users;
 		$data = [];
 
 		foreach($users as $user){
-			$new = [
+			$data[] = [
 				'uid'         => $user->id,
 				'port'        => $user->port,
 				'passwd'      => $user->passwd,
@@ -47,7 +46,6 @@ class VNetController extends BaseController {
 				'speed_limit' => $user->speed_limit,
 				'enable'      => $user->enable
 			];
-			$data[] = $new;
 		}
 
 		if($data){

+ 41 - 61
app/Http/Controllers/AuthController.php

@@ -15,6 +15,7 @@ use App\Models\UserLoginLog;
 use App\Models\UserSubscribe;
 use App\Models\Verify;
 use App\Models\VerifyCode;
+use App\Services\UserService;
 use Auth;
 use Cache;
 use Captcha;
@@ -100,7 +101,7 @@ class AuthController extends Controller {
 			$this->addUserLoginLog($user->id, getClientIp());
 
 			// 更新登录信息
-			User::uid()->update(['last_login' => time()]);
+			Auth::getUser()->update(['last_login' => time()]);
 
 			// 根据权限跳转
 			if($user->is_admin){
@@ -284,8 +285,7 @@ class AuthController extends Controller {
 
 				// 校验邀请码合法性
 				if($code){
-					$codeEnable = Invite::query()->whereCode($code)->whereStatus(0)->doesntExist();
-					if($codeEnable){
+					if($Invite::whereCode($code)->whereStatus(0)->doesntExist()){
 						return Redirect::back()
 						               ->withInput($request->except(['code']))
 						               ->withErrors(trans('auth.code_error'));
@@ -301,11 +301,7 @@ class AuthController extends Controller {
 					               ->withErrors(trans('auth.captcha_null'));
 				}
 
-				$verifyCode = VerifyCode::query()
-				                        ->whereAddress($email)
-				                        ->whereCode($verify_code)
-				                        ->whereStatus(0)
-				                        ->firstOrFail();
+				$verifyCode = VerifyCode::whereAddress($email)->whereCode($verify_code)->whereStatus(0)->first();
 				if(!$verifyCode){
 					return Redirect::back()
 					               ->withInput($request->except(['verify_code']))
@@ -340,20 +336,20 @@ class AuthController extends Controller {
 
 			// 获取aff
 			$affArr = $this->getAff($code, $aff);
-			$referral_uid = $affArr['referral_uid'];
+			$inviter_id = $affArr['inviter_id'];
 
-			$transfer_enable = MB * (self::$sysConfig['default_traffic'] + ($referral_uid? self::$sysConfig['referral_traffic'] : 0));
+			$transfer_enable = MB * (self::$sysConfig['default_traffic'] + ($inviter_id? self::$sysConfig['referral_traffic'] : 0));
 
 			// 创建新用户
-			$uid = Helpers::addUser($email, Hash::make($password), $transfer_enable,
-				self::$sysConfig['default_days'], $referral_uid);
+			$uid = Helpers::addUser($email, Hash::make($password), $transfer_enable, self::$sysConfig['default_days'],
+				$inviter_id);
 
 			// 注册失败,抛出异常
 			if(!$uid){
 				return Redirect::back()->withInput()->withErrors(trans('auth.register_fail'));
 			}
 			// 更新昵称
-			User::query()->whereId($uid)->update(['username' => $username]);
+			User::find($uid)->update(['username' => $username]);
 
 			// 生成订阅码
 			$subscribe = new UserSubscribe();
@@ -371,7 +367,7 @@ class AuthController extends Controller {
 
 			// 更新邀请码
 			if(self::$sysConfig['is_invite_register'] && $affArr['code_id']){
-				Invite::query()->whereId($affArr['code_id'])->update(['fuid' => $uid, 'status' => 1]);
+				Invite::find($affArr['code_id'])->update(['invitee_id' => $uid, 'status' => 1]);
 			}
 
 			// 清除邀请人Cookie
@@ -389,17 +385,15 @@ class AuthController extends Controller {
 				Session::flash('regSuccessMsg', trans('auth.register_active_tip'));
 			}else{
 				// 则直接给推荐人加流量
-				if($referral_uid){
-					$referralUser = User::find($referral_uid);
-					if($referralUser && $referralUser->expire_time >= date('Y-m-d')){
-						User::query()
-						    ->whereId($referral_uid)
-						    ->increment('transfer_enable', self::$sysConfig['referral_traffic'] * MB);
+				if($inviter_id){
+					$referralUser = User::find($inviter_id);
+					if($referralUser && $referralUser->expired_at >= date('Y-m-d')){
+						(new UserService($referralUser))->incrementData(self::$sysConfig['referral_traffic'] * MB);
 					}
 				}
 
 				if(self::$sysConfig['is_activate_account'] == 1){
-					User::query()->whereId($uid)->update(['status' => 1]);
+					User::find($uid)->update(['status' => 1]);
 				}
 
 				Session::flash('regSuccessMsg', trans('auth.register_success'));
@@ -408,9 +402,7 @@ class AuthController extends Controller {
 			return Redirect::to('login')->withInput();
 		}
 
-		$view['emailList'] = self::$sysConfig['is_email_filtering'] != 2? false : EmailFilter::query()
-		                                                                                        ->whereType(2)
-		                                                                                        ->get();
+		$view['emailList'] = self::$sysConfig['is_email_filtering'] != 2? false : EmailFilter::whereType(2)->get();
 		Session::put('register_token', makeRandStr(16));
 
 		return Response::view('auth.register', $view);
@@ -452,44 +444,35 @@ class AuthController extends Controller {
 	/**
 	 * 获取AFF
 	 *
-	 * @param  string    $code  邀请码
-	 * @param  int|null  $aff   URL中的aff参数
+	 * @param  string|null  $code  邀请码
+	 * @param  int|null     $aff   URL中的aff参数
 	 *
 	 * @return array
 	 */
-	private function getAff($code = '', $aff = null): array {
-		// 邀请人ID
-		$referral_uid = 0;
-
-		// 邀请码ID
-		$code_id = 0;
+	private function getAff($code = null, $aff = null): array {
+		$data = ['inviter_id' => null, 'code_id' => 0];// 邀请人ID 与 邀请码ID
 
 		// 有邀请码先用邀请码,用谁的邀请码就给谁返利
 		if($code){
-			$inviteCode = Invite::query()->whereCode($code)->whereStatus(0)->first();
+			$inviteCode = Invite::whereCode($code)->whereStatus(0)->first();
 			if($inviteCode){
-				$referral_uid = $inviteCode->uid;
-				$code_id = $inviteCode->id;
+				$data['inviter_id'] = $inviteCode->inviter_id;
+				$data['code_id'] = $inviteCode->id;
 			}
 		}
 
 		// 没有用邀请码或者邀请码是管理员生成的,则检查cookie或者url链接
-		if(!$referral_uid){
+		if(!$data['inviter_id']){
 			// 检查一下cookie里有没有aff
 			$cookieAff = \Request::hasCookie('register_aff')? \Request::cookie('register_aff') : 0;
 			if($cookieAff){
-				$affUser = User::query()->whereId($cookieAff)->exists();
-				$referral_uid = $affUser? $cookieAff : 0;
+				$data['inviter_id'] = User::find($cookieAff)? $cookieAff : 0;
 			}elseif($aff){ // 如果cookie里没有aff,就再检查一下请求的url里有没有aff,因为有些人的浏览器会禁用了cookie,比如chrome开了隐私模式
-				$affUser = User::query()->whereId($aff)->exists();
-				$referral_uid = $affUser? $aff : 0;
+				$data['inviter_id'] = User::find($aff)? $aff : 0;
 			}
 		}
 
-		return [
-			'referral_uid' => $referral_uid,
-			'code_id'      => $code_id
-		];
+		return $data;
 	}
 
 	// 生成申请的请求地址
@@ -529,7 +512,7 @@ class AuthController extends Controller {
 			}
 
 			// 查找账号
-			$user = User::query()->whereEmail($email)->first();
+			$user = User::whereEmail($email)->first();
 			if(!$user){
 				return Redirect::back()->withErrors(trans('auth.email_notExist'));
 			}
@@ -585,7 +568,8 @@ class AuthController extends Controller {
 
 			$password = $request->input('password');
 			// 校验账号
-			$verify = Verify::type(1)->with('user')->whereToken($token)->first();
+			$verify = Verify::type(1)->whereToken($token)->first();
+			$user = $verify->user;
 			if(!$verify){
 				return Redirect::to('login');
 			}
@@ -594,7 +578,7 @@ class AuthController extends Controller {
 				return Redirect::back()->withErrors(trans('auth.overtime'));
 			}
 
-			if($verify->user->status < 0){
+			if($user->status < 0){
 				return Redirect::back()->withErrors(trans('auth.email_banned'));
 			}
 
@@ -603,8 +587,7 @@ class AuthController extends Controller {
 			}
 
 			// 更新密码
-			$ret = User::query()->whereId($verify->user_id)->update(['password' => Hash::make($password)]);
-			if(!$ret){
+			if(!$user->update(['password' => Hash::make($password)])){
 				return Redirect::back()->withErrors(trans('auth.reset_password_fail'));
 			}
 
@@ -656,7 +639,7 @@ class AuthController extends Controller {
 			}
 
 			// 查找账号
-			$user = User::query()->whereEmail($email)->firstOrFail();
+			$user = User::whereEmail($email)->firstOrFail();
 			if($user->status < 0){
 				return Redirect::back()->withErrors(trans('auth.login_ban',
 					['email' => self::$sysConfig['webmaster_email']]));
@@ -700,11 +683,12 @@ class AuthController extends Controller {
 		}
 
 		$verify = Verify::type(1)->with('user')->whereToken($token)->first();
+		$user = $verify->user;
 		if(!$verify){
 			return Redirect::to('login');
 		}
 
-		if(empty($verify->user)){
+		if(empty($user)){
 			Session::flash('errorMsg', trans('auth.overtime'));
 
 			return Response::view('auth.active');
@@ -716,7 +700,7 @@ class AuthController extends Controller {
 			return Response::view('auth.active');
 		}
 
-		if($verify->user->status != 0){
+		if($user->status != 0){
 			Session::flash('errorMsg', trans('auth.email_normal'));
 
 			return Response::view('auth.active');
@@ -733,8 +717,7 @@ class AuthController extends Controller {
 		}
 
 		// 更新账号状态
-		$ret = User::query()->whereId($verify->user_id)->update(['status' => 1]);
-		if(!$ret){
+		if(!$user->update(['status' => 1])){
 			Session::flash('errorMsg', trans('auth.active_fail'));
 
 			return Redirect::back();
@@ -745,12 +728,9 @@ class AuthController extends Controller {
 		$verify->save();
 
 		// 账号激活后给邀请人送流量
-		if($verify->user->referral_uid){
-			$transfer_enable = self::$sysConfig['referral_traffic'] * MB;
-
-			User::query()
-			    ->whereId($verify->user->referral_uid)
-			    ->increment('transfer_enable', $transfer_enable, ['enable' => 1]);
+		$inviter = $user->inviter;
+		if($inviter){
+			(new UserService($inviter))->incrementData(self::$sysConfig['referral_traffic'] * MB);
 		}
 
 		Session::flash('successMsg', trans('auth.active_success'));
@@ -815,7 +795,7 @@ class AuthController extends Controller {
 
 	// 公开的邀请码列表
 	public function free(): \Illuminate\Http\Response {
-		$view['inviteList'] = Invite::query()->whereUid(0)->whereStatus(0)->paginate();
+		$view['inviteList'] = Invite::whereInviterId(0)->whereStatus(0)->paginate();
 
 		return Response::view('auth.free', $view);
 	}

+ 10 - 11
app/Http/Controllers/Controller.php

@@ -91,7 +91,7 @@ class Controller extends BaseController {
 
 	// 获取邮箱后缀
 	public function emailFilterList($type): array {
-		return EmailFilter::query()->whereType($type)->pluck('words')->toArray();
+		return EmailFilter::whereType($type)->pluck('words')->toArray();
 	}
 
 	// 将Base64图片转换为本地图片并保存
@@ -146,11 +146,10 @@ class Controller extends BaseController {
 	 * @return string
 	 */
 	public function getUserNodeInfo($uid, $nodeId, $infoType): string {
-		$user = User::whereId($uid)->firstOrFail();
-		$node = Node::whereId($nodeId)->firstOrFail();
+		$user = User::find($uid);
+		$node = Node::find($nodeId);
 		$scheme = null;
-		// 获取分组名称
-		$group = $node->level_name;
+		$group = sysConfig('website_name');// 分组名称
 		$host = $node->is_relay? $node->relay_server : ($node->server?: $node->ip);
 		$data = null;
 		switch($node->type){
@@ -241,13 +240,13 @@ class Controller extends BaseController {
 	// 流量使用图表
 	public function dataFlowChart($id, $is_node = 0): array {
 		if($is_node){
-			$currentFlow = UserDataFlowLog::query()->whereNodeId($id);
-			$hourlyFlow = NodeHourlyDataFlow::query()->whereNodeId($id);
-			$dailyFlow = NodeDailyDataFlow::query()->whereNodeId($id);
+			$currentFlow = UserDataFlowLog::whereNodeId($id);
+			$hourlyFlow = NodeHourlyDataFlow::whereNodeId($id);
+			$dailyFlow = NodeDailyDataFlow::whereNodeId($id);
 		}else{
-			$currentFlow = UserDataFlowLog::query()->whereUserId($id);
-			$hourlyFlow = UserHourlyDataFlow::query()->userHourly($id);
-			$dailyFlow = UserDailyDataFlow::query()->userDaily($id);
+			$currentFlow = UserDataFlowLog::whereUserId($id);
+			$hourlyFlow = UserHourlyDataFlow::userHourly($id);
+			$dailyFlow = UserDailyDataFlow::userDaily($id);
 		}
 		$currentFlow = $currentFlow->where('log_time', '>=', strtotime(date('Y-m-d H:00')))->sum(DB::raw('u + d'));
 		$hourlyFlow = $hourlyFlow->whereDate('created_at', date('Y-m-d'))->pluck('total', 'created_at')->toArray();

+ 1 - 142
app/Http/Controllers/Gateway/AbstractPayment.php

@@ -3,15 +3,10 @@
 namespace App\Http\Controllers\Gateway;
 
 use App\Components\Helpers;
-use App\Models\Goods;
-use App\Models\Order;
 use App\Models\Payment;
 use App\Models\PaymentCallback;
-use App\Models\ReferralLog;
-use App\Models\User;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
-use Log;
 
 abstract class AbstractPayment {
 	protected static $sysConfig;
@@ -24,147 +19,11 @@ abstract class AbstractPayment {
 
 	abstract public function notify(Request $request): void;
 
-	protected function postPayment($data, $method): int {
-		// 获取需要的信息
-		$payment = Payment::query()->whereTradeNo($data)->latest()->first();
-		// 是否为余额购买套餐
-		if($payment){
-			if($payment->status === 1){// 已处理
-				return 0;
-			}
-			Payment::query()->whereTradeNo($data)->update(['status' => 1]);
-			$order = Order::find($payment->oid);
-		}else{
-			$order = Order::find($data);
-		}
-		$goods = Goods::find($order->goods_id);
-		$user = User::find($order->user_id);
-
-		//余额充值
-		if($order->goods_id == 0){
-			Order::query()->whereOid($order->oid)->update(['status' => 2]);
-			User::query()->whereId($order->user_id)->increment('credit', $order->amount * 100);
-			// 余额变动记录日志
-			Helpers::addUserCreditLog($order->user_id, $order->oid, $order->user->credit,
-				$order->user->credit + $order->amount, $order->amount, '用户'.$method.'充值余额');
-
-			return 0;
-		}
-
-		// 商品为流量或者套餐
-		switch($goods->type){
-			case 1:
-				Order::query()->whereOid($order->oid)->update(['status' => 2]);
-				User::query()->whereId($order->user_id)->increment('transfer_enable', $goods->traffic * MB);
-				Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable,
-					$user->transfer_enable + $goods->traffic * MB, '['.$method.']加上用户购买的套餐流量');
-				break;
-			case 2:
-				$activePlan = Order::query()
-				                   ->whereUserId($user->id)
-				                   ->with(['goods'])
-				                   ->whereIsExpire(0)
-				                   ->whereStatus(2)
-				                   ->whereHas('goods', static function($q) {
-					                   $q->whereType(2);
-				                   })
-				                   ->exists();
-
-				// 2为开始生效,3为预支付
-				$order->status = $activePlan? 3 : 2;
-				$order->save();
-
-				if($activePlan){
-					// 预支付订单, 刷新账号有效时间用于流量重置判断
-					User::query()->whereId($order->user_id)->update([
-						'expire_time' => date('Y-m-d',
-							strtotime("+".$goods->days." days", strtotime($user->expire_time)))
-					]);
-				}else{
-					// 如果买的是套餐,则先将之前购买的套餐都无效化,重置用户已用、可用流量为0
-					Order::query()->whereUserId($user->id)->with(['goods'])->whereHas('goods', static function($q) {
-						$q->where('type', '<=', 2);
-					})->whereIsExpire(0)->whereStatus(2)->where('oid', '<>', $order->oid)->update([
-						'expired_at' => date('Y-m-d H:i:s'),
-						'is_expire'  => 1
-					]);
-
-					User::query()->whereId($order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
-					Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, 0,
-						'['.$method.']用户购买新套餐,先清空流量');
-
-					$userTraffic = $goods->traffic * MB;
-					// 添加账号有效期
-					$expireTime = date('Y-m-d', strtotime("+".$goods->days." days"));
-					//账号下一个重置时间
-					$nextResetTime = date('Y-m-d', strtotime("+".$goods->period." days"));
-					if($nextResetTime >= $expireTime){
-						$nextResetTime = null;
-					}
-
-					User::query()->whereId($order->user_id)->increment('invite_num', $goods->invite_num?: 0, [
-						'transfer_enable' => $userTraffic,
-						'reset_time'      => $nextResetTime,
-						'expire_time'     => $expireTime,
-						'level'           => $goods->level,
-						'enable'          => 1
-					]);
-					Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, $userTraffic,
-						'['.$method.']加上用户购买的套餐流量');
-				}
-
-				// 是否返利
-				if($order->user->referral_uid && self::$sysConfig['referral_type']){
-					//获取历史返利记录
-					$referral = ReferralLog::whereUserId($order->user_id)->get();
-					// 无记录 / 首次返利
-					if(!$referral && self::$sysConfig['is_invite_register']){
-						// 邀请注册功能开启时,返还邀请者邀请名额
-						User::query()->whereId($order->user->referral_uid)->increment('invite_num', 1);
-					}
-					//按照返利模式进行返利判断
-					if(self::$sysConfig['referral_type'] == 2 || (self::$sysConfig['referral_type'] == 1 && !$referral)){
-						$this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount,
-							$order->amount * self::$sysConfig['referral_percent']);
-					}
-				}
-
-				break;
-			default:
-				Log::info('【处理订单】出现错误-未知套餐类型');
-		}
-
-		return 0;
-	}
-
-	/**
-	 * 添加返利日志
-	 *
-	 * @param  int  $userId     用户ID
-	 * @param  int  $refUserId  返利用户ID
-	 * @param  int  $oid        订单ID
-	 * @param  int  $amount     发生金额
-	 * @param  int  $refAmount  返利金额
-	 *
-	 * @return int
-	 */
-	private function addReferralLog($userId, $refUserId, $oid, $amount, $refAmount): int {
-		$log = new ReferralLog();
-		$log->user_id = $userId;
-		$log->ref_user_id = $refUserId;
-		$log->order_id = $oid;
-		$log->amount = $amount;
-		$log->ref_amount = $refAmount;
-		$log->status = 0;
-
-		return $log->save();
-	}
-
 	protected function creatNewPayment($uid, $oid, $amount): Payment {
 		$payment = new Payment();
 		$payment->trade_no = makeRandStr(8);
 		$payment->user_id = $uid;
-		$payment->oid = $oid;
+		$payment->order_id = $oid;
 		$payment->amount = $amount;
 		$payment->save();
 

+ 9 - 4
app/Http/Controllers/Gateway/BitpayX.php

@@ -11,7 +11,7 @@ use Response;
 
 class BitpayX extends AbstractPayment {
 	public function purchase($request): JsonResponse {
-		$payment = $this->creatNewPayment(Auth::id(), $request->input('oid'), $request->input('amount'));
+		$payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
 		$data = [
 			'merchant_order_id' => $payment->trade_no,
@@ -28,7 +28,7 @@ class BitpayX extends AbstractPayment {
 
 		if($result['status'] === 200 || $result['status'] === 201){
 			$result['payment_url'] .= '&lang=zh';
-			Payment::whereId($payment->id)->update(['url' => $result['payment_url']]);
+			$payment->update(['url' => $result['payment_url']]);
 
 			return Response::json(['status' => 'success', 'url' => $result['payment_url'], 'message' => '创建订单成功!']);
 		}
@@ -73,8 +73,13 @@ class BitpayX extends AbstractPayment {
 	public function notify($request): void {
 		$tradeNo = $request->input(['merchant_order_id']);
 		if($request->input(['status']) === 'PAID' && hash_equals($this->sign($tradeNo), $request->input(['token']))){
-			$this->postPayment($tradeNo, 'BitPayX');
-			exit(json_encode(['status' => 200]));
+			$payment = Payment::whereTradeNo($tradeNo)->first();
+			if($payment){
+				$ret = $payment->order->update(['status' => 2]);
+				if($ret){
+					exit(json_encode(['status' => 200]));
+				}
+			}
 		}
 		exit(json_encode(['status' => 400]));
 	}

+ 9 - 4
app/Http/Controllers/Gateway/CodePay.php

@@ -9,7 +9,7 @@ use Response;
 
 class CodePay extends AbstractPayment {
 	public function purchase($request): JsonResponse {
-		$payment = $this->creatNewPayment(Auth::id(), $request->input('oid'), $request->input('amount'));
+		$payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
 		$data = [
 			'id'         => self::$sysConfig['codepay_id'],
@@ -24,7 +24,7 @@ class CodePay extends AbstractPayment {
 		$data['sign'] = $this->aliStyleSign($data, self::$sysConfig['codepay_key']);
 
 		$url = self::$sysConfig['codepay_url'].http_build_query($data);
-		Payment::whereId($payment->id)->update(['url' => $url]);
+		$payment->update(['url' => $url]);
 
 		return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
 	}
@@ -34,8 +34,13 @@ class CodePay extends AbstractPayment {
 		if($trade_no && $request->input('pay_no')
 		   && $this->verify($request->except('method'), self::$sysConfig['codepay_key'], $request->input('sign'),
 				false)){
-			$this->postPayment($trade_no, '码支付');
-			exit('success');
+			$payment = Payment::whereTradeNo($trade_no)->first();
+			if($payment){
+				$ret = $payment->order->update(['status' => 2]);
+				if($ret){
+					exit('success');
+				}
+			}
 		}
 		exit('fail');
 	}

+ 9 - 4
app/Http/Controllers/Gateway/EPay.php

@@ -11,7 +11,7 @@ use Response;
 
 class EPay extends AbstractPayment {
 	public function purchase(Request $request): JsonResponse {
-		$payment = $this->creatNewPayment(Auth::id(), $request->input('oid'), $request->input('amount'));
+		$payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
 		switch($request->input('type')){
 			case 2:
@@ -39,7 +39,7 @@ class EPay extends AbstractPayment {
 		$data['sign'] = $this->aliStyleSign($data, self::$sysConfig['epay_key']);
 
 		$url = self::$sysConfig['epay_url'].'submit.php?'.http_build_query($data);
-		Payment::whereId($payment->id)->update(['url' => $url]);
+		$payment->update(['url' => $url]);
 
 		return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
 	}
@@ -47,8 +47,13 @@ class EPay extends AbstractPayment {
 	public function notify(Request $request): void {
 		if($request->input('trade_status') === 'TRADE_SUCCESS'
 		   && $this->verify($request->except('method'), self::$sysConfig['epay_key'], $request->input('sign'))){
-			$this->postPayment($request->input('out_trade_no'), 'EPay');
-			exit('SUCCESS');
+			$payment = Payment::whereTradeNo($request->input('out_trade_no'))->first();
+			if($payment){
+				$ret = $payment->order->update(['status' => 2]);
+				if($ret){
+					exit('SUCCESS');
+				}
+			}
 		}
 		exit('FAIL');
 	}

+ 10 - 6
app/Http/Controllers/Gateway/F2Fpay.php

@@ -31,7 +31,7 @@ class F2Fpay extends AbstractPayment {
 	}
 
 	public function purchase($request): JsonResponse {
-		$payment = $this->creatNewPayment(Auth::id(), $request->input('oid'), $request->input('amount'));
+		$payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
 		$data = [
 			'body'        => '',
@@ -54,7 +54,7 @@ class F2Fpay extends AbstractPayment {
 			exit;
 		}
 
-		Payment::whereId($payment->id)->update(['qr_code' => 1, 'url' => $result['qr_code']]);
+		$payment->update(['qr_code' => 1, 'url' => $result['qr_code']]);
 
 		return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
 	}
@@ -79,11 +79,15 @@ class F2Fpay extends AbstractPayment {
 			exit;
 		}
 
-		$ret = "fail";
 		if($result['code'] == 10000 && $result['msg'] === "Success"){
-			$ret = "success";
 			if($_POST['trade_status'] === 'TRADE_FINISHED' || $_POST['trade_status'] === 'TRADE_SUCCESS'){
-				$this->postPayment($request->input('out_trade_no'), '支付宝当面付');
+				$payment = Payment::whereTradeNo($request->input('out_trade_no'))->first();
+				if($payment){
+					$ret = $payment->order->update(['status' => 2]);
+					if($ret){
+						exit('success');
+					}
+				}
 			}else{
 				Log::info('支付宝当面付-POST:交易失败['.getClientIp().']');
 			}
@@ -92,6 +96,6 @@ class F2Fpay extends AbstractPayment {
 		}
 
 		// 返回验证结果
-		exit($ret);
+		exit('fail');
 	}
 }

+ 7 - 10
app/Http/Controllers/Gateway/Local.php

@@ -6,26 +6,23 @@ namespace App\Http\Controllers\Gateway;
 use App\Components\Helpers;
 use App\Models\Goods;
 use App\Models\Order;
-use App\Models\User;
-use Auth;
 use Illuminate\Http\JsonResponse;
 use Response;
 
 class Local extends AbstractPayment {
 	public function purchase($request): JsonResponse {
-		$amount = $request->input('amount');
-		$order = Order::find($request->input('oid'));
-		$goods = Goods::query()->whereStatus(1)->whereId($request->input('goods_id'))->first();
-		$user = Auth::getUser();
+		$order = Order::find($request->input('id'));
+		$goods = Goods::find($request->input('goods_id'));
+		$user = $order->user;
 
 		if($user && $goods){
-			User::query()->whereId($user->id)->decrement('credit', $amount * 100);
+			$user->update(['credit' => $user->credit - $order->amount]);
 			// 记录余额操作日志
-			Helpers::addUserCreditLog($user->id, $order->oid, $user->credit, $user->credit - $amount, -1 * $amount,
-				'购买商品'.$goods->name);
+			Helpers::addUserCreditLog($user->id, $order->id, $user->credit + $order->amount, $user->credit,
+				-1 * $order->amount, '购买商品'.$goods->name);
 		}
 
-		$this->postPayment($order->oid, '余额');
+		$order->update(['status' => 2]);
 
 		return Response::json(['status' => 'success', 'message' => '购买完成!']);
 	}

+ 10 - 5
app/Http/Controllers/Gateway/PayJs.php

@@ -20,7 +20,7 @@ class PayJs extends AbstractPayment {
 	}
 
 	public function purchase($request): JsonResponse {
-		$payment = $this->creatNewPayment(Auth::id(), $request->input('oid'), $request->input('amount'));
+		$payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
 		$result = (new Pay($this::$config))->cashier([
 			'body'         => self::$sysConfig['subject_name']?: self::$sysConfig['website_name'],
@@ -30,7 +30,7 @@ class PayJs extends AbstractPayment {
 		]);
 
 		// 获取收款二维码内容
-		Payment::whereId($payment->id)->update(['qr_code' => 1, 'url' => $result]);
+		$payment->update(['qr_code' => 1, 'url' => $result]);
 
 		//$this->addPamentCallback($payment->trade_no, null, $payment->amount * 100);
 		return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
@@ -40,9 +40,14 @@ class PayJs extends AbstractPayment {
 		$data = (new Pay($this::$config))->notify();
 
 		if($data['return_code'] == 1){
-			$this->postPayment($data['out_trade_no'], 'PayJs');
-			exit("success");
+			$payment = Payment::whereTradeNo($data['out_trade_no'])->first();
+			if($payment){
+				$ret = $payment->order->update(['status' => 2]);
+				if($ret){
+					exit('success');
+				}
+			}
 		}
-		exit("fail");
+		exit('fail');
 	}
 }

+ 11 - 9
app/Http/Controllers/Gateway/PayPal.php

@@ -3,7 +3,6 @@
 
 namespace App\Http\Controllers\Gateway;
 
-use App\Models\Order;
 use App\Models\Payment;
 use Auth;
 use Exception;
@@ -50,7 +49,7 @@ class PayPal extends AbstractPayment {
 	}
 
 	public function purchase($request): JsonResponse {
-		$payment = $this->creatNewPayment(Auth::id(), $request->input('oid'), $request->input('amount'));
+		$payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
 		$data = $this->getCheckoutData($payment->trade_no, $payment->amount);
 
@@ -61,7 +60,7 @@ class PayPal extends AbstractPayment {
 
 				return Response::json(['status' => 'fail', 'message' => '创建订单失败,请使用其他方式或通知管理员!']);
 			}
-			Payment::whereId($payment->id)->update(['url' => $response['paypal_link']]);
+			$payment->update(['url' => $response['paypal_link']]);
 
 			return Response::json(['status' => 'success', 'url' => $response['paypal_link'], 'message' => '创建订单成功!']);
 		}catch(Exception $e){
@@ -98,15 +97,15 @@ class PayPal extends AbstractPayment {
 		$response = $this->provider->getExpressCheckoutDetails($token);
 
 		if(in_array(strtoupper($response['ACK']), ['SUCCESS', 'SUCCESSWITHWARNING'])){
-			$payment = Payment::query()->whereTradeNo($response['INVNUM'])->firstOrFail();
+			$payment = Payment::whereTradeNo($response['INVNUM'])->firstOrFail();
 			$data = $this->getCheckoutData($payment->trade_no, $payment->amount);
 			// Perform transaction on PayPal
 			$payment_status = $this->provider->doExpressCheckoutPayment($data, $token, $PayerID);
 			$status = $payment_status['PAYMENTINFO_0_PAYMENTSTATUS'];
 
 			if(!strcasecmp($status, 'Completed') || !strcasecmp($status, 'Processed')){
-				Log::info("Order $payment->oid has been paid successfully!");
-				Order::whereOid($payment->oid)->update(['status' => 1]);
+				Log::info("Order $payment->order_id has been paid successfully!");
+				$payment->order->update(['status' => 1]);
 			}else{
 				Log::error("Error processing PayPal payment for Order $payment->id!");
 			}
@@ -127,10 +126,13 @@ class PayPal extends AbstractPayment {
 		$response = (string) $this->provider->verifyIPN($post);
 
 		if($response === 'VERIFIED' && $request['invoice']){
-			if(Payment::query()->whereTradeNo($request['invoice'])->first()->status == 0){
-				$this->postPayment($request['invoice'], 'PayPal');
+			$payment = Payment::whereTradeNo($request['invoice'])->first();
+			if($payment && $payment->status == 0){
+				$ret = $payment->order->update(['status' => 2]);
+				if($ret){
+					exit('success');
+				}
 			}
-			exit("success");
 		}
 		exit("fail");
 	}

+ 39 - 50
app/Http/Controllers/NodeController.php

@@ -11,8 +11,8 @@ use App\Models\Node;
 use App\Models\NodeAuth;
 use App\Models\NodeCertificate;
 use App\Models\NodeDailyDataFlow;
+use App\Models\NodeHeartBeat;
 use App\Models\NodeHourlyDataFlow;
-use App\Models\NodeInfo;
 use App\Models\NodeLabel;
 use App\Models\NodeOnlineLog;
 use App\Models\NodePing;
@@ -46,23 +46,18 @@ class NodeController extends Controller {
 		$nodeList = $query->orderByDesc('status')->orderBy('id')->paginate(15)->appends($request->except('page'));
 		foreach($nodeList as $node){
 			// 在线人数
-			$online_log = NodeOnlineLog::query()
-			                           ->whereNodeId($node->id)
+			$online_log = NodeOnlineLog::whereNodeId($node->id)
 			                           ->where('log_time', '>=', strtotime("-5 minutes"))
 			                           ->latest('log_time')
 			                           ->first();
 			$node->online_users = empty($online_log)? 0 : $online_log->online_user;
 
 			// 已产生流量
-			$totalTraffic = NodeDailyDataFlow::query()->whereNodeId($node->id)->sum('total');
+			$totalTraffic = NodeDailyDataFlow::whereNodeId($node->id)->sum('total');
 			$node->transfer = flowAutoShow($totalTraffic);
 
 			// 负载(10分钟以内)
-			$node_info = NodeInfo::query()
-			                     ->whereNodeId($node->id)
-			                     ->where('log_time', '>=', strtotime("-10 minutes"))
-			                     ->latest('log_time')
-			                     ->first();
+			$node_info = $node->nodeHeartBeat()->recently()->first();
 			$node->isOnline = empty($node_info) || empty($node_info->load)? 0 : 1;
 			$node->load = $node->isOnline? $node_info->load : '离线';
 			$node->uptime = empty($node_info)? 0 : seconds2time($node_info->uptime);
@@ -161,10 +156,10 @@ class NodeController extends Controller {
 			$view['methodList'] = Helpers::methodList();
 			$view['protocolList'] = Helpers::protocolList();
 			$view['obfsList'] = Helpers::obfsList();
-			$view['countryList'] = Country::query()->orderBy('code')->get();
-			$view['levelList'] = Level::query()->orderBy('level')->get();
-			$view['labelList'] = Label::query()->orderByDesc('sort')->orderBy('id')->get();
-			$view['dvList'] = NodeCertificate::query()->orderBy('id')->get();
+			$view['countryList'] = Country::orderBy('code')->get();
+			$view['levelList'] = Level::orderBy('level')->get();
+			$view['labelList'] = Label::orderByDesc('sort')->orderBy('id')->get();
+			$view['dvList'] = NodeCertificate::orderBy('id')->get();
 
 			return Response::view('admin.node.nodeInfo', $view);
 		}
@@ -228,7 +223,7 @@ class NodeController extends Controller {
 	// 生成节点标签
 	private function makeLabels($nodeId, $labels): void {
 		// 先删除所有该节点的标签
-		NodeLabel::query()->whereNodeId($nodeId)->delete();
+		NodeLabel::whereNodeId($nodeId)->delete();
 
 		if(!empty($labels) && is_array($labels)){
 			foreach($labels as $label){
@@ -242,7 +237,7 @@ class NodeController extends Controller {
 
 	// 获取节点地理位置
 	private function getNodeGeo($id): bool {
-		$nodes = Node::query()->whereStatus(1);
+		$nodes = Node::whereStatus(1);
 		if($id){
 			$nodes = $nodes->whereId($id)->get();
 		}else{
@@ -252,8 +247,7 @@ class NodeController extends Controller {
 		foreach($nodes as $node){
 			$data = getIPInfo($node->is_ddns == 1? gethostbyname($node->server) : $node->ip);
 			if($data){
-				$ret = Node::query()->whereId($node->id)->update(['geo' => $data['latitude'].','.$data['longitude']]);
-				if($ret){
+				if($node->update(['geo' => $data['latitude'].','.$data['longitude']])){
 					$result++;
 				}
 			}
@@ -328,7 +322,7 @@ class NodeController extends Controller {
 				// 生成节点标签
 				$this->makeLabels($id, $request->input('labels'));
 
-				Node::query()->whereId($id)->update($data);
+				Node::whereId($id)->update($data);
 				// TODO:更新节点绑定的域名DNS(将节点IP更新到域名DNS 的A记录)
 
 				DB::commit();
@@ -342,21 +336,16 @@ class NodeController extends Controller {
 				return Response::json(['status' => 'fail', 'message' => '编辑失败:'.$e->getMessage()]);
 			}
 		}else{
-			$node = Node::query()->with(['label'])->whereId($id)->first();
-			if($node){
-				$node->labels = $node->label->pluck('label_id');
-			}
-
-			$view['node'] = $node;
+			$view['node'] = Node::with('labels')->find($id);
 			$view['methodList'] = Helpers::methodList();
 			$view['protocolList'] = Helpers::protocolList();
 			$view['obfsList'] = Helpers::obfsList();
-			$view['countryList'] = Country::query()->orderBy('code')->get();
-			$view['levelList'] = Level::query()->orderBy('level')->get();
-			$view['labelList'] = Label::query()->orderByDesc('sort')->orderBy('id')->get();
-			$view['dvList'] = NodeCertificate::query()->orderBy('id')->get();
+			$view['countryList'] = Country::orderBy('code')->get();
+			$view['levelList'] = Level::orderBy('level')->get();
+			$view['labelList'] = Label::orderByDesc('sort')->orderBy('id')->get();
+			$view['dvList'] = NodeCertificate::orderBy('id')->get();
 
-			return view('admin.node.nodeInfo', $view)->with(compact('node'));
+			return Response::view('admin.node.nodeInfo', $view);
 		}
 	}
 
@@ -372,18 +361,18 @@ class NodeController extends Controller {
 		try{
 			DB::beginTransaction();
 			// 删除分组关联、节点标签、节点相关日志
-			Node::query()->whereId($id)->delete();
-			NodeLabel::query()->whereNodeId($id)->delete();
-			NodeInfo::query()->whereNodeId($id)->delete();
-			NodeOnlineLog::query()->whereNodeId($id)->delete();
-			NodeDailyDataFlow::query()->whereNodeId($id)->delete();
-			NodeHourlyDataFlow::query()->whereNodeId($id)->delete();
-			NodePing::query()->whereNodeId($id)->delete();
-			UserDailyDataFlow::query()->whereNodeId($id)->delete();
-			UserHourlyDataFlow::query()->whereNodeId($id)->delete();
-			UserDataFlowLog::query()->whereNodeId($id)->delete();
-			NodeAuth::query()->whereNodeId($id)->delete();
-			NodeRule::query()->whereNodeId($id)->delete();
+			Node::whereId($id)->delete();
+			NodeLabel::whereNodeId($id)->delete();
+			NodeHeartBeat::whereNodeId($id)->delete();
+			NodeOnlineLog::whereNodeId($id)->delete();
+			NodeDailyDataFlow::whereNodeId($id)->delete();
+			NodeHourlyDataFlow::whereNodeId($id)->delete();
+			NodePing::whereNodeId($id)->delete();
+			UserDailyDataFlow::whereNodeId($id)->delete();
+			UserHourlyDataFlow::whereNodeId($id)->delete();
+			UserDataFlowLog::whereNodeId($id)->delete();
+			NodeAuth::whereNodeId($id)->delete();
+			NodeRule::whereNodeId($id)->delete();
 			foreach(RuleGroup::all() as $ruleGroup){
 				$nodes = $ruleGroup->nodes;
 				if($nodes && in_array($id, $nodes, true)){
@@ -460,7 +449,7 @@ class NodeController extends Controller {
 			$query->whereNodeId($node_id);
 		}
 
-		$view['nodeList'] = Node::query()->orderBy('id')->get();
+		$view['nodeList'] = Node::orderBy('id')->get();
 		$view['pingLogs'] = $query->latest()->paginate(15)->appends($request->except('page'));
 
 		return Response::view('admin.logs.nodePingLog', $view);
@@ -468,14 +457,14 @@ class NodeController extends Controller {
 
 	// 节点授权列表
 	public function authList(Request $request): \Illuminate\Http\Response {
-		$view['list'] = NodeAuth::query()->orderBy('node_id')->paginate(15)->appends($request->except('page'));
+		$view['list'] = NodeAuth::orderBy('node_id')->paginate(15)->appends($request->except('page'));
 		return Response::view('admin.node.authList', $view);
 	}
 
 	// 添加节点授权
 	public function addAuth(): JsonResponse {
-		$nodeArray = Node::query()->whereStatus(1)->orderBy('id')->pluck('id')->toArray();
-		$authArray = NodeAuth::query()->orderBy('id')->pluck('node_id')->toArray();
+		$nodeArray = Node::whereStatus(1)->orderBy('id')->pluck('id')->toArray();
+		$authArray = NodeAuth::orderBy('id')->pluck('node_id')->toArray();
 
 		if($nodeArray == $authArray){
 			return Response::json(['status' => 'success', 'message' => '没有需要生成授权的节点']);
@@ -494,7 +483,7 @@ class NodeController extends Controller {
 	// 删除节点授权
 	public function delAuth(Request $request): JsonResponse {
 		try{
-			NodeAuth::query()->whereId($request->input('id'))->delete();
+			NodeAuth::whereId($request->input('id'))->delete();
 		}catch(Exception $e){
 			return Response::json(['status' => 'fail', 'message' => '错误:'.var_export($e, true)]);
 		}
@@ -503,7 +492,7 @@ class NodeController extends Controller {
 
 	// 重置节点授权
 	public function refreshAuth(Request $request): ?JsonResponse {
-		$ret = NodeAuth::query()->whereId($request->input('id'))->update([
+		$ret = NodeAuth::whereId($request->input('id'))->update([
 			'key'    => makeRandStr(16),
 			'secret' => makeRandStr(8)
 		]);
@@ -516,7 +505,7 @@ class NodeController extends Controller {
 
 	// 域名证书列表
 	public function certificateList(Request $request): \Illuminate\Http\Response {
-		$DvList = NodeCertificate::query()->orderBy('id')->paginate(15)->appends($request->except('page'));
+		$DvList = NodeCertificate::orderBy('id')->paginate(15)->appends($request->except('page'));
 		foreach($DvList as $Dv){
 			if($Dv->key && $Dv->pem){
 				$DvInfo = openssl_x509_parse($Dv->pem);
@@ -554,7 +543,7 @@ class NodeController extends Controller {
 		$Dv = NodeCertificate::find($request->input('id'));
 		if($request->isMethod('POST')){
 			if($Dv){
-				$ret = NodeCertificate::query()->update([
+				$ret = NodeCertificate::whereId($Dv->id)->update([
 					'domain' => $request->input('domain'),
 					'key'    => $request->input('key'),
 					'pem'    => $request->input('pem')
@@ -573,7 +562,7 @@ class NodeController extends Controller {
 	// 删除域名证书
 	public function delCertificate(Request $request): JsonResponse {
 		try{
-			NodeCertificate::query()->whereId($request->input('id'))->delete();
+			NodeCertificate::whereId($request->input('id'))->delete();
 		}catch(Exception $e){
 			return Response::json(['status' => 'fail', 'message' => '错误:'.var_export($e, true)]);
 		}

+ 20 - 36
app/Http/Controllers/PaymentController.php

@@ -64,7 +64,7 @@ class PaymentController extends Controller {
 	}
 
 	public static function getStatus(Request $request): JsonResponse {
-		$payment = Payment::query()->whereTradeNo($request->input('trade_no'))->first();
+		$payment = Payment::whereTradeNo($request->input('trade_no'))->first();
 		if($payment){
 			if($payment->status == 1){
 				return Response::json(['status' => 'success', 'message' => '支付成功']);
@@ -89,7 +89,7 @@ class PaymentController extends Controller {
 		$pay_type = $request->input('pay_type');
 		$amount = 0;
 
-		$goods = Goods::query()->whereStatus(1)->whereId($goods_id)->first();
+		$goods = Goods::find($goods_id);
 		// 充值余额
 		if($credit){
 			if(!is_numeric($credit) || $credit <= 0){
@@ -98,21 +98,19 @@ class PaymentController extends Controller {
 			$amount = $credit;
 			// 购买服务
 		}elseif($goods_id && self::$method){
-			if(!$goods){
-				return Response::json(['status' => 'fail', 'message' => '订单创建失败:商品或服务已下架']);
+			if(!$goods || !$goods->status){
+				return Response::json(['status' => 'fail', 'message' => '订单创建失败:商品已下架']);
 			}
 
 			// 是否有生效的套餐
-			$activePlan = Order::uid()->with(['goods'])->whereHas('goods', static function($q) {
-				$q->whereType(2);
-			})->whereStatus(2)->whereIsExpire(0)->doesntExist();
+			$activePlan = Order::userActivePlan()->doesntExist();
 
-			//无生效套餐,禁止购买加油包
+			// 无生效套餐,禁止购买加油包
 			if($goods->type == 1 && $activePlan){
 				return Response::json(['status' => 'fail', 'message' => '购买加油包前,请先购买套餐']);
 			}
 
-			//非余额付款下,检查对应的在线支付是否开启
+			//非余额付款下,检查在线支付是否开启
 			if(self::$method !== 'credit'){
 				// 判断是否开启在线支付
 				if(!sysConfig('is_onlinePay')){
@@ -120,10 +118,11 @@ class PaymentController extends Controller {
 				}
 
 				// 判断是否存在同个商品的未支付订单
-				$existsOrder = Order::uid()->whereStatus(0)->whereGoodsId($goods_id)->exists();
-				if($existsOrder){
+				if(Order::uid()->whereStatus(0)->exists()){
 					return Response::json(['status' => 'fail', 'message' => '订单创建失败:尚有未支付的订单,请先去支付']);
 				}
+			}elseif(self::$method === 'credit' && Auth::getUser()->credit < $amount){ // 验证账号余额是否充足
+				return Response::json(['status' => 'fail', 'message' => '您的余额不足,请先充值']);
 			}
 
 			// 单个商品限购
@@ -132,20 +131,20 @@ class PaymentController extends Controller {
 				if($count >= $goods->limit_num){
 					return Response::json([
 						'status'  => 'fail',
-						'message' => '此商品/服务限购'.$goods->limit_num.'次,您已购买'.$count.'次'
+						'message' => '此商品限购'.$goods->limit_num.'次,您已购买'.$count.'次'
 					]);
 				}
 			}
 
-			// 使用优惠券
+			// 使用优惠券 TODO 代码整合至 CouponService
 			if($coupon_sn){
-				$coupon = Coupon::query()->whereStatus(0)->whereIn('type', [1, 2])->whereSn($coupon_sn)->first();
+				$coupon = Coupon::whereStatus(0)->whereIn('type', [1, 2])->whereSn($coupon_sn)->first();
 				if(!$coupon){
 					return Response::json(['status' => 'fail', 'message' => '订单创建失败:优惠券不存在']);
 				}
 
 				// 计算实际应支付总价
-				$amount = $coupon->type == 2? $goods->price * $coupon->discount / 10 : $goods->price - $coupon->amount;
+				$amount = $coupon->type == 2? $goods->price * $coupon->value / 100 : $goods->price - $coupon->value;
 				$amount = $amount > 0? round($amount, 2) : 0; // 四舍五入保留2位小数,避免无法正常创建订单
 			}else{
 				$amount = $goods->price;
@@ -159,11 +158,6 @@ class PaymentController extends Controller {
 			if($amount == 0 && self::$method !== 'credit'){
 				return Response::json(['status' => 'fail', 'message' => '订单创建失败:订单总价为0,无需使用在线支付']);
 			}
-
-			// 验证账号余额是否充足
-			if(self::$method === 'credit' && Auth::getUser()->credit < $amount){
-				return Response::json(['status' => 'fail', 'message' => '您的余额不足,请先充值']);
-			}
 		}
 
 		$orderSn = date('ymdHis').random_int(100000, 999999);
@@ -176,7 +170,6 @@ class PaymentController extends Controller {
 		$order->coupon_id = !empty($coupon)? $coupon->id : 0;
 		$order->origin_amount = $credit?: $goods->price;
 		$order->amount = $amount;
-		$order->expired_at = $credit? null : date("Y-m-d H:i:s", strtotime("+".$goods->days." days"));
 		$order->is_expire = 0;
 		$order->pay_type = $pay_type;
 		$order->pay_way = self::$method;
@@ -185,37 +178,28 @@ class PaymentController extends Controller {
 
 		// 使用优惠券,减少可使用次数
 		if(!empty($coupon)){
-			if($coupon->usage_count > 0){
-				Coupon::whereId($coupon->id)->decrement('usage_count', 1);
+			if($coupon->usable_times > 0){
+				Coupon::whereId($coupon->id)->decrement('usable_times', 1);
 			}
 
-			Helpers::addCouponLog($coupon->id, $goods_id, $order->oid, '订单支付使用');
+			Helpers::addCouponLog('订单支付使用', $coupon->id, $goods_id, $order->id);
 		}
 
-		$request->merge(['oid' => $order->oid, 'amount' => $amount, 'type' => $pay_type]);
+		$request->merge(['id' => $order->id, 'type' => $pay_type, 'amount' => $amount]);
 
 		// 生成支付单
 		return self::getClient()->purchase($request);
 	}
 
 	public function close(Request $request): JsonResponse {
-		$oid = $request->input('oid');
-		$order = Order::find($oid);
-		$payment = Payment::query()->whereOid($oid)->first();
+		$order = Order::find($request->input('id'));
 		if($order){
-			$ret = Order::query()->whereOid($oid)->update(['status' => -1]);
-			if(!$ret){
+			if(!$order->update(['status' => -1])){
 				return Response::json(['status' => 'fail', 'message' => '关闭订单失败']);
 			}
 		}else{
 			return Response::json(['status' => 'fail', 'message' => '未找到订单']);
 		}
-		if($payment){
-			$ret = Payment::query()->whereOid($oid)->update(['status' => -1]);
-			if(!$ret){
-				return Response::json(['status' => 'fail', 'message' => '关闭在线订单失败']);
-			}
-		}
 		return Response::json(['status' => 'success', 'message' => '关闭订单成功']);
 	}
 

+ 0 - 61
app/Http/Controllers/ServiceController.php

@@ -1,61 +0,0 @@
-<?php
-
-
-namespace App\Http\Controllers;
-
-use App\Components\Helpers;
-use App\Models\Goods;
-use App\Models\Order;
-use App\Models\User;
-
-class ServiceController extends Controller {
-	public function activePrepaidOrder($oid): void {
-		// 取出预支付订单
-		$prepaidOrder = Order::find($oid);
-		//去除使用中的套餐和 流量包
-		Order::query()
-		     ->whereUserId($prepaidOrder->user_id)
-		     ->whereStatus(2)
-		     ->whereIsExpire(0)
-		     ->update(['expired_at' => date('Y-m-d H:i:s'), 'is_expire' => 1]);
-		//取出对应套餐信息
-		$prepaidGood = Goods::find($prepaidOrder->goods_id);
-		//激活预支付套餐
-		Order::query()->whereOid($prepaidOrder->oid)->update([
-			'expired_at' => date("Y-m-d H:i:s", strtotime("+".$prepaidGood->days." days")),
-			'status'     => 2
-		]);
-		//取出用户信息
-		$user = User::find($prepaidOrder->user_id);
-
-		$userTraffic = $prepaidGood->traffic * MB;
-		//拿出可能存在的其余套餐, 推算 最新的到期时间
-		$expire_time = date('Y-m-d', strtotime("+".$prepaidGood->days." days"));
-		$prepaidOrders = Order::query()->whereUserId($prepaidOrder->user_id)->whereStatus(3)->get();
-		foreach($prepaidOrders as $paidOrder){
-			//取出对应套餐信息
-			$goods = Goods::find($paidOrder->goods_id);
-			$expire_time = date('Y-m-d', strtotime("+".$goods->days." days", strtotime($expire_time)));
-		}
-		//计算账号下一个重置时间
-		$nextResetTime = date('Y-m-d', strtotime("+".$prepaidGood->period." days"));
-		if($nextResetTime >= $expire_time){
-			$nextResetTime = null;
-		}
-
-		//赋予等级
-		$level = $prepaidOrder->goods->level;
-
-		Helpers::addUserTrafficModifyLog($prepaidOrder->user_id, $prepaidOrder->oid, $user->transfer_enable,
-			$userTraffic, '[预支付订单激活]加上用户购买的套餐流量');
-		User::query()->whereId($prepaidOrder->user_id)->increment('invite_num', $prepaidOrder->goods->invite_num?: 0, [
-			'u'               => 0,
-			'd'               => 0,
-			'transfer_enable' => $userTraffic,
-			'expire_time'     => $expire_time,
-			'reset_time'      => $nextResetTime,
-			'level'           => $level
-		]);
-	}
-
-}

+ 16 - 14
app/Http/Controllers/User/AffiliateController.php

@@ -7,7 +7,6 @@ use App\Http\Controllers\Controller;
 use App\Models\Order;
 use App\Models\ReferralApply;
 use App\Models\ReferralLog;
-use App\Models\User;
 use Auth;
 use Illuminate\Http\JsonResponse;
 use Response;
@@ -28,14 +27,17 @@ class AffiliateController extends Controller {
 		$view['referral_traffic'] = flowAutoShow(self::$sysConfig['referral_traffic'] * MB);
 		$view['referral_percent'] = self::$sysConfig['referral_percent'];
 		$view['referral_money'] = self::$sysConfig['referral_money'];
-		$view['totalAmount'] = ReferralLog::uid()->sum('ref_amount') / 100;
-		$view['canAmount'] = ReferralLog::uid()->whereStatus(0)->sum('ref_amount') / 100;
-		$view['link'] = self::$sysConfig['website_url'].'/register?aff='.Auth::id();
-		$view['referralLogList'] = ReferralLog::uid()->with('user')->latest()->paginate(10, ['*'], 'log_page');
-		$view['referralApplyList'] = ReferralApply::uid()->with('user')->latest()->paginate(10, ['*'], 'apply_page');
-		$view['referralUserList'] = User::query()
+		$view['totalAmount'] = ReferralLog::uid()->sum('commission') / 100;
+		$view['canAmount'] = ReferralLog::uid()->whereStatus(0)->sum('commission') / 100;
+		$view['aff_link'] = self::$sysConfig['website_url'].'/register?aff='.Auth::id();
+		$view['referralLogList'] = ReferralLog::uid()
+		                                      ->with('invitee:id,email')
+		                                      ->latest()
+		                                      ->paginate(10, ['*'], 'log_page');
+		$view['referralApplyList'] = ReferralApply::uid()->latest()->paginate(10, ['*'], 'apply_page');
+		$view['referralUserList'] = Auth::getUser()
+		                                ->invitees()
 		                                ->select(['email', 'created_at'])
-		                                ->whereReferralUid(Auth::id())
 		                                ->latest()
 		                                ->paginate(10, ['*'], 'user_page');
 
@@ -45,7 +47,7 @@ class AffiliateController extends Controller {
 	// 申请提现
 	public function extractMoney(): JsonResponse {
 		// 判断账户是否过期
-		if(Auth::getUser()->expire_time < date('Y-m-d')){
+		if(Auth::getUser()->expired_at < date('Y-m-d')){
 			return Response::json(['status' => 'fail', 'message' => '申请失败:账号已过期,请先购买服务吧']);
 		}
 
@@ -56,9 +58,9 @@ class AffiliateController extends Controller {
 		}
 
 		// 校验可以提现金额是否超过系统设置的阀值
-		$ref_amount = ReferralLog::uid()->whereStatus(0)->sum('ref_amount');
-		$ref_amount /= 100;
-		if($ref_amount < self::$sysConfig['referral_money']){
+		$commission = ReferralLog::uid()->whereStatus(0)->sum('commission');
+		$commission /= 100;
+		if($commission < self::$sysConfig['referral_money']){
 			return Response::json([
 				'status'  => 'fail',
 				'message' => '申请失败:满'.self::$sysConfig['referral_money'].'元才可以提现,继续努力吧'
@@ -67,9 +69,9 @@ class AffiliateController extends Controller {
 
 		$ref = new ReferralApply();
 		$ref->user_id = Auth::id();
-		$ref->before = $ref_amount;
+		$ref->before = $commission;
 		$ref->after = 0;
-		$ref->amount = $ref_amount;
+		$ref->amount = $commission;
 		$ref->link_logs = ReferralLog::uid()->whereStatus(0)->pluck('id')->toArray();
 		$ref->status = 0;
 		if($ref->save()){

+ 6 - 11
app/Http/Controllers/User/SubscribeController.php

@@ -4,7 +4,6 @@ namespace App\Http\Controllers\User;
 
 use App\Components\Helpers;
 use App\Http\Controllers\Controller;
-use App\Models\Node;
 use App\Models\User;
 use App\Models\UserSubscribe;
 use App\Models\UserSubscribeLog;
@@ -29,7 +28,7 @@ class SubscribeController extends Controller {
 		$this->subType = $request->input('type');
 
 		// 检查订阅码是否有效
-		$subscribe = UserSubscribe::query()->whereCode($code)->first();
+		$subscribe = UserSubscribe::whereCode($code)->first();
 		if(!$subscribe){
 			exit($this->infoGenerator('使用的订阅链接错误!请重新从官网获取!'));
 		}
@@ -58,7 +57,7 @@ class SubscribeController extends Controller {
 				exit($this->infoGenerator('账号流量耗尽!请前往官网购买或重置流量!'));
 			}
 
-			if($user->expire_time < date('Y-m-d')){
+			if($user->expired_at < date('Y-m-d')){
 				exit($this->infoGenerator('账号过期!请前往官网购买!'));
 			}
 
@@ -72,11 +71,7 @@ class SubscribeController extends Controller {
 		$this->subscribeLog($subscribe->id, getClientIp(), $request->headers);
 
 		// 获取这个账号可用节点
-		$query = Node::query()
-		             ->whereStatus(1)
-		             ->whereIsSubscribe(1)
-		             ->groupNodePermit($user->group_id)
-		             ->where('level', '<=', $user->level);
+		$query = $user->whereIsSubscribe(1)->userAccessNodes();
 
 		if($this->subType === 1){
 			$query = $query->whereIn('type', [1, 4]);
@@ -98,7 +93,7 @@ class SubscribeController extends Controller {
 
 		// 展示到期时间和剩余流量
 		if(self::$sysConfig['is_custom_subscribe']){
-			$scheme .= $this->infoGenerator('到期时间: '.($user->expire_time < date('Y-m-d')? '过期' : $user->expire_time)).$this->infoGenerator('剩余流量: '.flowAutoShow($user->transfer_enable - $user->u - $user->d));
+			$scheme .= $this->infoGenerator('到期时间: '.($user->expired_at < date('Y-m-d')? '过期' : $user->expired_at)).$this->infoGenerator('剩余流量: '.flowAutoShow($user->transfer_enable - $user->u - $user->d));
 		}
 
 		// 控制客户端最多获取节点数
@@ -119,7 +114,7 @@ class SubscribeController extends Controller {
 
 		// 适配Quantumult的自定义订阅头
 		if(self::$sysConfig['is_custom_subscribe']){
-			$headers['Subscription-Userinfo'] = 'upload='.$user->u.'; download='.$user->d.'; total='.$user->transfer_enable.'; expire='.strtotime($user->expire_time);
+			$headers['Subscription-Userinfo'] = 'upload='.$user->u.'; download='.$user->d.'; total='.$user->transfer_enable.'; expire='.strtotime($user->expired_at);
 		}
 
 		return Response::make(base64url_encode($scheme), 200, $headers);
@@ -159,7 +154,7 @@ class SubscribeController extends Controller {
 	// 写入订阅访问日志
 	private function subscribeLog($subscribeId, $ip, $headers): void {
 		$log = new UserSubscribeLog();
-		$log->sid = $subscribeId;
+		$log->subscribe_id = $subscribeId;
 		$log->request_ip = $ip;
 		$log->request_time = date('Y-m-d H:i:s');
 		$log->request_header = $headers;

+ 74 - 122
app/Http/Controllers/UserController.php

@@ -11,8 +11,7 @@ use App\Models\Coupon;
 use App\Models\Goods;
 use App\Models\Invite;
 use App\Models\Node;
-use App\Models\NodeInfo;
-use App\Models\NodeLabel;
+use App\Models\NodeHeartBeat;
 use App\Models\NodePing;
 use App\Models\Order;
 use App\Models\Ticket;
@@ -21,6 +20,7 @@ use App\Models\User;
 use App\Models\UserHourlyDataFlow;
 use App\Models\UserLoginLog;
 use App\Models\UserSubscribe;
+use App\Services\UserService;
 use Auth;
 use Cache;
 use DB;
@@ -55,19 +55,16 @@ class UserController extends Controller {
 		$totalTransfer = $user->transfer_enable;
 		$usedTransfer = $user->u + $user->d;
 		$unusedTransfer = $totalTransfer - $usedTransfer > 0? $totalTransfer - $usedTransfer : 0;
-		$expireTime = $user->expire_time;
-		$view['remainDays'] = $expireTime < date('Y-m-d')? -1 : ceil((strtotime($expireTime) - time()) / Day);
-		$view['resetDays'] = $user->reset_time? ceil((strtotime($user->reset_time) - time()) / Day) : 0;
+		$expireTime = $user->expired_at;
+		$view['remainDays'] = $expireTime < date('Y-m-d')? -1 : Helpers::daysToNow($expireTime);
+		$view['resetDays'] = $user->reset_time? Helpers::daysToNow($user->reset_time) : 0;
 		$view['unusedTransfer'] = $unusedTransfer;
 		$view['expireTime'] = $expireTime;
 		$view['banedTime'] = $user->ban_time? date('Y-m-d H:i:s', $user->ban_time) : 0;
 		$view['unusedPercent'] = $totalTransfer > 0? round($unusedTransfer / $totalTransfer, 2) : 0;
 		$view['noticeList'] = Article::type(2)->latest()->Paginate(1); // 公告
 		//流量异常判断
-		$hourlyTraffic = UserHourlyDataFlow::query()
-		                                   ->userHourly($user->id)
-		                                   ->where('created_at', '>=', date('Y-m-d H:i:s', time() - Minute * 65))
-		                                   ->sum('total');
+		$hourlyTraffic = UserHourlyDataFlow::userRecentUsed($user->id)->sum('total');
 		$view['isTrafficWarning'] = $hourlyTraffic >= (self::$sysConfig['traffic_ban_value'] * GB)?: 0;
 		//付费用户判断
 		$view['not_paying_user'] = Order::uid()
@@ -75,7 +72,7 @@ class UserController extends Controller {
 		                                ->whereIsExpire(0)
 		                                ->where('origin_amount', '>', 0)
 		                                ->doesntExist();
-		$view['userLoginLog'] = UserLoginLog::query()->whereUserId($user->id)->latest()->first(); // 近期登录日志
+		$view['userLoginLog'] = UserLoginLog::whereUserId($user->id)->latest()->first(); // 近期登录日志
 		$view = array_merge($view, $this->dataFlowChart($user->id));
 
 		return Response::view('user.index', $view);
@@ -96,8 +93,8 @@ class UserController extends Controller {
 
 		$traffic = random_int((int) self::$sysConfig['min_rand_traffic'],
 				(int) self::$sysConfig['max_rand_traffic']) * MB;
-		$ret = User::uid()->increment('transfer_enable', $traffic);
-		if(!$ret){
+
+		if(!(new UserService())->incrementData($traffic)){
 			return Response::json(['status' => 'fail', 'message' => '签到失败,系统异常']);
 		}
 
@@ -131,43 +128,29 @@ class UserController extends Controller {
 		}
 
 		// 获取当前用户可用节点
-		$nodeList = Node::query()
-		                ->whereStatus(1)
-		                ->groupNodePermit($user->group_id)
-		                ->where('level', '<=', $user->level)
-		                ->orderByDesc('sort')
-		                ->orderBy('id')
-		                ->get();
-
-		$nodesGeo = $nodeList->pluck('name', 'geo')->toArray();
+		$nodeList = $user->userAccessNodes()->with(['labels', 'level_table'])->get();
+
+		$view['nodesGeo'] = $nodeList->pluck('name', 'geo')->toArray();
+		$onlineNode = NodeHeartBeat::recently()->distinct()->pluck('node_id')->toArray();
+		$pingNodeLogs = NodePing::whereMonth('created_at', date('m'))->get(['node_id', 'ct', 'cu', 'cm', 'hk']);
 		foreach($nodeList as $node){
-			$node->ct = number_format(NodePing::query()->whereNodeId($node->id)->where('ct', '>', '0')->avg('ct'), 1,
-				'.', '');
-			$node->cu = number_format(NodePing::query()->whereNodeId($node->id)->where('cu', '>', '0')->avg('cu'), 1,
-				'.', '');
-			$node->cm = number_format(NodePing::query()->whereNodeId($node->id)->where('cm', '>', '0')->avg('cm'), 1,
-				'.', '');
-			$node->hk = number_format(NodePing::query()->whereNodeId($node->id)->where('hk', '>', '0')->avg('hk'), 1,
-				'.', '');
+			$data = $pingNodeLogs->where('node_id', $node->id);
+			$node->ct = round($data->pluck('ct')->filter()->avg(), 2);
+			$node->cu = round($data->pluck('cu')->filter()->avg(), 2);
+			$node->cm = round($data->pluck('cm')->filter()->avg(), 2);
+			$node->hk = round($data->pluck('hk')->filter()->avg(), 2);
 
 			// 节点在线状态
-			$node->offline = NodeInfo::query()
-			                         ->whereNodeId($node->id)
-			                         ->where('log_time', '>=', strtotime("-10 minutes"))
-			                         ->latest('log_time')
-			                         ->doesntExist();
-			// 节点标签
-			$node->labels = NodeLabel::query()->whereNodeId($node->id)->get();
+			$node->offline = !in_array($node->id, $onlineNode);
 		}
 		$view['nodeList'] = $nodeList?: [];
-		$view['nodesGeo'] = $nodesGeo;
 
 		return Response::view('user.nodeList', $view);
 	}
 
 	// 公告详情
 	public function article(Request $request): \Illuminate\Http\Response {
-		$view['info'] = Article::query()->findOrFail($request->input('id'));
+		$view['info'] = Article::findOrFail($request->input('id'));
 
 		return Response::view('user.article', $view);
 	}
@@ -198,8 +181,7 @@ class UserController extends Controller {
 					return Redirect::to('profile#tab_1')->withErrors('演示环境禁止修改管理员密码');
 				}
 
-				$ret = User::uid()->update(['password' => Hash::make($new_password)]);
-				if(!$ret){
+				if(!$user->update(['password' => Hash::make($new_password)])){
 					return Redirect::to('profile#tab_1')->withErrors('修改失败');
 				}
 
@@ -208,8 +190,7 @@ class UserController extends Controller {
 			}
 
 			if($passwd){
-				$ret = User::uid()->update(['passwd' => $passwd]);
-				if(!$ret){
+				if(!$user->update(['passwd' => $passwd])){
 					return Redirect::to('profile#tab_3')->withErrors('修改失败');
 				}
 
@@ -221,8 +202,7 @@ class UserController extends Controller {
 				return Redirect::to('profile#tab_2')->withErrors('修改失败,昵称不能为空值');
 			}
 
-			$ret = User::uid()->update(['username' => $username, 'wechat' => $wechat, 'qq' => $qq]);
-			if(!$ret){
+			if(!$user->update(['username' => $username, 'wechat' => $wechat, 'qq' => $qq])){
 				return Redirect::to('profile#tab_2')->withErrors('修改失败');
 			}
 
@@ -237,27 +217,18 @@ class UserController extends Controller {
 		$user = Auth::getUser();
 		// 余额充值商品,只取10个
 		$view['chargeGoodsList'] = Goods::type(3)->whereStatus(1)->orderBy('price')->limit(10)->get();
-		$view['goodsList'] = Goods::query()
-		                          ->whereStatus(1)
+		$view['goodsList'] = Goods::whereStatus(1)
 		                          ->where('type', '<=', '2')
 		                          ->orderByDesc('type')
 		                          ->orderByDesc('sort')
 		                          ->paginate(10)
 		                          ->appends($request->except('page'));
-		$renewOrder = Order::query()
-		                   ->with(['goods'])
-		                   ->whereUserId($user->id)
-		                   ->whereStatus(2)
-		                   ->whereIsExpire(0)
-		                   ->whereHas('goods', static function($q) {
-			                   $q->whereType(2);
-		                   })
-		                   ->first();
-		$renewPrice = $renewOrder? Goods::find($renewOrder->goods_id) : 0;
+		$renewOrder = Order::userActivePlan($user->id)->first();
+		$renewPrice = $renewOrder? $renewOrder->goods : 0;
 		$view['renewTraffic'] = $renewPrice? $renewPrice->renew : 0;
 		// 有重置日时按照重置日为标准,否者就以过期日为标准
-		$dataPlusDays = $user->reset_time?: $user->expire_time;
-		$view['dataPlusDays'] = $dataPlusDays > date('Y-m-d')? ceil((strtotime($dataPlusDays) - time()) / Day) : 0;
+		$dataPlusDays = $user->reset_time?: $user->expired_at;
+		$view['dataPlusDays'] = $dataPlusDays > date('Y-m-d')? Helpers::daysToNow($dataPlusDays) : 0;
 
 		return Response::view('user.services', $view);
 	}
@@ -265,23 +236,16 @@ class UserController extends Controller {
 	//重置流量
 	public function resetUserTraffic(): ?JsonResponse {
 		$user = Auth::getUser();
-		$order = Order::uid()
-		              ->whereStatus(2)
-		              ->whereIsExpire(0)
-		              ->with(['goods'])
-		              ->whereHas('goods', static function($q) {
-			              $q->whereType(2);
-		              })
-		              ->first();
-		$renewCost = Goods::find($order->goods_id)->renew;
+		$order = Order::userActivePlan()->first();
+		$renewCost = $order->goods->renew;
 		if($user->credit < $renewCost){
 			return Response::json(['status' => 'fail', 'message' => '余额不足,请充值余额']);
 		}
 
-		User::uid()->update(['u' => 0, 'd' => 0]);
+		$user->update(['u' => 0, 'd' => 0]);
 
 		// 扣余额
-		User::query()->whereId($user->id)->decrement('credit', $renewCost * 100);
+		(new UserService($user))->updateCredit(-$renewCost);
 
 		// 记录余额操作日志
 		Helpers::addUserCreditLog($user->id, '', $user->credit, $user->credit - $renewCost, -1 * $renewCost,
@@ -300,28 +264,28 @@ class UserController extends Controller {
 	// 订单
 	public function invoices(Request $request): \Illuminate\Http\Response {
 		$view['orderList'] = Order::uid()
-		                          ->with(['user', 'goods', 'coupon', 'payment'])
-		                          ->orderByDesc('oid')
+		                          ->with(['goods', 'payment'])
+		                          ->orderByDesc('id')
 		                          ->paginate(10)
 		                          ->appends($request->except('page'));
+		$view['prepaidPlan'] = Order::userPrepay()->exists();
 
 		return Response::view('user.invoices', $view);
 	}
 
-	public function activeOrder(Request $request): JsonResponse {
-		$oid = $request->input('oid');
-		$prepaidOrder = Order::find($oid);
-		if(!$prepaidOrder){
-			return Response::json(['status' => 'fail', 'message' => '查无此单!']);
-		}
+	public function closePlan(): JsonResponse {
+		$activePlan = Order::userActivePlan()->first();
+		$activePlan->is_expire = 1;
 
-		if($prepaidOrder->status != 3){
-			return Response::json(['status' => 'fail', 'message' => '非预支付订单,无需再次启动!']);
+		if($activePlan->save()){
+			// 关闭先前套餐后,新套餐自动运行
+			if(Order::userActivePlan()->exists()){
+				return Response::json(['status' => 'success', 'message' => '激活成功']);
+			}
+			return Response::json(['status' => 'success', 'message' => '关闭']);
 		}
 
-		(new ServiceController)->activePrepaidOrder($oid);
-
-		return Response::json(['status' => 'success', 'message' => '激活成功']);
+		return Response::json(['status' => 'fail', 'message' => '关闭失败']);
 	}
 
 	// 订单明细
@@ -415,7 +379,7 @@ class UserController extends Controller {
 		}
 
 		$view['ticket'] = $ticket;
-		$view['replyList'] = TicketReply::query()->whereTicketId($id)->with('user')->oldest()->get();
+		$view['replyList'] = TicketReply::whereTicketId($id)->with('user')->oldest()->get();
 
 		return Response::view('user.replyTicket', $view);
 	}
@@ -436,13 +400,13 @@ class UserController extends Controller {
 
 	// 邀请码
 	public function invite(): \Illuminate\Http\Response {
-		if(Order::uid()->whereStatus(2)->whereIsExpire(0)->where('origin_amount', '>', 0)->doesntExist()){
+		if(Order::uid()->active()->where('origin_amount', '>', 0)->doesntExist()){
 			return Response::view('auth.error',
 				['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返 回</a>']);
 		}
 
 		$view['num'] = Auth::getUser()->invite_num; // 还可以生成的邀请码数量
-		$view['inviteList'] = Invite::uid()->with(['generator', 'user'])->paginate(10); // 邀请码列表
+		$view['inviteList'] = Invite::uid()->with(['invitee', 'inviter'])->paginate(10); // 邀请码列表
 		$view['referral_traffic'] = flowAutoShow(self::$sysConfig['referral_traffic'] * MB);
 		$view['referral_percent'] = self::$sysConfig['referral_percent'];
 
@@ -457,8 +421,8 @@ class UserController extends Controller {
 		}
 
 		$obj = new Invite();
-		$obj->uid = $user->id;
-		$obj->fuid = 0;
+		$obj->inviter_id = $user->id;
+		$obj->invitee_id = 0;
 		$obj->code = strtoupper(mb_substr(md5(microtime().makeRandStr()), 8, 12));
 		$obj->status = 0;
 		$obj->dateline = date('Y-m-d H:i:s', strtotime("+".self::$sysConfig['user_invite_days']." days"));
@@ -478,7 +442,7 @@ class UserController extends Controller {
 			return Response::json(['status' => 'fail', 'title' => '使用失败', 'message' => '请输入您的优惠劵!']);
 		}
 
-		$coupon = Coupon::query()->whereSn($coupon_sn)->whereIn('type', [1, 2])->first();
+		$coupon = Coupon::whereSn($coupon_sn)->whereIn('type', [1, 2])->first();
 		if(!$coupon){
 			return Response::json(['status' => 'fail', 'title' => '优惠券不存在', 'message' => '请确认优惠券是否输入正确!']);
 		}
@@ -491,14 +455,14 @@ class UserController extends Controller {
 			return Response::json(['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已失效!']);
 		}
 
-		if($coupon->available_end < time()){
+		if($coupon->end_time < time()){
 			$coupon->status = 2;
 			$coupon->save();
 
 			return Response::json(['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已失效!']);
 		}
 
-		if($coupon->available_start > time()){
+		if($coupon->start_time > time()){
 			return Response::json(['status' => 'fail', 'title' => '优惠券尚未生效', 'message' => '请等待活动正式开启']);
 		}
 
@@ -507,10 +471,9 @@ class UserController extends Controller {
 		}
 
 		$data = [
-			'name'     => $coupon->name,
-			'type'     => $coupon->type,
-			'amount'   => $coupon->amount,
-			'discount' => $coupon->discount
+			'name'  => $coupon->name,
+			'type'  => $coupon->type,
+			'value' => $coupon->value
 		];
 
 		return Response::json(['status' => 'success', 'data' => $data, 'message' => '优惠券有效']);
@@ -519,21 +482,14 @@ class UserController extends Controller {
 	// 购买服务
 	public function buy($goods_id) {
 		$user = Auth::getUser();
-		$goods = Goods::query()->whereId($goods_id)->whereStatus(1)->first();
+		$goods = Goods::whereId($goods_id)->whereStatus(1)->first();
 		if(empty($goods)){
 			return Redirect::to('services');
 		}
 		// 有重置日时按照重置日为标准,否者就以过期日为标准
-		$dataPlusDays = $user->reset_time?: $user->expire_time;
-		$view['dataPlusDays'] = $dataPlusDays > date('Y-m-d')? ceil((strtotime($dataPlusDays) - time()) / Day) : 0;
-		$view['activePlan'] = Order::uid()
-		                           ->with(['goods'])
-		                           ->whereIsExpire(0)
-		                           ->whereStatus(2)
-		                           ->whereHas('goods', static function($q) {
-			                           $q->whereType(2);
-		                           })
-		                           ->exists();
+		$dataPlusDays = $user->reset_time?: $user->expired_at;
+		$view['dataPlusDays'] = $dataPlusDays > date('Y-m-d')? Helpers::daysToNow($dataPlusDays) : 0;
+		$view['activePlan'] = Order::userActivePlan()->exists();
 		$view['goods'] = $goods;
 
 		return Response::view('user.buy', $view);
@@ -543,30 +499,26 @@ class UserController extends Controller {
 	public function help(): \Illuminate\Http\Response {
 		//$view['articleList'] = Article::type(1)->orderByDesc('sort')->latest()->limit(10)->paginate(5);
 		$data = [];
-		if(Node::query()->whereIn('type', [1, 4])->whereStatus(1)->exists()){
+		if(Node::whereIn('type', [1, 4])->whereStatus(1)->exists()){
 			$data[] = 'ss';
 			//array_push
 		}
-		if(Node::query()->whereType(2)->whereStatus(1)->exists()){
+		if(Node::whereType(2)->whereStatus(1)->exists()){
 			$data[] = 'v2';
 		}
-		if(Node::query()->whereType(3)->whereStatus(1)->exists()){
+		if(Node::whereType(3)->whereStatus(1)->exists()){
 			$data[] = 'trojan';
 		}
 
 		$view['sub'] = $data;
 
 		//付费用户判断
-		$view['not_paying_user'] = Order::uid()
-		                                ->whereStatus(2)
-		                                ->whereIsExpire(0)
-		                                ->where('origin_amount', '>', 0)
-		                                ->doesntExist();
+		$view['not_paying_user'] = Order::uid()->active()->where('origin_amount', '>', 0)->doesntExist();
 		//客户端安装
 		$view['Shadowrocket_install'] = 'itms-services://?action=download-manifest&url='.self::$sysConfig['website_url'].'/clients/Shadowrocket.plist';
 		$view['Quantumult_install'] = 'itms-services://?action=download-manifest&url='.self::$sysConfig['website_url'].'/clients/Quantumult.plist';
 		// 订阅连接
-		$subscribe = UserSubscribe::query()->whereUserId(Auth::id())->firstOrFail();
+		$subscribe = UserSubscribe::whereUserId(Auth::id())->firstOrFail();
 		$view['subscribe_status'] = $subscribe->status;
 		$subscribe_link = (self::$sysConfig['subscribe_domain']?: self::$sysConfig['website_url']).'/s/'.$subscribe->code;
 		$view['link'] = $subscribe_link;
@@ -585,10 +537,10 @@ class UserController extends Controller {
 			DB::beginTransaction();
 
 			// 更换订阅码
-			UserSubscribe::uid()->update(['code' => Helpers::makeSubscribeCode()]);
+			Auth::getUser()->subscribe->update(['code' => Helpers::makeSubscribeCode()]);
 
 			// 更换连接密码
-			User::uid()->update(['passwd' => makeRandStr()]);
+			Auth::getUser()->update(['passwd' => makeRandStr()]);
 
 			DB::commit();
 
@@ -617,7 +569,7 @@ class UserController extends Controller {
 		return Response::json(['status' => 'fail', 'message' => '身份切换失败']);
 	}
 
-	// 卡券余额充值
+	// Todo 卡券余额合并至CouponService
 	public function charge(Request $request): ?JsonResponse {
 		$validator = Validator::make($request->all(), [
 			'coupon_sn' => [
@@ -632,23 +584,23 @@ class UserController extends Controller {
 			return Response::json(['status' => 'fail', 'message' => $validator->getMessageBag()->first()]);
 		}
 
-		$coupon = Coupon::query()->whereSn($request->input('coupon_sn'))->firstOrFail();
+		$coupon = Coupon::whereSn($request->input('coupon_sn'))->firstOrFail();
 
 		try{
 			DB::beginTransaction();
 			// 写入日志
 			$user = Auth::getUser();
-			Helpers::addUserCreditLog($user->id, 0, $user->credit, $user->credit + $coupon->amount, $coupon->amount,
+			Helpers::addUserCreditLog($user->id, 0, $user->credit, $user->credit + $coupon->value, $coupon->value,
 				'用户手动充值 - [充值券:'.$request->input('coupon_sn').']');
 
 			// 余额充值
-			User::uid()->increment('credit', $coupon->amount * 100);
+			(new UserService($user))->updateCredit($coupon->value);
 
 			// 更改卡券状态
-			Coupon::query()->whereId($coupon->id)->update(['status' => 1]);
+			Coupon::find($coupon->id)->update(['status' => 1]);
 
 			// 写入卡券日志
-			Helpers::addCouponLog($coupon->id, 0, 0, '账户余额充值使用');
+			Helpers::addCouponLog('账户余额充值使用', $coupon->id);
 
 			DB::commit();
 

+ 2 - 2
app/Http/Middleware/WebApi.php

@@ -35,8 +35,8 @@ class WebApi {
 			return $this->returnData('Unknown Node!');
 		}
 
-		$nodeAuth = NodeAuth::query()->whereNodeId($id)->first();
-		if(!$nodeAuth || $key != $nodeAuth->key){// key不存在/不匹配
+		$nodeAuth = NodeAuth::whereNodeId($id)->first();
+		if(!$nodeAuth || $key !== $nodeAuth->key){// key不存在/不匹配
 			return $this->returnData('Token is invalid!');
 		}
 

+ 58 - 0
app/Jobs/VNet/addUser.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace App\Jobs\VNet;
+
+use App\Models\User;
+use GuzzleHttp\Client;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class addUser implements ShouldQueue {
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+	private static $data;
+	private static $url;
+	private $nodes;
+
+	public function __construct(User $users, $nodes) {
+		$this->nodes = $nodes;
+		if($users->count() > 1){
+			self::$url = '/api/v2/user/add/list';
+		}else{
+			self::$url = '/api/user/add';
+		}
+		$data = [];
+		foreach($users as $user){
+			$data[] = [
+				'uid'         => $user->id,
+				'port'        => $user->port,
+				'passwd'      => $user->passwd,
+				'speed_limit' => $user->speed_limit,
+				'enable'      => $user->enable,
+			];
+		}
+		self::$data = $data;
+	}
+
+	public function handle(): void {
+		foreach($this->nodes as $node){
+			self::send(($node->server?: $node->ip).':'.$node->push_port, $node->auth->secret);
+		}
+	}
+
+	private static function send($host, $secret): void {
+		$client = new Client([
+			'base_uri' => $host,
+			'timeout'  => 15,
+			'headers'  => [
+				'secret'       => $secret,
+				'content-type' => 'application/json'
+			]
+		]);
+
+		$client->post(self::$url, ['body' => json_encode(self::$data)]);
+	}
+}

+ 45 - 0
app/Jobs/VNet/delUser.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Jobs\VNet;
+
+use GuzzleHttp\Client;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class delUser implements ShouldQueue {
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+	private static $userIds;
+	private $nodes;
+
+	public function __construct($userIds, $nodes) {
+		self::$userIds = $userIds;
+		$this->nodes = $nodes;
+	}
+
+	public function handle(): void {
+		foreach($this->nodes as $node){
+			self::send(($node->server?: $node->ip).':'.$node->push_port, $node->auth->secret);
+		}
+	}
+
+	private static function send($host, $secret): void {
+		$client = new Client([
+			'base_uri' => $host,
+			'timeout'  => 15,
+			'headers'  => [
+				'secret'       => $secret,
+				'content-type' => 'application/json'
+			]
+		]);
+
+		if(is_array(self::$userIds)){
+			$client->post('/api/v2/user/del/list', ['body' => json_encode(self::$userIds)]);
+		}else{
+			$client->post('/api/user/del/'.self::$userIds);
+		}
+	}
+}

+ 48 - 0
app/Jobs/VNet/editUser.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\Jobs\VNet;
+
+use App\Models\User;
+use GuzzleHttp\Client;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class editUser implements ShouldQueue {
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+	private static $data;
+	private $nodes;
+
+	public function __construct(User $user, $nodes) {
+		$this->nodes = $nodes;
+		self::$data = [
+			'uid'         => $user->id,
+			'port'        => $user->port,
+			'passwd'      => $user->passwd,
+			'speed_limit' => $user->speed_limit,
+			'enable'      => $user->enable,
+		];
+	}
+
+	public function handle(): void {
+		foreach($this->nodes as $node){
+			self::send(($node->server?: $node->ip).':'.$node->push_port, $node->auth->secret);
+		}
+	}
+
+	private static function send($host, $secret): void {
+		$client = new Client([
+			'base_uri' => $host,
+			'timeout'  => 15,
+			'headers'  => [
+				'secret'       => $secret,
+				'content-type' => 'application/json'
+			]
+		]);
+
+		$client->post('/api/user/edit', ['body' => json_encode(self::$data)]);
+	}
+}

+ 53 - 0
app/Jobs/VNet/reloadNode.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace App\Jobs\VNet;
+
+use App\Models\Node;
+use GuzzleHttp\Client;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class reloadNode implements ShouldQueue {
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+	private static $host;
+	private static $secret;
+	private static $data;
+
+	public function __construct(Node $node) {
+		self::$host = ($node->server?: $node->ip).':'.$node->push_port;
+		self::$secret = $node->auth->secret;
+		self::$data = [
+			'id'           => $node->id,
+			'method'       => $node->method,
+			'protocol'     => $node->protocol,
+			'obfs'         => $node->obfs,
+			'obfs_param'   => $node->obfs_param?: '',
+			'is_udp'       => $node->is_udp,
+			'speed_limit'  => $node->speed_limit,
+			'client_limit' => $node->client_limit,
+			'single'       => $node->single,
+			'port'         => (string) $node->port,
+			'passwd'       => $node->passwd?: '',
+			'push_port'    => $node->push_port,
+			'secret'       => $node->auth->secret,
+			'redirect_url' => sysConfig('redirect_url')
+		];
+	}
+
+	public function handle(): void {
+		$client = new Client([
+			'base_uri' => self::$host,
+			'timeout'  => 15,
+			'headers'  => [
+				'secret'       => self::$secret,
+				'content-type' => 'application/json'
+			]
+		]);
+
+		$client->post('/api/v2/node/reload', ['body' => json_encode(self::$data)]);
+	}
+}

+ 1 - 1
app/Mail/activeUser.php

@@ -28,6 +28,6 @@ class activeUser extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/closeTicket.php

@@ -31,6 +31,6 @@ class closeTicket extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/newTicket.php

@@ -31,6 +31,6 @@ class newTicket extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/nodeCrashWarning.php

@@ -27,6 +27,6 @@ class nodeCrashWarning extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/replyTicket.php

@@ -31,6 +31,6 @@ class replyTicket extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/resetPassword.php

@@ -28,6 +28,6 @@ class resetPassword extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/sendUserInfo.php

@@ -28,6 +28,6 @@ class sendUserInfo extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/sendVerifyCode.php

@@ -28,6 +28,6 @@ class sendVerifyCode extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/userExpireWarning.php

@@ -28,6 +28,6 @@ class userExpireWarning extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/userExpireWarningToday.php

@@ -24,6 +24,6 @@ class userExpireWarningToday extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 1
app/Mail/userTrafficWarning.php

@@ -28,6 +28,6 @@ class userTrafficWarning extends Mailable implements ShouldQueue {
 
 	// 发件失败处理
 	public function failed(Exception $e): void {
-		NotificationLog::query()->whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
+		NotificationLog::whereId($this->id)->update(['status' => -1, 'error' => $e->getMessage()]);
 	}
 }

+ 1 - 32
app/Models/Article.php

@@ -2,49 +2,18 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
 /**
  * 文章
- *
- * @property int                             $id
- * @property int|null                        $type       类型:1-文章、2-站内公告、3-站外公告
- * @property string                          $title      标题
- * @property string|null                     $author     作者
- * @property string|null                     $summary    简介
- * @property string|null                     $logo       LOGO
- * @property string|null                     $content    内容
- * @property int                             $sort       排序
- * @property \Illuminate\Support\Carbon      $created_at 创建时间
- * @property \Illuminate\Support\Carbon      $updated_at 最后更新时间
- * @property \Illuminate\Support\Carbon|null $deleted_at 删除时间
- * @method static Builder|Article newModelQuery()
- * @method static Builder|Article newQuery()
- * @method static Builder|Article onlyTrashed()
- * @method static Builder|Article query()
- * @method static Builder|Article type($type)
- * @method static Builder|Article whereAuthor($value)
- * @method static Builder|Article whereContent($value)
- * @method static Builder|Article whereCreatedAt($value)
- * @method static Builder|Article whereDeletedAt($value)
- * @method static Builder|Article whereId($value)
- * @method static Builder|Article whereLogo($value)
- * @method static Builder|Article whereSort($value)
- * @method static Builder|Article whereSummary($value)
- * @method static Builder|Article whereTitle($value)
- * @method static Builder|Article whereType($value)
- * @method static Builder|Article whereUpdatedAt($value)
- * @method static Builder|Article withTrashed()
- * @method static Builder|Article withoutTrashed()
- * @mixin \Eloquent
  */
 class Article extends Model {
 	use SoftDeletes;
 
 	protected $table = 'article';
 	protected $dates = ['deleted_at'];
+	protected $guarded = ['id', 'created_at'];
 
 	// 筛选类型
 	public function scopeType($query, $type) {

+ 4 - 12
app/Models/Config.php

@@ -2,24 +2,16 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 系统配置
- *
- * @property int         $id
- * @property string      $name  配置名
- * @property string|null $value 配置值
- * @method static Builder|Config newModelQuery()
- * @method static Builder|Config newQuery()
- * @method static Builder|Config query()
- * @method static Builder|Config whereId($value)
- * @method static Builder|Config whereName($value)
- * @method static Builder|Config whereValue($value)
- * @mixin \Eloquent
  */
 class Config extends Model {
 	public $timestamps = false;
+	public $incrementing = false;
 	protected $table = 'config';
+	protected $primaryKey = 'name';
+	protected $keyType = 'string';
+	protected $fillable = ['value'];
 }

+ 4 - 12
app/Models/Country.php

@@ -2,24 +2,16 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 国家/地区
- *
- * @property int    $id
- * @property string $name 名称
- * @property string $code 代码
- * @method static Builder|Country newModelQuery()
- * @method static Builder|Country newQuery()
- * @method static Builder|Country query()
- * @method static Builder|Country whereCode($value)
- * @method static Builder|Country whereId($value)
- * @method static Builder|Country whereName($value)
- * @mixin \Eloquent
  */
 class Country extends Model {
 	public $timestamps = false;
+	public $incrementing = false;
 	protected $table = 'country';
+	protected $primaryKey = 'code';
+	protected $keyType = 'string';
+	protected $fillable = ['*'];
 }

+ 1 - 64
app/Models/Coupon.php

@@ -2,84 +2,21 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
 /**
  * 优惠券
- *
- * @property int                             $id
- * @property string                          $name            优惠券名称
- * @property string                          $logo            优惠券LOGO
- * @property string                          $sn              优惠券码
- * @property int                             $type            类型:1-抵用券、2-折扣券、3-充值券
- * @property int                             $usage_count     可使用次数
- * @property int                             $amount          金额,单位分
- * @property float                           $discount        折扣
- * @property int                             $rule            使用限制,单位分
- * @property int                             $available_start 有效期开始
- * @property int                             $available_end   有效期结束
- * @property int                             $status          状态:0-未使用、1-已使用、2-已失效
- * @property \Illuminate\Support\Carbon      $created_at      创建时间
- * @property \Illuminate\Support\Carbon      $updated_at      最后更新时间
- * @property \Illuminate\Support\Carbon|null $deleted_at      删除时间
- * @method static Builder|Coupon newModelQuery()
- * @method static Builder|Coupon newQuery()
- * @method static Builder|Coupon onlyTrashed()
- * @method static Builder|Coupon query()
- * @method static Builder|Coupon type($type)
- * @method static Builder|Coupon whereAmount($value)
- * @method static Builder|Coupon whereAvailableEnd($value)
- * @method static Builder|Coupon whereAvailableStart($value)
- * @method static Builder|Coupon whereCreatedAt($value)
- * @method static Builder|Coupon whereDeletedAt($value)
- * @method static Builder|Coupon whereDiscount($value)
- * @method static Builder|Coupon whereId($value)
- * @method static Builder|Coupon whereLogo($value)
- * @method static Builder|Coupon whereName($value)
- * @method static Builder|Coupon whereRule($value)
- * @method static Builder|Coupon whereSn($value)
- * @method static Builder|Coupon whereStatus($value)
- * @method static Builder|Coupon whereType($value)
- * @method static Builder|Coupon whereUpdatedAt($value)
- * @method static Builder|Coupon whereUsageCount($value)
- * @method static Builder|Coupon withTrashed()
- * @method static Builder|Coupon withoutTrashed()
- * @mixin \Eloquent
  */
 class Coupon extends Model {
 	use SoftDeletes;
 
 	protected $table = 'coupon';
 	protected $dates = ['deleted_at'];
+	protected $fillable = ['usable_times', 'status'];
 
 	// 筛选类型
 	public function scopeType($query, $type) {
 		return $query->whereType($type);
 	}
-
-	public function getAmountAttribute($value) {
-		return $value / 100;
-	}
-
-	public function setAmountAttribute($value): void {
-		$this->attributes['amount'] = $value * 100;
-	}
-
-	public function getDiscountAttribute($value) {
-		return $value * 10;
-	}
-
-	public function setDiscountAttribute($value): void {
-		$this->attributes['discount'] = $value / 10;
-	}
-
-	public function getRuleAttribute($value) {
-		return $value / 100;
-	}
-
-	public function setRuleAttribute($value): void {
-		$this->attributes['rule'] = $value * 100;
-	}
 }

+ 1 - 19
app/Models/CouponLog.php

@@ -2,30 +2,12 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 优惠券使用日志
- *
- * @property int                        $id
- * @property int                        $coupon_id   优惠券ID
- * @property int                        $goods_id    商品ID
- * @property int                        $order_id    订单ID
- * @property string                     $description 备注
- * @property \Illuminate\Support\Carbon $created_at  创建时间
- * @method static Builder|CouponLog newModelQuery()
- * @method static Builder|CouponLog newQuery()
- * @method static Builder|CouponLog query()
- * @method static Builder|CouponLog whereCouponId($value)
- * @method static Builder|CouponLog whereCreatedAt($value)
- * @method static Builder|CouponLog whereDescription($value)
- * @method static Builder|CouponLog whereGoodsId($value)
- * @method static Builder|CouponLog whereId($value)
- * @method static Builder|CouponLog whereOrderId($value)
- * @mixin \Eloquent
  */
 class CouponLog extends Model {
-	const UPDATED_AT = null;
+	public const UPDATED_AT = null;
 	protected $table = 'coupon_log';
 }

+ 0 - 12
app/Models/EmailFilter.php

@@ -2,22 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 邮箱后缀过滤
- *
- * @property int    $id
- * @property int    $type  类型:1-黑名单、2-白名单
- * @property string $words 邮箱后缀
- * @method static Builder|EmailFilter newModelQuery()
- * @method static Builder|EmailFilter newQuery()
- * @method static Builder|EmailFilter query()
- * @method static Builder|EmailFilter whereId($value)
- * @method static Builder|EmailFilter whereType($value)
- * @method static Builder|EmailFilter whereWords($value)
- * @mixin \Eloquent
  */
 class EmailFilter extends Model {
 	public $timestamps = false;

+ 0 - 53
app/Models/Goods.php

@@ -2,64 +2,11 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
 /**
  * 商品
- *
- * @property int                             $id
- * @property string                          $name        商品名称
- * @property string|null                     $logo        商品图片地址
- * @property int                             $traffic     商品内含多少流量,单位MiB
- * @property int                             $type        商品类型:1-流量包、2-套餐
- * @property int                             $price       售价,单位分
- * @property int                             $level       购买后给用户授权的等级
- * @property int                             $renew       流量重置价格,单位分
- * @property int                             $period      流量自动重置周期
- * @property string|null                     $info        商品信息
- * @property string|null                     $description 商品描述
- * @property int                             $days        有效期
- * @property int                             $invite_num  赠送邀请码数
- * @property int                             $limit_num   限购数量,默认为0不限购
- * @property string                          $color       商品颜色
- * @property int                             $sort        排序
- * @property int                             $is_hot      是否热销:0-否、1-是
- * @property int                             $status      状态:0-下架、1-上架
- * @property \Illuminate\Support\Carbon      $created_at  创建时间
- * @property \Illuminate\Support\Carbon      $updated_at  最后更新时间
- * @property \Illuminate\Support\Carbon|null $deleted_at  删除时间
- * @property-read mixed                      $traffic_label
- * @method static Builder|Goods newModelQuery()
- * @method static Builder|Goods newQuery()
- * @method static Builder|Goods onlyTrashed()
- * @method static Builder|Goods query()
- * @method static Builder|Goods type($type)
- * @method static Builder|Goods whereColor($value)
- * @method static Builder|Goods whereCreatedAt($value)
- * @method static Builder|Goods whereDays($value)
- * @method static Builder|Goods whereDeletedAt($value)
- * @method static Builder|Goods whereDescription($value)
- * @method static Builder|Goods whereId($value)
- * @method static Builder|Goods whereInfo($value)
- * @method static Builder|Goods whereInviteNum($value)
- * @method static Builder|Goods whereIsHot($value)
- * @method static Builder|Goods whereLevel($value)
- * @method static Builder|Goods whereLimitNum($value)
- * @method static Builder|Goods whereLogo($value)
- * @method static Builder|Goods whereName($value)
- * @method static Builder|Goods wherePeriod($value)
- * @method static Builder|Goods wherePrice($value)
- * @method static Builder|Goods whereRenew($value)
- * @method static Builder|Goods whereSort($value)
- * @method static Builder|Goods whereStatus($value)
- * @method static Builder|Goods whereTraffic($value)
- * @method static Builder|Goods whereType($value)
- * @method static Builder|Goods whereUpdatedAt($value)
- * @method static Builder|Goods withTrashed()
- * @method static Builder|Goods withoutTrashed()
- * @mixin \Eloquent
  */
 class Goods extends Model {
 	use SoftDeletes;

+ 7 - 37
app/Models/Invite.php

@@ -3,60 +3,30 @@
 namespace App\Models;
 
 use Auth;
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\HasOne;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
 /**
  * 邀请码
- *
- * @property int                             $id
- * @property int                             $uid        邀请人ID
- * @property int                             $fuid       受邀人ID
- * @property string                          $code       邀请码
- * @property int                             $status     邀请码状态:0-未使用、1-已使用、2-已过期
- * @property \Illuminate\Support\Carbon      $dateline   有效期至
- * @property \Illuminate\Support\Carbon      $created_at 创建时间
- * @property \Illuminate\Support\Carbon      $updated_at 最后更新时间
- * @property \Illuminate\Support\Carbon|null $deleted_at 删除时间
- * @property-read \App\Models\User|null      $generator
- * @property-read string                     $status_label
- * @property-read \App\Models\User|null      $user
- * @method static Builder|Invite newModelQuery()
- * @method static Builder|Invite newQuery()
- * @method static Builder|Invite onlyTrashed()
- * @method static Builder|Invite query()
- * @method static Builder|Invite uid()
- * @method static Builder|Invite whereCode($value)
- * @method static Builder|Invite whereCreatedAt($value)
- * @method static Builder|Invite whereDateline($value)
- * @method static Builder|Invite whereDeletedAt($value)
- * @method static Builder|Invite whereFuid($value)
- * @method static Builder|Invite whereId($value)
- * @method static Builder|Invite whereStatus($value)
- * @method static Builder|Invite whereUid($value)
- * @method static Builder|Invite whereUpdatedAt($value)
- * @method static Builder|Invite withTrashed()
- * @method static Builder|Invite withoutTrashed()
- * @mixin \Eloquent
  */
 class Invite extends Model {
 	use SoftDeletes;
 
 	protected $table = 'invite';
 	protected $dates = ['dateline', 'deleted_at'];
+	protected $fillable = ['invitee_id', 'status'];
 
 	public function scopeUid($query) {
-		return $query->whereUid(Auth::id());
+		return $query->whereInviterId(Auth::id());
 	}
 
-	public function generator(): HasOne {
-		return $this->hasOne(User::class, 'id', 'uid');
+	public function inviter(): BelongsTo {
+		return $this->belongsTo(User::class);
 	}
 
-	public function user(): HasOne {
-		return $this->hasOne(User::class, 'id', 'fuid');
+	public function invitee(): BelongsTo {
+		return $this->belongsTo(User::class);
 	}
 
 	public function getStatusLabelAttribute(): string {

+ 5 - 12
app/Models/Label.php

@@ -2,24 +2,17 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
 
 /**
  * 标签
- *
- * @property int    $id
- * @property string $name 名称
- * @property int    $sort 排序值
- * @method static Builder|Label newModelQuery()
- * @method static Builder|Label newQuery()
- * @method static Builder|Label query()
- * @method static Builder|Label whereId($value)
- * @method static Builder|Label whereName($value)
- * @method static Builder|Label whereSort($value)
- * @mixin \Eloquent
  */
 class Label extends Model {
 	public $timestamps = false;
 	protected $table = 'label';
+
+	public function nodes(): HasMany {
+		return $this->hasMany(NodeLabel::class);
+	}
 }

+ 0 - 12
app/Models/Level.php

@@ -2,22 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 等级
- *
- * @property int    $id
- * @property int    $level 等级
- * @property string $name  等级名称
- * @method static Builder|Level newModelQuery()
- * @method static Builder|Level newQuery()
- * @method static Builder|Level query()
- * @method static Builder|Level whereId($value)
- * @method static Builder|Level whereLevel($value)
- * @method static Builder|Level whereName($value)
- * @mixin \Eloquent
  */
 class Level extends Model {
 	public $timestamps = false;

+ 0 - 25
app/Models/Marketing.php

@@ -2,35 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 营销
- *
- * @property int                        $id
- * @property int                        $type       类型:1-邮件群发
- * @property string                     $receiver   接收者
- * @property string                     $title      标题
- * @property string                     $content    内容
- * @property string|null                $error      错误信息
- * @property int                        $status     状态:-1-失败、0-待发送、1-成功
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property \Illuminate\Support\Carbon $updated_at 最后更新时间
- * @property-read string                $status_label
- * @method static Builder|Marketing newModelQuery()
- * @method static Builder|Marketing newQuery()
- * @method static Builder|Marketing query()
- * @method static Builder|Marketing whereContent($value)
- * @method static Builder|Marketing whereCreatedAt($value)
- * @method static Builder|Marketing whereError($value)
- * @method static Builder|Marketing whereId($value)
- * @method static Builder|Marketing whereReceiver($value)
- * @method static Builder|Marketing whereStatus($value)
- * @method static Builder|Marketing whereTitle($value)
- * @method static Builder|Marketing whereType($value)
- * @method static Builder|Marketing whereUpdatedAt($value)
- * @mixin \Eloquent
  */
 class Marketing extends Model {
 	protected $table = 'marketing';

+ 18 - 108
app/Models/Node.php

@@ -2,133 +2,43 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Database\Eloquent\Relations\HasOne;
 
 /**
  * 节点配置信息
- *
- * @property int                                                                   $id
- * @property int                                                                   $type           服务类型:1-Shadowsocks(R)、2-V2ray、3-Trojan、4-VNet
- * @property string                                                                $name           名称
- * @property string                                                                $country_code   国家代码
- * @property string|null                                                           $server         服务器域名地址
- * @property string|null                                                           $ip             服务器IPV4地址
- * @property string|null                                                           $ipv6           服务器IPV6地址
- * @property int                                                                   $level          等级:0-无等级,全部可见
- * @property int                                                                   $speed_limit    节点限速,为0表示不限速,单位Byte
- * @property int                                                                   $client_limit   设备数限制
- * @property string|null                                                           $relay_server   中转地址
- * @property int|null                                                              $relay_port     中转端口
- * @property string|null                                                           $description    节点简单描述
- * @property string|null                                                           $geo            节点地理位置
- * @property string                                                                $method         加密方式
- * @property string                                                                $protocol       协议
- * @property string|null                                                           $protocol_param 协议参数
- * @property string                                                                $obfs           混淆
- * @property string|null                                                           $obfs_param     混淆参数
- * @property float                                                                 $traffic_rate   流量比率
- * @property int                                                                   $is_subscribe   是否允许用户订阅该节点:0-否、1-是
- * @property int                                                                   $is_ddns        是否使用DDNS:0-否、1-是
- * @property int                                                                   $is_relay       是否中转节点:0-否、1-是
- * @property int                                                                   $is_udp         是否启用UDP:0-不启用、1-启用
- * @property int                                                                   $push_port      消息推送端口
- * @property int                                                                   $detection_type 节点检测: 0-关闭、1-只检测TCP、2-只检测ICMP、3-检测全部
- * @property int                                                                   $compatible     兼容SS
- * @property int                                                                   $single         启用单端口功能:0-否、1-是
- * @property int|null                                                              $port           单端口的端口号或连接端口号
- * @property string|null                                                           $passwd         单端口的连接密码
- * @property int                                                                   $sort           排序值,值越大越靠前显示
- * @property int                                                                   $status         状态:0-维护、1-正常
- * @property int                                                                   $v2_alter_id    V2Ray额外ID
- * @property int                                                                   $v2_port        V2Ray服务端口
- * @property string                                                                $v2_method      V2Ray加密方式
- * @property string                                                                $v2_net         V2Ray传输协议
- * @property string                                                                $v2_type        V2Ray伪装类型
- * @property string                                                                $v2_host        V2Ray伪装的域名
- * @property string                                                                $v2_path        V2Ray的WS/H2路径
- * @property int                                                                   $v2_tls         V2Ray连接TLS:0-未开启、1-开启
- * @property string|null                                                           $tls_provider   V2Ray节点的TLS提供商授权信息
- * @property \Illuminate\Support\Carbon                                            $created_at     创建时间
- * @property \Illuminate\Support\Carbon                                            $updated_at     最后更新时间
- * @property-read \App\Models\NodeAuth|null                                        $auth
- * @property-read string                                                           $level_name
- * @property-read string                                                           $type_label
- * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\NodeLabel[] $label
- * @property-read int|null                                                         $label_count
- * @method static Builder|Node groupNodePermit($group_id = 0)
- * @method static Builder|Node newModelQuery()
- * @method static Builder|Node newQuery()
- * @method static Builder|Node query()
- * @method static Builder|Node whereClientLimit($value)
- * @method static Builder|Node whereCompatible($value)
- * @method static Builder|Node whereCountryCode($value)
- * @method static Builder|Node whereCreatedAt($value)
- * @method static Builder|Node whereDescription($value)
- * @method static Builder|Node whereDetectionType($value)
- * @method static Builder|Node whereGeo($value)
- * @method static Builder|Node whereId($value)
- * @method static Builder|Node whereIp($value)
- * @method static Builder|Node whereIpv6($value)
- * @method static Builder|Node whereIsDdns($value)
- * @method static Builder|Node whereIsRelay($value)
- * @method static Builder|Node whereIsSubscribe($value)
- * @method static Builder|Node whereIsUdp($value)
- * @method static Builder|Node whereLevel($value)
- * @method static Builder|Node whereMethod($value)
- * @method static Builder|Node whereName($value)
- * @method static Builder|Node whereObfs($value)
- * @method static Builder|Node whereObfsParam($value)
- * @method static Builder|Node wherePasswd($value)
- * @method static Builder|Node wherePort($value)
- * @method static Builder|Node whereProtocol($value)
- * @method static Builder|Node whereProtocolParam($value)
- * @method static Builder|Node wherePushPort($value)
- * @method static Builder|Node whereRelayPort($value)
- * @method static Builder|Node whereRelayServer($value)
- * @method static Builder|Node whereServer($value)
- * @method static Builder|Node whereSingle($value)
- * @method static Builder|Node whereSort($value)
- * @method static Builder|Node whereSpeedLimit($value)
- * @method static Builder|Node whereStatus($value)
- * @method static Builder|Node whereTlsProvider($value)
- * @method static Builder|Node whereTrafficRate($value)
- * @method static Builder|Node whereType($value)
- * @method static Builder|Node whereUpdatedAt($value)
- * @method static Builder|Node whereV2AlterId($value)
- * @method static Builder|Node whereV2Host($value)
- * @method static Builder|Node whereV2Method($value)
- * @method static Builder|Node whereV2Net($value)
- * @method static Builder|Node whereV2Path($value)
- * @method static Builder|Node whereV2Port($value)
- * @method static Builder|Node whereV2Tls($value)
- * @method static Builder|Node whereV2Type($value)
- * @mixin \Eloquent
  */
 class Node extends Model {
 	protected $table = 'ss_node';
+	protected $guarded = ['id', 'created_at'];
 
-	public function label(): HasMany {
-		return $this->hasMany(NodeLabel::class, 'node_id', 'id');
+	public function labels(): HasMany {
+		return $this->hasMany(NodeLabel::class);
+	}
+
+	public function nodeHeartBeat(): HasMany {
+		return $this->hasMany(NodeHeartBeat::class);
 	}
 
 	public function auth(): HasOne {
-		return $this->hasOne(NodeAuth::class, 'node_id', 'id');
+		return $this->hasOne(NodeAuth::class);
 	}
 
-	public function getLevelNameAttribute(): string {
-		return Level::whereLevel($this->attributes['level'])->first()->name;
+	public function level_table(): HasOne {
+		return $this->hasOne(Level::class, 'level', 'level');
 	}
 
-	// Node查询,查用户所在分组Node权限
-	public function scopeGroupNodePermit($query, $group_id = 0) {
-		$userGroup = UserGroup::find($group_id);
+	public function scopeUserAllowNodes($query, $user_group_id, $user_level) {
+		$userGroup = UserGroup::find($user_group_id);
 		if($userGroup){
-			return $query->whereIn('id', $userGroup->nodes);
+			$query->whereIn('id', $userGroup->nodes);
 		}
-		return $query;
+		return $query->whereStatus(1)->where('level', '<=', $user_level?: 0);
+	}
+
+	public function getNodeAccessUsersAttribute() {
+		return User::nodeAllowUsers($this->attributes['id'], $this->attributes['level'])->get();
 	}
 
 	public function getTypeLabelAttribute(): string {

+ 3 - 22
app/Models/NodeAuth.php

@@ -2,35 +2,16 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\HasOne;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 节点授权密钥
- *
- * @property int                        $id
- * @property int                        $node_id    授权节点ID
- * @property string                     $key        认证KEY
- * @property string                     $secret     通信密钥
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property \Illuminate\Support\Carbon $updated_at 最后更新时间
- * @property-read \App\Models\Node|null $node
- * @method static Builder|NodeAuth newModelQuery()
- * @method static Builder|NodeAuth newQuery()
- * @method static Builder|NodeAuth query()
- * @method static Builder|NodeAuth whereCreatedAt($value)
- * @method static Builder|NodeAuth whereId($value)
- * @method static Builder|NodeAuth whereKey($value)
- * @method static Builder|NodeAuth whereNodeId($value)
- * @method static Builder|NodeAuth whereSecret($value)
- * @method static Builder|NodeAuth whereUpdatedAt($value)
- * @mixin \Eloquent
  */
 class NodeAuth extends Model {
 	protected $table = 'node_auth';
 
-	public function node(): HasOne {
-		return $this->hasOne(Node::class, 'id', 'node_id');
+	public function node(): BelongsTo {
+		return $this->belongsTo(Node::class);
 	}
 }

+ 0 - 18
app/Models/NodeCertificate.php

@@ -2,28 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 伪装域名证书
- *
- * @property int                        $id
- * @property string                     $domain     域名
- * @property string|null                $key        域名证书KEY
- * @property string|null                $pem        域名证书PEM
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property \Illuminate\Support\Carbon $updated_at 最后更新时间
- * @method static Builder|NodeCertificate newModelQuery()
- * @method static Builder|NodeCertificate newQuery()
- * @method static Builder|NodeCertificate query()
- * @method static Builder|NodeCertificate whereCreatedAt($value)
- * @method static Builder|NodeCertificate whereDomain($value)
- * @method static Builder|NodeCertificate whereId($value)
- * @method static Builder|NodeCertificate whereKey($value)
- * @method static Builder|NodeCertificate wherePem($value)
- * @method static Builder|NodeCertificate whereUpdatedAt($value)
- * @mixin \Eloquent
  */
 class NodeCertificate extends Model {
 	protected $table = 'node_certificate';

+ 4 - 25
app/Models/NodeDailyDataFlow.php

@@ -2,38 +2,17 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\HasOne;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 节点每日流量统计
- *
- * @property int                        $id
- * @property int                        $node_id    节点ID
- * @property int                        $u          上传流量
- * @property int                        $d          下载流量
- * @property int                        $total      总流量
- * @property string|null                $traffic    总流量(带单位)
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property-read \App\Models\Node|null $info
- * @method static Builder|NodeDailyDataFlow newModelQuery()
- * @method static Builder|NodeDailyDataFlow newQuery()
- * @method static Builder|NodeDailyDataFlow query()
- * @method static Builder|NodeDailyDataFlow whereCreatedAt($value)
- * @method static Builder|NodeDailyDataFlow whereD($value)
- * @method static Builder|NodeDailyDataFlow whereId($value)
- * @method static Builder|NodeDailyDataFlow whereNodeId($value)
- * @method static Builder|NodeDailyDataFlow whereTotal($value)
- * @method static Builder|NodeDailyDataFlow whereTraffic($value)
- * @method static Builder|NodeDailyDataFlow whereU($value)
- * @mixin \Eloquent
  */
 class NodeDailyDataFlow extends Model {
-	const UPDATED_AT = null;
+	public const UPDATED_AT = null;
 	protected $table = 'node_daily_data_flow';
 
-	public function info(): HasOne {
-		return $this->hasOne(Node::class, 'id', 'node_id');
+	public function node(): BelongsTo {
+		return $this->belongsTo(Node::class);
 	}
 }

+ 17 - 0
app/Models/NodeHeartBeat.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 节点负载信息
+ */
+class NodeHeartBeat extends Model {
+	public $timestamps = false;
+	protected $table = 'ss_node_info';
+
+	public function scopeRecently($query) {
+		return $query->where('log_time', '>=', strtotime("-10 minutes"))->latest('log_time');
+	}
+}

+ 4 - 25
app/Models/NodeHourlyDataFlow.php

@@ -2,38 +2,17 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\HasOne;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 节点每日流量统计
- *
- * @property int                        $id
- * @property int                        $node_id    节点ID
- * @property int                        $u          上传流量
- * @property int                        $d          下载流量
- * @property int                        $total      总流量
- * @property string|null                $traffic    总流量(带单位)
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property-read \App\Models\Node|null $info
- * @method static Builder|NodeHourlyDataFlow newModelQuery()
- * @method static Builder|NodeHourlyDataFlow newQuery()
- * @method static Builder|NodeHourlyDataFlow query()
- * @method static Builder|NodeHourlyDataFlow whereCreatedAt($value)
- * @method static Builder|NodeHourlyDataFlow whereD($value)
- * @method static Builder|NodeHourlyDataFlow whereId($value)
- * @method static Builder|NodeHourlyDataFlow whereNodeId($value)
- * @method static Builder|NodeHourlyDataFlow whereTotal($value)
- * @method static Builder|NodeHourlyDataFlow whereTraffic($value)
- * @method static Builder|NodeHourlyDataFlow whereU($value)
- * @mixin \Eloquent
  */
 class NodeHourlyDataFlow extends Model {
-	const UPDATED_AT = null;
+	public const UPDATED_AT = null;
 	protected $table = 'node_hourly_data_flow';
 
-	public function info(): HasOne {
-		return $this->hasOne(Node::class, 'id', 'node_id');
+	public function node(): BelongsTo {
+		return $this->belongsTo(Node::class);
 	}
 }

+ 0 - 29
app/Models/NodeInfo.php

@@ -1,29 +0,0 @@
-<?php
-
-namespace App\Models;
-
-use Illuminate\Database\Eloquent\Builder;
-use Illuminate\Database\Eloquent\Model;
-
-/**
- * 节点负载信息
- *
- * @property int    $id
- * @property int    $node_id  节点ID
- * @property int    $uptime   后端存活时长,单位秒
- * @property string $load     负载
- * @property int    $log_time 记录时间
- * @method static Builder|NodeInfo newModelQuery()
- * @method static Builder|NodeInfo newQuery()
- * @method static Builder|NodeInfo query()
- * @method static Builder|NodeInfo whereId($value)
- * @method static Builder|NodeInfo whereLoad($value)
- * @method static Builder|NodeInfo whereLogTime($value)
- * @method static Builder|NodeInfo whereNodeId($value)
- * @method static Builder|NodeInfo whereUptime($value)
- * @mixin \Eloquent
- */
-class NodeInfo extends Model {
-	public $timestamps = false;
-	protected $table = 'ss_node_info';
-}

+ 7 - 16
app/Models/NodeLabel.php

@@ -2,30 +2,21 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\HasOne;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 节点标签
- *
- * @property int                         $id
- * @property int                         $node_id  节点ID
- * @property int                         $label_id 标签ID
- * @property-read \App\Models\Label|null $labelInfo
- * @method static Builder|NodeLabel newModelQuery()
- * @method static Builder|NodeLabel newQuery()
- * @method static Builder|NodeLabel query()
- * @method static Builder|NodeLabel whereId($value)
- * @method static Builder|NodeLabel whereLabelId($value)
- * @method static Builder|NodeLabel whereNodeId($value)
- * @mixin \Eloquent
  */
 class NodeLabel extends Model {
 	public $timestamps = false;
 	protected $table = 'node_label';
 
-	public function labelInfo(): HasOne {
-		return $this->hasOne(Label::class, 'id', 'label_id');
+	public function node(): BelongsTo {
+		return $this->belongsTo(Node::class);
+	}
+
+	public function label(): BelongsTo {
+		return $this->belongsTo(Label::class);
 	}
 }

+ 0 - 14
app/Models/NodeOnlineLog.php

@@ -2,24 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 节点用户在线情况
- *
- * @property int $id
- * @property int $node_id     节点ID
- * @property int $online_user 在线用户数
- * @property int $log_time    记录时间
- * @method static Builder|NodeOnlineLog newModelQuery()
- * @method static Builder|NodeOnlineLog newQuery()
- * @method static Builder|NodeOnlineLog query()
- * @method static Builder|NodeOnlineLog whereId($value)
- * @method static Builder|NodeOnlineLog whereLogTime($value)
- * @method static Builder|NodeOnlineLog whereNodeId($value)
- * @method static Builder|NodeOnlineLog whereOnlineUser($value)
- * @mixin \Eloquent
  */
 class NodeOnlineLog extends Model {
 	public $timestamps = false;

+ 2 - 24
app/Models/NodeOnlineUserIp.php

@@ -2,43 +2,21 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 节点在线用户IP信息
- *
- * @property int                   $id
- * @property int                   $node_id    节点ID
- * @property int                   $user_id    用户ID
- * @property int                   $port       端口
- * @property string                $type       类型:all、tcp、udp
- * @property string|null           $ip         连接IP:每个IP用,号隔开
- * @property int                   $created_at 上报时间
- * @property-read \App\Models\Node $node
- * @property-read \App\Models\User $user
- * @method static Builder|NodeOnlineUserIp newModelQuery()
- * @method static Builder|NodeOnlineUserIp newQuery()
- * @method static Builder|NodeOnlineUserIp query()
- * @method static Builder|NodeOnlineUserIp whereCreatedAt($value)
- * @method static Builder|NodeOnlineUserIp whereId($value)
- * @method static Builder|NodeOnlineUserIp whereIp($value)
- * @method static Builder|NodeOnlineUserIp whereNodeId($value)
- * @method static Builder|NodeOnlineUserIp wherePort($value)
- * @method static Builder|NodeOnlineUserIp whereType($value)
- * @method static Builder|NodeOnlineUserIp whereUserId($value)
- * @mixin \Eloquent
  */
 class NodeOnlineUserIp extends Model {
 	public $timestamps = false;
 	protected $table = 'ss_node_ip';
 
 	public function node(): BelongsTo {
-		return $this->belongsTo(Node::class, 'node_id', 'id');
+		return $this->belongsTo(Node::class);
 	}
 
 	public function user(): BelongsTo {
-		return $this->belongsTo(User::class, 'user_id', 'id');
+		return $this->belongsTo(User::class);
 	}
 }

+ 4 - 25
app/Models/NodePing.php

@@ -2,38 +2,17 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\HasOne;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 节点定时Ping测速
- *
- * @property int                        $id
- * @property int                        $node_id    对应节点id
- * @property int                        $ct         电信
- * @property int                        $cu         联通
- * @property int                        $cm         移动
- * @property int                        $hk         香港
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property-read \App\Models\Node|null $node
- * @method static Builder|NodePing newModelQuery()
- * @method static Builder|NodePing newQuery()
- * @method static Builder|NodePing query()
- * @method static Builder|NodePing whereCm($value)
- * @method static Builder|NodePing whereCreatedAt($value)
- * @method static Builder|NodePing whereCt($value)
- * @method static Builder|NodePing whereCu($value)
- * @method static Builder|NodePing whereHk($value)
- * @method static Builder|NodePing whereId($value)
- * @method static Builder|NodePing whereNodeId($value)
- * @mixin \Eloquent
  */
 class NodePing extends Model {
-	const UPDATED_AT = null;
+	public const UPDATED_AT = null;
 	protected $table = 'node_ping';
 
-	public function node(): HasOne {
-		return $this->hasOne(Node::class, 'id', 'node_id');
+	public function node(): BelongsTo {
+		return $this->belongsTo(Node::class);
 	}
 }

+ 0 - 18
app/Models/NodeRule.php

@@ -2,28 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 节点审计规则关联
- *
- * @property int                        $id
- * @property int|null                   $node_id    节点ID
- * @property int|null                   $rule_id    审计规则ID
- * @property int                        $is_black   是否黑名单模式:0-不是、1-是
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property \Illuminate\Support\Carbon $updated_at 最后更新时间
- * @method static Builder|NodeRule newModelQuery()
- * @method static Builder|NodeRule newQuery()
- * @method static Builder|NodeRule query()
- * @method static Builder|NodeRule whereCreatedAt($value)
- * @method static Builder|NodeRule whereId($value)
- * @method static Builder|NodeRule whereIsBlack($value)
- * @method static Builder|NodeRule whereNodeId($value)
- * @method static Builder|NodeRule whereRuleId($value)
- * @method static Builder|NodeRule whereUpdatedAt($value)
- * @mixin \Eloquent
  */
 class NodeRule extends Model {
 	protected $table = 'node_rule';

+ 0 - 24
app/Models/NotificationLog.php

@@ -2,34 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 推送通知日志
- *
- * @property int                        $id
- * @property int                        $type       类型:1-邮件、2-ServerChan、3-Bark、4-Telegram
- * @property string                     $address    收信地址
- * @property string                     $title      标题
- * @property string                     $content    内容
- * @property int                        $status     状态:-1发送失败、0-等待发送、1-发送成功
- * @property string|null                $error      发送失败抛出的异常信息
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property \Illuminate\Support\Carbon $updated_at 最后更新时间
- * @method static Builder|NotificationLog newModelQuery()
- * @method static Builder|NotificationLog newQuery()
- * @method static Builder|NotificationLog query()
- * @method static Builder|NotificationLog whereAddress($value)
- * @method static Builder|NotificationLog whereContent($value)
- * @method static Builder|NotificationLog whereCreatedAt($value)
- * @method static Builder|NotificationLog whereError($value)
- * @method static Builder|NotificationLog whereId($value)
- * @method static Builder|NotificationLog whereStatus($value)
- * @method static Builder|NotificationLog whereTitle($value)
- * @method static Builder|NotificationLog whereType($value)
- * @method static Builder|NotificationLog whereUpdatedAt($value)
- * @mixin \Eloquent
  */
 class NotificationLog extends Model {
 	protected $table = 'notification_log';

+ 40 - 54
app/Models/Order.php

@@ -3,78 +3,64 @@
 namespace App\Models;
 
 use Auth;
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasOne;
 
 /**
  * 订单
- *
- * @property int                             $oid
- * @property string                          $order_sn      订单编号
- * @property int                             $user_id       操作人
- * @property int                             $goods_id      商品ID
- * @property int                             $coupon_id     优惠券ID
- * @property int                             $origin_amount 订单原始总价,单位分
- * @property int                             $amount        订单总价,单位分
- * @property \Illuminate\Support\Carbon|null $expired_at    过期时间
- * @property int                             $is_expire     是否已过期:0-未过期、1-已过期
- * @property int                             $pay_type      支付渠道:0-余额、1-支付宝、2-QQ、3-微信、4-虚拟货币、5-paypal
- * @property string                          $pay_way       支付方式:balance、f2fpay、codepay、payjs、bitpayx等
- * @property int                             $status        订单状态:-1-已关闭、0-待支付、1-已支付待确认、2-已完成
- * @property \Illuminate\Support\Carbon      $created_at    创建时间
- * @property \Illuminate\Support\Carbon      $updated_at    最后更新时间
- * @property-read \App\Models\Coupon|null    $coupon
- * @property-read string                     $pay_type_icon
- * @property-read string                     $pay_type_label
- * @property-read string                     $pay_way_label
- * @property-read string                     $status_label
- * @property-read \App\Models\Goods|null     $goods
- * @property-read \App\Models\Payment|null   $payment
- * @property-read \App\Models\User|null      $user
- * @method static Builder|Order newModelQuery()
- * @method static Builder|Order newQuery()
- * @method static Builder|Order query()
- * @method static Builder|Order uid()
- * @method static Builder|Order whereAmount($value)
- * @method static Builder|Order whereCouponId($value)
- * @method static Builder|Order whereCreatedAt($value)
- * @method static Builder|Order whereExpiredAt($value)
- * @method static Builder|Order whereGoodsId($value)
- * @method static Builder|Order whereIsExpire($value)
- * @method static Builder|Order whereOid($value)
- * @method static Builder|Order whereOrderSn($value)
- * @method static Builder|Order whereOriginAmount($value)
- * @method static Builder|Order wherePayType($value)
- * @method static Builder|Order wherePayWay($value)
- * @method static Builder|Order whereStatus($value)
- * @method static Builder|Order whereUpdatedAt($value)
- * @method static Builder|Order whereUserId($value)
- * @mixin \Eloquent
  */
 class Order extends Model {
 	protected $table = 'order';
-	protected $primaryKey = 'oid';
 	protected $dates = ['expired_at'];
+	protected $fillable = ['expired_at', 'is_expire', 'status'];
 
-	public function scopeUid($query) {
-		return $query->whereUserId(Auth::id());
+	public function user(): BelongsTo {
+		return $this->belongsTo(User::class);
 	}
 
-	public function user(): HasOne {
-		return $this->hasOne(User::class, 'id', 'user_id');
+	public function goods(): BelongsTo {
+		return $this->belongsTo(Goods::class)->withTrashed();
 	}
 
-	public function goods(): HasOne {
-		return $this->hasOne(Goods::class, 'id', 'goods_id')->withTrashed();
+	public function coupon(): BelongsTo {
+		return $this->belongsTo(Coupon::class)->withTrashed();
 	}
 
-	public function coupon(): HasOne {
-		return $this->hasOne(Coupon::class, 'id', 'coupon_id')->withTrashed();
+	public function payment(): HasOne {
+		return $this->hasOne(Payment::class);
 	}
 
-	public function payment(): HasOne {
-		return $this->hasOne(Payment::class, 'oid', 'oid');
+	public function scopeUid($query, $uid = null) {
+		return $query->whereUserId($uid?: Auth::id());
+	}
+
+	public function scopeRecentUnPay($query) {
+		return $query->whereStatus(0)->where('created_at', '<=', date("Y-m-d H:i:s", strtotime("-15 minutes")));
+	}
+
+	public function scopeUserPrepay($query, $uid = null) {
+		return $query->uid($uid)->whereStatus(3);
+	}
+
+	public function scopeActive($query) {
+		return $query->whereIsExpire(0)->whereStatus(2);
+	}
+
+	public function scopeActivePlan($query) {
+		return $query->active()->with('goods')->whereHas('goods', static function($list) { $list->whereType(2); });
+	}
+
+	public function scopeActivePackage($query) {
+		return $query->active()->with('goods')->whereHas('goods', static function($list) { $list->whereType(1); });
+	}
+
+	public function scopeUserActivePlan($query, $uid = null) {
+		return $query->uid($uid)->activePlan();
+	}
+
+	public function scopeUserActivePackage($query, $uid = null) {
+		return $query->uid($uid)->activePackage();
 	}
 
 	// 订单状态

+ 3 - 32
app/Models/Payment.php

@@ -3,55 +3,26 @@
 namespace App\Models;
 
 use Auth;
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 支付单
- *
- * @property int                        $id
- * @property string                     $trade_no   支付单号(本地订单号)
- * @property int                        $user_id    用户ID
- * @property int                        $oid        本地订单ID
- * @property int                        $amount     金额,单位分
- * @property string|null                $qr_code    支付二维码
- * @property string|null                $url        支付链接
- * @property int                        $status     支付状态:-1-支付失败、0-等待支付、1-支付成功
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property \Illuminate\Support\Carbon $updated_at 最后更新时间
- * @property-read string                $status_label
- * @property-read \App\Models\Order     $order
- * @property-read \App\Models\User      $user
- * @method static Builder|Payment newModelQuery()
- * @method static Builder|Payment newQuery()
- * @method static Builder|Payment query()
- * @method static Builder|Payment uid()
- * @method static Builder|Payment whereAmount($value)
- * @method static Builder|Payment whereCreatedAt($value)
- * @method static Builder|Payment whereId($value)
- * @method static Builder|Payment whereOid($value)
- * @method static Builder|Payment whereQrCode($value)
- * @method static Builder|Payment whereStatus($value)
- * @method static Builder|Payment whereTradeNo($value)
- * @method static Builder|Payment whereUpdatedAt($value)
- * @method static Builder|Payment whereUrl($value)
- * @method static Builder|Payment whereUserId($value)
- * @mixin \Eloquent
  */
 class Payment extends Model {
 	protected $table = 'payment';
+	protected $fillable = ['qr_code', 'url', 'status'];
 
 	public function scopeUid($query) {
 		return $query->whereUserId(Auth::id());
 	}
 
 	public function user(): BelongsTo {
-		return $this->belongsTo(User::class, 'user_id', 'id');
+		return $this->belongsTo(User::class);
 	}
 
 	public function order(): BelongsTo {
-		return $this->belongsTo(Order::class, 'oid', 'oid');
+		return $this->belongsTo(Order::class);
 	}
 
 	public function getAmountAttribute($value) {

+ 0 - 21
app/Models/PaymentCallback.php

@@ -2,31 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 支付回调日志
- *
- * @property int                        $id
- * @property string                     $trade_no     本地订单号
- * @property string                     $out_trade_no 外部订单号(支付平台)
- * @property int                        $amount       交易金额,单位分
- * @property int                        $status       交易状态:0-失败、1-成功
- * @property \Illuminate\Support\Carbon $created_at   创建时间
- * @property \Illuminate\Support\Carbon $updated_at   最后更新时间
- * @property-read string                $status_label
- * @method static Builder|PaymentCallback newModelQuery()
- * @method static Builder|PaymentCallback newQuery()
- * @method static Builder|PaymentCallback query()
- * @method static Builder|PaymentCallback whereAmount($value)
- * @method static Builder|PaymentCallback whereCreatedAt($value)
- * @method static Builder|PaymentCallback whereId($value)
- * @method static Builder|PaymentCallback whereOutTradeNo($value)
- * @method static Builder|PaymentCallback whereStatus($value)
- * @method static Builder|PaymentCallback whereTradeNo($value)
- * @method static Builder|PaymentCallback whereUpdatedAt($value)
- * @mixin \Eloquent
  */
 class PaymentCallback extends Model {
 	protected $table = 'payment_callback';

+ 0 - 20
app/Models/ProductsPool.php

@@ -2,30 +2,10 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * 产品名称池
- *
- * @property int                        $id
- * @property string                     $name       名称
- * @property int                        $min_amount 适用最小金额,单位分
- * @property int                        $max_amount 适用最大金额,单位分
- * @property int                        $status     状态:0-未启用、1-已启用
- * @property \Illuminate\Support\Carbon $created_at 创建时间
- * @property \Illuminate\Support\Carbon $updated_at 最后更新时间
- * @method static Builder|ProductsPool newModelQuery()
- * @method static Builder|ProductsPool newQuery()
- * @method static Builder|ProductsPool query()
- * @method static Builder|ProductsPool whereCreatedAt($value)
- * @method static Builder|ProductsPool whereId($value)
- * @method static Builder|ProductsPool whereMaxAmount($value)
- * @method static Builder|ProductsPool whereMinAmount($value)
- * @method static Builder|ProductsPool whereName($value)
- * @method static Builder|ProductsPool whereStatus($value)
- * @method static Builder|ProductsPool whereUpdatedAt($value)
- * @mixin \Eloquent
  */
 class ProductsPool extends Model {
 	protected $table = 'products_pool';

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно